output: Introduce pivot tables.
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 17 Jul 2017 22:13:16 +0000 (15:13 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 1 Jan 2019 06:20:16 +0000 (22:20 -0800)
123 files changed:
Smake
doc/statistics.texi
doc/tutorial.texi
doc/utilities.texi
perl-module/t/Pspp.t
src/data/settings.c
src/data/settings.h
src/data/variable.c
src/language/data-io/data-parser.c
src/language/data-io/dataset.c
src/language/data-io/list.c
src/language/data-io/print.c
src/language/dictionary/mrsets.c
src/language/dictionary/split-file.c
src/language/dictionary/sys-file-info.c
src/language/stats/binomial.c
src/language/stats/chisquare.c
src/language/stats/cochran.c
src/language/stats/correlations.c
src/language/stats/crosstabs.q
src/language/stats/descriptives.c
src/language/stats/examine.c
src/language/stats/factor.c
src/language/stats/frequencies.c
src/language/stats/friedman.c
src/language/stats/glm.c
src/language/stats/graph.c
src/language/stats/jonckheere-terpstra.c
src/language/stats/kruskal-wallis.c
src/language/stats/ks-one-sample.c
src/language/stats/logistic.c
src/language/stats/mann-whitney.c
src/language/stats/mcnemar.c
src/language/stats/means.c
src/language/stats/median.c
src/language/stats/npar-summary.c
src/language/stats/npar-summary.h
src/language/stats/npar.c
src/language/stats/oneway.c
src/language/stats/quick-cluster.c
src/language/stats/rank.c
src/language/stats/regression.c
src/language/stats/reliability.c
src/language/stats/roc.c
src/language/stats/runs.c
src/language/stats/sign.c
src/language/stats/t-test-indep.c
src/language/stats/t-test-one-sample.c
src/language/stats/t-test-paired.c
src/language/stats/wilcoxon.c
src/language/utilities/output.c
src/language/utilities/set.q
src/math/categoricals.c
src/math/categoricals.h
src/math/covariance.c
src/math/covariance.h
src/math/interaction.c
src/output/ascii.c
src/output/automake.mk
src/output/cairo.c
src/output/html.c
src/output/odt.c
src/output/pivot-output.c [new file with mode: 0644]
src/output/pivot-table.c [new file with mode: 0644]
src/output/pivot-table.h [new file with mode: 0644]
src/output/tab.c
src/output/tab.h
src/output/table-casereader.c [deleted file]
src/output/table.c
src/output/table.h
src/ui/gui/psppire-output-window.c
tests/automake.mk
tests/data/pc+-file-reader.at
tests/data/por-file.at
tests/data/sys-file-reader.at
tests/data/sys-file.at
tests/language/data-io/data-list.at
tests/language/data-io/dataset.at
tests/language/data-io/get-data-psql.at
tests/language/data-io/get-data-spreadsheet.at
tests/language/data-io/get-data-txt.at
tests/language/data-io/list.at
tests/language/data-io/matrix-data.at
tests/language/data-io/save.at
tests/language/dictionary/attributes.at
tests/language/dictionary/mrsets.at
tests/language/dictionary/split-file.at
tests/language/dictionary/sys-file-info.at
tests/language/dictionary/value-labels.at
tests/language/dictionary/variable-display.at
tests/language/dictionary/vector.at
tests/language/dictionary/weight.at
tests/language/expressions/evaluate.at
tests/language/lexer/variable-parser.at
tests/language/stats/aggregate.at
tests/language/stats/autorecode.at
tests/language/stats/correlations.at
tests/language/stats/crosstabs.at
tests/language/stats/descriptives.at
tests/language/stats/examine.at
tests/language/stats/factor.at
tests/language/stats/flip.at
tests/language/stats/frequencies.at
tests/language/stats/glm.at
tests/language/stats/logistic.at
tests/language/stats/means.at
tests/language/stats/npar.at
tests/language/stats/oneway.at
tests/language/stats/quick-cluster.at
tests/language/stats/rank.at
tests/language/stats/regression.at
tests/language/stats/reliability.at
tests/language/stats/roc.at
tests/language/stats/t-test.at
tests/language/utilities/set.at
tests/language/utilities/title.at
tests/language/xforms/compute.at
tests/language/xforms/count.at
tests/language/xforms/recode.at
tests/output/ascii.at
tests/output/render.at
tests/output/tables.at
tests/perl-module.at

diff --git a/Smake b/Smake
index 91b4230f5cc2b040165449d769e8ef3fd4e5c17c..5669ad079fdac5db1c454681b25f5ffe04789984 100644 (file)
--- a/Smake
+++ b/Smake
@@ -70,6 +70,7 @@ GNULIB_MODULES = \
        memcasecmp \
        memchr \
        memchr2 \
+       memmem \
        mempcpy \
        memrchr \
        minmax \
index c46189bd0709394fe2552ee9783915126c9442a3..9e9ed9081bd603db13641fccd8dbfce416656af0 100644 (file)
@@ -70,11 +70,8 @@ excluded on a variable by variable basis; if @subcmd{LISTWISE} is set, then
 the entire case is excluded whenever any value in that case has a
 system-missing or, if @subcmd{INCLUDE} is set, user-missing value.
 
-The @subcmd{FORMAT} subcommand affects the output format.  Currently the
-@subcmd{LABELS/NOLABELS} and @subcmd{NOINDEX/INDEX} settings are not used.
-When @subcmd{SERIAL} is
-set, both valid and missing number of cases are listed in the output;
-when @subcmd{NOSERIAL} is set, only valid cases are listed.
+The @subcmd{FORMAT} subcommand has no effect.  It is accepted for
+backward compatibility.
 
 The @subcmd{SAVE} subcommand causes @cmd{DESCRIPTIVES} to calculate Z scores for all
 the specified variables.  The Z scores are saved to new variables.
@@ -646,8 +643,7 @@ When set to @subcmd{TABLE}, the default, missing values are dropped on a table b
 table basis.  When set to @subcmd{INCLUDE}, user-missing values are included in
 tables and statistics.  When set to @subcmd{REPORT}, which is allowed only in
 integer mode, user-missing values are included in tables but marked with
-an @samp{M} (for ``missing'') and excluded from statistical
-calculations.
+a footnote and excluded from statistical calculations.
 
 Currently the @subcmd{WRITE} subcommand is ignored.
 
index 47f22cc10323bd49ba520919a63290e0c35fefe3..c6928c810c187def008b7a9456a62a2f0865fa91 100644 (file)
@@ -197,12 +197,15 @@ shown along with the data.
 It should show the following output:
 @example
 @group
-Case#     forename   height
------ ------------ --------
-    1 Ahmed          188.00 
-    2 Bertram        167.00 
-    3 Catherine      134.23 
-    4 David          109.10 
+           Data List
++-----------+---------+------+
+|Case Number| forename|height|
++-----------+---------+------+
+|1          |Ahmed    |188.00|
+|2          |Bertram  |167.00|
+|3          |Catherine|134.23|
+|4          |David    |109.10|
++-----------+---------+------+
 @end group
 @end example
 @noindent
@@ -350,14 +353,16 @@ data and identify the erroneous values.
 
 Output:
 @example
-DESCRIPTIVES.  Valid cases = 40; cases with missing value(s) = 0.
-+--------#--+-------+-------+-------+-------+
-|Variable# N|  Mean |Std Dev|Minimum|Maximum|
-#========#==#=======#=======#=======#=======#
-|sex     #40|    .45|    .50|    .00|   1.00|
-|height  #40|1677.12| 262.87| 179.00|1903.00|
-|weight  #40|  72.12|  26.70| -55.60|  92.07|
-+--------#--+-------+-------+-------+-------+
+                  Descriptive Statistics
++---------------------+--+-------+-------+-------+-------+
+|                     | N|  Mean |Std Dev|Minimum|Maximum|
++---------------------+--+-------+-------+-------+-------+
+|Sex of subject       |40|    .45|    .50|Male   |Female |
+|Weight in kilograms  |40|  72.12|  26.70|  -55.6|   92.1|
+|Height in millimeters|40|1677.12| 262.87|    179|   1903|
+|Valid N (listwise)   |40|       |       |       |       |
+|Missing N (listwise) | 0|       |       |       |       |
++---------------------+--+-------+-------+-------+-------+
 @end example
 @end cartouche
 @caption{Using the @cmd{DESCRIPTIVES} command to display simple 
@@ -395,25 +400,24 @@ represent data entry errors.
 
 Output:
 @example
-#===============================#===========#=======#
-#                               #Case Number| Value #
-#===============================#===========#=======#
-#Height in millimetres Highest 1#         14|1903.00#
-#                              2#         15|1884.00#
-#                              3#         12|1801.65#
-#                     ----------#-----------+-------#
-#                       Lowest 1#         30| 179.00#
-#                              2#         31|1598.00#
-#                              3#         28|1601.00#
-#                     ----------#-----------+-------#
-#Weight in kilograms   Highest 1#         13|  92.07#
-#                              2#          5|  92.07#
-#                              3#         17|  91.74#
-#                     ----------#-----------+-------#
-#                       Lowest 1#         38| -55.60#
-#                              2#         39|  54.48#
-#                              3#         33|  55.45#
-#===============================#===========#=======#
+                   Extreme Values
++-------------------------------+-----------+-----+
+|                               |Case Number|Value|
++-------------------------------+-----------+-----+
+|Height in millimeters Highest 1|         14| 1903|
+|                              2|         15| 1884|
+|                              3|         12| 1802|
+|                      Lowest  1|         30|  179|
+|                              2|         31| 1598|
+|                              3|         28| 1601|
++-------------------------------+-----------+-----+
+|Weight in kilograms   Highest 1|         13| 92.1|
+|                              2|          5| 92.1|
+|                              3|         17| 91.7|
+|                      Lowest  1|         38|-55.6|
+|                              2|         39| 54.5|
+|                              3|         33| 55.4|
++-------------------------------+-----------+-----+
 @end example
 @end cartouche
 @caption{Using the @cmd{EXAMINE} command to see the extremities of the data
@@ -523,21 +527,23 @@ negatively scaled variables) requests reliability statistics for
 
 Output (dictionary information omitted for clarity):
 @example
-1.1 RELIABILITY.  Case Processing Summary
-#==============#==#======#
-#              # N|   %  #
-#==============#==#======#
-#Cases Valid   #17|100.00#
-#      Excluded# 0|   .00#
-#      Total   #17|100.00#
-#==============#==#======#
-
-1.2 RELIABILITY.  Reliability Statistics
-#================#==========#
-#Cronbach's Alpha#N of Items#
-#================#==========#
-#             .81#         3#
-#================#==========#
+Scale: ANY
+
+Case Processing Summary
++--------+--+-------+
+|Cases   | N|Percent|
++--------+--+-------+
+|Valid   |17| 100.0%|
+|Excluded| 0|    .0%|
+|Total   |17| 100.0%|
++--------+--+-------+
+
+    Reliability Statistics
++----------------+----------+
+|Cronbach's Alpha|N of Items|
++----------------+----------+
+|             .81|         3|
++----------------+----------+
 @end example
 @end cartouche
 @caption{Recoding negatively scaled variables, and testing for
@@ -606,43 +612,66 @@ an appropriate non-parametric test instead of a linear one.
 
 Output:
 @example
-1.2 EXAMINE.  Descriptives
-#====================================================#=========#==========#
-#                                                    #Statistic|Std. Error#
-#====================================================#=========#==========#
-#mtbf    Mean                                        #   8.32  |   1.62   #
-#        95% Confidence Interval for Mean Lower Bound#   4.85  |          #
-#                                         Upper Bound#  11.79  |          #
-#        5% Trimmed Mean                             #   7.69  |          #
-#        Median                                      #   8.12  |          #
-#        Variance                                    #  39.21  |          #
-#        Std. Deviation                              #   6.26  |          #
-#        Minimum                                     #   1.63  |          #
-#        Maximum                                     #  26.47  |          #
-#        Range                                       #  24.84  |          #
-#        Interquartile Range                         #   5.83  |          #
-#        Skewness                                    #   1.85  |    .58   #
-#        Kurtosis                                    #   4.49  |   1.12   #
-#====================================================#=========#==========#
-
-2.2 EXAMINE.  Descriptives
-#====================================================#=========#==========#
-#                                                    #Statistic|Std. Error#
-#====================================================#=========#==========#
-#mtbf_ln Mean                                        #   1.88  |    .19   #
-#        95% Confidence Interval for Mean Lower Bound#   1.47  |          #
-#                                         Upper Bound#   2.29  |          #
-#        5% Trimmed Mean                             #   1.88  |          #
-#        Median                                      #   2.09  |          #
-#        Variance                                    #   .54   |          #
-#        Std. Deviation                              #   .74   |          #
-#        Minimum                                     #   .49   |          #
-#        Maximum                                     #   3.28  |          #
-#        Range                                       #   2.79  |          #
-#        Interquartile Range                         #   .92   |          #
-#        Skewness                                    #   -.16  |    .58   #
-#        Kurtosis                                    #   -.09  |   1.12   #
-#====================================================#=========#==========#
+                       Case Processing Summary
++-----------------------------------+-------------------------------+
+|                                   |             Cases             |
+|                                   +----------+---------+----------+
+|                                   |   Valid  | Missing |   Total  |
+|                                   | N|Percent|N|Percent| N|Percent|
++-----------------------------------+--+-------+-+-------+--+-------+
+|Mean time between failures (months)|15| 100.0%|0|    .0%|15| 100.0%|
++-----------------------------------+--+-------+-+-------+--+-------+
+
+                                  Descriptives
++----------------------------------------------------------+---------+--------+
+|                                                          |         |  Std.  |
+|                                                          |Statistic|  Error |
++----------------------------------------------------------+---------+--------+
+|Mean time between        Mean                             |     8.32|    1.62|
+|failures (months)        95% Confidence Interval Lower    |     4.85|        |
+|                         for Mean                Bound    |         |        |
+|                                                 Upper    |    11.79|        |
+|                                                 Bound    |         |        |
+|                         5% Trimmed Mean                  |     7.69|        |
+|                         Median                           |     8.12|        |
+|                         Variance                         |    39.21|        |
+|                         Std. Deviation                   |     6.26|        |
+|                         Minimum                          |     1.63|        |
+|                         Maximum                          |    26.47|        |
+|                         Range                            |    24.84|        |
+|                         Interquartile Range              |     5.83|        |
+|                         Skewness                         |     1.85|     .58|
+|                         Kurtosis                         |     4.49|    1.12|
++----------------------------------------------------------+---------+--------+
+
+         Case Processing Summary
++-------+-------------------------------+
+|       |             Cases             |
+|       +----------+---------+----------+
+|       |   Valid  | Missing |   Total  |
+|       | N|Percent|N|Percent| N|Percent|
++-------+--+-------+-+-------+--+-------+
+|mtbf_ln|15| 100.0%|0|    .0%|15| 100.0%|
++-------+--+-------+-+-------+--+-------+
+
+                                Descriptives
++----------------------------------------------------+---------+----------+
+|                                                    |Statistic|Std. Error|
++----------------------------------------------------+---------+----------+
+|mtbf_ln Mean                                        |     1.88|       .19|
+|        95% Confidence Interval for Mean Lower Bound|     1.47|          |
+|                                         Upper Bound|     2.29|          |
+|        5% Trimmed Mean                             |     1.88|          |
+|        Median                                      |     2.09|          |
+|        Variance                                    |      .54|          |
+|        Std. Deviation                              |      .74|          |
+|        Minimum                                     |      .49|          |
+|        Maximum                                     |     3.28|          |
+|        Range                                       |     2.79|          |
+|        Interquartile Range                         |      .92|          |
+|        Skewness                                    |     -.16|       .58|
+|        Kurtosis                                    |     -.09|      1.12|
++----------------------------------------------------+---------+----------+
 @end example
 @end cartouche
 @caption{Testing for normality using the @cmd{EXAMINE} command and applying
@@ -752,28 +781,82 @@ suggest that the body temperature of male and female persons are different.
 @end example
 Output:
 @example
-1.1 T-TEST.  Group Statistics
-#==================#==#=======#==============#========#
-#              sex | N|  Mean |Std. Deviation|SE. Mean#
-#==================#==#=======#==============#========#
-#height      Male  |22|1796.49|         49.71|   10.60#
-#            Female|17|1610.77|         25.43|    6.17#
-#temperature Male  |22|  36.68|          1.95|     .42#
-#            Female|18|  37.43|          1.61|     .38#
-#==================#==#=======#==============#========#
-1.2 T-TEST.  Independent Samples Test
-#===========================#=========#===============================   =#
-#                           # Levene's| t-test for Equality of Means      #
-#                           #----+----+------+-----+------+---------+-   -#
-#                           #    |    |      |     |      |         |     #
-#                           #    |    |      |     |Sig. 2|         |     #
-#                           #  F |Sig.|   t  |  df |tailed|Mean Diff|     #
-#===========================#====#====#======#=====#======#=========#=   =#
-#height      Equal variances# .97| .33| 14.02|37.00|   .00|   185.72| ... #
-#          Unequal variances#    |    | 15.15|32.71|   .00|   185.72| ... #
-#temperature Equal variances# .31| .58| -1.31|38.00|   .20|     -.75| ... #
-#          Unequal variances#    |    | -1.33|37.99|   .19|     -.75| ... #
-#===========================#====#====#======#=====#======#=========#=   =#
+                                Group Statistics
++-------------------------------------------+--+-------+-------------+--------+
+|                                           |  |       |     Std.    |  S.E.  |
+|                                     Group | N|  Mean |  Deviation  |  Mean  |
++-------------------------------------------+--+-------+-------------+--------+
+|Height in millimeters                Male  |22|1796.49|        49.71|   10.60|
+|                                     Female|17|1610.77|        25.43|    6.17|
++-------------------------------------------+--+-------+-------------+--------+
+|Internal body temperature in degrees Male  |22|  36.68|         1.95|     .42|
+|Celcius                              Female|18|  37.43|         1.61|     .38|
++-------------------------------------------+--+-------+-------------+--------+
+
+                          Independent Samples Test
++---------------------+-----------------------------------------------------
+|                     | Levene's
+|                     | Test for
+|                     | Equality
+|                     |    of
+|                     | Variances               T-Test for Equality of Means
+|                     +----+-----+-----+-----+-------+----------+----------+
+|                     |    |     |     |     |       |          |          |
+|                     |    |     |     |     |       |          |          |
+|                     |    |     |     |     |       |          |          |
+|                     |    |     |     |     |       |          |          |
+|                     |    |     |     |     |  Sig. |          |          |
+|                     |    |     |     |     |  (2-  |   Mean   |Std. Error|
+|                     |  F | Sig.|  t  |  df |tailed)|Difference|Difference|
++---------------------+----+-----+-----+-----+-------+----------+----------+
+|Height in   Equal    | .97| .331|14.02|37.00|   .000|    185.72|     13.24|
+|millimeters variances|    |     |     |     |       |          |          |
+|            assumed  |    |     |     |     |       |          |          |
+|            Equal    |    |     |15.15|32.71|   .000|    185.72|     12.26|
+|            variances|    |     |     |     |       |          |          |
+|            not      |    |     |     |     |       |          |          |
+|            assumed  |    |     |     |     |       |          |          |
++---------------------+----+-----+-----+-----+-------+----------+----------+
+|Internal    Equal    | .31| .581|-1.31|38.00|   .198|      -.75|       .57|
+|body        variances|    |     |     |     |       |          |          |
+|temperature assumed  |    |     |     |     |       |          |          |
+|in degrees  Equal    |    |     |-1.33|37.99|   .190|      -.75|       .56|
+|Celcius     variances|    |     |     |     |       |          |          |
+|            not      |    |     |     |     |       |          |          |
+|            assumed  |    |     |     |     |       |          |          |
++---------------------+----+-----+-----+-----+-------+----------+----------+
+
++---------------------+-------------+
+|                     |             |
+|                     |             |
+|                     |             |
+|                     |             |
+|                     |             |
+|                     +-------------+
+|                     |     95%     |
+|                     |  Confidence |
+|                     | Interval of |
+|                     |     the     |
+|                     |  Difference |
+|                     +------+------+
+|                     | Lower| Upper|
++---------------------+------+------+
+|Height in   Equal    |158.88|212.55|
+|millimeters variances|      |      |
+|            assumed  |      |      |
+|            Equal    |160.76|210.67|
+|            variances|      |      |
+|            not      |      |      |
+|            assumed  |      |      |
++---------------------+------+------+
+|Internal    Equal    | -1.91|   .41|
+|body        variances|      |      |
+|temperature assumed  |      |      |
+|in degrees  Equal    | -1.89|   .39|
+|Celcius     variances|      |      |
+|            not      |      |      |
+|            assumed  |      |      |
++---------------------+------+------+
 @end example                                                          
 @end cartouche
 @caption{The @cmd{T-TEST} command tests for differences of means. 
@@ -816,44 +899,33 @@ identifies the potential linear relationship. @xref{REGRESSION}.
 @prompt{PSPP>} regression /variables = mtbf duty_cycle /dependent = mttr.
 @prompt{PSPP>} regression /variables = mtbf /dependent = mttr.
 @end example
-Output:
+Output (excerpts):
 @example
-1.3(1) REGRESSION.  Coefficients
-#=============================================#====#==========#====#=====#
-#                                             #  B |Std. Error|Beta|  t  #
-#========#====================================#====#==========#====#=====#
-#        |(Constant)                          #9.81|      1.50| .00| 6.54#
-#        |Mean time between failures (months) #3.10|       .10| .99|32.43#
-#        |Ratio of working to non-working time#1.09|      1.78| .02|  .61#
-#        |                                    #    |          |    |     #
-#========#====================================#====#==========#====#=====#
-
-1.3(2) REGRESSION.  Coefficients
-#=============================================#============#
-#                                             #Significance#
-#========#====================================#============#
-#        |(Constant)                          #         .10#
-#        |Mean time between failures (months) #         .00#
-#        |Ratio of working to non-working time#         .55#
-#        |                                    #            #
-#========#====================================#============#
-2.3(1) REGRESSION.  Coefficients
-#============================================#=====#==========#====#=====#
-#                                            #  B  |Std. Error|Beta|  t  #
-#========#===================================#=====#==========#====#=====#
-#        |(Constant)                         #10.50|       .96| .00|10.96#
-#        |Mean time between failures (months)# 3.11|       .09| .99|33.39#
-#        |                                   #     |          |    |     #
-#========#===================================#=====#==========#====#=====#
-
-2.3(2) REGRESSION.  Coefficients
-#============================================#============#
-#                                            #Significance#
-#========#===================================#============#
-#        |(Constant)                         #         .06#
-#        |Mean time between failures (months)#         .00#
-#        |                                   #            #
-#========#===================================#============#
+                  Coefficients (Mean time to repair (hours) )
++------------------------+-----------------------------------------+-----+----+
+|                        |    Unstandardized        Standardized   |     |    |
+|                        |     Coefficients         Coefficients   |     |    |
+|                        +---------+-----------+-------------------+     |    |
+|                        |    B    | Std. Error|        Beta       |  t  |Sig.|
++------------------------+---------+-----------+-------------------+-----+----+
+|(Constant)              |     9.81|       1.50|                .00| 6.54|.000|
+|Mean time between       |     3.10|        .10|                .99|32.43|.000|
+|failures (months)       |         |           |                   |     |    |
+|Ratio of working to non-|     1.09|       1.78|                .02|  .61|.552|
+|working time            |         |           |                   |     |    |
++------------------------+---------+-----------+-------------------+-----+----+
+
+                  Coefficients (Mean time to repair (hours) )
++-----------------------+------------------------------------------+-----+----+
+|                       |    Unstandardized         Standardized   |     |    |
+|                       |     Coefficients          Coefficients   |     |    |
+|                       +---------+------------+-------------------+     |    |
+|                       |    B    | Std. Error |        Beta       |  t  |Sig.|
++-----------------------+---------+------------+-------------------+-----+----+
+|(Constant)             |    10.50|         .96|                .00|10.96|.000|
+|Mean time between      |     3.11|         .09|                .99|33.39|.000|
+|failures (months)      |         |            |                   |     |    |
++-----------------------+---------+------------+-------------------+-----+----+
 @end example
 @end cartouche
 @caption{Linear regression analysis to find a predictor for
index c2dba0e4799653cba2f1a874c40b369a143b03a8..598431d5efa43c40daf960dcfaa4bb5b549b4b01 100644 (file)
@@ -353,7 +353,7 @@ otherwise it is @code{Auto}.
 @display
 OUTPUT MODIFY
        /SELECT TABLES
-       /TABLECELLS SELECT = [ @{SIGNIFICANCE, COUNT@} ]
+       /TABLECELLS SELECT = [ @var{class}... ]
                    FORMAT = @var{fmt_spec}.
 @end display
 @note{In the above synopsis the characters @samp{[} and @samp{]} are literals.
@@ -370,13 +370,27 @@ brackets.  This list determines the classes of values should be selected for mod
 Each class can be:
 
 @table @asis
+@item RESIDUAL
+Residual values.  Default: @t{F40.2}.
+
+@item CORRELATION
+Correlations.  Default: @t{F40.3}.
+
+@item PERCENT
+Percentages.  Default: @t{PCT40.1}.
+
 @item SIGNIFICANCE
-Significance of tests (p-values).
+Significance of tests (p-values).  Default: @t{F40.3}.
 
 @item COUNT
-Counts or sums of weights.
+Counts or sums of weights.  For a weighted data set, the default is
+the weight variable's print format.  For an unweighted data set, the
+default is F40.0.
 @end table
 
+For most other numeric values that appear in tables, @code{SET FORMAT}
+may be used to specify the format (@pxref{SET FORMAT}).
+
 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.
 
@@ -531,6 +545,7 @@ as a field separator in the @cmd{DATA LIST} command (@pxref{DATA LIST}).
 The default value is determined from the system locale.
 
 @item FORMAT
+@anchor{SET FORMAT}
 Allows the default numeric input/output format to be specified.  The
 default is F8.2.  @xref{Input and Output Formats}.
 
index f7ff632cf78fdf4407a420a00db7293b62170b74..61ed4616b95e9a10f4f526fcac1f8075985d3284 100644 (file)
@@ -180,15 +180,15 @@ Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Fo
 id,1,,Scale,Input,8,Right,F2.0,F2.0,
 name,2,,Nominal,Input,20,Left,A20,A20,
 
-File label: This is the file label
-
-Documents in the active dataset:
+Table: File Label
+Label,This is the file label
 
+Table: Documents
 This is a document line
 
 Table: Data List
 id,name
-21,wheelbarrow         
+21,wheelbarrow
 RESULT
 
 
@@ -251,13 +251,13 @@ string,2,My String,Nominal,Input,8,Left,A8,A8,"""this    ""; ""that    """
 longstring,3,My Long String,Nominal,Input,9,Left,A9,A9,
 
 Table: Value Labels
-Variable,Value,Label
-integer,0,Zero
+Variable Value,,Label
+My Integer,0,Zero
 ,1,Unity
 ,2,Duality
-string,xx      ,foo
-,yy      ,bar
-longstring,xxx      ,xfoo
+My String,xx,foo
+,yy,bar
+My Long String,xxx,xfoo
 RESULT
 
   }
index 114200cf060d5a4ed0d5adc2c910f2a3e81b0c42..f4efb99fa84ee0d4eedd18236f72db9c6b363954 100644 (file)
@@ -76,8 +76,8 @@ struct settings
 
   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
 
-  enum settings_var_style var_output_style;
-  enum settings_value_style value_output_style;
+  enum settings_value_show show_values;
+  enum settings_value_show show_variables;
 };
 
 static struct settings the_settings = {
@@ -121,8 +121,8 @@ static struct settings the_settings = {
    0,
    SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL},
 
-  SETTINGS_VAR_STYLE_LABELS,
-  SETTINGS_VAL_STYLE_LABELS
+  SETTINGS_VALUE_SHOW_LABEL,
+  SETTINGS_VALUE_SHOW_LABEL
 };
 
 /* Initializes the settings module. */
@@ -707,29 +707,27 @@ settings_get_output_routing (enum settings_output_type type)
   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
 }
 
-enum settings_value_style
-settings_get_value_style (void)
+enum settings_value_show
+settings_get_show_values (void)
 {
-  return the_settings.value_output_style;
+  return the_settings.show_values;
 }
 
 void
-settings_set_value_style (enum settings_value_style s)
+settings_set_show_values (enum settings_value_show s)
 {
-  the_settings.value_output_style = s;
+  the_settings.show_values = s;
 }
 
 
-
-enum settings_var_style
-settings_get_var_style (void)
+enum settings_value_show
+settings_get_show_variables (void)
 {
-  return the_settings.var_output_style;
+  return the_settings.show_variables;
 }
 
-
 void
-settings_set_var_style (enum settings_var_style s)
+settings_set_show_variables (enum settings_value_show s)
 {
-  the_settings.var_output_style = s;
+  the_settings.show_variables = s;
 }
index c499293ebb54a49648297af98ce35119295c7b0d..cc16576d31054e21670f3a3b42457654399f647e 100644 (file)
@@ -105,26 +105,26 @@ void settings_set_testing_mode (bool);
 int settings_get_fuzzbits (void);
 void settings_set_fuzzbits (int);
 
-enum settings_var_style
+/* Whether to show variable or value labels or the underlying value or variable
+   name. */
+enum settings_value_show
   {
-    SETTINGS_VAR_STYLE_NAMES,
-    SETTINGS_VAR_STYLE_LABELS,
-    SETTINGS_VAR_STYLE_BOTH
+    /* Use higher-level default.
+       In a pivot_value, the default is taken from the pivot_table.
+       In a pivot_table, the default is a global default.
+       As a global default, this is invalid. */
+    SETTINGS_VALUE_SHOW_DEFAULT = 0,
+
+    SETTINGS_VALUE_SHOW_VALUE = 1, /* Show value or variable name only. */
+    SETTINGS_VALUE_SHOW_LABEL = 2, /* Show label only. */
+    SETTINGS_VALUE_SHOW_BOTH = 3,  /* Show both value/name and label. */
   };
 
-enum settings_value_style
-  {
-    SETTINGS_VAL_STYLE_VALUES,
-    SETTINGS_VAL_STYLE_LABELS,
-    SETTINGS_VAL_STYLE_BOTH
-  };
-
-
-enum settings_value_style settings_get_value_style (void);
-enum settings_var_style settings_get_var_style (void);
+enum settings_value_show settings_get_show_values (void);
+enum settings_value_show settings_get_show_variables (void);
 
-void settings_set_value_style (enum settings_value_style s);
-void settings_set_var_style (enum settings_var_style s);
+void settings_set_show_values (enum settings_value_show);
+void settings_set_show_variables (enum settings_value_show);
 
 
 enum behavior_mode {
index 14b122fee0eb1d2cdbe95b1fbc22bfa6757dbfda..25b3228de345fb1399440586c85059bb77be9358 100644 (file)
@@ -571,33 +571,28 @@ void
 var_append_value_name (const struct variable *v, const union value *value,
                       struct string *str)
 {
-  enum settings_value_style style = settings_get_value_style ();
-  const char *name = var_lookup_value_label (v, value);
+  const char *label = var_lookup_value_label (v, value);
 
-  switch (style)
+  switch (settings_get_show_values ())
     {
-    case SETTINGS_VAL_STYLE_VALUES:
+    case SETTINGS_VALUE_SHOW_VALUE:
       append_value (v, value, str);
       break;
 
-    case SETTINGS_VAL_STYLE_LABELS:
-      if (name == NULL)
-       append_value (v, value, str);
+    default:
+    case SETTINGS_VALUE_SHOW_LABEL:
+      if (label)
+       ds_put_cstr (str, label);
       else
-       ds_put_cstr (str, name);
+       append_value (v, value, str);
       break;
 
-    case SETTINGS_VAL_STYLE_BOTH:
-    default:
+    case SETTINGS_VALUE_SHOW_BOTH:
       append_value (v, value, str);
-      if (name != NULL)
-       {
-         ds_put_cstr (str, " (");
-         ds_put_cstr (str, name);
-         ds_put_cstr (str, ")");
-       }
+      if (label != NULL)
+        ds_put_format (str, " %s", label);
       break;
-    };
+    }
 }
 \f
 /* Print and write formats. */
@@ -720,24 +715,19 @@ update_vl_string (const struct variable *v)
 const char *
 var_to_string (const struct variable *v)
 {
-  enum settings_var_style style = settings_get_var_style ();
-
-  switch (style)
-  {
-    case SETTINGS_VAR_STYLE_NAMES:
+  switch (settings_get_show_variables ())
+    {
+    case SETTINGS_VALUE_SHOW_VALUE:
       return v->name;
-      break;
-    case SETTINGS_VAR_STYLE_LABELS:
+
+    case SETTINGS_VALUE_SHOW_LABEL:
+    default:
       return v->label != NULL ? v->label : v->name;
-      break;
-    case SETTINGS_VAR_STYLE_BOTH:
+
+    case SETTINGS_VALUE_SHOW_BOTH:
       update_vl_string (v);
       return ds_cstr (&v->name_and_label);
-      break;
-    default:
-      NOT_REACHED ();
-      break;
-  };
+    }
 }
 
 /* Returns V's variable label, or a null pointer if it has none. */
index 1d8a493e0db49e54b96f0d1063fd5ab69f6bc95f..d223b05304ae06e18bad367b00348ac53401b115 100644 (file)
 #include "language/data-io/data-reader.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 /* Data parser for textual data like that read by DATA LIST. */
@@ -664,37 +665,48 @@ static void
 dump_fixed_table (const struct data_parser *parser,
                   const struct file_handle *fh)
 {
-  struct tab_table *t;
-  size_t i;
-
-  t = tab_create (4, parser->field_cnt + 1);
-  tab_headers (t, 0, 0, 1, 0);
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
-  tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, parser->field_cnt);
-  tab_hline (t, TAL_2, 0, 3, 1);
-
-  for (i = 0; i < parser->field_cnt; i++)
+  /* XXX This should not be preformatted. */
+  char *title = xasprintf (ngettext ("Reading %d record from %s.",
+                                     "Reading %d records from %s.",
+                                     parser->records_per_case),
+                           parser->records_per_case, fh_get_name (fh));
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_user_text (title, -1));
+  free (title);
+
+  pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Attributes"),
+    N_("Record"), N_("Columns"), N_("Format"));
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+  variables->root->show_label = true;
+  for (size_t i = 0; i < parser->field_cnt; i++)
     {
       struct field *f = &parser->fields[i];
-      char fmt_string[FMT_STRING_LEN_MAX + 1];
-      int row = i + 1;
-
-      tab_text (t, 0, row, TAB_LEFT, f->name);
-      tab_text_format (t, 1, row, 0, "%d", f->record);
-      tab_text_format (t, 2, row, 0, "%3d-%3d",
-                       f->first_column, f->first_column + f->format.w - 1);
-      tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
-                fmt_to_string (&f->format, fmt_string));
+
+      /* XXX It would be better to have the actual variable here. */
+      int variable_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_user_text (f->name, -1));
+
+      pivot_table_put2 (table, 0, variable_idx,
+                        pivot_value_new_integer (f->record));
+
+      int first_column = f->first_column;
+      int last_column = f->first_column + f->format.w - 1;
+      char *columns = xasprintf ("%3d-%3d", first_column, last_column);
+      pivot_table_put2 (table, 1, variable_idx,
+                        pivot_value_new_user_text (columns, -1));
+      free (columns);
+
+      char str[FMT_STRING_LEN_MAX + 1];
+      pivot_table_put2 (table, 2, variable_idx,
+                        pivot_value_new_user_text (
+                          fmt_to_string (&f->format, str), -1));
+
     }
 
-  tab_title (t, ngettext ("Reading %d record from %s.",
-                          "Reading %d records from %s.",
-                          parser->records_per_case),
-             parser->records_per_case, fh_get_name (fh));
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 /* Displays a table giving information on free-format variable parsing
@@ -703,30 +715,31 @@ static void
 dump_delimited_table (const struct data_parser *parser,
                       const struct file_handle *fh)
 {
-  struct tab_table *t;
-  size_t i;
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("Reading free-form data from %s."),
+                                 fh_get_name (fh)));
 
-  t = tab_create (2, parser->field_cnt + 1);
-  tab_headers (t, 0, 0, 1, 0);
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Format"));
-  tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, parser->field_cnt);
-  tab_hline (t, TAL_2, 0, 1, 1);
+  pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Attributes"), N_("Format"));
 
-  for (i = 0; i < parser->field_cnt; i++)
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+  variables->root->show_label = true;
+  for (size_t i = 0; i < parser->field_cnt; i++)
     {
       struct field *f = &parser->fields[i];
-      char str[FMT_STRING_LEN_MAX + 1];
-      int row = i + 1;
 
-      tab_text (t, 0, row, TAB_LEFT, f->name);
-      tab_text (t, 1, row, TAB_LEFT | TAB_FIX,
-                fmt_to_string (&f->format, str));
-    }
+      /* XXX It would be better to have the actual variable here. */
+      int variable_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_user_text (f->name, -1));
 
-  tab_title (t, _("Reading free-form data from %s."), fh_get_name (fh));
+      char str[FMT_STRING_LEN_MAX + 1];
+      pivot_table_put2 (table, 0, variable_idx,
+                        pivot_value_new_user_text (
+                          fmt_to_string (&f->format, str), -1));
+    }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 /* Displays a table giving information on how PARSER will read
index dbf0d35573a49863680210f61895cd71a932708c..cf25f74799f3031e68dc34b95c41c1ae084ef9b8 100644 (file)
 #include "data/session.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/message.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 \f
 static int
@@ -240,22 +241,19 @@ int
 cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   struct session *session = dataset_session (ds);
-  struct dataset **datasets, **p;
-  struct tab_table *t;
-  size_t i, n;
-
-  n = session_n_datasets (session);
-  datasets = xmalloc (n * sizeof *datasets);
-  p = datasets;
+  size_t n = session_n_datasets (session);
+  struct dataset **datasets = xmalloc (n * sizeof *datasets);
+  struct dataset **p = datasets;
   session_for_each_dataset (session, dataset_display_cb, &p);
   qsort (datasets, n, sizeof *datasets, sort_datasets);
 
-  t = tab_create (1, n + 1);
-  tab_headers (t, 0, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
-  tab_hline (t, TAL_2, 0, 0, 1);
-  tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Dataset"));
-  for (i = 0; i < n; i++)
+  struct pivot_table *table = pivot_table_create (N_("Datasets"));
+
+  struct pivot_dimension *datasets_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dataset"));
+  datasets_dim->hide_all_labels = true;
+
+  for (size_t i = 0; i < n; i++)
     {
       struct dataset *ds = datasets[i];
       const char *name;
@@ -264,16 +262,18 @@ cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds)
       if (name[0] == '\0')
         name = _("unnamed dataset");
 
-      if (ds == session_active_dataset (session))
-        tab_text_format (t, 0, i + 1, TAB_LEFT, "%s %s",
-                         name, _("(active dataset)"));
-      else
-        tab_text (t, 0, i + 1, TAB_LEFT, name);
+      char *text = (ds == session_active_dataset (session)
+                    ? xasprintf ("%s (%s)", name, _("active dataset"))
+                    : xstrdup (name));
+
+      int dataset_idx = pivot_category_create_leaf (
+        datasets_dim->root, pivot_value_new_integer (i));
+
+      pivot_table_put1 (table, dataset_idx,
+                        pivot_value_new_user_text_nocopy (text));
     }
-  tab_title (t, "Open datasets.");
-  tab_submit (t);
 
-  free (datasets);
+  pivot_table_submit (table);
 
   return CMD_SUCCESS;
 }
index 55ccc4d2da3e15b843ab1acd4c0aca0232599100..920d66e322b4009c518cbc5ef1a4fbc9eca5a501 100644 (file)
@@ -36,7 +36,7 @@
 #include "libpspp/ll.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "output/table-item.h"
 
 #include "gl/intprops.h"
@@ -45,6 +45,7 @@
 #include "gl/xmalloca.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 enum numbering
@@ -84,52 +85,48 @@ list_execute (const struct lst_cmd *lcmd, struct dataset *ds)
   grouper = casegrouper_create_splits (proc_open (ds), dict);
   while (casegrouper_get_next_group (grouper, &group))
     {
-      struct ccase *ccase;
-      struct table *t = NULL;
-
-      ccase = casereader_peek (group, 0);
-      if (ccase != NULL)
+      struct ccase *c = casereader_peek (group, 0);
+      if (c != NULL)
         {
-          output_split_file_values (ds, ccase);
-          case_unref (ccase);
+          output_split_file_values (ds, c);
+          case_unref (c);
         }
 
       group = casereader_project (group, &sc);
-      if (lcmd->numbering == format_numbered)
-        group = casereader_create_arithmetic_sequence (group, 1, 1);
       group = casereader_select (group, lcmd->first - 1,
                                  (lcmd->last != LONG_MAX ? lcmd->last
                                   : CASENUMBER_MAX), lcmd->step);
 
-      if (lcmd->numbering == format_numbered)
-        {
-          struct fmt_spec fmt;
-          size_t col;
-          int width;
+      struct pivot_table *table = pivot_table_create (N_("Data List"));
+      table->show_values = table->show_variables = SETTINGS_VALUE_SHOW_VALUE;
 
-          width = lcmd->last == LONG_MAX ? 5 : intlog10 (lcmd->last);
-          fmt = fmt_for_output (FMT_F, width, 0);
-          col = caseproto_get_n_widths (casereader_get_proto (group)) - 1;
+      struct pivot_dimension *variables = pivot_dimension_create (
+        table, PIVOT_AXIS_COLUMN, N_("Variables"));
+      for (int i = 0; i < lcmd->n_variables; i++)
+        pivot_category_create_leaf (
+          variables->root, pivot_value_new_variable (lcmd->v_variables[i]));
 
-          t = table_from_casereader (group, col, _("Case Number"), &fmt);
-        }
+      struct pivot_dimension *cases = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Case Number"));
+      if (lcmd->numbering == format_numbered)
+        cases->root->show_label = true;
       else
-        t = NULL;
+        cases->hide_all_labels = true;
 
-      for (i = 0; i < lcmd->n_variables; i++)
+      casenumber case_num = 1;
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
         {
-          const struct variable *var = lcmd->v_variables[i];
-          struct table *c;
+          int case_idx = pivot_category_create_leaf (
+            cases->root, pivot_value_new_integer (case_num++));
 
-          c = table_from_casereader (group, i, var_get_name (var),
-                                     var_get_print_format (var));
-          t = table_hpaste (t, c);
+          for (int i = 0; i < lcmd->n_variables; i++)
+            pivot_table_put2 (table, i, case_idx,
+                              pivot_value_new_var_value (
+                                lcmd->v_variables[i], case_data_idx (c, i)));
         }
-
       casereader_destroy (group);
 
-      if (t)
-       table_item_submit (table_item_create (t, "Data List", NULL));
+      pivot_table_submit (table);
     }
   ok = casegrouper_destroy (grouper);
   ok = proc_commit (ds) && ok;
index 0396df55b08cf24fa55e76dd0b6c998a3e7d6f4f..4545a222df0c5f01ae350446d423ac3eafee0bc7 100644 (file)
 #include "libpspp/misc.h"
 #include "libpspp/pool.h"
 #include "libpspp/u8-line.h"
+#include "output/pivot-table.h"
 #include "output/tab.h"
 #include "output/text-item.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 /* Describes what to do when an output field is encountered. */
@@ -99,7 +101,7 @@ static trns_proc_func print_text_trns_proc, print_binary_trns_proc;
 static trns_free_func print_trns_free;
 static bool parse_specs (struct lexer *, struct pool *tmp_pool, struct print_trns *,
                         struct dictionary *dict, enum which_formats);
-static void dump_table (struct print_trns *, const struct file_handle *);
+static void dump_table (struct print_trns *);
 \f
 /* Basic parsing. */
 
@@ -233,7 +235,7 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds,
 
   /* Output the variable table if requested. */
   if (print_table)
-    dump_table (trns, fh);
+    dump_table (trns);
 
   /* Put the transformation in the queue. */
   add_transformation (ds,
@@ -425,59 +427,43 @@ parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
 /* Prints the table produced by the TABLE subcommand to the listing
    file. */
 static void
-dump_table (struct print_trns *trns, const struct file_handle *fh)
+dump_table (struct print_trns *trns)
 {
+  struct pivot_table *table = pivot_table_create (N_("Print Summary"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"),
+                          N_("Record"), N_("Columns"), N_("Format"));
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+
   struct prt_out_spec *spec;
-  struct tab_table *t;
-  int spec_cnt;
-  int row;
-
-  spec_cnt = ll_count (&trns->specs);
-  t = tab_create (4, spec_cnt + 1);
-  tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt);
-  tab_hline (t, TAL_2, 0, 3, 1);
-  tab_headers (t, 0, 0, 1, 0);
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
-  row = 1;
   ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
     {
+      if (spec->type != PRT_VAR)
+        continue;
+
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (spec->var));
+
+      pivot_table_put2 (table, 0, row,
+                        pivot_value_new_integer (spec->record));
+      int last_column = spec->first_column + spec->format.w - 1;
+      pivot_table_put2 (table, 1, row, pivot_value_new_user_text_nocopy (
+                          xasprintf ("%3d-%3d",
+                                     spec->first_column, last_column)));
+
       char fmt_string[FMT_STRING_LEN_MAX + 1];
-      int width;
-      switch (spec->type)
-        {
-        case PRT_LITERAL:
-          tab_text_format (t, 0, row, TAB_LEFT | TAB_FIX, "`%.*s'",
-                           (int) ds_length (&spec->string),
-                           ds_data (&spec->string));
-          width = ds_length (&spec->string);
-          break;
-        case PRT_VAR:
-          tab_text (t, 0, row, TAB_LEFT, var_get_name (spec->var));
-          tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
-                    fmt_to_string (&spec->format, fmt_string));
-          width = spec->format.w;
-          break;
-        default:
-          NOT_REACHED ();
-       }
-      tab_text_format (t, 1, row, 0, "%d", spec->record);
-      tab_text_format (t, 2, row, 0, "%3d-%3d",
-                       spec->first_column, spec->first_column + width - 1);
-      row++;
+      pivot_table_put2 (table, 2, row, pivot_value_new_user_text (
+                          fmt_to_string (&spec->format, fmt_string), -1));
     }
 
-  if (fh != NULL)
-    tab_title (t, ngettext ("Writing %zu record to %s.",
-                            "Writing %zu records to %s.", trns->record_cnt),
-               trns->record_cnt, fh_get_name (fh));
-  else
-    tab_title (t, ngettext ("Writing %zu record.",
-                            "Writing %zu records.", trns->record_cnt),
-               trns->record_cnt);
-  tab_submit (t);
+  int row = pivot_category_create_leaf (
+    variables->root, pivot_value_new_text (N_("N of Records")));
+  pivot_table_put2 (table, 0, row,
+                    pivot_value_new_integer (trns->record_cnt));
+
+  pivot_table_submit (table);
 }
 \f
 /* Transformation, for all-text output. */
index 621516b9ecdc82eaaceaf480d5f958142dc353a1..97ab2c1fb4ffdded42110f9812ef73d3454a777b 100644 (file)
 #include "libpspp/str.h"
 #include "libpspp/stringi-map.h"
 #include "libpspp/stringi-set.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 static bool parse_group (struct lexer *, struct dictionary *, enum mrset_type);
@@ -521,16 +522,11 @@ parse_delete (struct lexer *lexer, struct dictionary *dict)
 static bool
 parse_display (struct lexer *lexer, struct dictionary *dict)
 {
-  struct string details, var_names;
   struct stringi_set mrset_names_set;
-  char **mrset_names;
-  struct tab_table *table;
-  size_t i, n;
-
   if (!parse_mrset_names (lexer, dict, &mrset_names_set))
     return false;
 
-  n = stringi_set_count (&mrset_names_set);
+  size_t n = stringi_set_count (&mrset_names_set);
   if (n == 0)
     {
       if (dict_get_n_mrsets (dict) == 0)
@@ -540,71 +536,53 @@ parse_display (struct lexer *lexer, struct dictionary *dict)
       return true;
     }
 
-  table = tab_create (3, n + 1);
-  tab_headers (table, 0, 0, 1, 0);
-  tab_box (table, TAL_1, TAL_1, TAL_1, TAL_1, 0, 0, 2, n);
-  tab_hline (table, TAL_2, 0, 2, 1);
-  tab_title (table, "%s", _("Multiple Response Sets"));
-  tab_text (table, 0, 0, TAB_EMPH | TAB_LEFT, _("Name"));
-  tab_text (table, 1, 0, TAB_EMPH | TAB_LEFT, _("Variables"));
-  tab_text (table, 2, 0, TAB_EMPH | TAB_LEFT, _("Details"));
-
-  ds_init_empty (&details);
-  ds_init_empty (&var_names);
-  mrset_names = stringi_set_get_sorted_array (&mrset_names_set);
-  for (i = 0; i < n; i++)
+  struct pivot_table *table = pivot_table_create (
+    N_("Multiple Response Sets"));
+
+  pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Attributes"),
+    N_("Label"), N_("Encoding"), N_("Counted Value"), N_("Member Variables"));
+
+  struct pivot_dimension *mrsets = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Name"));
+  mrsets->root->show_label = true;
+
+  char **mrset_names = stringi_set_get_sorted_array (&mrset_names_set);
+  for (size_t i = 0; i < n; i++)
     {
       const struct mrset *mrset = dict_lookup_mrset (dict, mrset_names[i]);
-      const int row = i + 1;
-      size_t j;
-
-      /* Details. */
-      ds_clear (&details);
-      ds_put_format (&details, "%s\n", (mrset->type == MRSET_MD
-                                        ? _("Multiple dichotomy set")
-                                        : _("Multiple category set")));
+
+      int row = pivot_category_create_leaf (
+        mrsets->root, pivot_value_new_user_text (mrset->name, -1));
+
       if (mrset->label != NULL)
-        ds_put_format (&details, "%s: %s\n", _("Label"), mrset->label);
+        pivot_table_put2 (table, 0, row,
+                          pivot_value_new_user_text (mrset->label, -1));
+
+      pivot_table_put2 (table, 1, row,
+                        pivot_value_new_text (mrset->type == MRSET_MD
+                                              ? _("Dichotomies")
+                                              : _("Categories")));
+
       if (mrset->type == MRSET_MD)
-        {
-          if (mrset->label != NULL || mrset->label_from_var_label)
-            ds_put_format (&details, "%s: %s\n", _("Label source"),
-                           (mrset->label_from_var_label
-                            ? _("First variable label among variables")
-                            : _("Provided by user")));
-          ds_put_format (&details, "%s: ", _("Counted value"));
-          if (mrset->width == 0)
-            ds_put_format (&details, "%.0f\n", mrset->counted.f);
-          else
-            {
-              const uint8_t *raw = value_str (&mrset->counted, mrset->width);
-              char *utf8 = recode_string ("UTF-8", dict_get_encoding (dict),
-                                          CHAR_CAST (const char *, raw),
-                                          mrset->width);
-              ds_put_format (&details, "`%s'\n", utf8);
-              free (utf8);
-            }
-          ds_put_format (&details, "%s: %s\n", _("Category label source"),
-                         (mrset->cat_source == MRSET_VARLABELS
-                          ? _("Variable labels")
-                          : _("Value labels of counted value")));
-        }
+        pivot_table_put2 (table, 2, row,
+                          pivot_value_new_value (
+                            &mrset->counted, mrset->width,
+                            &F_8_0, dict_get_encoding (dict)));
 
       /* Variable names. */
-      ds_clear (&var_names);
-      for (j = 0; j < mrset->n_vars; j++)
+      struct string var_names = DS_EMPTY_INITIALIZER;
+      for (size_t j = 0; j < mrset->n_vars; j++)
         ds_put_format (&var_names, "%s\n", var_get_name (mrset->vars[j]));
-
-      tab_text (table, 0, row, TAB_LEFT, mrset_names[i]);
-      tab_text (table, 1, row, TAB_LEFT, ds_cstr (&var_names));
-      tab_text (table, 2, row, TAB_LEFT, ds_cstr (&details));
+      ds_chomp_byte (&var_names, '\n');
+      pivot_table_put2 (table, 3, row,
+                        pivot_value_new_user_text_nocopy (
+                          ds_steal_cstr (&var_names)));
     }
   free (mrset_names);
-  ds_destroy (&var_names);
-  ds_destroy (&details);
   stringi_set_destroy (&mrset_names_set);
 
-  tab_submit (table);
+  pivot_table_submit (table);
 
   return true;
 }
index fda5cfd00c6a71e591cdaa680cb528c4bff46f9d..73cc20a0570ddb9d8ed4e4c324356a578aa2ffdf 100644 (file)
 #include "language/lexer/variable-parser.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 int
@@ -67,38 +68,26 @@ void
 output_split_file_values (const struct dataset *ds, const struct ccase *c)
 {
   const struct dictionary *dict = dataset_dict (ds);
-  const struct variable *const *split;
-  struct tab_table *t;
-  size_t split_cnt;
-  int i;
-
-  split_cnt = dict_get_split_cnt (dict);
-  if (split_cnt == 0)
+  size_t n_vars = dict_get_split_cnt (dict);
+  if (n_vars == 0)
     return;
 
-  t = tab_create (3, split_cnt + 1);
-  tab_text (t, 0, 0, TAB_NONE, _("Variable"));
-  tab_text (t, 1, 0, TAB_LEFT, _("Value"));
-  tab_text (t, 2, 0, TAB_LEFT, _("Label"));
-  split = dict_get_split_vars (dict);
-  for (i = 0; i < split_cnt; i++)
-    {
-      const struct variable *v = split[i];
-      char *s;
-      const char *val_lab;
-      const struct fmt_spec *print = var_get_print_format (v);
-
-      tab_text_format (t, 0, i + 1, TAB_LEFT, "%s", var_get_name (v));
-
-      s = data_out (case_data (c, v), dict_get_encoding (dict), print);
+  struct pivot_table *table = pivot_table_create (N_("Split Values"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Value"),
+                          N_("Value"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+  variables->root->show_label = true;
 
-      tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, s);
-
-      free (s);
+  for (size_t i = 0; i < n_vars; i++)
+    {
+      const struct variable *v = dict_get_split_vars (dict)[i];
+      int row = pivot_category_create_leaf (variables->root,
+                                            pivot_value_new_variable (v));
 
-      val_lab = var_lookup_value_label (v, case_data (c, v));
-      if (val_lab)
-       tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
+      pivot_table_put2 (table, 0, row,
+                        pivot_value_new_var_value (v, case_data (c, v)));
     }
-  tab_submit (t);
+
+  pivot_table_submit (table);
 }
index a0e608623290ff3b90fde776c5f21c64d4c665a6..9cb551044914098e389c044e0d48e8098a856365 100644 (file)
@@ -42,7 +42,7 @@
 #include "libpspp/misc.h"
 #include "libpspp/pool.h"
 #include "libpspp/string-array.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "output/text-item.h"
 #include "output/table-item.h"
 
@@ -89,6 +89,16 @@ static void report_encodings (const struct file_handle *, struct pool *,
                               char **titles, bool *ids,
                               char **strings, size_t n_strings);
 
+static void
+add_row (struct pivot_table *table, const char *attribute,
+         struct pivot_value *value)
+{
+  int row = pivot_category_create_leaf (table->dimensions[0]->root,
+                                        pivot_value_new_text (attribute));
+  if (value)
+    pivot_table_put1 (table, row, value);
+}
+
 /* SYSFILE INFO utility. */
 int
 cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
@@ -96,11 +106,9 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   struct any_reader *any_reader;
   struct file_handle *h;
   struct dictionary *d;
-  struct tab_table *t;
   struct casereader *reader;
   struct any_read_info info;
   char *encoding;
-  int r;
 
   h = NULL;
   encoding = NULL;
@@ -171,76 +179,67 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
     goto error;
   casereader_destroy (reader);
 
-  t = tab_create (2, 11 + (info.product_ext != NULL));
-  r = 0;
-  
-  tab_text (t, 0, r, TAB_LEFT, _("File:"));
-  tab_text (t, 1, r++, TAB_LEFT, fh_get_file_name (h));
-
-  tab_text (t, 0, r, TAB_LEFT, _("Label:"));
-  {
-    const char *label = dict_get_label (d);
-    if (label == NULL)
-      label = _("No label.");
-    tab_text (t, 1, r++, TAB_LEFT, label);
-  }
-
-  tab_text (t, 0, r, TAB_LEFT, _("Created:"));
-  tab_text_format (t, 1, r++, TAB_LEFT, "%s %s by %s",
-                   info.creation_date, info.creation_time, info.product);
-
-  if (info.product_ext)
-    {
-      tab_text (t, 0, r, TAB_LEFT, _("Product:"));
-      tab_text (t, 1, r++, TAB_LEFT, info.product_ext);
-    }
-
-  tab_text (t, 0, r, TAB_LEFT, _("Integer Format:"));
-  tab_text (t, 1, r++, TAB_LEFT,
-            info.integer_format == INTEGER_MSB_FIRST ? _("Big Endian")
-            : info.integer_format == INTEGER_LSB_FIRST ? _("Little Endian")
-            : _("Unknown"));
-
-  tab_text (t, 0, r, TAB_LEFT, _("Real Format:"));
-  tab_text (t, 1, r++, TAB_LEFT,
-            info.float_format == FLOAT_IEEE_DOUBLE_LE ? _("IEEE 754 LE.")
-            : info.float_format == FLOAT_IEEE_DOUBLE_BE ? _("IEEE 754 BE.")
-            : info.float_format == FLOAT_VAX_D ? _("VAX D.")
-            : info.float_format == FLOAT_VAX_G ? _("VAX G.")
-            : info.float_format == FLOAT_Z_LONG ? _("IBM 390 Hex Long.")
-            : _("Unknown"));
-
-  tab_text (t, 0, r, TAB_LEFT, _("Variables:"));
-  tab_text_format (t, 1, r++, TAB_LEFT, "%zu", dict_get_var_cnt (d));
-
-  tab_text (t, 0, r, TAB_LEFT, _("Cases:"));
-  if (info.case_cnt == -1)
-    tab_text (t, 1, r, TAB_LEFT, _("Unknown"));
-  else
-    tab_text_format (t, 1, r, TAB_LEFT, "%ld", (long int) info.case_cnt);
-  r++;
-
-  tab_text (t, 0, r, TAB_LEFT, _("Type:"));
-  tab_text (t, 1, r++, TAB_LEFT, gettext (info.klass->name));
+  struct pivot_table *table = pivot_table_create (N_("File Information"));
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Attribute"));
 
-  tab_text (t, 0, r, TAB_LEFT, _("Weight:"));
-  {
-    struct variable *weight_var = dict_get_weight (d);
-    tab_text (t, 1, r++, TAB_LEFT,
-              (weight_var != NULL
-               ? var_get_name (weight_var) : _("Not weighted.")));
-  }
+  add_row (table, N_("File"),
+           pivot_value_new_user_text (fh_get_file_name (h), -1));
 
-  tab_text (t, 0, r, TAB_LEFT, _("Compression:"));
-  tab_text_format (t, 1, r++, TAB_LEFT,
-                   info.compression == ANY_COMP_NONE ? _("None")
-                   : info.compression == ANY_COMP_SIMPLE ? "SAV"
-                   : "ZSAV");
+  const char *label = dict_get_label (d);
+  add_row (table, N_("Label"),
+           label ? pivot_value_new_user_text (label, -1) : NULL);
 
-  tab_text (t, 0, r, TAB_LEFT, _("Encoding:"));
-  tab_text (t, 1, r++, TAB_LEFT, dict_get_encoding (d));
+  add_row (table, N_("Created"),
+           pivot_value_new_user_text_nocopy (
+             xasprintf ("%s %s by %s", info.creation_date,
+                        info.creation_time, info.product)));
 
-  tab_submit (t);
+  if (info.product_ext)
+    add_row (table, N_("Product"),
+             pivot_value_new_user_text (info.product_ext, -1));
+
+  add_row (table, N_("Integer Format"),
+           pivot_value_new_text (
+             info.integer_format == INTEGER_MSB_FIRST ? N_("Big Endian")
+             : info.integer_format == INTEGER_LSB_FIRST ? N_("Little Endian")
+             : N_("Unknown")));
+
+  add_row (table, N_("Real Format"),
+           pivot_value_new_text (
+             info.float_format == FLOAT_IEEE_DOUBLE_LE ? N_("IEEE 754 LE.")
+             : info.float_format == FLOAT_IEEE_DOUBLE_BE ? N_("IEEE 754 BE.")
+             : info.float_format == FLOAT_VAX_D ? N_("VAX D.")
+             : info.float_format == FLOAT_VAX_G ? N_("VAX G.")
+             : info.float_format == FLOAT_Z_LONG ? N_("IBM 390 Hex Long.")
+             : N_("Unknown")));
+
+  add_row (table, N_("Variables"),
+           pivot_value_new_integer (dict_get_var_cnt (d)));
+
+  add_row (table, N_("Cases"),
+           (info.case_cnt == -1
+            ? pivot_value_new_text (N_("Unknown"))
+            : pivot_value_new_integer (info.case_cnt)));
+
+  add_row (table, N_("Type"),
+           pivot_value_new_text (info.klass->name));
+
+  struct variable *weight_var = dict_get_weight (d);
+  add_row (table, N_("Weight"),
+           (weight_var
+            ? pivot_value_new_variable (weight_var)
+            : pivot_value_new_text (N_("Not weighted"))));
+
+  add_row (table, N_("Compression"),
+           (info.compression == ANY_COMP_NONE
+            ? pivot_value_new_text (N_("None"))
+            : pivot_value_new_user_text (
+              info.compression == ANY_COMP_SIMPLE ? "SAV" : "ZSAV", -1)));
+
+  add_row (table, N_("Encoding"),
+           pivot_value_new_user_text (dict_get_encoding (d), -1));
+
+  pivot_table_submit (table);
 
   size_t n_vars = dict_get_var_cnt (d);
   const struct variable **vars = xnmalloc (n_vars, sizeof *vars);
@@ -288,12 +287,16 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
     {
       if (!lex_force_match_id (lexer, "LABEL"))
        return CMD_FAILURE;
-      if (dict_get_label (dataset_dict (ds)) == NULL)
-       tab_output_text (TAB_LEFT,
-                        _("The active dataset does not have a file label."));
-      else
-        tab_output_text_format (TAB_LEFT, _("File label: %s"),
-                                dict_get_label (dataset_dict (ds)));
+
+      const char *label = dict_get_label (dataset_dict (ds));
+
+      struct pivot_table *table = pivot_table_create (N_("File Label"));
+      pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Label"),
+                              N_("Label"));
+      pivot_table_put1 (table, 0,
+                        (label ? pivot_value_new_user_text (label, -1)
+                         : pivot_value_new_text (N_("(none)"))));
+      pivot_table_submit (table);
     }
   else
     {
@@ -391,36 +394,43 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
 static void
 display_macros (void)
 {
-  tab_output_text (TAB_LEFT, _("Macros not supported."));
+  msg (SW, _("Macros not supported."));
 }
 
 static void
 display_documents (const struct dictionary *dict)
 {
-  const struct string_array *documents = dict_get_documents (dict);
+  struct pivot_table *table = pivot_table_create (N_("Documents"));
+  struct pivot_dimension *d = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Documents"), N_("Document"));
+  d->hide_all_labels = true;
 
-  if (string_array_is_empty (documents))
-    tab_output_text (TAB_LEFT, _("The active dataset dictionary does not "
-                                 "contain any documents."));
+  const struct string_array *documents = dict_get_documents (dict);
+  if (!documents->n)
+    pivot_table_put1 (table, 0, pivot_value_new_text (N_("(none)")));
   else
     {
-      size_t i;
-
-      tab_output_text (TAB_LEFT | TAT_TITLE,
-                      _("Documents in the active dataset:"));
-      for (i = 0; i < dict_get_document_line_cnt (dict); i++)
-        tab_output_text (TAB_LEFT | TAB_FIX, dict_get_document_line (dict, i));
+      struct string s = DS_EMPTY_INITIALIZER;
+      for (size_t i = 0; i < documents->n; i++)
+        {
+          if (i)
+            ds_put_byte (&s, '\n');
+          ds_put_cstr (&s, documents->strings[i]);
+        }
+      pivot_table_put1 (table, 0,
+                        pivot_value_new_user_text_nocopy (ds_steal_cstr (&s)));
     }
+
+  pivot_table_submit (table);
 }
 
 static void
 display_variables (const struct variable **vl, size_t n, int flags)
 {
-  int nc = count_one_bits (flags);
-  struct tab_table *t = tab_create (nc, n + 1);
-  tab_title (t, "%s", _("Variables"));
-  tab_headers (t, 0, 0, 1, 0);
-  tab_hline (t, TAL_2, 0, nc - 1, 1);
+  struct pivot_table *table = pivot_table_create (N_("Variables"));
+
+  struct pivot_dimension *attributes = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Attributes"));
 
   struct heading
     {
@@ -428,7 +438,6 @@ display_variables (const struct variable **vl, size_t n, int flags)
       const char *title;
     };
   static const struct heading headings[] = {
-    { DF_NAME, N_("Name") },
     { DF_POSITION, N_("Position") },
     { DF_LABEL, N_("Label") },
     { DF_MEASUREMENT_LEVEL, N_("Measurement Level") },
@@ -439,97 +448,121 @@ display_variables (const struct variable **vl, size_t n, int flags)
     { DF_WRITE_FORMAT, N_("Write Format") },
     { DF_MISSING_VALUES, N_("Missing Values") },
   };
-  for (size_t i = 0, x = 0; i < sizeof headings / sizeof *headings; i++)
+  for (size_t i = 0; i < sizeof headings / sizeof *headings; i++)
     if (flags & headings[i].flag)
-      tab_text (t, x++, 0, TAB_LEFT | TAT_TITLE, gettext (headings[i].title));
+      pivot_category_create_leaf (attributes->root,
+                                  pivot_value_new_text (headings[i].title));
+
+  struct pivot_dimension *names = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Name"));
+  names->root->show_label = true;
 
   for (size_t i = 0; i < n; i++)
     {
       const struct variable *v = vl[i];
-      size_t y = i + 1;
-      size_t x = 0;
-      if (flags & DF_NAME)
-        tab_text (t, x++, y, TAB_LEFT, var_get_name (v));
+
+      struct pivot_value *name = pivot_value_new_variable (v);
+      name->variable.show = SETTINGS_VALUE_SHOW_VALUE;
+      int row = pivot_category_create_leaf (names->root, name);
+
+      int x = 0;
       if (flags & DF_POSITION)
-        {
-          char s[INT_BUFSIZE_BOUND (size_t)];
+        pivot_table_put2 (table, x++, row, pivot_value_new_integer (
+                            var_get_dict_index (v) + 1));
 
-          sprintf (s, "%zu", var_get_dict_index (v) + 1);
-          tab_text (t, x++, y, TAB_LEFT, s);
-        }
       if (flags & DF_LABEL)
         {
           const char *label = var_get_label (v);
           if (label)
-            tab_text (t, x, y, TAB_LEFT, label);
+            pivot_table_put2 (table, x, row,
+                              pivot_value_new_user_text (label, -1));
           x++;
         }
+
       if (flags & DF_MEASUREMENT_LEVEL)
-        tab_text (t, x++, y, TAB_LEFT,
-                  gettext (measure_to_string (var_get_measure (v))));
+        pivot_table_put2 (
+          table, x++, row,
+          pivot_value_new_text (measure_to_string (var_get_measure (v))));
+
       if (flags & DF_ROLE)
-        tab_text (t, x++, y, TAB_LEFT,
-                  gettext (var_role_to_string (var_get_role (v))));
+        pivot_table_put2 (
+          table, x++, row,
+          pivot_value_new_text (var_role_to_string (var_get_role (v))));
+
       if (flags & DF_WIDTH)
-        {
-          char s[INT_BUFSIZE_BOUND (int)];
-          sprintf (s, "%d", var_get_display_width (v));
-          tab_text (t, x++, y, TAB_RIGHT, s);
-        }
+        pivot_table_put2 (
+          table, x++, row,
+          pivot_value_new_integer (var_get_display_width (v)));
+
       if (flags & DF_ALIGNMENT)
-        tab_text (t, x++, y, TAB_LEFT,
-                  gettext (alignment_to_string (var_get_alignment (v))));
+        pivot_table_put2 (
+          table, x++, row,
+          pivot_value_new_text (alignment_to_string (
+                                  var_get_alignment (v))));
+
       if (flags & DF_PRINT_FORMAT)
         {
           const struct fmt_spec *print = var_get_print_format (v);
           char s[FMT_STRING_LEN_MAX + 1];
 
-          tab_text (t, x++, y, TAB_LEFT, fmt_to_string (print, s));
+          pivot_table_put2 (
+            table, x++, row,
+            pivot_value_new_user_text (fmt_to_string (print, s), -1));
         }
+
       if (flags & DF_WRITE_FORMAT)
         {
           const struct fmt_spec *write = var_get_write_format (v);
           char s[FMT_STRING_LEN_MAX + 1];
 
-          tab_text (t, x++, y, TAB_LEFT, fmt_to_string (write, s));
+          pivot_table_put2 (
+            table, x++, row,
+            pivot_value_new_user_text (fmt_to_string (write, s), -1));
         }
+
       if (flags & DF_MISSING_VALUES)
         {
-          const struct missing_values *mv = var_get_missing_values (v);
-
-          char *s = mv_to_string (mv, var_get_encoding (v));
+          char *s = mv_to_string (var_get_missing_values (v),
+                                  var_get_encoding (v));
           if (s)
-            {
-              tab_text (t, x, y, TAB_LEFT, s);
-              free (s);
-            }
-          x++;
+            pivot_table_put2 (
+              table, x, row,
+              pivot_value_new_user_text_nocopy (s));
 
-          assert (x == nc);
+          x++;
         }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
+}
+
+static bool
+any_value_labels (const struct variable **vars, size_t n_vars)
+{
+  for (size_t i = 0; i < n_vars; i++)
+    if (val_labs_count (var_get_value_labels (vars[i])))
+      return true;
+  return false;
 }
 
 static void
 display_value_labels (const struct variable **vars, size_t n_vars)
 {
-  size_t n_value_labels = 0;
-  for (size_t i = 0; i < n_vars; i++)
-    n_value_labels += val_labs_count (var_get_value_labels (vars[i]));
-  if (!n_value_labels)
+  if (!any_value_labels (vars, n_vars))
     return;
 
-  struct tab_table *t = tab_create (3, n_value_labels + 1);
-  tab_title (t, "%s", _("Value Labels"));
-  tab_headers (t, 0, 0, 1, 0);
-  tab_hline (t, TAL_2, 0, 2, 1);
-  tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
-  tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value"));
-  tab_text (t, 2, 0, TAB_LEFT | TAT_TITLE, _("Label"));
+  struct pivot_table *table = pivot_table_create (N_("Value Labels"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN,
+                          N_("Label"), N_("Label"));
+
+  struct pivot_dimension *values = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable Value"));
+  values->root->show_label = true;
+
+  struct pivot_footnote *missing_footnote = pivot_table_create_footnote (
+    table, pivot_value_new_text (N_("User-missing value")));
 
-  int y = 1;
   for (size_t i = 0; i < n_vars; i++)
     {
       const struct val_labs *val_labs = var_get_value_labels (vars[i]);
@@ -537,21 +570,44 @@ display_value_labels (const struct variable **vars, size_t n_vars)
       if (!n_labels)
         continue;
 
-      tab_joint_text (t, 0, y, 0, y + (n_labels - 1), TAB_LEFT,
-                      var_get_name (vars[i]));
+      struct pivot_category *group = pivot_category_create_group__ (
+        values->root, pivot_value_new_variable (vars[i]));
 
       const struct val_lab **labels = val_labs_sorted (val_labs);
       for (size_t j = 0; j < n_labels; j++)
         {
           const struct val_lab *vl = labels[j];
 
-          tab_value (t, 1, y, TAB_NONE, &vl->value, vars[i], NULL);
-          tab_text (t, 2, y, TAB_LEFT, val_lab_get_escaped_label (vl));
-          y++;
+          struct pivot_value *value = pivot_value_new_var_value (
+            vars[i], &vl->value);
+          if (value->type == PIVOT_VALUE_NUMERIC)
+            value->numeric.show = SETTINGS_VALUE_SHOW_VALUE;
+          else
+            value->string.show = SETTINGS_VALUE_SHOW_VALUE;
+          if (var_is_value_missing (vars[i], &vl->value, MV_USER))
+            pivot_value_add_footnote (value, missing_footnote);
+          int row = pivot_category_create_leaf (group, value);
+
+          struct pivot_value *label = pivot_value_new_var_value (
+            vars[i], &vl->value);
+          char *escaped_label = xstrdup (val_lab_get_escaped_label (vl));
+          if (label->type == PIVOT_VALUE_NUMERIC)
+            {
+              free (label->numeric.value_label);
+              label->numeric.value_label = escaped_label;
+              label->numeric.show = SETTINGS_VALUE_SHOW_LABEL;
+            }
+          else
+            {
+              free (label->string.value_label);
+              label->string.value_label = escaped_label;
+              label->string.show = SETTINGS_VALUE_SHOW_LABEL;
+            }
+          pivot_table_put2 (table, 0, row, label);
         }
       free (labels);
     }
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 \f
 static bool
@@ -575,15 +631,19 @@ count_attributes (const struct attrset *set, int flags)
   return n_attrs;
 }
 
-static int
-display_attrset (const char *name, const struct attrset *set, int flags,
-                 struct tab_table *t, int y)
+static void
+display_attrset (struct pivot_table *table, struct pivot_value *set_name,
+                 const struct attrset *set, int flags)
 {
   size_t n_total = count_attributes (set, flags);
   if (!n_total)
-    return y;
+    {
+      pivot_value_destroy (set_name);
+      return;
+    }
 
-  tab_joint_text (t, 0, y, 0, y + (n_total - 1), TAB_LEFT, name);
+  struct pivot_category *group = pivot_category_create_group__ (
+    table->dimensions[1]->root, set_name);
 
   size_t n_attrs = attrset_count (set);
   struct attribute **attrs = attrset_sorted (set);
@@ -598,43 +658,44 @@ display_attrset (const char *name, const struct attrset *set, int flags,
       size_t n_values = attribute_get_n_values (attr);
       for (size_t j = 0; j < n_values; j++)
         {
-          if (n_values > 1)
-            tab_text_format (t, 1, y, TAB_LEFT, "%s[%zu]", name, j + 1);
-          else
-            tab_text (t, 1, y, TAB_LEFT, name);
-          tab_text (t, 2, y, TAB_LEFT, attribute_get_value (attr, j));
-          y++;
+          int row = pivot_category_create_leaf (
+            group,
+            (n_values > 1
+             ? pivot_value_new_user_text_nocopy (xasprintf (
+                                                   "%s[%zu]", name, j + 1))
+             : pivot_value_new_user_text (name, -1)));
+          pivot_table_put2 (table, 0, row,
+                            pivot_value_new_user_text (
+                              attribute_get_value (attr, j), -1));
         }
     }
   free (attrs);
-
-  return y;
 }
 
 static void
 display_attributes (const struct attrset *dict_attrset,
                     const struct variable **vars, size_t n_vars, int flags)
 {
-  size_t n_attributes = count_attributes (dict_attrset, flags);
-  for (size_t i = 0; i < n_vars; i++)
-    n_attributes += count_attributes (var_get_attributes (vars[i]), flags);
-  if (!n_attributes)
-    return;
+  struct pivot_table *table = pivot_table_create (
+    N_("Variable and Dataset Attributes"));
 
-  struct tab_table *t = tab_create (3, n_attributes + 1);
-  tab_title (t, "%s", _("Variable and Dataset Attributes"));
-  tab_headers (t, 0, 0, 1, 0);
-  tab_hline (t, TAL_2, 0, 2, 1);
-  tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
-  tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Name"));
-  tab_text (t, 2, 0, TAB_LEFT | TAT_TITLE, _("Value"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN,
+                          N_("Value"), N_("Value"));
 
-  int y = display_attrset (_("(dataset)"), dict_attrset, flags, t, 1);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable and Name"));
+  variables->root->show_label = true;
+
+  display_attrset (table, pivot_value_new_text (N_("(dataset)")),
+                   dict_attrset, flags);
   for (size_t i = 0; i < n_vars; i++)
-    y = display_attrset (var_get_name (vars[i]), var_get_attributes (vars[i]),
-                         flags, t, y);
+    display_attrset (table, pivot_value_new_variable (vars[i]),
+                     var_get_attributes (vars[i]), flags);
 
-  tab_submit (t);
+  if (pivot_table_is_empty (table))
+    pivot_table_destroy (table);
+  else
+    pivot_table_submit (table);
 }
 
 /* Display a list of vectors.  If SORTED is nonzero then they are
@@ -642,66 +703,52 @@ display_attributes (const struct attrset *dict_attrset,
 static void
 display_vectors (const struct dictionary *dict, int sorted)
 {
-  const struct vector **vl;
-  int i;
-  struct tab_table *t;
-  size_t nvec;
-  size_t nrow;
-  size_t row;
-
-  nvec = dict_get_vector_cnt (dict);
-  if (nvec == 0)
+  size_t n_vectors = dict_get_vector_cnt (dict);
+  if (n_vectors == 0)
     {
       msg (SW, _("No vectors defined."));
       return;
     }
 
-  vl = xnmalloc (nvec, sizeof *vl);
-  nrow = 0;
-  for (i = 0; i < nvec; i++)
-    {
-      vl[i] = dict_get_vector (dict, i);
-      nrow += vector_get_var_cnt (vl[i]);
-    }
+  const struct vector **vectors = xnmalloc (n_vectors, sizeof *vectors);
+  for (size_t i = 0; i < n_vectors; i++)
+    vectors[i] = dict_get_vector (dict, i);
   if (sorted)
-    qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name);
-
-  t = tab_create (4, nrow + 1);
-  tab_headers (t, 0, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 3, nrow);
-  tab_box (t, -1, -1, -1, TAL_1, 0, 0, 3, nrow);
-  tab_hline (t, TAL_2, 0, 3, 1);
-  tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Vector"));
-  tab_text (t, 1, 0, TAT_TITLE | TAB_LEFT, _("Position"));
-  tab_text (t, 2, 0, TAT_TITLE | TAB_LEFT, _("Variable"));
-  tab_text (t, 3, 0, TAT_TITLE | TAB_LEFT, _("Print Format"));
-
-  row = 1;
-  for (i = 0; i < nvec; i++)
+    qsort (vectors, n_vectors, sizeof *vectors, compare_vector_ptrs_by_name);
+
+  struct pivot_table *table = pivot_table_create (N_("Vectors"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Attributes"),
+                          N_("Variable"), N_("Print Format"));
+  struct pivot_dimension *vector_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Vector and Position"));
+  vector_dim->root->show_label = true;
+
+  for (size_t i = 0; i < n_vectors; i++)
     {
-      const struct vector *vec = vl[i];
-      size_t j;
+      const struct vector *vec = vectors[i];
 
-      tab_joint_text (t, 0, row, 0, row + vector_get_var_cnt (vec) - 1,
-                      TAB_LEFT, vector_get_name (vl[i]));
+      struct pivot_category *group = pivot_category_create_group__ (
+        vector_dim->root, pivot_value_new_user_text (
+          vector_get_name (vectors[i]), -1));
 
-      for (j = 0; j < vector_get_var_cnt (vec); j++)
+      for (size_t j = 0; j < vector_get_var_cnt (vec); j++)
         {
           struct variable *var = vector_get_var (vec, j);
+
+          int row = pivot_category_create_leaf (
+            group, pivot_value_new_integer (j + 1));
+
+          pivot_table_put2 (table, 0, row, pivot_value_new_variable (var));
           char fmt_string[FMT_STRING_LEN_MAX + 1];
           fmt_to_string (var_get_print_format (var), fmt_string);
-
-          tab_text_format (t, 1, row, TAB_RIGHT, "%zu", j + 1);
-          tab_text (t, 2, row, TAB_LEFT, var_get_name (var));
-          tab_text (t, 3, row, TAB_LEFT, fmt_string);
-          row++;
+          pivot_table_put2 (table, 1, row,
+                            pivot_value_new_user_text (fmt_string, -1));
         }
-      tab_hline (t, TAL_1, 0, 3, row);
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 
-  free (vl);
+  free (vectors);
 }
 \f
 /* Encoding analysis. */
@@ -901,12 +948,9 @@ report_encodings (const struct file_handle *h, struct pool *pool,
 {
   struct encoding encodings[N_ENCODING_NAMES];
   size_t n_encodings, n_unique_strings;
-  size_t i, j;
-  struct tab_table *t;
-  size_t row;
 
   n_encodings = 0;
-  for (i = 0; i < N_ENCODING_NAMES; i++)
+  for (size_t i = 0; i < N_ENCODING_NAMES; i++)
     {
       char **utf8_strings;
       struct encoding *e;
@@ -919,7 +963,7 @@ report_encodings (const struct file_handle *h, struct pool *pool,
 
       /* Hash utf8_strings. */
       hash = 0;
-      for (j = 0; j < n_strings; j++)
+      for (size_t j = 0; j < n_strings; j++)
         hash = hash_string (utf8_strings[j], hash);
 
       /* If there's a duplicate encoding, just mark it. */
@@ -942,68 +986,78 @@ report_encodings (const struct file_handle *h, struct pool *pool,
       return;
     }
 
-  t = tab_create (2, n_encodings + 1);
-  tab_title (t, _("Usable encodings for %s."), fh_get_name (h));
-  tab_caption (t, _("Encodings that can successfully read %s (by specifying "
-                    "the encoding name on the GET command's ENCODING "
-                    "subcommand).  Encodings that yield identical text are "
-                    "listed together."), fh_get_name (h));
-  tab_headers (t, 1, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 1, n_encodings);
-  tab_hline (t, TAL_1, 0, 1, 1);
-  tab_text (t, 0, 0, TAB_RIGHT, "#");
-  tab_text (t, 1, 0, TAB_LEFT, _("Encodings"));
-  for (i = 0; i < n_encodings; i++)
+  /* Table of valid encodings. */
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("Usable encodings for %s."),
+                                 fh_get_name (h)));
+  table->caption = pivot_value_new_text_format (
+    N_("Encodings that can successfully read %s (by specifying the encoding "
+       "name on the GET command's ENCODING subcommand).  Encodings that "
+       "yield identical text are listed together."),
+    fh_get_name (h));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Encodings"),
+                          N_("Encodings"));
+  struct pivot_dimension *number = pivot_dimension_create__ (
+    table, PIVOT_AXIS_ROW, pivot_value_new_user_text ("#", -1));
+  number->root->show_label = true;
+
+  for (size_t i = 0; i < n_encodings; i++)
     {
-      struct string s;
-
-      ds_init_empty (&s);
-      for (j = 0; j < 64; j++)
+      struct string s = DS_EMPTY_INITIALIZER;
+      for (size_t j = 0; j < 64; j++)
         if (encodings[i].encodings & (UINT64_C (1) << j))
           ds_put_format (&s, "%s, ", encoding_names[j]);
       ds_chomp (&s, ss_cstr (", "));
 
-      tab_text_format (t, 0, i + 1, TAB_RIGHT, "%zu", i + 1);
-      tab_text (t, 1, i + 1, TAB_LEFT, ds_cstr (&s));
-      ds_destroy (&s);
+      int row = pivot_category_create_leaf (number->root,
+                                            pivot_value_new_integer (i + 1));
+      pivot_table_put2 (
+        table, 0, row, pivot_value_new_user_text_nocopy (ds_steal_cstr (&s)));
     }
-  tab_submit (t);
+  pivot_table_submit (table);
 
   n_unique_strings = 0;
-  for (i = 0; i < n_strings; i++)
+  for (size_t i = 0; i < n_strings; i++)
     if (!all_equal (encodings, n_encodings, i))
       n_unique_strings++;
   if (!n_unique_strings)
     return;
 
-  t = tab_create (3, (n_encodings * n_unique_strings) + 1);
-  tab_title (t, _("%s encoded text strings."), fh_get_name (h));
-  tab_caption (t, _("Text strings in the file dictionary that the previously "
-                    "listed encodings interpret differently, along with the "
-                    "interpretations."));
-  tab_headers (t, 1, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 2, n_encodings * n_unique_strings);
-  tab_hline (t, TAL_1, 0, 2, 1);
-
-  tab_text (t, 0, 0, TAB_LEFT, _("Purpose"));
-  tab_text (t, 1, 0, TAB_RIGHT, "#");
-  tab_text (t, 2, 0, TAB_LEFT, _("Text"));
-
-  row = 1;
-  for (i = 0; i < n_strings; i++)
+  /* Table of alternative interpretations. */
+  table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("%s Encoded Text Strings"),
+                                 fh_get_name (h)));
+  table->caption = pivot_value_new_text (
+    N_("Text strings in the file dictionary that the previously listed "
+       "encodings interpret differently, along with the interpretations."));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Text"), N_("Text"));
+
+  number = pivot_dimension_create__ (table, PIVOT_AXIS_ROW,
+                                     pivot_value_new_user_text ("#", -1));
+  number->root->show_label = true;
+  for (size_t i = 0; i < n_encodings; i++)
+    pivot_category_create_leaf (number->root,
+                                pivot_value_new_integer (i + 1));
+
+  struct pivot_dimension *purpose = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Purpose"));
+  purpose->root->show_label = true;
+
+  for (size_t i = 0; i < n_strings; i++)
     if (!all_equal (encodings, n_encodings, i))
       {
         int prefix = equal_prefix (encodings, n_encodings, i);
         int suffix = equal_suffix (encodings, n_encodings, i);
 
-        tab_joint_text (t, 0, row, 0, row + n_encodings - 1,
-                        TAB_LEFT, titles[i]);
-        tab_hline (t, TAL_1, 0, 2, row);
-        for (j = 0; j < n_encodings; j++)
+        int purpose_idx = pivot_category_create_leaf (
+          purpose->root, pivot_value_new_user_text (titles[i], -1));
+
+        for (size_t j = 0; j < n_encodings; j++)
           {
             const char *s = encodings[j].utf8_strings[i] + prefix;
 
-            tab_text_format (t, 1, row, TAB_RIGHT, "%zu", j + 1);
             if (prefix || suffix)
               {
                 size_t len = strlen (s) - suffix;
@@ -1015,12 +1069,16 @@ report_encodings (const struct file_handle *h, struct pool *pool,
                 ds_put_substring (&entry, ss_buffer (s, len));
                 if (suffix)
                   ds_put_cstr (&entry, "...");
-                tab_text (t, 2, row, TAB_LEFT, ds_cstr (&entry));
+
+                pivot_table_put3 (table, 0, j, purpose_idx,
+                                  pivot_value_new_user_text_nocopy (
+                                    ds_steal_cstr (&entry)));
               }
             else
-              tab_text (t, 2, row, TAB_LEFT, s);
-            row++;
+              pivot_table_put3 (table, 0, j, purpose_idx,
+                                pivot_value_new_user_text (s, -1));
           }
       }
-  tab_submit (t);
+
+  pivot_table_submit (table);
 }
index 00f37ab8b7e825f3b39fa81f489e06dff204a327..0ab004364d3b1f77018c9b02ede905e2bdc4a707 100644 (file)
 #include "libpspp/compiler.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 #include "gl/minmax.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 static double calculate_binomial_internal (double n1, double n2,
@@ -151,7 +152,6 @@ binomial_execute (const struct dataset *ds,
                  bool exact UNUSED,
                  double timer UNUSED)
 {
-  int v;
   const struct dictionary *dict = dataset_dict (ds);
   const struct one_sample_test *ost = UP_CAST (test, const struct one_sample_test, parent);
   const struct binomial_test *bst = UP_CAST (ost, const struct binomial_test, parent);
@@ -170,7 +170,7 @@ binomial_execute (const struct dataset *ds,
         value = bst->category2;
 
       cat[i] = xnmalloc (ost->n_vars, sizeof *cat[i]);
-      for (v = 0; v < ost->n_vars; v++)
+      for (size_t v = 0; v < ost->n_vars; v++)
         {
           cat[i][v].values[0].f = value;
           cat[i][v].count = 0;
@@ -179,88 +179,76 @@ binomial_execute (const struct dataset *ds,
 
   if (do_binomial (dataset_dict (ds), input, ost, cat[0], cat[1], exclude))
     {
-      const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-      struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1);
-      tab_set_format (table, RC_WEIGHT, wfmt);
-
-      tab_title (table, _("Binomial Test"));
-
-      tab_headers (table, 2, 0, 1, 0);
-
-      tab_box (table, TAL_1, TAL_1, -1, TAL_1,
-               0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
-
-      for (v = 0 ; v < ost->n_vars; ++v)
+      struct pivot_table *table = pivot_table_create (N_("Binomial Test"));
+      pivot_table_set_weight_var (table, dict_get_weight (dict));
+
+      pivot_dimension_create (
+        table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+        N_("Category"),
+        N_("N"), PIVOT_RC_COUNT,
+        N_("Observed Prop."), PIVOT_RC_OTHER,
+        N_("Test Prop."), PIVOT_RC_OTHER,
+        (bst->p == 0.5
+         ? N_("Exact Sig. (2-tailed)")
+         : N_("Exact Sig. (1-tailed)")), PIVOT_RC_SIGNIFICANCE);
+
+      pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Groups"),
+                              N_("Group 1"), N_("Group 2"), N_("Total"));
+
+      struct pivot_dimension *variables = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Variables"));
+
+      for (size_t v = 0; v < ost->n_vars; ++v)
         {
-          double n_total, sig;
-         struct string catstr[2];
           const struct variable *var = ost->vars[v];
 
-         ds_init_empty (&catstr[0]);
-         ds_init_empty (&catstr[1]);
+          int var_idx = pivot_category_create_leaf (
+            variables->root, pivot_value_new_variable (var));
 
-         if ( bst->cutpoint != SYSMIS)
-           {
-             ds_put_format (&catstr[0], "<= %.*g",
-                             DBL_DIG + 1, bst->cutpoint);
-           }
+          /* Category. */
+          if (bst->cutpoint != SYSMIS)
+            pivot_table_put3 (
+              table, 0, 0, var_idx,
+              pivot_value_new_user_text_nocopy (
+                xasprintf ("<= %.*g", DBL_DIG + 1, bst->cutpoint)));
           else
+            for (int i = 0; i < 2; i++)
+              pivot_table_put3 (
+                table, 0, i, var_idx,
+                pivot_value_new_var_value (var, cat[i][v].values));
+
+          double n_total = cat[0][v].count + cat[1][v].count;
+          double sig = calculate_binomial (cat[0][v].count, cat[1][v].count,
+                                           bst->p);
+          struct entry
             {
-              var_append_value_name (var, cat[0][v].values, &catstr[0]);
-              var_append_value_name (var, cat[1][v].values, &catstr[1]);
+              int stat_idx;
+              int group_idx;
+              double x;
+            }
+          entries[] = {
+            /* N. */
+            { 1, 0, cat[0][v].count },
+            { 1, 1, cat[1][v].count },
+            { 1, 2, n_total },
+            /* Observed Prop. */
+            { 2, 0, cat[0][v].count / n_total },
+            { 2, 1, cat[1][v].count / n_total },
+            { 2, 2, 1.0 },
+            /* Test Prop. */
+            { 3, 0, bst->p },
+            /* Significance. */
+            { 4, 0, sig }
+          };
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            {
+              const struct entry *e = &entries[i];
+              pivot_table_put3 (table, e->stat_idx, e->group_idx,
+                                var_idx, pivot_value_new_number (e->x));
             }
-
-          tab_hline (table, TAL_1, 0, tab_nc (table) -1, 1 + v * 3);
-
-          /* Titles */
-          tab_text (table, 0, 1 + v * 3, TAB_LEFT, var_to_string (var));
-          tab_text (table, 1, 1 + v * 3, TAB_LEFT, _("Group1"));
-          tab_text (table, 1, 2 + v * 3, TAB_LEFT, _("Group2"));
-          tab_text (table, 1, 3 + v * 3, TAB_LEFT, _("Total"));
-
-          /* Test Prop */
-          tab_double (table, 5, 1 + v * 3, TAB_NONE, bst->p, NULL, RC_OTHER);
-
-          /* Category labels */
-          tab_text (table, 2, 1 + v * 3, TAB_NONE, ds_cstr (&catstr[0]));
-         tab_text (table, 2, 2 + v * 3, TAB_NONE, ds_cstr (&catstr[1]));
-
-          /* Observed N */
-          tab_double (table, 3, 1 + v * 3, TAB_NONE, cat[0][v].count, NULL, RC_WEIGHT);
-          tab_double (table, 3, 2 + v * 3, TAB_NONE, cat[1][v].count, NULL, RC_WEIGHT);
-
-          n_total = cat[0][v].count + cat[1][v].count;
-          tab_double (table, 3, 3 + v * 3, TAB_NONE, n_total, NULL, RC_WEIGHT);
-
-          /* Observed Proportions */
-          tab_double (table, 4, 1 + v * 3, TAB_NONE,
-                     cat[0][v].count / n_total, NULL, RC_OTHER);
-          tab_double (table, 4, 2 + v * 3, TAB_NONE,
-                     cat[1][v].count / n_total, NULL, RC_OTHER);
-
-          tab_double (table, 4, 3 + v * 3, TAB_NONE,
-                     (cat[0][v].count + cat[1][v].count) / n_total, NULL, RC_OTHER);
-
-          /* Significance */
-          sig = calculate_binomial (cat[0][v].count, cat[1][v].count, bst->p);
-          tab_double (table, 6, 1 + v * 3, TAB_NONE, sig, NULL, RC_PVALUE);
-
-         ds_destroy (&catstr[0]);
-         ds_destroy (&catstr[1]);
         }
 
-      tab_text (table,  2, 0,  TAB_CENTER, _("Category"));
-      tab_text (table,  3, 0,  TAB_CENTER, _("N"));
-      tab_text (table,  4, 0,  TAB_CENTER, _("Observed Prop."));
-      tab_text (table,  5, 0,  TAB_CENTER, _("Test Prop."));
-
-      tab_text_format (table,  6, 0,  TAB_CENTER,
-                       _("Exact Sig. (%d-tailed)"),
-                       bst->p == 0.5 ? 2 : 1);
-
-      tab_vline (table, TAL_2, 2, 0, tab_nr (table) -1);
-      tab_submit (table);
+      pivot_table_submit (table);
     }
 
   for (i = 0; i < 2; i++)
index dd04749f987ac8ab0a5d2bc5531cfd92f8f25abe..df540651d7541b6beb56a94cdb20408cbc57056e 100644 (file)
 #include "libpspp/hash-functions.h"
 #include "libpspp/message.h"
 #include "libpspp/taint.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 /* Adds frequency counts of each value of VAR in INPUT between LO and HI to
@@ -125,158 +126,6 @@ create_freq_hash (const struct dictionary *dict,
   return casereader_destroy (input);
 }
 
-static struct tab_table *
-create_variable_frequency_table (const struct dictionary *dict,
-                                struct casereader *input,
-                                const struct chisquare_test *test,
-                                int v, struct hmap *freq_hash)
-
-{
-  int i;
-  const struct one_sample_test *ost = (const struct one_sample_test*)test;
-  int n_cells;
-  struct tab_table *table ;
-  const struct variable *var =  ost->vars[v];
-
-  const struct variable *wvar = dict_get_weight (dict);
-  const struct fmt_spec *wfmt = wvar ? var_get_print_format (wvar) : & F_8_0;
-
-  hmap_init (freq_hash);
-  if (!create_freq_hash (dict, input, var, freq_hash))
-    {
-      freq_hmap_destroy (freq_hash, var_get_width (var));
-      return NULL;
-    }
-
-  n_cells = hmap_count (freq_hash);
-
-  if ( test->n_expected > 0 && n_cells != test->n_expected )
-    {
-      msg(ME, _("CHISQUARE test specified %d expected values, but"
-               " %d distinct values were encountered in variable %s."),
-         test->n_expected, n_cells,
-         var_get_name (var)
-         );
-      freq_hmap_destroy (freq_hash, var_get_width (var));
-      return NULL;
-    }
-
-  table = tab_create(4, n_cells + 2);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_title (table, "%s", var_to_string(var));
-  tab_text (table, 1, 0, TAB_LEFT, _("Observed N"));
-  tab_text (table, 2, 0, TAB_LEFT, _("Expected N"));
-  tab_text (table, 3, 0, TAB_LEFT, _("Residual"));
-
-  tab_headers (table, 1, 0, 1, 0);
-
-  tab_box (table, TAL_1, TAL_1, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
-
-  tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 1);
-
-  tab_vline (table, TAL_2, 1, 0, tab_nr(table) - 1);
-  for ( i = 2 ; i < 4 ; ++i )
-    tab_vline (table, TAL_1, i, 0, tab_nr(table) - 1);
-
-
-  tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
-
-  return table;
-}
-
-
-static struct tab_table *
-create_combo_frequency_table (const struct dictionary *dict, const struct chisquare_test *test)
-{
-  int i;
-  const struct one_sample_test *ost = (const struct one_sample_test*)test;
-
-  struct tab_table *table ;
-
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-  int n_cells = test->hi - test->lo + 1;
-
-  table = tab_create(1 + ost->n_vars * 4, n_cells + 3);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_title (table, _("Frequencies"));
-  for ( i = 0 ; i < ost->n_vars ; ++i )
-    {
-      const struct variable *var = ost->vars[i];
-      tab_text (table, i * 4 + 1, 1, TAB_LEFT, _("Category"));
-      tab_text (table, i * 4 + 2, 1, TAB_LEFT, _("Observed N"));
-      tab_text (table, i * 4 + 3, 1, TAB_LEFT, _("Expected N"));
-      tab_text (table, i * 4 + 4, 1, TAB_LEFT, _("Residual"));
-
-      tab_vline (table, TAL_2, i * 4 + 1,
-                0, tab_nr (table) - 1);
-
-      tab_vline (table, TAL_1, i * 4 + 2,
-                0, tab_nr (table) - 1);
-
-      tab_vline (table, TAL_1, i * 4 + 3,
-                1, tab_nr (table) - 1);
-
-      tab_vline (table, TAL_1, i * 4 + 4,
-                1, tab_nr (table) - 1);
-
-
-      tab_joint_text (table,
-                     i * 4 + 1, 0,
-                     i * 4 + 4, 0,
-                     TAB_CENTER,
-                     var_to_string (var));
-    }
-
-  for ( i = test->lo ; i <= test->hi ; ++i )
-    tab_double (table, 0, 2 + i - test->lo, TAB_LEFT, 1 + i - test->lo, NULL, RC_INTEGER);
-
-  tab_headers (table, 1, 0, 2, 0);
-
-  tab_box (table, TAL_1, TAL_1, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
-
-  tab_hline (table, TAL_1, 1, tab_nc(table) - 1, 1);
-  tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 2);
-
-  tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
-
-  return table;
-}
-
-
-static struct tab_table *
-create_stats_table (const struct chisquare_test *test)
-{
-  const struct one_sample_test *ost = (const struct one_sample_test*) test;
-
-  struct tab_table *table;
-  table = tab_create (1 + ost->n_vars, 4);
-  tab_title (table, _("Test Statistics"));
-  tab_headers (table, 1, 0, 1, 0);
-
-  tab_box (table, TAL_1, TAL_1, -1, -1,
-          0, 0, tab_nc(table) - 1, tab_nr(table) - 1 );
-
-  tab_box (table, -1, -1, -1, TAL_1,
-          1, 0, tab_nc(table) - 1, tab_nr(table) - 1 );
-
-
-  tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
-  tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1);
-
-
-  tab_text (table, 0, 1, TAB_LEFT, _("Chi-Square"));
-  tab_text (table, 0, 2, TAB_LEFT, _("df"));
-  tab_text (table, 0, 3, TAB_LEFT, _("Asymp. Sig."));
-
-  return table;
-}
-
-
 void
 chisquare_execute (const struct dataset *ds,
                   struct casereader *input,
@@ -290,7 +139,6 @@ chisquare_execute (const struct dataset *ds,
   struct chisquare_test *cst = UP_CAST (test, struct chisquare_test,
                                         parent.parent);
   struct one_sample_test *ost = &cst->parent;
-  int n_cells = 0;
   double total_expected = 0.0;
 
   double *df = xzalloc (sizeof (*df) * ost->n_vars);
@@ -305,66 +153,78 @@ chisquare_execute (const struct dataset *ds,
       for ( v = 0 ; v < ost->n_vars ; ++v )
        {
           const struct variable *var = ost->vars[v];
-         double total_obs = 0.0;
-         struct hmap freq_hash;
+
+         struct hmap freq_hash = HMAP_INITIALIZER (freq_hash);
           struct casereader *reader =
             casereader_create_filter_missing (casereader_clone (input),
                                               &var, 1, exclude,
                                              NULL, NULL);
-         struct tab_table *freq_table =
-            create_variable_frequency_table (dict, reader, cst, v, &freq_hash);
+          if (!create_freq_hash (dict, reader, var, &freq_hash))
+            {
+              freq_hmap_destroy (&freq_hash, var_get_width (var));
+              return;
+            }
 
-         struct freq **ff;
+         size_t n_cells = hmap_count (&freq_hash);
+          if (cst->n_expected > 0 && n_cells != cst->n_expected)
+            {
+              msg (ME, _("CHISQUARE test specified %d expected values, but "
+                         "variable %s has %d distinct values."),
+                   cst->n_expected, var_get_name (var), n_cells);
+              freq_hmap_destroy (&freq_hash, var_get_width (var));
+              continue;
+            }
+
+          struct pivot_table *table = pivot_table_create__ (
+            pivot_value_new_variable (var));
+          pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-         if ( NULL == freq_table )
-            continue;
-          ff = freq_hmap_sort (&freq_hash, var_get_width (var));
+          pivot_dimension_create (
+            table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+            N_("Observed N"), PIVOT_RC_COUNT,
+            N_("Expected N"), PIVOT_RC_OTHER,
+            N_("Residual"), PIVOT_RC_RESIDUAL);
 
-         n_cells = hmap_count (&freq_hash);
+          struct freq **ff = freq_hmap_sort (&freq_hash, var_get_width (var));
 
-         for ( i = 0 ; i < n_cells ; ++i )
+         double total_obs = 0.0;
+         for (size_t i = 0; i < n_cells; i++)
            total_obs += ff[i]->count;
 
+          struct pivot_dimension *values = pivot_dimension_create (
+            table, PIVOT_AXIS_ROW, N_("Value"));
+          values->root->show_label = true;
+
          xsq[v] = 0.0;
-         for ( i = 0 ; i < n_cells ; ++i )
+         for (size_t i = 0; i < n_cells; i++)
            {
-             struct string str;
-             double exp;
-             const union value *observed_value = &ff[i]->values[0];
-
-             ds_init_empty (&str);
-             var_append_value_name (var, observed_value, &str);
-
-             /* The key */
-             tab_text (freq_table, 0, i + 1, TAB_LEFT, ds_cstr (&str));
-             ds_destroy (&str);
-
-
-             /* The observed N */
-             tab_double (freq_table, 1, i + 1, TAB_NONE,
-                         ff[i]->count, NULL, RC_WEIGHT);
-
-             if ( cst->n_expected > 0 )
-               exp = cst->expected[i] * total_obs / total_expected ;
-             else
-               exp = total_obs / (double) n_cells;
-
-             tab_double (freq_table, 2, i + 1, TAB_NONE,
-                         exp, NULL, RC_OTHER);
-
-             /* The residual */
-             tab_double (freq_table, 3, i + 1, TAB_NONE,
-                         ff[i]->count - exp, NULL, RC_OTHER);
+              int row = pivot_category_create_leaf (
+                values->root, pivot_value_new_var_value (
+                  var, &ff[i]->values[0]));
+
+              double exp = (cst->n_expected > 0
+                            ? cst->expected[i] * total_obs / total_expected
+                            : total_obs / (double) n_cells);
+              double entries[] = {
+                ff[i]->count,
+                exp,
+                ff[i]->count - exp,
+              };
+              for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+                pivot_table_put2 (
+                  table, j, row, pivot_value_new_number (entries[j]));
 
              xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp;
            }
 
          df[v] = n_cells - 1.0;
 
-         tab_double (freq_table, 1, i + 1, TAB_NONE,
-                     total_obs, NULL, RC_WEIGHT);
+          int row = pivot_category_create_leaf (
+            values->root, pivot_value_new_text (N_("Total")));
+          pivot_table_put2 (table, 0, row,
+                            pivot_value_new_number (total_obs));
 
-         tab_submit (freq_table);
+          pivot_table_submit (table);
 
           freq_hmap_destroy (&freq_hash, var_get_width (var));
           free (ff);
@@ -372,22 +232,38 @@ chisquare_execute (const struct dataset *ds,
     }
   else  /* ranged == true */
     {
-      struct tab_table *freq_table = create_combo_frequency_table (dict, cst);
-
-      n_cells = cst->hi - cst->lo + 1;
-
-      for ( v = 0 ; v < ost->n_vars ; ++v )
+      struct pivot_table *table = pivot_table_create (N_("Frequencies"));
+      pivot_table_set_weight_var (table, dict_get_weight (dict));
+
+      pivot_dimension_create (
+        table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+        N_("Category"),
+        N_("Observed N"), PIVOT_RC_COUNT,
+        N_("Expected N"), PIVOT_RC_OTHER,
+        N_("Residual"), PIVOT_RC_RESIDUAL);
+
+      struct pivot_dimension *var_dim
+        = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variable"));
+      for ( size_t i = 0 ; i < ost->n_vars ; ++i )
+        pivot_category_create_leaf (var_dim->root,
+                                    pivot_value_new_variable (ost->vars[i]));
+
+      struct pivot_dimension *category_dim
+        = pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Category"));
+      size_t n_cells = cst->hi - cst->lo + 1;
+      for (size_t i = 0 ; i < n_cells; ++i )
+        pivot_category_create_leaf (category_dim->root,
+                                    pivot_value_new_integer (i + 1));
+      pivot_category_create_leaves (category_dim->root, N_("Total"));
+
+      for ( size_t v = 0 ; v < ost->n_vars ; ++v )
        {
           const struct variable *var = ost->vars[v];
-         double total_obs = 0.0;
           struct casereader *reader =
             casereader_create_filter_missing (casereader_clone (input),
                                               &var, 1, exclude,
                                              NULL, NULL);
-         struct hmap freq_hash;
-         struct freq **ff;
-
-          hmap_init (&freq_hash);
+         struct hmap freq_hash = HMAP_INITIALIZER (freq_hash);
           if (!create_freq_hash_with_range (dict, reader, var,
                                             cst->lo, cst->hi, &freq_hash))
             {
@@ -395,79 +271,76 @@ chisquare_execute (const struct dataset *ds,
               continue;
             }
 
-          ff = freq_hmap_sort (&freq_hash, var_get_width (var));
+         struct freq **ff = freq_hmap_sort (&freq_hash, var_get_width (var));
 
-         for ( i = 0 ; i < hmap_count (&freq_hash) ; ++i )
+          double total_obs = 0.0;
+         for ( size_t i = 0 ; i < hmap_count (&freq_hash) ; ++i )
            total_obs += ff[i]->count;
 
          xsq[v] = 0.0;
-         for ( i = 0 ; i < hmap_count (&freq_hash) ; ++i )
+         for ( size_t i = 0 ; i < hmap_count (&freq_hash) ; ++i )
            {
-             struct string str;
-             double exp;
-
-             const union value *observed_value = &ff[i]->values[0];
+              /* Category. */
+              pivot_table_put3 (table, 0, v, i,
+                                pivot_value_new_var_value (
+                                  var, &ff[i]->values[0]));
+
+              double exp = (cst->n_expected > 0
+                            ? cst->expected[i] * total_obs / total_expected
+                            : total_obs / (double) hmap_count (&freq_hash));
+              double entries[] = {
+                ff[i]->count,
+                exp,
+                ff[i]->count - exp,
+              };
+              for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+                pivot_table_put3 (table, j + 1, v, i,
+                                  pivot_value_new_number (entries[j]));
 
-             ds_init_empty (&str);
-             var_append_value_name (ost->vars[v], observed_value, &str);
-             /* The key */
-             tab_text  (freq_table, v * 4 + 1, i + 2 , TAB_LEFT,
-                        ds_cstr (&str));
-             ds_destroy (&str);
-
-             /* The observed N */
-             tab_double (freq_table, v * 4 + 2, i + 2 , TAB_NONE,
-                         ff[i]->count, NULL, RC_WEIGHT);
-
-             if ( cst->n_expected > 0 )
-               exp = cst->expected[i] * total_obs / total_expected ;
-             else
-               exp = total_obs / (double) hmap_count (&freq_hash);
-
-             /* The expected N */
-             tab_double (freq_table, v * 4 + 3, i + 2 , TAB_NONE,
-                         exp, NULL, RC_OTHER);
-
-             /* The residual */
-             tab_double (freq_table, v * 4 + 4, i + 2 , TAB_NONE,
-                         ff[i]->count - exp, NULL, RC_OTHER);
 
              xsq[v] += (ff[i]->count - exp) * (ff[i]->count - exp) / exp;
            }
 
-
-         tab_double (freq_table, v * 4 + 2, tab_nr (freq_table) - 1, TAB_NONE,
-                     total_obs, NULL, RC_WEIGHT);
-
          df[v] = n_cells - 1.0;
 
          freq_hmap_destroy (&freq_hash, var_get_width (var));
           free (ff);
+
+          pivot_table_put3 (table, 1, v, n_cells,
+                            pivot_value_new_number (total_obs));
        }
 
-      tab_submit (freq_table);
+      pivot_table_submit (table);
     }
   ok = !taint_has_tainted_successor (casereader_get_taint (input));
   casereader_destroy (input);
 
   if (ok)
     {
-      struct tab_table *stats_table = create_stats_table (cst);
+      struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
 
-      /* Populate the summary statistics table */
-      for ( v = 0 ; v < ost->n_vars ; ++v )
+      pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                              N_("Chi-square"), PIVOT_RC_OTHER,
+                              N_("df"), PIVOT_RC_INTEGER,
+                              N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE);
+
+      struct pivot_dimension *variables = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Variable"));
+
+      for ( size_t v = 0 ; v < ost->n_vars ; ++v )
         {
           const struct variable *var = ost->vars[v];
 
-          tab_text (stats_table, 1 + v, 0, TAB_CENTER, var_get_name (var));
-
-          tab_double (stats_table, 1 + v, 1, TAB_NONE, xsq[v], NULL, RC_OTHER);
-          tab_double (stats_table, 1 + v, 2, TAB_NONE, df[v], NULL, RC_INTEGER);
+          int row = pivot_category_create_leaf (
+            variables->root, pivot_value_new_variable (var));
 
-          tab_double (stats_table, 1 + v, 3, TAB_NONE,
-                     gsl_cdf_chisq_Q (xsq[v], df[v]), NULL, RC_PVALUE);
+          double sig = gsl_cdf_chisq_Q (xsq[v], df[v]);
+          double entries[] = { xsq[v], df[v], sig };
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            pivot_table_put2 (table, i, row,
+                              pivot_value_new_number (entries[i]));
         }
-      tab_submit (stats_table);
+      pivot_table_submit (table);
     }
 
   free (xsq);
index 091715694e0aa064f202e0334c88c8acdbc3be00..480248637f4b1890dd463e37f1e9fea6518bf3f8 100644 (file)
 #include "libpspp/cast.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 struct cochran
@@ -146,103 +147,53 @@ cochran_execute (const struct dataset *ds,
 static void
 show_freqs_box (const struct one_sample_test *ost, const struct cochran *ct)
 {
-  int i;
-  const struct fmt_spec *wfmt = dict_get_weight_format (ct->dict);
-
-  const int row_headers = 1;
-  const int column_headers = 2;
-  struct tab_table *table =
-    tab_create (row_headers + 2, column_headers + ost->n_vars);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Frequencies"));
-
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_joint_text (table, 1, 0, 2, 0,
-                 TAT_TITLE | TAB_CENTER, _("Value"));
-
-  tab_text_format (table, 1, 1, 0, _("Success (%.*g)"),
-                   DBL_DIG + 1, ct->success);
-  tab_text_format (table, 2, 1, 0, _("Failure (%.*g)"),
-                   DBL_DIG + 1, ct->failure);
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  for (i = 0 ; i < ost->n_vars ; ++i)
+  struct pivot_table *table = pivot_table_create (N_("Frequencies"));
+  pivot_table_set_weight_var (table, dict_get_weight (ct->dict));
+
+  char *success = xasprintf (_("Success (%.*g)"), DBL_DIG + 1, ct->success);
+  char *failure = xasprintf (_("Failure (%.*g)"), DBL_DIG + 1, ct->failure);
+  struct pivot_dimension *values = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Value"),
+    success, PIVOT_RC_COUNT,
+    failure, PIVOT_RC_COUNT);
+  values->root->show_label = true;
+  free (failure);
+  free (success);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+
+  for (size_t i = 0 ; i < ost->n_vars ; ++i)
     {
-      tab_text (table, 0, column_headers + i,
-               TAB_LEFT, var_to_string (ost->vars[i]));
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (ost->vars[i]));
 
-      tab_double (table, 1, column_headers + i, 0,
-                 ct->hits[i], NULL, RC_WEIGHT);
-
-      tab_double (table, 2, column_headers + i, 0,
-                 ct->misses[i], NULL, RC_WEIGHT);
+      pivot_table_put2 (table, 0, row, pivot_value_new_number (ct->hits[i]));
+      pivot_table_put2 (table, 1, row, pivot_value_new_number (ct->misses[i]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
-
-
 static void
 show_sig_box (const struct cochran *ch)
 {
-  const struct fmt_spec *wfmt = dict_get_weight_format (ch->dict);
-
-  const int row_headers = 1;
-  const int column_headers = 0;
-  struct tab_table *table =
-    tab_create (row_headers + 1, column_headers + 4);
-
-
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Test Statistics"));
-
-  tab_text (table,  0, column_headers,
-           TAT_TITLE | TAB_LEFT , _("N"));
-
-  tab_text (table,  0, 1 + column_headers,
-           TAT_TITLE | TAB_LEFT , _("Cochran's Q"));
-
-  tab_text (table,  0, 2 + column_headers,
-           TAT_TITLE | TAB_LEFT, _("df"));
-
-  tab_text (table,  0, 3 + column_headers,
-           TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  tab_double (table, 1, column_headers,
-             0, ch->cc, NULL, RC_WEIGHT);
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
 
-  tab_double (table, 1, column_headers + 1,
-             0, ch->q, NULL, RC_OTHER);
+  pivot_table_set_weight_format (table, dict_get_weight_format (ch->dict));
 
-  tab_double (table, 1, column_headers + 2,
-             0, ch->df, NULL, RC_INTEGER);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Value"), N_("Value"));
 
-  tab_double (table, 1, column_headers + 3,
-             0, gsl_cdf_chisq_Q (ch->q, ch->df),
-             NULL, RC_PVALUE);
+  pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("N"), PIVOT_RC_COUNT,
+    N_("Cochran's Q"), PIVOT_RC_SIGNIFICANCE,
+    N_("df"), PIVOT_RC_INTEGER,
+    N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_submit (table);
+  double sig = gsl_cdf_chisq_Q (ch->q, ch->df);
+  double entries[] = { ch->cc, ch->q, ch->df, sig };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    pivot_table_put2 (table, 0, i, pivot_value_new_number (entries[i]));
+  pivot_table_submit (table);
 }
index 207ec77528bd68b50b3357a4eab970070a47cc12..826a640a8e99a6956cf069baaf35da4c17dc3fd7 100644 (file)
@@ -36,7 +36,7 @@
 #include "math/correlation.h"
 #include "math/covariance.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 #include "gl/minmax.h"
@@ -83,77 +83,39 @@ struct corr_opts
 
 
 static void
-output_descriptives (const struct corr *corr, const gsl_matrix *means,
+output_descriptives (const struct corr *corr, const struct corr_opts *opts,
+                     const gsl_matrix *means,
                     const gsl_matrix *vars, const gsl_matrix *ns)
 {
-  const int nr = corr->n_vars_total + 1;
-  const int nc = 4;
-  int c, r;
+  struct pivot_table *table = pivot_table_create (
+    N_("Descriptive Statistics"));
+  pivot_table_set_weight_var (table, opts->wv);
 
-  const int heading_columns = 1;
-  const int heading_rows = 1;
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Mean"), PIVOT_RC_OTHER,
+                          N_("Std. Deviation"), PIVOT_RC_OTHER,
+                          N_("N"), PIVOT_RC_COUNT);
 
-  struct tab_table *t = tab_create (nc, nr);
-  tab_title (t, _("Descriptive Statistics"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
 
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
-
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("N"));
-
-  for (r = 0 ; r < corr->n_vars_total ; ++r)
+  for (size_t r = 0 ; r < corr->n_vars_total ; ++r)
     {
       const struct variable *v = corr->vars[r];
-      tab_text (t, 0, r + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v));
-
-      for (c = 1 ; c < nc ; ++c)
-       {
-         double x ;
-         double n;
-         switch (c)
-           {
-           case 1:
-             x = gsl_matrix_get (means, r, 0);
-             break;
-           case 2:
-             x = gsl_matrix_get (vars, r, 0);
 
-             /* Here we want to display the non-biased estimator */
-             n = gsl_matrix_get (ns, r, 0);
-             x *= n / (n -1);
-
-             x = sqrt (x);
-             break;
-           case 3:
-             x = gsl_matrix_get (ns, r, 0);
-             break;
-           default:
-             NOT_REACHED ();
-           };
+      int row = pivot_category_create_leaf (variables->root,
+                                            pivot_value_new_variable (v));
 
-         tab_double (t, c, r + heading_rows, 0, x, NULL, RC_OTHER);
-       }
+      double mean = gsl_matrix_get (means, r, 0);
+      /* Here we want to display the non-biased estimator */
+      double n = gsl_matrix_get (ns, r, 0);
+      double stddev = sqrt (gsl_matrix_get (vars, r, 0) * n / (n - 1));
+      double entries[] = { mean, stddev, n };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 static void
@@ -161,123 +123,84 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
                    const gsl_matrix *cm, const gsl_matrix *samples,
                    const gsl_matrix *cv)
 {
-  int r, c;
-  struct tab_table *t;
-  int matrix_cols;
-  int nr = corr->n_vars1;
-  int nc = matrix_cols = corr->n_vars_total > corr->n_vars1 ?
-    corr->n_vars_total - corr->n_vars1 : corr->n_vars1;
-
-  const struct fmt_spec *wfmt = opts->wv ? var_get_print_format (opts->wv) : & F_8_0;
-
-  const int heading_columns = 2;
-  const int heading_rows = 1;
-
-  int rows_per_variable = opts->missing_type == CORR_LISTWISE ? 2 : 3;
-
-  if (opts->statistics & STATS_XPROD)
-    rows_per_variable += 2;
-
-  /* Two header columns */
-  nc += heading_columns;
-
-  /* Three data per variable */
-  nr *= rows_per_variable;
-
-  /* One header row */
-  nr += heading_rows;
-
-  t = tab_create (nc, nr);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_title (t, _("Correlations"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
+  struct pivot_table *table = pivot_table_create (N_("Correlations"));
+  pivot_table_set_weight_var (table, opts->wv);
 
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
+  /* Column variable dimension. */
+  struct pivot_dimension *columns = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Variables"));
 
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_vline (t, TAL_1, 1, heading_rows, nr - 1);
-
-  /* Row Headers */
-  for (r = 0 ; r < corr->n_vars1 ; ++r)
-    {
-      tab_text (t, 0, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE,
-               var_to_string (corr->vars[r]));
-
-      tab_text (t, 1, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Pearson Correlation"));
-      tab_text (t, 1, 2 + r * rows_per_variable, TAB_LEFT | TAT_TITLE,
-               (opts->tails == 2) ? _("Sig. (2-tailed)") : _("Sig. (1-tailed)"));
-
-      if (opts->statistics & STATS_XPROD)
-       {
-         tab_text (t, 1, 3 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Cross-products"));
-         tab_text (t, 1, 4 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Covariance"));
-       }
-
-      if ( opts->missing_type != CORR_LISTWISE )
-       tab_text (t, 1, rows_per_variable + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("N"));
-
-      tab_hline (t, TAL_1, 0, nc - 1, r * rows_per_variable + 1);
-    }
-
-  /* Column Headers */
-  for (c = 0 ; c < matrix_cols ; ++c)
+  int matrix_cols = (corr->n_vars_total > corr->n_vars1
+                     ? corr->n_vars_total - corr->n_vars1
+                     : corr->n_vars1);
+  for (int c = 0; c < matrix_cols; c++)
     {
       const struct variable *v = corr->n_vars_total > corr->n_vars1 ?
        corr->vars[corr->n_vars1 + c] : corr->vars[c];
-      tab_text (t, heading_columns + c, 0, TAB_LEFT | TAT_TITLE, var_to_string (v));
+      pivot_category_create_leaf (columns->root, pivot_value_new_variable (v));
     }
 
-  for (r = 0 ; r < corr->n_vars1 ; ++r)
-    {
-      const int row = r * rows_per_variable + heading_rows;
-      for (c = 0 ; c < matrix_cols ; ++c)
-       {
-         unsigned char flags = 0;
-         const int col_index = corr->n_vars_total > corr->n_vars1 ?
-           corr->n_vars1 + c :
-           c;
-         double pearson = gsl_matrix_get (cm, r, col_index);
-         double w = gsl_matrix_get (samples, r, col_index);
-         double sig = opts->tails * significance_of_correlation (pearson, w);
-
-         if ( opts->missing_type != CORR_LISTWISE )
-           tab_double (t, c + heading_columns, row + rows_per_variable - 1, 0, w, NULL, RC_WEIGHT);
+  /* Statistics dimension. */
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("Pearson Correlation"), PIVOT_RC_CORRELATION,
+    opts->tails == 2 ? N_("Sig. (2-tailed)") : N_("Sig. (1-tailed)"),
+    PIVOT_RC_SIGNIFICANCE);
 
-         if ( col_index != r)
-           tab_double (t, c + heading_columns, row + 1, 0,  sig, NULL, RC_PVALUE);
+  if (opts->statistics & STATS_XPROD)
+    pivot_category_create_leaves (statistics->root, N_("Cross-products"),
+                                  N_("Covariance"));
 
-         if ( opts->sig && col_index != r && sig < 0.05)
-           flags = TAB_EMPH;
+  if (opts->missing_type != CORR_LISTWISE)
+    pivot_category_create_leaves (statistics->root, N_("N"), PIVOT_RC_COUNT);
 
-         tab_double (t, c + heading_columns, row, flags, pearson, NULL, RC_OTHER);
+  /* Row variable dimension. */
+  struct pivot_dimension *rows = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+  for (size_t r = 0; r < corr->n_vars1; r++)
+    pivot_category_create_leaf (rows->root,
+                                pivot_value_new_variable (corr->vars[r]));
 
-         if (opts->statistics & STATS_XPROD)
-           {
-             double cov = gsl_matrix_get (cv, r, col_index);
-             const double xprod_dev = cov * w;
-             cov *= w / (w - 1.0);
+  struct pivot_footnote *sig_footnote = pivot_table_create_footnote (
+    table, pivot_value_new_text (N_("Significant at .05 level")));
 
-             tab_double (t, c + heading_columns, row + 2, 0, xprod_dev, NULL, RC_OTHER);
-             tab_double (t, c + heading_columns, row + 3, 0, cov, NULL, RC_OTHER);
-           }
-       }
-    }
+  for (int r = 0; r < corr->n_vars1; r++)
+    for (int c = 0; c < matrix_cols; c++)
+      {
+        const int col_index = (corr->n_vars_total > corr->n_vars1
+                               ? corr->n_vars1 + c
+                               : c);
+        double pearson = gsl_matrix_get (cm, r, col_index);
+        double w = gsl_matrix_get (samples, r, col_index);
+        double sig = opts->tails * significance_of_correlation (pearson, w);
+
+        double entries[5];
+        int n = 0;
+        entries[n++] = pearson;
+        entries[n++] = col_index != r ? sig : SYSMIS;
+        if (opts->statistics & STATS_XPROD)
+          {
+            double cov = gsl_matrix_get (cv, r, col_index);
+            const double xprod_dev = cov * w;
+            cov *= w / (w - 1.0);
+
+            entries[n++] = xprod_dev;
+            entries[n++] = cov;
+          }
+        if (opts->missing_type != CORR_LISTWISE)
+          entries[n++] = w;
+
+        for (int i = 0; i < n; i++)
+          if (entries[i] != SYSMIS)
+            {
+              struct pivot_value *v = pivot_value_new_number (entries[i]);
+              if (!i && opts->sig && col_index != r && sig < 0.05)
+                pivot_value_add_footnote (v, sig_footnote);
+              pivot_table_put3 (table, c, i, r, v);
+            }
+      }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
@@ -319,7 +242,7 @@ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr
   corr_matrix = correlation_from_covariance (cov_matrix, var_matrix);
 
   if ( opts->statistics & STATS_DESCRIPTIVES)
-    output_descriptives (corr, mean_matrix, var_matrix, samples_matrix);
+    output_descriptives (corr, opts, mean_matrix, var_matrix, samples_matrix);
 
   output_correlation (corr, opts, corr_matrix,
                      samples_matrix, cov_matrix);
index c44ccf64c796fd095e9883835487bfd8669606a2..dfafbe9f3eba199717d66ce2e8ce8a736d1bd6f3 100644 (file)
@@ -55,7 +55,7 @@
 #include "libpspp/misc.h"
 #include "libpspp/pool.h"
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "output/chart-item.h"
 #include "output/charts/barchart.h"
 
@@ -131,6 +131,7 @@ struct crosstabulation
     /* Constants (0 or more). */
     int n_consts;
     struct xtab_var *const_vars;
+    size_t *const_indexes;
 
     /* Data. */
     struct hmap data;
@@ -203,7 +204,6 @@ static void tabulate_general_case (struct crosstabulation *, const struct ccase
 static void tabulate_integer_case (struct crosstabulation *, const struct ccase *,
                                    double weight);
 static void postcalc (struct crosstabs_proc *);
-static void submit (struct crosstabulation *, struct tab_table *);
 
 static double
 round_weight (const struct crosstabs_proc *proc, double weight)
@@ -211,6 +211,33 @@ round_weight (const struct crosstabs_proc *proc, double weight)
   return proc->round_down ? floor (weight) : floor (weight + 0.5);
 }
 
+#define FOR_EACH_POPULATED_COLUMN(C, XT) \
+  for (int C = next_populated_column (0, XT); \
+       C < (XT)->vars[COL_VAR].n_values;      \
+       C = next_populated_column (C + 1, XT))
+static int
+next_populated_column (int c, const struct crosstabulation *xt)
+{
+  int n_columns = xt->vars[COL_VAR].n_values;
+  for (; c < n_columns; c++)
+    if (xt->col_tot[c])
+      break;
+  return c;
+}
+
+#define FOR_EACH_POPULATED_ROW(R, XT) \
+  for (int R = next_populated_row (0, XT); R < (XT)->vars[ROW_VAR].n_values; \
+       R = next_populated_row (R + 1, XT))
+static int
+next_populated_row (int r, const struct crosstabulation *xt)
+{
+  int n_rows = xt->vars[ROW_VAR].n_values;
+  for (; r < n_rows; r++)
+    if (xt->row_tot[r])
+      break;
+  return r;
+}
+
 /* Parses and executes the CROSSTABS procedure. */
 int
 cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
@@ -806,16 +833,26 @@ make_crosstabulation_subset (struct crosstabulation *xt, size_t row0,
   if (xt->n_vars > 2)
     {
       assert (xt->n_consts == 0);
-      subset->missing = xt->missing;
       subset->n_vars = 2;
       subset->vars = xt->vars;
 
       subset->n_consts = xt->n_vars - 2;
       subset->const_vars = xt->vars + 2;
+      subset->const_indexes = xcalloc (subset->n_consts,
+                                       sizeof *subset->const_indexes);
       for (size_t i = 0; i < subset->n_consts; i++)
         {
-          subset->const_vars[i].n_values = 1;
-          subset->const_vars[i].values = &xt->entries[row0]->values[2 + i];
+          const union value *value = &xt->entries[row0]->values[2 + i];
+
+          for (size_t j = 0; j < xt->vars[2 + i].n_values; j++)
+            if (value_equal (&xt->vars[2 + i].values[j], value,
+                             var_get_width (xt->vars[2 + i].var)))
+              {
+                subset->const_indexes[i] = j;
+                goto found;
+              }
+          NOT_REACHED ();
+        found: ;
         }
     }
   subset->entries = &xt->entries[row0];
@@ -879,115 +916,80 @@ compare_table_entry_3way_inv (const void *ap_, const void *bp_, const void *xt_)
   return -compare_table_entry_3way (ap_, bp_, xt_);
 }
 
-static int
-find_first_difference (const struct crosstabulation *xt, size_t row)
-{
-  if (row == 0)
-    return xt->n_vars - 1;
-  else
-    {
-      const struct freq *a = xt->entries[row];
-      const struct freq *b = xt->entries[row - 1];
-      int col;
-
-      for (col = xt->n_vars - 1; col >= 0; col--)
-        if (compare_table_entry_var_3way (a, b, xt, col))
-          return col;
-      NOT_REACHED ();
-    }
-}
-
 /* Output a table summarizing the cases processed. */
 static void
 make_summary_table (struct crosstabs_proc *proc)
 {
-  struct tab_table *summary;
-  struct crosstabulation *xt;
-  struct string name;
-  int i;
+  struct pivot_table *table = pivot_table_create (N_("Summary"));
+  pivot_table_set_weight_var (table, dict_get_weight (proc->dict));
 
-  summary = tab_create (7, 3 + proc->n_pivots);
-  tab_set_format (summary, RC_WEIGHT, &proc->weight_format);
-  tab_title (summary, _("Summary."));
-  tab_headers (summary, 1, 0, 3, 0);
-  tab_joint_text (summary, 1, 0, 6, 0, TAB_CENTER, _("Cases"));
-  tab_joint_text (summary, 1, 1, 2, 1, TAB_CENTER, _("Valid"));
-  tab_joint_text (summary, 3, 1, 4, 1, TAB_CENTER, _("Missing"));
-  tab_joint_text (summary, 5, 1, 6, 1, TAB_CENTER, _("Total"));
-  tab_hline (summary, TAL_1, 1, 6, 1);
-  tab_hline (summary, TAL_1, 1, 6, 2);
-  tab_vline (summary, TAL_1, 3, 1, 1);
-  tab_vline (summary, TAL_1, 5, 1, 1);
-  for (i = 0; i < 3; i++)
-    {
-      tab_text (summary, 1 + i * 2, 2, TAB_RIGHT, _("N"));
-      tab_text (summary, 2 + i * 2, 2, TAB_RIGHT, _("Percent"));
-    }
-  tab_offset (summary, 0, 3);
-
-  ds_init_empty (&name);
-  for (xt = &proc->pivots[0]; xt < &proc->pivots[proc->n_pivots]; xt++)
-    {
-      double valid;
-      double n[3];
-      size_t i;
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT);
 
-      tab_hline (summary, TAL_1, 0, 6, 0);
+  struct pivot_dimension *cases = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Cases"),
+    N_("Valid"), N_("Missing"), N_("Total"));
+  cases->root->show_label = true;
 
-      ds_clear (&name);
-      for (i = 0; i < xt->n_vars; i++)
+  struct pivot_dimension *tables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Crosstabulation"));
+  for (struct crosstabulation *xt = &proc->pivots[0];
+       xt < &proc->pivots[proc->n_pivots]; xt++)
+    {
+      struct string name = DS_EMPTY_INITIALIZER;
+      for (size_t i = 0; i < xt->n_vars; i++)
         {
           if (i > 0)
-            ds_put_cstr (&name, " * ");
+            ds_put_cstr (&name, " × ");
           ds_put_cstr (&name, var_to_string (xt->vars[i].var));
         }
-      tab_text (summary, 0, 0, TAB_LEFT, ds_cstr (&name));
 
-      valid = 0.;
-      for (i = 0; i < xt->n_entries; i++)
+      int row = pivot_category_create_leaf (
+        tables->root,
+        pivot_value_new_user_text_nocopy (ds_steal_cstr (&name)));
+
+      double valid = 0.;
+      for (size_t i = 0; i < xt->n_entries; i++)
         valid += xt->entries[i]->count;
 
+      double n[3];
       n[0] = valid;
       n[1] = xt->missing;
       n[2] = n[0] + n[1];
-      for (i = 0; i < 3; i++)
+      for (int i = 0; i < 3; i++)
         {
-          tab_double (summary, i * 2 + 1, 0, TAB_RIGHT, n[i], NULL, RC_WEIGHT);
-          tab_text_format (summary, i * 2 + 2, 0, TAB_RIGHT, "%.1f%%",
-                           n[i] / n[2] * 100.);
+          pivot_table_put3 (table, 0, i, row, pivot_value_new_number (n[i]));
+          pivot_table_put3 (table, 1, i, row,
+                            pivot_value_new_number (n[i] / n[2] * 100.0));
         }
-
-      tab_next_row (summary);
     }
-  ds_destroy (&name);
 
-  submit (NULL, summary);
+  pivot_table_submit (table);
 }
 \f
 /* Output. */
 
-static struct tab_table *create_crosstab_table (struct crosstabs_proc *,
-                                                struct crosstabulation *);
-static struct tab_table *create_chisq_table (struct crosstabs_proc *proc, struct crosstabulation *);
-static struct tab_table *create_sym_table (struct crosstabs_proc *proc, struct crosstabulation *);
-static struct tab_table *create_risk_table (struct crosstabs_proc *proc, struct crosstabulation *);
-static struct tab_table *create_direct_table (struct crosstabs_proc *proc, struct crosstabulation *);
-static void display_dimensions (struct crosstabs_proc *, struct crosstabulation *,
-                                struct tab_table *, int first_difference);
+static struct pivot_table *create_crosstab_table (
+  struct crosstabs_proc *, struct crosstabulation *,
+  size_t crs_leaves[CRS_CL_count]);
+static struct pivot_table *create_chisq_table (struct crosstabulation *);
+static struct pivot_table *create_sym_table (struct crosstabulation *);
+static struct pivot_table *create_risk_table (
+  struct crosstabulation *, struct pivot_dimension **risk_statistics);
+static struct pivot_table *create_direct_table (struct crosstabulation *);
 static void display_crosstabulation (struct crosstabs_proc *,
                                      struct crosstabulation *,
-                                     struct tab_table *);
-static void display_chisq (struct crosstabulation *, struct tab_table *,
-                           bool *showed_fisher);
-static void display_symmetric (struct crosstabs_proc *, struct crosstabulation *,
-                               struct tab_table *);
-static void display_risk (struct crosstabulation *, struct tab_table *);
-static void display_directional (struct crosstabs_proc *, struct crosstabulation *,
-                                 struct tab_table *);
-static void table_value_missing (struct crosstabs_proc *proc,
-                                 struct tab_table *table, int c, int r,
-                                unsigned char opt, const union value *v,
-                                const struct variable *var);
+                                     struct pivot_table *,
+                                     size_t crs_leaves[CRS_CL_count]);
+static void display_chisq (struct crosstabulation *, struct pivot_table *);
+static void display_symmetric (struct crosstabs_proc *,
+                               struct crosstabulation *, struct pivot_table *);
+static void display_risk (struct crosstabulation *, struct pivot_table *,
+                          struct pivot_dimension *risk_statistics);
+static void display_directional (struct crosstabs_proc *,
+                                 struct crosstabulation *,
+                                 struct pivot_table *);
 static void delete_missing (struct crosstabulation *);
 static void build_matrix (struct crosstabulation *);
 
@@ -995,15 +997,8 @@ static void build_matrix (struct crosstabulation *);
 static void
 output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt)
 {
-  struct tab_table *table = NULL; /* Crosstabulation table. */
-  struct tab_table *chisq = NULL; /* Chi-square table. */
-  bool showed_fisher = false;
-  struct tab_table *sym = NULL;   /* Symmetric measures table. */
-  struct tab_table *risk = NULL;  /* Risk estimate table. */
-  struct tab_table *direct = NULL; /* Directional measures table. */
-  size_t row0, row1;
-
-  enum_var_values (xt, COL_VAR, proc->descending);
+  for (size_t i = 0; i < xt->n_vars; i++)
+    enum_var_values (xt, i, proc->descending);
 
   if (xt->vars[COL_VAR].n_values == 0)
     {
@@ -1012,7 +1007,7 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt)
 
       ds_init_cstr (&vars, var_to_string (xt->vars[0].var));
       for (i = 1; i < xt->n_vars; i++)
-        ds_put_format (&vars, " * %s", var_to_string (xt->vars[i].var));
+        ds_put_format (&vars, " × %s", var_to_string (xt->vars[i].var));
 
       /* TRANSLATORS: The %s here describes a crosstabulation.  It takes the
          form "var1 * var2 * var3 * ...".  */
@@ -1024,32 +1019,38 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt)
       return;
     }
 
-  if (proc->cells)
-    table = create_crosstab_table (proc, xt);
-  if (proc->statistics & (1u << CRS_ST_CHISQ))
-    chisq = create_chisq_table (proc, xt);
-  if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC)
-                          | (1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU)
-                          | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_CORR)
-                          | (1u << CRS_ST_KAPPA)))
-    sym = create_sym_table (proc, xt);
-  if (proc->statistics & (1u << CRS_ST_RISK))
-    risk = create_risk_table (proc, xt);
-  if (proc->statistics & ((1u << CRS_ST_LAMBDA) | (1u << CRS_ST_UC)
-                          | (1u << CRS_ST_D) | (1u << CRS_ST_ETA)))
-    direct = create_direct_table (proc, xt);
-
-  row0 = row1 = 0;
+  size_t crs_leaves[CRS_CL_count];
+  struct pivot_table *table = (proc->cells
+                               ? create_crosstab_table (proc, xt, crs_leaves)
+                               : NULL);
+  struct pivot_table *chisq = (proc->statistics & (1u << CRS_ST_CHISQ)
+                               ? create_chisq_table (xt)
+                               : NULL);
+  struct pivot_table *sym
+    = (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC)
+                           | (1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU)
+                           | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_CORR)
+                           | (1u << CRS_ST_KAPPA))
+       ? create_sym_table (xt)
+       : NULL);
+  struct pivot_dimension *risk_statistics = NULL;
+  struct pivot_table *risk = (proc->statistics & (1u << CRS_ST_RISK)
+                              ? create_risk_table (xt, &risk_statistics)
+                              : NULL);
+  struct pivot_table *direct
+    = (proc->statistics & ((1u << CRS_ST_LAMBDA) | (1u << CRS_ST_UC)
+                           | (1u << CRS_ST_D) | (1u << CRS_ST_ETA))
+       ? create_direct_table (xt)
+       : NULL);
+
+  size_t row0 = 0;
+  size_t row1 = 0;
   while (find_crosstab (xt, &row0, &row1))
     {
       struct crosstabulation x;
-      int first_difference;
 
       make_crosstabulation_subset (xt, row0, row1, &x);
 
-      /* Find all the row variable values. */
-      enum_var_values (&x, ROW_VAR, proc->descending);
-
       size_t n_rows = x.vars[ROW_VAR].n_values;
       size_t n_cols = x.vars[COL_VAR].n_values;
       if (size_overflow_p (xtimes (xtimes (n_rows, n_cols), sizeof (double))))
@@ -1058,71 +1059,52 @@ output_crosstabulation (struct crosstabs_proc *proc, struct crosstabulation *xt)
       x.col_tot = xmalloc (n_cols * sizeof *x.col_tot);
       x.mat = xmalloc (n_rows * n_cols * sizeof *x.mat);
 
-      /* Allocate table space for the matrix. */
-      if (table
-          && tab_row (table) + (n_rows + 1) * proc->n_cells > tab_nr (table))
-       tab_realloc (table, -1,
-                    MAX (tab_nr (table) + (n_rows + 1) * proc->n_cells,
-                         tab_nr (table) * xt->n_entries / x.n_entries));
-
       build_matrix (&x);
 
       /* Find the first variable that differs from the last subtable. */
-      first_difference = find_first_difference (xt, row0);
       if (table)
-        {
-          display_dimensions (proc, &x, table, first_difference);
-          display_crosstabulation (proc, &x, table);
-        }
+        display_crosstabulation (proc, &x, table, crs_leaves);
 
       if (proc->exclude == MV_NEVER)
        delete_missing (&x);
 
       if (chisq)
-        {
-          display_dimensions (proc, &x, chisq, first_difference);
-          display_chisq (&x, chisq, &showed_fisher);
-        }
+        display_chisq (&x, chisq);
+
       if (sym)
-        {
-          display_dimensions (proc, &x, sym, first_difference);
-          display_symmetric (proc, &x, sym);
-        }
+        display_symmetric (proc, &x, sym);
       if (risk)
-        {
-          display_dimensions (proc, &x, risk, first_difference);
-          display_risk (&x, risk);
-        }
+        display_risk (&x, risk, risk_statistics);
       if (direct)
-        {
-          display_dimensions (proc, &x, direct, first_difference);
-          display_directional (proc, &x, direct);
-        }
-
-      /* Free the parts of x that are not owned by xt.  In
-         particular we must not free x.cols, which is the same as
-         xt->cols, which is freed at the end of this function. */
-      free_var_values (&x, ROW_VAR);
+        display_directional (proc, &x, direct);
 
       free (x.mat);
       free (x.row_tot);
       free (x.col_tot);
     }
 
-  submit (NULL, table);
+  if (table)
+    pivot_table_submit (table);
 
   if (chisq)
+    pivot_table_submit (chisq);
+
+  if (sym)
+    pivot_table_submit (sym);
+
+  if (risk)
     {
-      if (!showed_fisher)
-       tab_resize (chisq, 4 + (xt->n_vars - 2), -1);
-      submit (xt, chisq);
+      if (!pivot_table_is_empty (risk))
+        pivot_table_submit (risk);
+      else
+        pivot_table_destroy (risk);
     }
 
-  submit (xt, sym);
-  submit (xt, risk);
-  submit (xt, direct);
+  if (direct)
+    pivot_table_submit (direct);
 
-  free_var_values (xt, COL_VAR);
+  for (size_t i = 0; i < xt->n_vars; i++)
+    free_var_values (xt, i);
 }
 
 static void
@@ -1210,213 +1192,245 @@ build_matrix (struct crosstabulation *x)
     x->total += x->col_tot[col];
 }
 
-static struct tab_table *
-create_crosstab_table (struct crosstabs_proc *proc, struct crosstabulation *xt)
+static void
+add_var_dimension (struct pivot_table *table, const struct xtab_var *var,
+                   enum pivot_axis_type axis_type, bool total)
 {
-  struct tuple
-    {
-      int value;
-      const char *name;
-    };
-  static const struct tuple names[] =
-    {
-      {CRS_CL_COUNT, N_("count")},
-      {CRS_CL_ROW, N_("row %")},
-      {CRS_CL_COLUMN, N_("column %")},
-      {CRS_CL_TOTAL, N_("total %")},
-      {CRS_CL_EXPECTED, N_("expected")},
-      {CRS_CL_RESIDUAL, N_("residual")},
-      {CRS_CL_SRESIDUAL, N_("std. resid.")},
-      {CRS_CL_ASRESIDUAL, N_("adj. resid.")},
-    };
-  const int n_names = sizeof names / sizeof *names;
-  const struct tuple *t;
+  struct pivot_dimension *d = pivot_dimension_create__ (
+    table, axis_type, pivot_value_new_variable (var->var));
 
-  struct tab_table *table;
-  struct string title;
-  struct crosstabulation x;
+  struct pivot_footnote *missing_footnote = pivot_table_create_footnote (
+    table, pivot_value_new_text (N_("Missing value")));
 
-  int i;
+  struct pivot_category *group = pivot_category_create_group__ (
+    d->root, pivot_value_new_variable (var->var));
+  for (size_t j = 0; j < var->n_values; j++)
+    {
+      struct pivot_value *value = pivot_value_new_var_value (
+        var->var, &var->values[j]);
+      if (var_is_value_missing (var->var, &var->values[j], MV_ANY))
+        pivot_value_add_footnote (value, missing_footnote);
+      pivot_category_create_leaf (group, value);
+    }
 
-  make_crosstabulation_subset (xt, 0, 0, &x);
-
-  size_t n_cols = x.vars[COL_VAR].n_values;
-  table = tab_create (x.n_consts + 1 + n_cols + 1,
-                      (x.n_entries / n_cols) * 3 / 2 * proc->n_cells + 10);
-  tab_headers (table, x.n_consts + 1, 0, 2, 0);
-  tab_set_format (table, RC_WEIGHT, &proc->weight_format);
-
-  /* First header line. */
-  tab_joint_text (table, x.n_consts + 1, 0,
-                  (x.n_consts + 1) + (n_cols - 1), 0,
-                  TAB_CENTER | TAT_TITLE, var_to_string (x.vars[COL_VAR].var));
-
-  tab_hline (table, TAL_1, x.n_consts + 1,
-             x.n_consts + 2 + n_cols - 2, 1);
-
-  /* Second header line. */
-  for (i = 2; i < x.n_consts + 2; i++)
-    tab_joint_text (table, x.n_consts + 2 - i - 1, 0,
-                    x.n_consts + 2 - i - 1, 1,
-                    TAB_RIGHT | TAT_TITLE, var_to_string (x.vars[i].var));
-  tab_text (table, x.n_consts + 2 - 2, 1, TAB_RIGHT | TAT_TITLE,
-            var_to_string (x.vars[ROW_VAR].var));
-  for (i = 0; i < n_cols; i++)
-    table_value_missing (proc, table, x.n_consts + 2 + i - 1, 1, TAB_RIGHT,
-                         &x.vars[COL_VAR].values[i], x.vars[COL_VAR].var);
-  tab_text (table, x.n_consts + 2 + n_cols - 1, 1, TAB_CENTER, _("Total"));
-
-  tab_hline (table, TAL_1, 0, x.n_consts + 2 + n_cols - 1, 2);
-  tab_vline (table, TAL_1, x.n_consts + 2 + n_cols - 1, 0, 1);
+  if (total)
+    pivot_category_create_leaf (d->root, pivot_value_new_text (N_("Total")));
+}
 
+static struct pivot_table *
+create_crosstab_table (struct crosstabs_proc *proc, struct crosstabulation *xt,
+                       size_t crs_leaves[CRS_CL_count])
+{
   /* Title. */
-  ds_init_empty (&title);
-  for (i = 0; i < x.n_consts + 2; i++)
+  struct string title = DS_EMPTY_INITIALIZER;
+  for (size_t i = 0; i < xt->n_vars; i++)
     {
       if (i)
-        ds_put_cstr (&title, " * ");
-      ds_put_cstr (&title, var_to_string (x.vars[i].var));
+        ds_put_cstr (&title, " × ");
+      ds_put_cstr (&title, var_to_string (xt->vars[i].var));
     }
-  for (i = 0; i < xt->n_consts; i++)
+  for (size_t i = 0; i < xt->n_consts; i++)
     {
       const struct variable *var = xt->const_vars[i].var;
+      const union value *value = &xt->entries[0]->values[2 + i];
       char *s;
 
       ds_put_format (&title, ", %s=", var_to_string (var));
 
       /* Insert the formatted value of VAR without any leading spaces. */
-      s = data_out (&xt->const_vars[i].values[0], var_get_encoding (var),
-                    var_get_print_format (var));
+      s = data_out (value, var_get_encoding (var), var_get_print_format (var));
       ds_put_cstr (&title, s + strspn (s, " "));
       free (s);
     }
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_user_text_nocopy (ds_steal_cstr (&title)));
+  pivot_table_set_weight_format (table, &proc->weight_format);
+  table->omit_empty = true;
 
-  ds_put_cstr (&title, " [");
-  i = 0;
-  for (t = names; t < &names[n_names]; t++)
-    if (proc->cells & (1u << t->value))
-      {
-        if (i++)
-          ds_put_cstr (&title, ", ");
-        ds_put_cstr (&title, gettext (t->name));
-      }
-  ds_put_cstr (&title, "].");
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"));
+
+  struct statistic
+    {
+      const char *label;
+      const char *rc;
+    };
+  static const struct statistic stats[CRS_CL_count] =
+    {
+      [CRS_CL_COUNT] = { N_("Count"), PIVOT_RC_COUNT },
+      [CRS_CL_ROW] = { N_("Row %"), PIVOT_RC_PERCENT },
+      [CRS_CL_COLUMN] = { N_("Column %"), PIVOT_RC_PERCENT },
+      [CRS_CL_TOTAL] = { N_("Total %"), PIVOT_RC_PERCENT },
+      [CRS_CL_EXPECTED] = { N_("Expected"), PIVOT_RC_OTHER },
+      [CRS_CL_RESIDUAL] = { N_("Residual"), PIVOT_RC_RESIDUAL },
+      [CRS_CL_SRESIDUAL] = { N_("Std. Residual"), PIVOT_RC_RESIDUAL },
+      [CRS_CL_ASRESIDUAL] = { N_("Adjusted Residual"), PIVOT_RC_RESIDUAL },
+    };
+  for (size_t i = 0; i < CRS_CL_count; i++)
+    if (proc->cells & (1u << i) && stats[i].label)
+        crs_leaves[i] = pivot_category_create_leaf_rc (
+          statistics->root, pivot_value_new_text (stats[i].label),
+          stats[i].rc);
 
-  tab_title (table, "%s", ds_cstr (&title));
-  ds_destroy (&title);
+  for (size_t i = 0; i < xt->n_vars; i++)
+    add_var_dimension (table, &xt->vars[i],
+                       i == COL_VAR ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW,
+                       true);
 
-  tab_offset (table, 0, 2);
   return table;
 }
 
-static struct tab_table *
-create_chisq_table (struct crosstabs_proc *proc, struct crosstabulation *xt)
+static struct pivot_table *
+create_chisq_table (struct crosstabulation *xt)
 {
-  struct tab_table *chisq;
-
-  size_t n_cols = xt->vars[COL_VAR].n_values;
-  chisq = tab_create (6 + (xt->n_vars - 2),
-                      xt->n_entries / n_cols * 3 / 2 * N_CHISQ + 10);
-  tab_headers (chisq, 1 + (xt->n_vars - 2), 0, 1, 0);
-  tab_set_format (chisq, RC_WEIGHT, &proc->weight_format);
-
-  tab_title (chisq, _("Chi-square tests."));
-
-  tab_offset (chisq, xt->n_vars - 2, 0);
-  tab_text (chisq, 0, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
-  tab_text (chisq, 1, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
-  tab_text (chisq, 2, 0, TAB_RIGHT | TAT_TITLE, _("df"));
-  tab_text (chisq, 3, 0, TAB_RIGHT | TAT_TITLE,
-            _("Asymp. Sig. (2-tailed)"));
-  tab_text_format (chisq, 4, 0, TAB_RIGHT | TAT_TITLE,
-            _("Exact Sig. (%d-tailed)"), 2);
-  tab_text_format (chisq, 5, 0, TAB_RIGHT | TAT_TITLE,
-            _("Exact Sig. (%d-tailed)"), 1);
-  tab_offset (chisq, 0, 1);
+  struct pivot_table *chisq = pivot_table_create (N_("Chi-Square Tests"));
+  pivot_table_set_weight_format (chisq, &xt->weight_format);
+  chisq->omit_empty = true;
+
+  pivot_dimension_create (
+    chisq, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("Pearson Chi-Square"),
+    N_("Likelihood Ratio"),
+    N_("Fisher's Exact Test"),
+    N_("Continuity Correction"),
+    N_("Linear-by-Linear Association"),
+    N_("N of Valid Cases"), PIVOT_RC_COUNT);
+
+  pivot_dimension_create (
+    chisq, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("Value"), PIVOT_RC_OTHER,
+    N_("df"), PIVOT_RC_COUNT,
+    N_("Asymptotic Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+    N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+    N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  for (size_t i = 2; i < xt->n_vars; i++)
+    add_var_dimension (chisq, &xt->vars[i], PIVOT_AXIS_ROW, false);
 
   return chisq;
 }
 
 /* Symmetric measures. */
-static struct tab_table *
-create_sym_table (struct crosstabs_proc *proc, struct crosstabulation *xt)
+static struct pivot_table *
+create_sym_table (struct crosstabulation *xt)
 {
-  struct tab_table *sym;
-
-  size_t n_cols = xt->vars[COL_VAR].n_values;
-  sym = tab_create (6 + (xt->n_vars - 2),
-                    xt->n_entries / n_cols * 7 + 10);
-
-  tab_set_format (sym, RC_WEIGHT, &proc->weight_format);
-
-  tab_headers (sym, 2 + (xt->n_vars - 2), 0, 1, 0);
-  tab_title (sym, _("Symmetric measures."));
-
-  tab_offset (sym, xt->n_vars - 2, 0);
-  tab_text (sym, 0, 0, TAB_LEFT | TAT_TITLE, _("Category"));
-  tab_text (sym, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
-  tab_text (sym, 2, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
-  tab_text (sym, 3, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error"));
-  tab_text (sym, 4, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T"));
-  tab_text (sym, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig."));
-  tab_offset (sym, 0, 1);
+  struct pivot_table *sym = pivot_table_create (N_("Symmetric Measures"));
+  pivot_table_set_weight_format (sym, &xt->weight_format);
+  sym->omit_empty = true;
+
+  pivot_dimension_create (
+    sym, PIVOT_AXIS_COLUMN, N_("Values"),
+    N_("Value"), PIVOT_RC_OTHER,
+    N_("Asymp. Std. Error"), PIVOT_RC_OTHER,
+    N_("Approx. T"), PIVOT_RC_OTHER,
+    N_("Approx. Sig."), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    sym, PIVOT_AXIS_ROW, N_("Statistics"));
+  pivot_category_create_group (
+    statistics->root, N_("Nominal by Nominal"),
+    N_("Phi"), N_("Cramer's V"), N_("Contingency Coefficient"));
+  pivot_category_create_group (
+    statistics->root, N_("Ordinal by Ordinal"),
+    N_("Kendall's tau-b"), N_("Kendall's tau-c"),
+    N_("Gamma"), N_("Spearman Correlation"));
+  pivot_category_create_group (
+    statistics->root, N_("Interval by Interval"),
+    N_("Pearson's R"));
+  pivot_category_create_group (
+    statistics->root, N_("Measure of Agreement"),
+    N_("Kappa"));
+  pivot_category_create_leaves (statistics->root, N_("N of Valid Cases"),
+                                PIVOT_RC_COUNT);
+
+  for (size_t i = 2; i < xt->n_vars; i++)
+    add_var_dimension (sym, &xt->vars[i], PIVOT_AXIS_ROW, false);
 
   return sym;
 }
 
 /* Risk estimate. */
-static struct tab_table *
-create_risk_table (struct crosstabs_proc *proc, struct crosstabulation *xt)
+static struct pivot_table *
+create_risk_table (struct crosstabulation *xt,
+                   struct pivot_dimension **risk_statistics)
 {
-  struct tab_table *risk;
+  struct pivot_table *risk = pivot_table_create (N_("Risk Estimate"));
+  pivot_table_set_weight_format (risk, &xt->weight_format);
+  risk->omit_empty = true;
 
-  size_t n_cols = xt->vars[COL_VAR].n_values;
-  risk = tab_create (4 + (xt->n_vars - 2), xt->n_entries / n_cols * 4 + 10);
-  tab_headers (risk, 1 + xt->n_vars - 2, 0, 2, 0);
-  tab_title (risk, _("Risk estimate."));
-  tab_set_format (risk, RC_WEIGHT, &proc->weight_format);
-
-  tab_offset (risk, xt->n_vars - 2, 0);
-  tab_joint_text_format (risk, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE,
-                         _("95%% Confidence Interval"));
-  tab_text (risk, 0, 1, TAB_LEFT | TAT_TITLE, _("Statistic"));
-  tab_text (risk, 1, 1, TAB_RIGHT | TAT_TITLE, _("Value"));
-  tab_text (risk, 2, 1, TAB_RIGHT | TAT_TITLE, _("Lower"));
-  tab_text (risk, 3, 1, TAB_RIGHT | TAT_TITLE, _("Upper"));
-  tab_hline (risk, TAL_1, 2, 3, 1);
-  tab_vline (risk, TAL_1, 2, 0, 1);
-  tab_offset (risk, 0, 2);
+  struct pivot_dimension *values = pivot_dimension_create (
+    risk, PIVOT_AXIS_COLUMN, N_("Values"),
+    N_("Value"), PIVOT_RC_OTHER);
+  pivot_category_create_group (
+    values->root, N_("95% Confidence Interval"),
+    N_("Lower"), PIVOT_RC_OTHER,
+    N_("Upper"), PIVOT_RC_OTHER);
+
+  *risk_statistics = pivot_dimension_create (
+    risk, PIVOT_AXIS_ROW, N_("Statistics"));
+
+  for (size_t i = 2; i < xt->n_vars; i++)
+    add_var_dimension (risk, &xt->vars[i], PIVOT_AXIS_ROW, false);
 
   return risk;
 }
 
-/* Directional measures. */
-static struct tab_table *
-create_direct_table (struct crosstabs_proc *proc, struct crosstabulation *xt)
+static void
+create_direct_stat (struct pivot_category *parent,
+                    const struct crosstabulation *xt,
+                    const char *name, bool symmetric)
 {
-  struct tab_table *direct;
+  struct pivot_category *group = pivot_category_create_group (
+    parent, name);
+  if (symmetric)
+    pivot_category_create_leaf (group, pivot_value_new_text (N_("Symmetric")));
+
+  char *row_label = xasprintf (_("%s Dependent"),
+                               var_to_string (xt->vars[ROW_VAR].var));
+  pivot_category_create_leaf (group, pivot_value_new_user_text_nocopy (
+                                row_label));
+
+  char *col_label = xasprintf (_("%s Dependent"),
+                               var_to_string (xt->vars[COL_VAR].var));
+  pivot_category_create_leaf (group, pivot_value_new_user_text_nocopy (
+                                col_label));
+}
 
-  size_t n_cols = xt->vars[COL_VAR].n_values;
-  direct = tab_create (7 + (xt->n_vars - 2),
-                       xt->n_entries / n_cols * 7 + 10);
-  tab_headers (direct, 3 + (xt->n_vars - 2), 0, 1, 0);
-  tab_title (direct, _("Directional measures."));
-  tab_set_format (direct, RC_WEIGHT, &proc->weight_format);
-
-  tab_offset (direct, xt->n_vars - 2, 0);
-  tab_text (direct, 0, 0, TAB_LEFT | TAT_TITLE, _("Category"));
-  tab_text (direct, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
-  tab_text (direct, 2, 0, TAB_LEFT | TAT_TITLE, _("Type"));
-  tab_text (direct, 3, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
-  tab_text (direct, 4, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error"));
-  tab_text (direct, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T"));
-  tab_text (direct, 6, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig."));
-  tab_offset (direct, 0, 1);
+/* Directional measures. */
+static struct pivot_table *
+create_direct_table (struct crosstabulation *xt)
+{
+  struct pivot_table *direct = pivot_table_create (N_("Directional Measures"));
+  pivot_table_set_weight_format (direct, &xt->weight_format);
+  direct->omit_empty = true;
+
+  pivot_dimension_create (
+    direct, PIVOT_AXIS_COLUMN, N_("Values"),
+    N_("Value"), PIVOT_RC_OTHER,
+    N_("Asymp. Std. Error"), PIVOT_RC_OTHER,
+    N_("Approx. T"), PIVOT_RC_OTHER,
+    N_("Approx Sig."), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    direct, PIVOT_AXIS_ROW, N_("Statistics"));
+  struct pivot_category *nn = pivot_category_create_group (
+    statistics->root, N_("Nominal by Nominal"));
+  create_direct_stat (nn, xt, N_("Lambda"), true);
+  create_direct_stat (nn, xt, N_("Goodman and Kruskal tau"), false);
+  create_direct_stat (nn, xt, N_("Uncertainty Coefficient"), true);
+  struct pivot_category *oo = pivot_category_create_group (
+    statistics->root, N_("Ordinal by Ordinal"));
+  create_direct_stat (oo, xt, N_("Somers' d"), true);
+  struct pivot_category *ni = pivot_category_create_group (
+    statistics->root, N_("Nominal by Interval"));
+  create_direct_stat (ni, xt, N_("Eta"), false);
+
+  for (size_t i = 2; i < xt->n_vars; i++)
+    add_var_dimension (direct, &xt->vars[i], PIVOT_AXIS_ROW, false);
 
   return direct;
 }
 
-
 /* Delete missing rows and columns for statistical analysis when
    /MISSING=REPORT. */
 static void
@@ -1446,34 +1460,6 @@ delete_missing (struct crosstabulation *xt)
       }
 }
 
-/* Prepare table T for submission, and submit it. */
-static void
-submit (struct crosstabulation *xt, struct tab_table *t)
-{
-  int i;
-
-  if (t == NULL)
-    return;
-
-  tab_resize (t, -1, 0);
-  if (tab_nr (t) == tab_t (t))
-    {
-      table_unref (&t->table);
-      return;
-    }
-  tab_offset (t, 0, 0);
-  if (xt != NULL)
-    for (i = 2; i < xt->n_vars; i++)
-      tab_text (t, xt->n_vars - i - 1, 0, TAB_RIGHT | TAT_TITLE,
-                var_to_string (xt->vars[i].var));
-  tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
-  tab_box (t, -1, -1, -1, TAL_1, tab_l (t), tab_t (t) - 1, tab_nc (t) - 1,
-          tab_nr (t) - 1);
-  tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1);
-
-  tab_submit (t);
-}
-
 static bool
 find_crosstab (struct crosstabulation *xt, size_t *row0p, size_t *row1p)
 {
@@ -1578,269 +1564,131 @@ static void
 free_var_values (const struct crosstabulation *xt, int var_idx)
 {
   struct xtab_var *xv = &xt->vars[var_idx];
-  free (xv->values);
+  //free (xv->values);
   xv->values = NULL;
   xv->n_values = 0;
 }
 
-/* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
-   from V, displayed with print format spec from variable VAR.  When
-   in REPORT missing-value mode, missing values have an M appended. */
-static void
-table_value_missing (struct crosstabs_proc *proc,
-                     struct tab_table *table, int c, int r, unsigned char opt,
-                    const union value *v, const struct variable *var)
-{
-  const char *label = var_lookup_value_label (var, v);
-  if (label != NULL)
-    tab_text (table, c, r, TAB_LEFT, label);
-  else
-    {
-      const struct fmt_spec *print = var_get_print_format (var);
-      if (proc->exclude == MV_NEVER && var_is_value_missing (var, v, MV_USER))
-        {
-          char *s = data_out (v, dict_get_encoding (proc->dict), print);
-          tab_text_format (table, c, r, opt, "%sM", s + strspn (s, " "));
-          free (s);
-        }
-      else
-        tab_value (table, c, r, opt, v, var, print);
-    }
-}
-
-/* Draws a line across TABLE at the current row to indicate the most
-   major dimension variable with index FIRST_DIFFERENCE out of N_VARS
-   that changed, and puts the values that changed into the table.  TB
-   and XT must be the corresponding table_entry and crosstab,
-   respectively. */
-static void
-display_dimensions (struct crosstabs_proc *proc, struct crosstabulation *xt,
-                    struct tab_table *table, int first_difference)
-{
-  tab_hline (table, TAL_1, xt->n_consts + xt->n_vars - first_difference - 1, tab_nc (table) - 1, 0);
-
-  for (; first_difference >= 2; first_difference--)
-    table_value_missing (proc, table, xt->n_consts + xt->n_vars - first_difference - 1, 0,
-                        TAB_RIGHT, &xt->entries[0]->values[first_difference],
-                        xt->vars[first_difference].var);
-}
-
-/* Put VALUE into cell (C,R) of TABLE, suffixed with character
-   SUFFIX if nonzero.  If MARK_MISSING is true the entry is
-   additionally suffixed with a letter `M'. */
-static void
-format_cell_entry (struct tab_table *table, int c, int r, double value,
-                   char suffix, bool mark_missing, const struct dictionary *dict)
-{
-  union value v;
-  char suffixes[3];
-  int suffix_len;
-  char *s;
-
-  v.f = value;
-  s = data_out (&v, dict_get_encoding (dict), settings_get_format ());
-
-  suffix_len = 0;
-  if (suffix != 0)
-    suffixes[suffix_len++] = suffix;
-  if (mark_missing)
-    suffixes[suffix_len++] = 'M';
-  suffixes[suffix_len] = '\0';
-
-  tab_text_format (table, c, r, TAB_RIGHT, "%s%s",
-                   s + strspn (s, " "), suffixes);
-
-  free (s);
-}
-
 /* Displays the crosstabulation table. */
 static void
 display_crosstabulation (struct crosstabs_proc *proc,
-                         struct crosstabulation *xt, struct tab_table *table)
+                         struct crosstabulation *xt, struct pivot_table *table,
+                         size_t crs_leaves[CRS_CL_count])
 {
   size_t n_rows = xt->vars[ROW_VAR].n_values;
   size_t n_cols = xt->vars[COL_VAR].n_values;
-  int last_row;
-  int r, c, i;
-  double *mp;
 
-  for (r = 0; r < n_rows; r++)
-    table_value_missing (proc, table, xt->n_consts + xt->n_vars - 2,
-                         r * proc->n_cells, TAB_RIGHT,
-                         &xt->vars[ROW_VAR].values[r],
-                         xt->vars[ROW_VAR].var);
-
-  tab_text (table, xt->n_vars - 2, n_rows * proc->n_cells,
-           TAB_LEFT, _("Total"));
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
+  assert (xt->n_vars == 2);
+  for (size_t i = 0; i < xt->n_consts; i++)
+    indexes[i + 3] = xt->const_indexes[i];
 
   /* Put in the actual cells. */
-  mp = xt->mat;
-  tab_offset (table, xt->n_consts + xt->n_vars - 1, -1);
-  for (r = 0; r < n_rows; r++)
+  double *mp = xt->mat;
+  for (size_t r = 0; r < n_rows; r++)
     {
-      if (proc->n_cells > 1)
-        tab_hline (table, TAL_1, -1, n_cols, 0);
-      for (c = 0; c < n_cols; c++)
+      if (!xt->row_tot[r] && proc->mode != INTEGER)
+        continue;
+
+      indexes[ROW_VAR + 1] = r;
+      for (size_t c = 0; c < n_cols; c++)
         {
-          bool mark_missing = false;
+          if (!xt->col_tot[c] && proc->mode != INTEGER)
+            continue;
+
+          indexes[COL_VAR + 1] = c;
+
           double expected_value = xt->row_tot[r] * xt->col_tot[c] / xt->total;
-          if (proc->exclude == MV_NEVER
-              && (var_is_num_missing (xt->vars[COL_VAR].var,
-                                      xt->vars[COL_VAR].values[c].f, MV_USER)
-                  || var_is_num_missing (xt->vars[ROW_VAR].var,
-                                         xt->vars[ROW_VAR].values[r].f,
-                                         MV_USER)))
-            mark_missing = true;
-          for (i = 0; i < proc->n_cells; i++)
-            {
-              double v;
-              int suffix = 0;
-
-              switch (proc->a_cells[i])
-                {
-                case CRS_CL_COUNT:
-                  v = *mp;
-                  break;
-                case CRS_CL_ROW:
-                  v = *mp / xt->row_tot[r] * 100.;
-                  suffix = '%';
-                  break;
-                case CRS_CL_COLUMN:
-                  v = *mp / xt->col_tot[c] * 100.;
-                  suffix = '%';
-                  break;
-                case CRS_CL_TOTAL:
-                  v = *mp / xt->total * 100.;
-                  suffix = '%';
-                  break;
-                case CRS_CL_EXPECTED:
-                  v = expected_value;
-                  break;
-                case CRS_CL_RESIDUAL:
-                  v = *mp - expected_value;
-                  break;
-                case CRS_CL_SRESIDUAL:
-                  v = (*mp - expected_value) / sqrt (expected_value);
-                  break;
-                case CRS_CL_ASRESIDUAL:
-                  v = ((*mp - expected_value)
-                       / sqrt (expected_value
+          double residual = *mp - expected_value;
+          double sresidual = residual / sqrt (expected_value);
+          double asresidual = (sresidual
                                * (1. - xt->row_tot[r] / xt->total)
-                               * (1. - xt->col_tot[c] / xt->total)));
-                  break;
-                default:
-                  NOT_REACHED ();
-                }
-              format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
+                               * (1. - xt->col_tot[c] / xt->total));
+          double entries[] = {
+            [CRS_CL_COUNT] = *mp,
+            [CRS_CL_ROW] = *mp / xt->row_tot[r] * 100.,
+            [CRS_CL_COLUMN] = *mp / xt->col_tot[c] * 100.,
+            [CRS_CL_TOTAL] = *mp / xt->total * 100.,
+            [CRS_CL_EXPECTED] = expected_value,
+            [CRS_CL_RESIDUAL] = residual,
+            [CRS_CL_SRESIDUAL] = sresidual,
+            [CRS_CL_ASRESIDUAL] = asresidual,
+          };
+          for (size_t i = 0; i < proc->n_cells; i++)
+            {
+              int cell = proc->a_cells[i];
+              indexes[0] = crs_leaves[cell];
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (entries[cell]));
             }
 
           mp++;
         }
-
-      tab_offset (table, -1, tab_row (table) + proc->n_cells);
     }
 
   /* Row totals. */
-  tab_offset (table, -1, tab_row (table) - proc->n_cells * n_rows);
-  for (r = 0; r < n_rows; r++)
-    {
-      bool mark_missing = false;
-
-      if (proc->exclude == MV_NEVER
-          && var_is_num_missing (xt->vars[ROW_VAR].var,
-                                 xt->vars[ROW_VAR].values[r].f, MV_USER))
-        mark_missing = true;
-
-      for (i = 0; i < proc->n_cells; i++)
+  for (size_t r = 0; r < n_rows; r++)
+    {
+      if (!xt->row_tot[r] && proc->mode != INTEGER)
+        continue;
+
+      double expected_value = xt->row_tot[r] / xt->total;
+      double entries[] = {
+        [CRS_CL_COUNT] = xt->row_tot[r],
+        [CRS_CL_ROW] = 100.0,
+        [CRS_CL_COLUMN] = expected_value * 100.,
+        [CRS_CL_TOTAL] = expected_value * 100.,
+        [CRS_CL_EXPECTED] = expected_value,
+        [CRS_CL_RESIDUAL] = SYSMIS,
+        [CRS_CL_SRESIDUAL] = SYSMIS,
+        [CRS_CL_ASRESIDUAL] = SYSMIS,
+      };
+      for (size_t i = 0; i < proc->n_cells; i++)
         {
-          char suffix = 0;
-          double v;
-
-          switch (proc->a_cells[i])
+          int cell = proc->a_cells[i];
+          double entry = entries[cell];
+          if (entry != SYSMIS)
             {
-            case CRS_CL_COUNT:
-              v = xt->row_tot[r];
-              break;
-            case CRS_CL_ROW:
-              v = 100.0;
-              suffix = '%';
-              break;
-            case CRS_CL_COLUMN:
-              v = xt->row_tot[r] / xt->total * 100.;
-              suffix = '%';
-              break;
-            case CRS_CL_TOTAL:
-              v = xt->row_tot[r] / xt->total * 100.;
-              suffix = '%';
-              break;
-            case CRS_CL_EXPECTED:
-            case CRS_CL_RESIDUAL:
-            case CRS_CL_SRESIDUAL:
-            case CRS_CL_ASRESIDUAL:
-              v = 0.;
-              break;
-            default:
-              NOT_REACHED ();
+              indexes[ROW_VAR + 1] = r;
+              indexes[COL_VAR + 1] = n_cols;
+              indexes[0] = crs_leaves[cell];
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (entry));
             }
-
-          format_cell_entry (table, n_cols, 0, v, suffix, mark_missing, proc->dict);
-          tab_next_row (table);
         }
     }
 
-  /* Column totals, grand total. */
-  last_row = 0;
-  if (proc->n_cells > 1)
-    tab_hline (table, TAL_1, -1, n_cols, 0);
-  for (c = 0; c <= n_cols; c++)
+  for (size_t c = 0; c <= n_cols; c++)
     {
-      double ct = c < n_cols ? xt->col_tot[c] : xt->total;
-      bool mark_missing = false;
-      int i;
+      if (c < n_cols && !xt->col_tot[c] && proc->mode != INTEGER)
+        continue;
 
-      if (proc->exclude == MV_NEVER && c < n_cols
-          && var_is_num_missing (xt->vars[COL_VAR].var,
-                                 xt->vars[COL_VAR].values[c].f, MV_USER))
-        mark_missing = true;
-
-      for (i = 0; i < proc->n_cells; i++)
+      double ct = c < n_cols ? xt->col_tot[c] : xt->total;
+      double expected_value = ct / xt->total;
+      double entries[] = {
+        [CRS_CL_COUNT] = ct,
+        [CRS_CL_ROW] = expected_value * 100.0,
+        [CRS_CL_COLUMN] = 100.0,
+        [CRS_CL_TOTAL] = expected_value * 100.,
+        [CRS_CL_EXPECTED] = expected_value,
+        [CRS_CL_RESIDUAL] = SYSMIS,
+        [CRS_CL_SRESIDUAL] = SYSMIS,
+        [CRS_CL_ASRESIDUAL] = SYSMIS,
+      };
+      for (size_t i = 0; i < proc->n_cells; i++)
         {
-          char suffix = 0;
-          double v;
-
-          switch (proc->a_cells[i])
+          int cell = proc->a_cells[i];
+          double entry = entries[cell];
+          if (entry != SYSMIS)
             {
-            case CRS_CL_COUNT:
-              v = ct;
-              break;
-            case CRS_CL_ROW:
-              v = ct / xt->total * 100.;
-              suffix = '%';
-              break;
-            case CRS_CL_COLUMN:
-              v = 100.;
-              suffix = '%';
-              break;
-            case CRS_CL_TOTAL:
-              v = ct / xt->total * 100.;
-              suffix = '%';
-              break;
-            case CRS_CL_EXPECTED:
-            case CRS_CL_RESIDUAL:
-            case CRS_CL_SRESIDUAL:
-            case CRS_CL_ASRESIDUAL:
-              continue;
-            default:
-              NOT_REACHED ();
+              indexes[ROW_VAR + 1] = n_rows;
+              indexes[COL_VAR + 1] = c;
+              indexes[0] = crs_leaves[cell];
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (entry));
             }
-
-          format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
         }
-      last_row = i;
     }
-
-  tab_offset (table, -1, tab_row (table) + last_row);
-  tab_offset (table, 0, -1);
 }
 
 static void calc_r (struct crosstabulation *,
@@ -1850,55 +1698,49 @@ static void calc_chisq (struct crosstabulation *,
 
 /* Display chi-square statistics. */
 static void
-display_chisq (struct crosstabulation *xt, struct tab_table *chisq,
-               bool *showed_fisher)
+display_chisq (struct crosstabulation *xt, struct pivot_table *chisq)
 {
-  static const char *chisq_stats[N_CHISQ] =
-    {
-      N_("Pearson Chi-Square"),
-      N_("Likelihood Ratio"),
-      N_("Fisher's Exact Test"),
-      N_("Continuity Correction"),
-      N_("Linear-by-Linear Association"),
-    };
   double chisq_v[N_CHISQ];
   double fisher1, fisher2;
   int df[N_CHISQ];
-
-  int i;
-
   calc_chisq (xt, chisq_v, df, &fisher1, &fisher2);
 
-  tab_offset (chisq, xt->n_consts + xt->n_vars - 2, -1);
-
-  for (i = 0; i < N_CHISQ; i++)
+  size_t *indexes = xnmalloc (chisq->n_dimensions, sizeof *indexes);
+  assert (xt->n_vars == 2);
+  for (size_t i = 0; i < xt->n_consts; i++)
+    indexes[i + 2] = xt->const_indexes[i];
+  for (int i = 0; i < N_CHISQ; i++)
     {
-      if ((i != 2 && chisq_v[i] == SYSMIS)
-         || (i == 2 && fisher1 == SYSMIS))
-       continue;
+      indexes[0] = i;
 
-      tab_text (chisq, 0, 0, TAB_LEFT, gettext (chisq_stats[i]));
-      if (i != 2)
-       {
-         tab_double (chisq, 1, 0, TAB_RIGHT, chisq_v[i], NULL, RC_OTHER);
-         tab_double (chisq, 2, 0, TAB_RIGHT, df[i], NULL, RC_WEIGHT);
-         tab_double (chisq, 3, 0, TAB_RIGHT,
-                     gsl_cdf_chisq_Q (chisq_v[i], df[i]), NULL, RC_PVALUE);
-       }
-      else
-       {
-         *showed_fisher = true;
-         tab_double (chisq, 4, 0, TAB_RIGHT, fisher2, NULL, RC_PVALUE);
-         tab_double (chisq, 5, 0, TAB_RIGHT, fisher1, NULL, RC_PVALUE);
-       }
-      tab_next_row (chisq);
+      double entries[5] = { SYSMIS, SYSMIS, SYSMIS, SYSMIS, SYSMIS };
+      if (i == 2)
+        {
+          entries[3] = fisher2;
+          entries[4] = fisher1;
+        }
+      else if (chisq_v[i] != SYSMIS)
+        {
+          entries[0] = chisq_v[i];
+          entries[1] = df[i];
+          entries[2] = gsl_cdf_chisq_Q (chisq_v[i], df[i]);
+        }
+
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        if (entries[j] != SYSMIS)
+          {
+            indexes[1] = j;
+            pivot_table_put (chisq, indexes, chisq->n_dimensions,
+                             pivot_value_new_number (entries[j]));
+        }
     }
 
-  tab_text (chisq, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_double (chisq, 1, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT);
-  tab_next_row (chisq);
+  indexes[0] = 5;
+  indexes[1] = 0;
+  pivot_table_put (chisq, indexes, chisq->n_dimensions,
+                   pivot_value_new_number (xt->total));
 
-  tab_offset (chisq, 0, -1);
+  free (indexes);
 }
 
 static int calc_symmetric (struct crosstabs_proc *, struct crosstabulation *,
@@ -1909,137 +1751,108 @@ static int calc_symmetric (struct crosstabs_proc *, struct crosstabulation *,
 /* Display symmetric measures. */
 static void
 display_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt,
-                   struct tab_table *sym)
+                   struct pivot_table *sym)
 {
-  static const char *categories[] =
-    {
-      N_("Nominal by Nominal"),
-      N_("Ordinal by Ordinal"),
-      N_("Interval by Interval"),
-      N_("Measure of Agreement"),
-    };
-
-  static const char *stats[N_SYMMETRIC] =
-    {
-      N_("Phi"),
-      N_("Cramer's V"),
-      N_("Contingency Coefficient"),
-      N_("Kendall's tau-b"),
-      N_("Kendall's tau-c"),
-      N_("Gamma"),
-      N_("Spearman Correlation"),
-      N_("Pearson's R"),
-      N_("Kappa"),
-    };
-
-  static const int stats_categories[N_SYMMETRIC] =
-    {
-      0, 0, 0, 1, 1, 1, 1, 2, 3,
-    };
-
-  int last_cat = -1;
   double sym_v[N_SYMMETRIC], sym_ase[N_SYMMETRIC], sym_t[N_SYMMETRIC];
   double somers_d_v[3], somers_d_ase[3], somers_d_t[3];
-  int i;
 
   if (!calc_symmetric (proc, xt, sym_v, sym_ase, sym_t,
                        somers_d_v, somers_d_ase, somers_d_t))
     return;
 
-  tab_offset (sym, xt->n_consts + xt->n_vars - 2, -1);
+  size_t *indexes = xnmalloc (sym->n_dimensions, sizeof *indexes);
+  assert (xt->n_vars == 2);
+  for (size_t i = 0; i < xt->n_consts; i++)
+    indexes[i + 2] = xt->const_indexes[i];
 
-  for (i = 0; i < N_SYMMETRIC; i++)
+  for (int i = 0; i < N_SYMMETRIC; i++)
     {
       if (sym_v[i] == SYSMIS)
        continue;
 
-      if (stats_categories[i] != last_cat)
-       {
-         last_cat = stats_categories[i];
-         tab_text (sym, 0, 0, TAB_LEFT, gettext (categories[last_cat]));
-       }
+      indexes[1] = i;
 
-      tab_text (sym, 1, 0, TAB_LEFT, gettext (stats[i]));
-      tab_double (sym, 2, 0, TAB_RIGHT, sym_v[i], NULL, RC_OTHER);
-      if (sym_ase[i] != SYSMIS)
-       tab_double (sym, 3, 0, TAB_RIGHT, sym_ase[i], NULL, RC_OTHER);
-      if (sym_t[i] != SYSMIS)
-       tab_double (sym, 4, 0, TAB_RIGHT, sym_t[i], NULL, RC_OTHER);
-      /*tab_double (sym, 5, 0, TAB_RIGHT, normal_sig (sym_v[i]), NULL, RC_PVALUE);*/
-      tab_next_row (sym);
+      double entries[] = { sym_v[i], sym_ase[i], sym_t[i] };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        if (entries[j] != SYSMIS)
+          {
+            indexes[0] = j;
+            pivot_table_put (sym, indexes, sym->n_dimensions,
+                             pivot_value_new_number (entries[j]));
+          }
     }
 
-  tab_text (sym, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_double (sym, 2, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT);
-  tab_next_row (sym);
-
-  tab_offset (sym, 0, -1);
+  indexes[1] = N_SYMMETRIC;
+  indexes[0] = 0;
+  struct pivot_value *total = pivot_value_new_number (xt->total);
+  pivot_value_set_rc (sym, total, PIVOT_RC_COUNT);
+  pivot_table_put (sym, indexes, sym->n_dimensions, total);
 }
 
-static int calc_risk (struct crosstabulation *,
-                      double[], double[], double[], union value *);
+static bool calc_risk (struct crosstabulation *,
+                       double[], double[], double[], union value *,
+                       double *);
 
 /* Display risk estimate. */
 static void
-display_risk (struct crosstabulation *xt, struct tab_table *risk)
+display_risk (struct crosstabulation *xt, struct pivot_table *risk,
+              struct pivot_dimension *risk_statistics)
 {
-  char buf[256];
-  double risk_v[3], lower[3], upper[3];
+  double risk_v[3], lower[3], upper[3], n_valid;
   union value c[2];
-  int i;
-
-  if (!calc_risk (xt, risk_v, upper, lower, c))
+  if (!calc_risk (xt, risk_v, upper, lower, c, &n_valid))
     return;
 
-  tab_offset (risk, xt->n_consts + xt->n_vars - 2, -1);
+  size_t *indexes = xnmalloc (risk->n_dimensions, sizeof *indexes);
+  assert (xt->n_vars == 2);
+  for (size_t i = 0; i < xt->n_consts; i++)
+    indexes[i + 2] = xt->const_indexes[i];
 
-  for (i = 0; i < 3; i++)
+  for (int i = 0; i < 3; i++)
     {
       const struct variable *cv = xt->vars[COL_VAR].var;
       const struct variable *rv = xt->vars[ROW_VAR].var;
-      int cvw = var_get_width (cv);
-      int rvw = var_get_width (rv);
 
       if (risk_v[i] == SYSMIS)
        continue;
 
+      struct string label = DS_EMPTY_INITIALIZER;
       switch (i)
        {
        case 0:
-         if (var_is_numeric (cv))
-           sprintf (buf, _("Odds Ratio for %s (%g / %g)"),
-                    var_to_string (cv), c[0].f, c[1].f);
-         else
-           sprintf (buf, _("Odds Ratio for %s (%.*s / %.*s)"),
-                    var_to_string (cv),
-                    cvw, value_str (&c[0], cvw),
-                    cvw, value_str (&c[1], cvw));
+          ds_put_format (&label, _("Odds Ratio for %s"), var_to_string (rv));
+          ds_put_cstr (&label, " (");
+          var_append_value_name (rv, &c[0], &label);
+          ds_put_cstr (&label, " / ");
+          var_append_value_name (rv, &c[1], &label);
+          ds_put_cstr (&label, ")");
          break;
        case 1:
        case 2:
-         if (var_is_numeric (rv))
-           sprintf (buf, _("For cohort %s = %.*g"),
-                    var_to_string (rv), DBL_DIG + 1,
-                     xt->vars[ROW_VAR].values[i - 1].f);
-         else
-           sprintf (buf, _("For cohort %s = %.*s"),
-                    var_to_string (rv),
-                    rvw, value_str (&xt->vars[ROW_VAR].values[i - 1], rvw));
+          ds_put_format (&label, _("For cohort %s = "), var_to_string (cv));
+          var_append_value_name (cv, &xt->vars[ROW_VAR].values[i - 1], &label);
          break;
        }
 
-      tab_text (risk, 0, 0, TAB_LEFT, buf);
-      tab_double (risk, 1, 0, TAB_RIGHT, risk_v[i], NULL, RC_OTHER);
-      tab_double (risk, 2, 0, TAB_RIGHT, lower[i], NULL, RC_OTHER);
-      tab_double (risk, 3, 0, TAB_RIGHT, upper[i], NULL, RC_OTHER);
-      tab_next_row (risk);
-    }
-
-  tab_text (risk, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_double (risk, 1, 0, TAB_RIGHT, xt->total, NULL, RC_WEIGHT);
-  tab_next_row (risk);
+      indexes[1] = pivot_category_create_leaf (
+        risk_statistics->root,
+        pivot_value_new_user_text_nocopy (ds_steal_cstr (&label)));
 
-  tab_offset (risk, 0, -1);
+      double entries[] = { risk_v[i], lower[i], upper[i] };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        {
+          indexes[0] = j;
+          pivot_table_put (risk, indexes, risk->n_dimensions,
+                           pivot_value_new_number (entries[i]));
+        }
+    }
+  indexes[1] = pivot_category_create_leaf (
+    risk_statistics->root,
+    pivot_value_new_text (N_("N of Valid Cases")));
+  indexes[0] = 0;
+  pivot_table_put (risk, indexes, risk->n_dimensions,
+                   pivot_value_new_number (n_valid));
+  free (indexes);
 }
 
 static int calc_directional (struct crosstabs_proc *, struct crosstabulation *,
@@ -2048,120 +1861,39 @@ static int calc_directional (struct crosstabs_proc *, struct crosstabulation *,
 
 /* Display directional measures. */
 static void
-display_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
-                     struct tab_table *direct)
+display_directional (struct crosstabs_proc *proc,
+                     struct crosstabulation *xt, struct pivot_table *direct)
 {
-  static const char *categories[] =
-    {
-      N_("Nominal by Nominal"),
-      N_("Ordinal by Ordinal"),
-      N_("Nominal by Interval"),
-    };
-
-  static const char *stats[] =
-    {
-      N_("Lambda"),
-      N_("Goodman and Kruskal tau"),
-      N_("Uncertainty Coefficient"),
-      N_("Somers' d"),
-      N_("Eta"),
-    };
-
-  static const char *types[] =
-    {
-      N_("Symmetric"),
-      N_("%s Dependent"),
-      N_("%s Dependent"),
-    };
-
-  static const int stats_categories[N_DIRECTIONAL] =
-    {
-      0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2,
-    };
-
-  static const int stats_stats[N_DIRECTIONAL] =
-    {
-      0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4,
-    };
-
-  static const int stats_types[N_DIRECTIONAL] =
-    {
-      0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2,
-    };
-
-  static const int *stats_lookup[] =
-    {
-      stats_categories,
-      stats_stats,
-      stats_types,
-    };
-
-  static const char **stats_names[] =
-    {
-      categories,
-      stats,
-      types,
-    };
-
-  int last[3] =
-    {
-      -1, -1, -1,
-    };
-
   double direct_v[N_DIRECTIONAL];
   double direct_ase[N_DIRECTIONAL];
   double direct_t[N_DIRECTIONAL];
   double sig[N_DIRECTIONAL];
-
-  int i;
-
   if (!calc_directional (proc, xt, direct_v, direct_ase, direct_t, sig))
     return;
 
-  tab_offset (direct, xt->n_consts + xt->n_vars - 2, -1);
+  size_t *indexes = xnmalloc (direct->n_dimensions, sizeof *indexes);
+  assert (xt->n_vars == 2);
+  for (size_t i = 0; i < xt->n_consts; i++)
+    indexes[i + 2] = xt->const_indexes[i];
 
-  for (i = 0; i < N_DIRECTIONAL; i++)
+  for (int i = 0; i < N_DIRECTIONAL; i++)
     {
       if (direct_v[i] == SYSMIS)
        continue;
 
-      {
-       int j;
-
-       for (j = 0; j < 3; j++)
-         if (last[j] != stats_lookup[j][i])
-           {
-             if (j < 2)
-               tab_hline (direct, TAL_1, j, 6, 0);
-
-             for (; j < 3; j++)
-               {
-                 const char *string;
-                 int k = last[j] = stats_lookup[j][i];
-
-                 if (k == 0)
-                   string = NULL;
-                 else if (k == 1)
-                   string = var_to_string (xt->vars[0].var);
-                 else
-                   string = var_to_string (xt->vars[1].var);
-
-                 tab_text_format (direct, j, 0, TAB_LEFT,
-                                   gettext (stats_names[j][k]), string);
-               }
-           }
-      }
+      indexes[1] = i;
 
-      tab_double (direct, 3, 0, TAB_RIGHT, direct_v[i], NULL, RC_OTHER);
-      if (direct_ase[i] != SYSMIS)
-       tab_double (direct, 4, 0, TAB_RIGHT, direct_ase[i], NULL, RC_OTHER);
-      if (direct_t[i] != SYSMIS)
-       tab_double (direct, 5, 0, TAB_RIGHT, direct_t[i], NULL, RC_OTHER);
-      tab_double (direct, 6, 0, TAB_RIGHT, sig[i], NULL, RC_PVALUE);
-      tab_next_row (direct);
+      double entries[] = {
+        direct_v[i], direct_ase[i], direct_t[i], sig[i],
+      };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        if (entries[j] != SYSMIS)
+          {
+            indexes[0] = j;
+            pivot_table_put (direct, indexes, direct->n_dimensions,
+                             pivot_value_new_number (entries[j]));
+          }
     }
-
-  tab_offset (direct, 0, -1);
 }
 \f
 /* Statistical calculations. */
@@ -2246,8 +1978,6 @@ calc_chisq (struct crosstabulation *xt,
             double chisq[N_CHISQ], int df[N_CHISQ],
            double *fisher1, double *fisher2)
 {
-  int r, c;
-
   chisq[0] = chisq[1] = 0.;
   chisq[2] = chisq[3] = chisq[4] = SYSMIS;
   *fisher1 = *fisher2 = SYSMIS;
@@ -2260,18 +1990,17 @@ calc_chisq (struct crosstabulation *xt,
       return;
     }
 
-  size_t n_rows = xt->vars[ROW_VAR].n_values;
   size_t n_cols = xt->vars[COL_VAR].n_values;
-  for (r = 0; r < n_rows; r++)
-    for (c = 0; c < n_cols; c++)
+  FOR_EACH_POPULATED_ROW (r, xt)
+    FOR_EACH_POPULATED_COLUMN (c, xt)
       {
-       const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total;
-       const double freq = xt->mat[n_cols * r + c];
-       const double residual = freq - expected;
+        const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total;
+        const double freq = xt->mat[n_cols * r + c];
+        const double residual = freq - expected;
 
         chisq[0] += residual * residual / expected;
-       if (freq)
-         chisq[1] += freq * log (expected / freq);
+        if (freq)
+          chisq[1] += freq * log (expected / freq);
       }
 
   if (chisq[0] == 0.)
@@ -2289,16 +2018,14 @@ calc_chisq (struct crosstabulation *xt,
 
       {
        int nz_cols[2];
-       int i, j;
-
-       for (i = j = 0; i < n_cols; i++)
-         if (xt->col_tot[i] != 0.)
-           {
-             nz_cols[j++] = i;
-             if (j == 2)
-               break;
-           }
 
+        int j = 0;
+        FOR_EACH_POPULATED_COLUMN (c, xt)
+          {
+            nz_cols[j++] = c;
+            if (j == 2)
+              break;
+          }
        assert (j == 2);
 
        f11 = xt->mat[nz_cols[0]];
@@ -2433,14 +2160,13 @@ calc_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt,
   if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC)))
     {
       double Xp = 0.;  /* Pearson chi-square. */
-      int r, c;
 
-      for (r = 0; r < n_rows; r++)
-        for (c = 0; c < n_cols; c++)
+      FOR_EACH_POPULATED_ROW (r, xt)
+        FOR_EACH_POPULATED_COLUMN (c, xt)
           {
-            const double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total;
-            const double freq = xt->mat[n_cols * r + c];
-            const double residual = freq - expected;
+            double expected = xt->row_tot[r] * xt->col_tot[c] / xt->total;
+            double freq = xt->mat[n_cols * r + c];
+            double residual = freq - expected;
 
             Xp += residual * residual / expected;
           }
@@ -2738,42 +2464,41 @@ calc_symmetric (struct crosstabs_proc *proc, struct crosstabulation *xt,
 }
 
 /* Calculate risk estimate. */
-static int
+static bool
 calc_risk (struct crosstabulation *xt,
-           double *value, double *upper, double *lower, union value *c)
+           double *value, double *upper, double *lower, union value *c,
+           double *n_valid)
 {
   size_t n_cols = xt->vars[COL_VAR].n_values;
   double f11, f12, f21, f22;
   double v;
 
-  {
-    int i;
-
-    for (i = 0; i < 3; i++)
-      value[i] = upper[i] = lower[i] = SYSMIS;
-  }
+  for (int i = 0; i < 3; i++)
+    value[i] = upper[i] = lower[i] = SYSMIS;
 
   if (xt->ns_rows != 2 || xt->ns_cols != 2)
-    return 0;
+    return false;
 
   {
+    /* Find populated columns. */
     int nz_cols[2];
-    int i, j;
-
-    for (i = j = 0; i < n_cols; i++)
-      if (xt->col_tot[i] != 0.)
-       {
-         nz_cols[j++] = i;
-         if (j == 2)
-           break;
-       }
-
-    assert (j == 2);
-
-    f11 = xt->mat[nz_cols[0]];
-    f12 = xt->mat[nz_cols[1]];
-    f21 = xt->mat[nz_cols[0] + n_cols];
-    f22 = xt->mat[nz_cols[1] + n_cols];
+    int n = 0;
+    FOR_EACH_POPULATED_COLUMN (c, xt)
+      nz_cols[n++] = c;
+    assert (n == 2);
+
+    /* Find populated rows. */
+    int nz_rows[2];
+    n = 0;
+    FOR_EACH_POPULATED_ROW (r, xt)
+      nz_rows[n++] = r;
+    assert (n == 2);
+
+    f11 = xt->mat[nz_cols[0] + n_cols * nz_rows[0]];
+    f12 = xt->mat[nz_cols[1] + n_cols * nz_rows[0]];
+    f21 = xt->mat[nz_cols[0] + n_cols * nz_rows[1]];
+    f22 = xt->mat[nz_cols[1] + n_cols * nz_rows[1]];
+    *n_valid = f11 + f12 + f21 + f22;
 
     c[0] = xt->vars[COL_VAR].values[nz_cols[0]];
     c[1] = xt->vars[COL_VAR].values[nz_cols[1]];
@@ -2796,7 +2521,7 @@ calc_risk (struct crosstabulation *xt,
   lower[2] = value[2] * exp (-1.960 * v);
   upper[2] = value[2] * exp (1.960 * v);
 
-  return 1;
+  return true;
 }
 
 /* Calculate directional measures. */
@@ -2807,63 +2532,58 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 {
   size_t n_rows = xt->vars[ROW_VAR].n_values;
   size_t n_cols = xt->vars[COL_VAR].n_values;
-  {
-    int i;
-
-    for (i = 0; i < N_DIRECTIONAL; i++)
-      v[i] = ase[i] = t[i] = sig[i] = SYSMIS;
-  }
+  for (int i = 0; i < N_DIRECTIONAL; i++)
+    v[i] = ase[i] = t[i] = sig[i] = SYSMIS;
 
   /* Lambda. */
   if (proc->statistics & (1u << CRS_ST_LAMBDA))
     {
+      /* Find maximum for each row and their sum. */
       double *fim = xnmalloc (n_rows, sizeof *fim);
       int *fim_index = xnmalloc (n_rows, sizeof *fim_index);
-      double *fmj = xnmalloc (n_cols, sizeof *fmj);
-      int *fmj_index = xnmalloc (n_cols, sizeof *fmj_index);
-      double sum_fim, sum_fmj;
-      double rm, cm;
-      int rm_index, cm_index;
-      int i, j;
-
-      /* Find maximum for each row and their sum. */
-      for (sum_fim = 0., i = 0; i < n_rows; i++)
+      double sum_fim = 0.0;
+      for (int i = 0; i < n_rows; i++)
        {
          double max = xt->mat[i * n_cols];
          int index = 0;
 
-         for (j = 1; j < n_cols; j++)
+         for (int j = 1; j < n_cols; j++)
            if (xt->mat[j + i * n_cols] > max)
              {
                max = xt->mat[j + i * n_cols];
                index = j;
              }
 
-         sum_fim += fim[i] = max;
+          fim[i] = max;
+         sum_fim += max;
          fim_index[i] = index;
        }
 
       /* Find maximum for each column. */
-      for (sum_fmj = 0., j = 0; j < n_cols; j++)
+      double *fmj = xnmalloc (n_cols, sizeof *fmj);
+      int *fmj_index = xnmalloc (n_cols, sizeof *fmj_index);
+      double sum_fmj = 0.0;
+      for (int j = 0; j < n_cols; j++)
        {
          double max = xt->mat[j];
          int index = 0;
 
-         for (i = 1; i < n_rows; i++)
+         for (int i = 1; i < n_rows; i++)
            if (xt->mat[j + i * n_cols] > max)
              {
                max = xt->mat[j + i * n_cols];
                index = i;
              }
 
-         sum_fmj += fmj[j] = max;
+          fmj[j] = max;
+         sum_fmj += max;
          fmj_index[j] = index;
        }
 
       /* Find maximum row total. */
-      rm = xt->row_tot[0];
-      rm_index = 0;
-      for (i = 1; i < n_rows; i++)
+      double rm = xt->row_tot[0];
+      int rm_index = 0;
+      for (int i = 1; i < n_rows; i++)
        if (xt->row_tot[i] > rm)
          {
            rm = xt->row_tot[i];
@@ -2871,9 +2591,9 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
          }
 
       /* Find maximum column total. */
-      cm = xt->col_tot[0];
-      cm_index = 0;
-      for (j = 1; j < n_cols; j++)
+      double cm = xt->col_tot[0];
+      int cm_index = 0;
+      for (int j = 1; j < n_cols; j++)
        if (xt->col_tot[j] > cm)
          {
            cm = xt->col_tot[j];
@@ -2886,10 +2606,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* ASE1 for Y given XT. */
       {
-        double accum;
-
-        accum = 0.;
-       for (i = 0; i < n_rows; i++)
+        double accum = 0.0;
+       for (int i = 0; i < n_rows; i++)
           if (cm_index == fim_index[i])
             accum += fim[i];
         ase[2] = sqrt ((xt->total - sum_fim) * (sum_fim + cm - 2. * accum)
@@ -2898,9 +2616,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* ASE0 for Y given XT. */
       {
-       double accum;
-
-       for (accum = 0., i = 0; i < n_rows; i++)
+       double accum = 0.0;
+       for (int i = 0; i < n_rows; i++)
          if (cm_index != fim_index[i])
            accum += (xt->mat[i * n_cols + fim_index[i]]
                      + xt->mat[i * n_cols + cm_index]);
@@ -2909,10 +2626,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* ASE1 for XT given Y. */
       {
-        double accum;
-
-        accum = 0.;
-       for (j = 0; j < n_cols; j++)
+        double accum = 0.0;
+       for (int j = 0; j < n_cols; j++)
           if (rm_index == fmj_index[j])
             accum += fmj[j];
         ase[1] = sqrt ((xt->total - sum_fmj) * (sum_fmj + rm - 2. * accum)
@@ -2921,9 +2636,8 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* ASE0 for XT given Y. */
       {
-       double accum;
-
-       for (accum = 0., j = 0; j < n_cols; j++)
+       double accum = 0.0;
+       for (int j = 0; j < n_cols; j++)
          if (rm_index != fmj_index[j])
            accum += (xt->mat[j + n_cols * fmj_index[j]]
                      + xt->mat[j + n_cols * rm_index]);
@@ -2932,11 +2646,10 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* Symmetric ASE0 and ASE1. */
       {
-       double accum0;
-       double accum1;
-
-       for (accum0 = accum1 = 0., i = 0; i < n_rows; i++)
-         for (j = 0; j < n_cols; j++)
+       double accum0 = 0.0;
+       double accum1 = 0.0;
+       for (int i = 0; i < n_rows; i++)
+         for (int j = 0; j < n_cols; j++)
            {
              int temp0 = (fmj_index[j] == i) + (fim_index[i] == j);
              int temp1 = (i == rm_index) + (j == cm_index);
@@ -2949,7 +2662,7 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
                       / (2. * xt->total - rm - cm));
       }
 
-      for (i = 0; i < 3; i++)
+      for (int i = 0; i < 3; i++)
         sig[i] = 2 * gsl_cdf_ugaussian_Q (t[i]);
 
       free (fim);
@@ -2959,21 +2672,22 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
       /* Tau. */
       {
-       double sum_fij2_ri, sum_fij2_ci;
-       double sum_ri2, sum_cj2;
-
-       for (sum_fij2_ri = sum_fij2_ci = 0., i = 0; i < n_rows; i++)
-         for (j = 0; j < n_cols; j++)
+       double sum_fij2_ri = 0.0;
+        double sum_fij2_ci = 0.0;
+        FOR_EACH_POPULATED_ROW (i, xt)
+          FOR_EACH_POPULATED_COLUMN (j, xt)
            {
              double temp = pow2 (xt->mat[j + i * n_cols]);
              sum_fij2_ri += temp / xt->row_tot[i];
              sum_fij2_ci += temp / xt->col_tot[j];
            }
 
-       for (sum_ri2 = 0., i = 0; i < n_rows; i++)
+       double sum_ri2 = 0.0;
+       for (int i = 0; i < n_rows; i++)
          sum_ri2 += pow2 (xt->row_tot[i]);
 
-       for (sum_cj2 = 0., j = 0; j < n_cols; j++)
+        double sum_cj2 = 0.0;
+       for (int j = 0; j < n_cols; j++)
          sum_cj2 += pow2 (xt->col_tot[j]);
 
        v[3] = (xt->total * sum_fij2_ci - sum_ri2) / (pow2 (xt->total) - sum_ri2);
@@ -2983,20 +2697,18 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
 
   if (proc->statistics & (1u << CRS_ST_UC))
     {
-      double UX, UY, UXY, P;
-      double ase1_yx, ase1_xy, ase1_sym;
-      int i, j;
+      double UX = 0.0;
+      FOR_EACH_POPULATED_ROW (i, xt)
+        UX -= xt->row_tot[i] / xt->total * log (xt->row_tot[i] / xt->total);
 
-      for (UX = 0., i = 0; i < n_rows; i++)
-       if (xt->row_tot[i] > 0.)
-         UX -= xt->row_tot[i] / xt->total * log (xt->row_tot[i] / xt->total);
+      double UY = 0.0;
+      FOR_EACH_POPULATED_COLUMN (j, xt)
+        UY -= xt->col_tot[j] / xt->total * log (xt->col_tot[j] / xt->total);
 
-      for (UY = 0., j = 0; j < n_cols; j++)
-       if (xt->col_tot[j] > 0.)
-         UY -= xt->col_tot[j] / xt->total * log (xt->col_tot[j] / xt->total);
-
-      for (UXY = P = 0., i = 0; i < n_rows; i++)
-       for (j = 0; j < n_cols; j++)
+      double UXY = 0.0;
+      double P = 0.0;
+      for (int i = 0; i < n_rows; i++)
+       for (int j = 0; j < n_cols; j++)
          {
            double entry = xt->mat[j + i * n_cols];
 
@@ -3007,8 +2719,11 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
            UXY -= entry / xt->total * log (entry / xt->total);
          }
 
-      for (ase1_yx = ase1_xy = ase1_sym = 0., i = 0; i < n_rows; i++)
-       for (j = 0; j < n_cols; j++)
+      double ase1_yx = 0.0;
+      double ase1_xy = 0.0;
+      double ase1_sym = 0.0;
+      for (int i = 0; i < n_rows; i++)
+       for (int j = 0; j < n_cols; j++)
          {
            double entry = xt->mat[j + i * n_cols];
 
@@ -3050,8 +2765,7 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
       if (calc_symmetric (proc, xt, v_dummy, ase_dummy, t_dummy,
                           somers_d_v, somers_d_ase, somers_d_t))
         {
-          int i;
-          for (i = 0; i < 3; i++)
+          for (int i = 0; i < 3; i++)
             {
               v[8 + i] = somers_d_v[i];
               ase[8 + i] = somers_d_ase[i];
@@ -3064,63 +2778,58 @@ calc_directional (struct crosstabs_proc *proc, struct crosstabulation *xt,
   /* Eta. */
   if (proc->statistics & (1u << CRS_ST_ETA))
     {
-      {
-       double sum_Xr, sum_X2r;
-       double SX, SXW;
-       int i, j;
-
-       for (sum_Xr = sum_X2r = 0., i = 0; i < n_rows; i++)
-         {
-           sum_Xr += xt->vars[ROW_VAR].values[i].f * xt->row_tot[i];
-           sum_X2r += pow2 (xt->vars[ROW_VAR].values[i].f) * xt->row_tot[i];
-         }
-       SX = sum_X2r - pow2 (sum_Xr) / xt->total;
-
-       for (SXW = 0., j = 0; j < n_cols; j++)
-         {
-           double cum;
-
-           for (cum = 0., i = 0; i < n_rows; i++)
-             {
-               SXW += (pow2 (xt->vars[ROW_VAR].values[i].f)
-                        * xt->mat[j + i * n_cols]);
-               cum += (xt->vars[ROW_VAR].values[i].f
-                        * xt->mat[j + i * n_cols]);
-             }
+      /* X dependent. */
+      double sum_Xr = 0.0;
+      double sum_X2r = 0.0;
+      for (int i = 0; i < n_rows; i++)
+        {
+          sum_Xr += xt->vars[ROW_VAR].values[i].f * xt->row_tot[i];
+          sum_X2r += pow2 (xt->vars[ROW_VAR].values[i].f) * xt->row_tot[i];
+        }
+      double SX = sum_X2r - pow2 (sum_Xr) / xt->total;
 
-           SXW -= cum * cum / xt->col_tot[j];
-         }
-       v[11] = sqrt (1. - SXW / SX);
-      }
+      double SXW = 0.0;
+      FOR_EACH_POPULATED_COLUMN (j, xt)
+        {
+          double cum = 0.0;
 
-      {
-       double sum_Yc, sum_Y2c;
-       double SY, SYW;
-       int i, j;
+          for (int i = 0; i < n_rows; i++)
+            {
+              SXW += (pow2 (xt->vars[ROW_VAR].values[i].f)
+                      * xt->mat[j + i * n_cols]);
+              cum += (xt->vars[ROW_VAR].values[i].f
+                      * xt->mat[j + i * n_cols]);
+            }
 
-       for (sum_Yc = sum_Y2c = 0., i = 0; i < n_cols; i++)
-         {
-           sum_Yc += xt->vars[COL_VAR].values[i].f * xt->col_tot[i];
-           sum_Y2c += pow2 (xt->vars[COL_VAR].values[i].f) * xt->col_tot[i];
-         }
-       SY = sum_Y2c - sum_Yc * sum_Yc / xt->total;
+          SXW -= cum * cum / xt->col_tot[j];
+        }
+      v[11] = sqrt (1. - SXW / SX);
 
-       for (SYW = 0., i = 0; i < n_rows; i++)
-         {
-           double cum;
+      /* Y dependent. */
+      double sum_Yc = 0.0;
+      double sum_Y2c = 0.0;
+      for (int i = 0; i < n_cols; i++)
+        {
+          sum_Yc += xt->vars[COL_VAR].values[i].f * xt->col_tot[i];
+          sum_Y2c += pow2 (xt->vars[COL_VAR].values[i].f) * xt->col_tot[i];
+        }
+      double SY = sum_Y2c - pow2 (sum_Yc) / xt->total;
 
-           for (cum = 0., j = 0; j < n_cols; j++)
-             {
-               SYW += (pow2 (xt->vars[COL_VAR].values[j].f)
-                        * xt->mat[j + i * n_cols]);
-               cum += (xt->vars[COL_VAR].values[j].f
-                        * xt->mat[j + i * n_cols]);
-             }
+      double SYW = 0.0;
+      FOR_EACH_POPULATED_ROW (i, xt)
+        {
+          double cum = 0.0;
+          for (int j = 0; j < n_cols; j++)
+            {
+              SYW += (pow2 (xt->vars[COL_VAR].values[j].f)
+                      * xt->mat[j + i * n_cols]);
+              cum += (xt->vars[COL_VAR].values[j].f
+                      * xt->mat[j + i * n_cols]);
+            }
 
-           SYW -= cum * cum / xt->row_tot[i];
-         }
-       v[12] = sqrt (1. - SYW / SY);
-      }
+          SYW -= cum * cum / xt->row_tot[i];
+        }
+      v[12] = sqrt (1. - SYW / SY);
     }
 
   return 1;
index 11a9f7f31e50fad3bf8fe540a046c9af57eaadd4..2738fb137ee6b558e44e28ec1d951a8064d4c8d0 100644 (file)
@@ -38,7 +38,7 @@
 #include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
@@ -136,26 +136,17 @@ struct dsc_var
     double stats[DSC_N_STATS]; /* All the stats' values. */
   };
 
-/* Output format. */
-enum dsc_format
-  {
-    DSC_LINE,           /* Abbreviated format. */
-    DSC_SERIAL          /* Long format. */
-  };
-
 /* A DESCRIPTIVES procedure. */
 struct dsc_proc
   {
     /* Per-variable info. */
+    struct dictionary *dict;    /* Dictionary. */
     struct dsc_var *vars;       /* Variables. */
     size_t var_cnt;             /* Number of variables. */
 
     /* User options. */
     enum dsc_missing_type missing_type; /* Treatment of missing values. */
     enum mv_class exclude;      /* Classes of missing values to exclude. */
-    int show_var_labels;        /* Nonzero to show variable labels. */
-    int show_index;             /* Nonzero to show variable index. */
-    enum dsc_format format;     /* Output format. */
 
     /* Accumulated results. */
     double missing_listwise;    /* Sum of weights of cases missing listwise. */
@@ -209,13 +200,11 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
 
   /* Create and initialize dsc. */
   dsc = xmalloc (sizeof *dsc);
+  dsc->dict = dict;
   dsc->vars = NULL;
   dsc->var_cnt = 0;
   dsc->missing_type = DSC_VARIABLE;
   dsc->exclude = MV_ANY;
-  dsc->show_var_labels = 1;
-  dsc->show_index = 0;
-  dsc->format = DSC_LINE;
   dsc->missing_listwise = 0.;
   dsc->valid = 0.;
   dsc->bad_warn = 1;
@@ -253,18 +242,15 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
           lex_match (lexer, T_EQUALS);
           while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
-              if (lex_match_id (lexer, "LABELS"))
-                dsc->show_var_labels = 1;
-              else if (lex_match_id (lexer, "NOLABELS"))
-                dsc->show_var_labels = 0;
-              else if (lex_match_id (lexer, "INDEX"))
-                dsc->show_index = 1;
-              else if (lex_match_id (lexer, "NOINDEX"))
-                dsc->show_index = 0;
-              else if (lex_match_id (lexer, "LINE"))
-                dsc->format = DSC_LINE;
-              else if (lex_match_id (lexer, "SERIAL"))
-                dsc->format = DSC_SERIAL;
+              if (lex_match_id (lexer, "LABELS")
+                  || lex_match_id (lexer, "NOLABELS")
+                  || lex_match_id (lexer, "INDEX")
+                  || lex_match_id (lexer, "NOINDEX")
+                  || lex_match_id (lexer, "LINE")
+                  || lex_match_id (lexer, "SERIAL"))
+                {
+                  /* Ignore. */
+                }
               else
                 {
                   lex_error (lexer, NULL);
@@ -589,37 +575,29 @@ generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc,
 static void
 dump_z_table (struct dsc_proc *dsc)
 {
-  size_t cnt = 0;
-  struct tab_table *t;
+  struct pivot_table *table = pivot_table_create (
+    N_("Mapping of Variables to Z-scores"));
 
-  {
-    size_t i;
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Names"),
+                          N_("Source"), N_("Target"));
 
-    for (i = 0; i < dsc->var_cnt; i++)
-      if (dsc->vars[i].z_name != NULL)
-       cnt++;
-  }
-
-  t = tab_create (2, cnt + 1);
-  tab_title (t, _("Mapping of variables to corresponding Z-scores."));
-  tab_headers (t, 0, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, cnt);
-  tab_hline (t, TAL_2, 0, 1, 1);
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source"));
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Target"));
+  struct pivot_dimension *names = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+  names->hide_all_labels = true;
 
-  {
-    size_t i, y;
+  for (size_t i = 0; i < dsc->var_cnt; i++)
+    if (dsc->vars[i].z_name != NULL)
+      {
+        int row = pivot_category_create_leaf (names->root,
+                                              pivot_value_new_number (i));
 
-    for (i = 0, y = 1; i < dsc->var_cnt; i++)
-      if (dsc->vars[i].z_name != NULL)
-       {
-         tab_text (t, 0, y, TAB_LEFT, var_to_string (dsc->vars[i].v));
-         tab_text (t, 1, y++, TAB_LEFT, dsc->vars[i].z_name);
-       }
-  }
+        pivot_table_put2 (table, 0, row,
+                          pivot_value_new_variable (dsc->vars[i].v));
+        pivot_table_put2 (table, 1, row,
+                          pivot_value_new_user_text (dsc->vars[i].z_name, -1));
+      }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 static void
@@ -1003,64 +981,53 @@ static algo_compare_func descriptives_compare_dsc_vars;
 static void
 display (struct dsc_proc *dsc)
 {
-  size_t i;
-  int nc;
-  struct tab_table *t;
-
-  nc = 1 + (dsc->format == DSC_SERIAL ? 2 : 1);
-  for (i = 0; i < DSC_N_STATS; i++)
+  struct pivot_table *table = pivot_table_create (
+    N_("Descriptive Statistics"));
+  pivot_table_set_weight_var (table, dict_get_weight (dsc->dict));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  pivot_category_create_leaf_rc (
+    statistics->root, pivot_value_new_text (N_("N")), PIVOT_RC_COUNT);
+  for (int i = 0; i < DSC_N_STATS; i++)
     if (dsc->show_stats & (1ul << i))
-      nc++;
+      pivot_category_create_leaf (statistics->root,
+                                  pivot_value_new_text (dsc_info[i].name));
 
   if (dsc->sort_by_stat != DSC_NONE)
     sort (dsc->vars, dsc->var_cnt, sizeof *dsc->vars,
           descriptives_compare_dsc_vars, dsc);
 
-  t = tab_create (nc, dsc->var_cnt + 1);
-  tab_headers (t, 1, 0, 1, 0);
-  tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, nc - 1, dsc->var_cnt);
-  tab_box (t, -1, -1, -1, TAL_1, 1, 0, nc - 1, dsc->var_cnt);
-  tab_hline (t, TAL_2, 0, nc - 1, 1);
-  tab_vline (t, TAL_2, 1, 0, dsc->var_cnt);
-
-  nc = 0;
-  tab_text (t, nc++, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
-  if (dsc->format == DSC_SERIAL)
-    {
-      tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, _("Valid N"));
-      tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, _("Missing N"));
-    }
-  else
-    tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, "N");
-
-  for (i = 0; i < DSC_N_STATS; i++)
-    if (dsc->show_stats & (1ul << i))
-      {
-       const char *title = gettext (dsc_info[i].name);
-       tab_text (t, nc++, 0, TAB_CENTER | TAT_TITLE, title);
-      }
-
-  for (i = 0; i < dsc->var_cnt; i++)
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+  for (size_t i = 0; i < dsc->var_cnt; i++)
     {
       struct dsc_var *dv = &dsc->vars[i];
-      size_t j;
 
-      nc = 0;
-      tab_text (t, nc++, i + 1, TAB_LEFT, var_to_string (dv->v));
-      tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->valid);
-      if (dsc->format == DSC_SERIAL)
-       tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->missing);
+      int row = pivot_category_create_leaf (variables->root,
+                                            pivot_value_new_variable (dv->v));
 
-      for (j = 0; j < DSC_N_STATS; j++)
+      int column = 0;
+      pivot_table_put2 (table, column++, row,
+                        pivot_value_new_number (dv->valid));
+
+      for (int j = 0; j < DSC_N_STATS; j++)
        if (dsc->show_stats & (1ul << j))
-         tab_double (t, nc++, i + 1, TAB_NONE, dv->stats[j], NULL, RC_OTHER);
+          {
+            union value v = { .f = dv->stats[j] };
+            struct pivot_value *pv = (j == DSC_MIN || j == DSC_MAX
+                                      ? pivot_value_new_var_value (dv->v, &v)
+                                      : pivot_value_new_number (dv->stats[j]));
+            pivot_table_put2 (table, column++, row, pv);
+          }
     }
 
-  tab_title (t, _("Valid cases = %.*g; cases with missing value(s) = %.*g."),
-            DBL_DIG + 1, dsc->valid,
-             DBL_DIG + 1, dsc->missing_listwise);
-
-  tab_submit (t);
+  int row = pivot_category_create_leaves (
+    variables->root, N_("Valid N (listwise)"), N_("Missing N (listwise)"));
+  pivot_table_put2 (table, 0, row, pivot_value_new_number (dsc->valid));
+  pivot_table_put2 (table, 0, row + 1,
+                    pivot_value_new_number (dsc->missing_listwise));
+  pivot_table_submit (table);
 }
 
 /* Compares `struct dsc_var's A and B according to the ordering
index 861f81f2d2aff284868acf8743c3cc13bfb5bcd5..4f47a6c95a38e95fdaa01785f95f2f51a07aab7d 100644 (file)
@@ -60,7 +60,7 @@
 #include "language/lexer/value-parser.h"
 #include "language/lexer/variable-parser.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -196,54 +196,6 @@ struct exploratory_stats
   double cmin;
 };
 
-
-/* Returns an array of (iact->n_vars) pointers to union value initialised to NULL.
-   The caller must free this array when no longer required. */
-static const union value **
-previous_value_alloc (const struct interaction *iact)
-{
-  int ivar_idx;
-
-  const union value **prev_val = xcalloc (iact->n_vars, sizeof (*prev_val));
-
-  for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-    prev_val[ivar_idx] = NULL;
-
-  return prev_val;
-}
-
-/* Set the contents of PREV_VAL to the values of C indexed by the variables of IACT */
-static int
-previous_value_record (const struct interaction *iact, const struct ccase *c, const union value **prev_val)
-{
-  int ivar_idx;
-  int diff_idx = -1;
-
-  for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-    {
-      const struct variable *ivar = iact->vars[ivar_idx];
-      const int width = var_get_width (ivar);
-      const union value *val = case_data (c, ivar);
-
-      if (prev_val[ivar_idx])
-        if (! value_equal (prev_val[ivar_idx], val, width))
-          {
-            diff_idx = ivar_idx;
-            break;
-          }
-    }
-
-  for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-    {
-      const struct variable *ivar = iact->vars[ivar_idx];
-      const union value *val = case_data (c, ivar);
-
-      prev_val[ivar_idx] = val;
-    }
-  return diff_idx;
-}
-
-
 static void
 show_boxplot_grouped (const struct examine *cmd, int iact_idx)
 {
@@ -589,888 +541,380 @@ show_histogram (const struct examine *cmd, int iact_idx)
     }
 }
 
-static void
-percentiles_report (const struct examine *cmd, int iact_idx)
+static struct pivot_value *
+new_value_with_missing_footnote (const struct variable *var,
+                                 const union value *value,
+                                 struct pivot_footnote *missing_footnote)
 {
-  const struct interaction *iact = cmd->iacts[iact_idx];
-  int i, v;
-  const int heading_columns = 1 + iact->n_vars + 1;
-  const int heading_rows = 2;
-  struct tab_table *t;
-
-  const size_t n_cats =  categoricals_n_count (cmd->cats, iact_idx);
-
-  const int rows_per_cat = 2;
-  const int rows_per_var = n_cats * rows_per_cat;
-
-  const int nr = heading_rows + cmd->n_dep_vars * rows_per_var;
-  const int nc = heading_columns + cmd->n_percentiles;
-
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Percentiles"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  /* Internal Vertical lines */
-  tab_box (t, -1, -1, -1, TAL_1,
-           heading_columns, 0, nc - 1, nr - 1);
-
-  /* External Frame */
-  tab_box (t, TAL_2, TAL_2, -1, -1,
-           0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_joint_text (t, heading_columns, 0,
-                  nc - 1, 0,
-                  TAT_TITLE | TAB_CENTER,
-                  _("Percentiles")
-                  );
-
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
-
-
-  for (i = 0; i < cmd->n_percentiles; ++i)
-    {
-      tab_text_format (t, heading_columns + i, 1,
-                       TAT_TITLE | TAB_CENTER,
-                       _("%g"), cmd->ptiles[i]);
-    }
+  struct pivot_value *pv = pivot_value_new_var_value (var, value);
+  if (var_is_value_missing (var, value, MV_USER))
+    pivot_value_add_footnote (pv, missing_footnote);
+  return pv;
+}
 
-  for (i = 0; i < iact->n_vars; ++i)
+static void
+create_interaction_dimensions (struct pivot_table *table,
+                               const struct categoricals *cats,
+                               const struct interaction *iact,
+                               struct pivot_footnote *missing_footnote)
+{
+  for (size_t i = iact->n_vars; i-- > 0; )
     {
-      tab_text (t,
-                1 + i, 1,
-                TAT_TITLE,
-                var_to_string (iact->vars[i])
-                );
+      const struct variable *var = iact->vars[i];
+      struct pivot_dimension *d = pivot_dimension_create__ (
+        table, PIVOT_AXIS_ROW, pivot_value_new_variable (var));
+      d->root->show_label = true;
+
+      size_t n;
+      union value *values = categoricals_get_var_values (cats, var, &n);
+      for (size_t j = 0; j < n; j++)
+        pivot_category_create_leaf (
+          d->root, new_value_with_missing_footnote (var, &values[j],
+                                                    missing_footnote));
     }
+}
 
+static struct pivot_footnote *
+create_missing_footnote (struct pivot_table *table)
+{
+  return pivot_table_create_footnote (
+    table, pivot_value_new_text (N_("User-missing value.")));
+}
 
+static void
+percentiles_report (const struct examine *cmd, int iact_idx)
+{
+  struct pivot_table *table = pivot_table_create (N_("Percentiles"));
+  table->omit_empty = true;
 
-  if (n_cats > 0)
-    {
-      tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1);
-
-      for (v = 0; v < cmd->n_dep_vars; ++v)
-       {
-         const union value **prev_vals = previous_value_alloc (iact);
-
-         int ivar_idx;
-         if ( v > 0 )
-           tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var);
-
-         tab_text (t,
-                   0, heading_rows + v * rows_per_var,
-                   TAT_TITLE | TAB_LEFT,
-                   var_to_string (cmd->dep_vars[v])
-                   );
-
-         for (i = 0; i < n_cats; ++i)
-           {
-             const struct ccase *c =
-               categoricals_get_case_by_category_real (cmd->cats,
-                                                       iact_idx, i);
-
-             const struct exploratory_stats *ess =
-               categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
-
-             const struct exploratory_stats *es = ess + v;
-
-             int diff_idx = previous_value_record (iact, c, prev_vals);
-
-             double hinges[3];
-             int p;
-
-             for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-               {
-                 const struct variable *ivar = iact->vars[ivar_idx];
-                 const union value *val = case_data (c, ivar);
+  struct pivot_dimension *percentiles = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Percentiles"));
+  percentiles->root->show_label = true;
+  for (int i = 0; i < cmd->n_percentiles; ++i)
+    pivot_category_create_leaf (
+      percentiles->root,
+      pivot_value_new_user_text_nocopy (xasprintf ("%g", cmd->ptiles[i])));
 
-                 if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                     || i == 0)
-                   {
-                     struct string str;
-                     ds_init_empty (&str);
-                     append_value_name (ivar, val, &str);
-
-                     tab_text (t,
-                               1 + ivar_idx,
-                               heading_rows + v * rows_per_var + i * rows_per_cat,
-                               TAT_TITLE | TAB_LEFT,
-                               ds_cstr (&str)
-                               );
-
-                     ds_destroy (&str);
-                   }
-               }
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("Weighted Average"), N_("Tukey's Hinges"));
 
-             if ( diff_idx != -1 && diff_idx < iact->n_vars)
-               {
-                 tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                            heading_rows + v * rows_per_var + i * rows_per_cat
-                            );
-               }
+  const struct interaction *iact = cmd->iacts[iact_idx];
+  struct pivot_footnote *missing_footnote = create_missing_footnote (table);
+  create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
 
-             tab_text (t, heading_columns - 1,
-                       heading_rows + v * rows_per_var + i * rows_per_cat,
-                       TAT_TITLE | TAB_LEFT,
-                       gettext (ptile_alg_desc [cmd->pc_alg]));
+  struct pivot_dimension *dep_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-             tukey_hinges_calculate (es->hinges, hinges);
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
 
-             for (p = 0; p < cmd->n_percentiles; ++p)
-               {
-                 tab_double (t, heading_columns + p,
-                             heading_rows + v * rows_per_var + i * rows_per_cat,
-                             0,
-                             percentile_calculate (es->percentiles[p], cmd->pc_alg),
-                             NULL, RC_OTHER);
+  size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
+  for (size_t v = 0; v < cmd->n_dep_vars; ++v)
+    {
+      indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
+        dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
 
-                 if (cmd->ptiles[p] == 25.0)
-                   {
-                     tab_double (t, heading_columns + p,
-                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                                 0,
-                                 hinges[0],
-                                 NULL, RC_OTHER);
-                   }
-                 else if (cmd->ptiles[p] == 50.0)
-                   {
-                     tab_double (t, heading_columns + p,
-                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                                 0,
-                                 hinges[1],
-                                 NULL, RC_OTHER);
-                   }
-                 else if (cmd->ptiles[p] == 75.0)
-                   {
-                     tab_double (t, heading_columns + p,
-                                 heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                                 0,
-                                 hinges[2],
-                                 NULL, RC_OTHER);
-                   }
-               }
+      for (size_t i = 0; i < n_cats; ++i)
+        {
+          for (size_t j = 0; j < iact->n_vars; j++)
+            {
+              int idx = categoricals_get_value_index_by_category_real (
+                cmd->cats, iact_idx, i, j);
+              indexes[table->n_dimensions - 2 - j] = idx;
+            }
 
+          const struct exploratory_stats *ess
+            = categoricals_get_user_data_by_category_real (
+              cmd->cats, iact_idx, i);
+          const struct exploratory_stats *es = ess + v;
 
-             tab_text (t, heading_columns - 1,
-                       heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                       TAT_TITLE | TAB_LEFT,
-                       _("Tukey's Hinges"));
+          double hinges[3];
+          tukey_hinges_calculate (es->hinges, hinges);
 
-           }
+          for (size_t pc_idx = 0; pc_idx < cmd->n_percentiles; ++pc_idx)
+            {
+              indexes[0] = pc_idx;
+
+              indexes[1] = 0;
+              double value = percentile_calculate (es->percentiles[pc_idx],
+                                                   cmd->pc_alg);
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (value));
+
+              double hinge = (cmd->ptiles[pc_idx] == 25.0 ? hinges[0]
+                              : cmd->ptiles[pc_idx] == 50.0 ? hinges[1]
+                              : cmd->ptiles[pc_idx] == 75.0 ? hinges[2]
+                              : SYSMIS);
+              if (hinge != SYSMIS)
+                {
+                  indexes[1] = 1;
+                  pivot_table_put (table, indexes, table->n_dimensions,
+                                   pivot_value_new_number (hinge));
+                }
+            }
+        }
 
-         free (prev_vals);
-       }
     }
-  tab_submit (t);
+  free (indexes);
+
+  pivot_table_submit (table);
 }
 
 static void
 descriptives_report (const struct examine *cmd, int iact_idx)
 {
-  const struct interaction *iact = cmd->iacts[iact_idx];
-  int i, v;
-  const int heading_columns = 1 + iact->n_vars + 2;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  size_t n_cats =  categoricals_n_count (cmd->cats, iact_idx);
-
-  const int rows_per_cat = 13;
-  const int rows_per_var = n_cats * rows_per_cat;
-
-  const int nr = heading_rows + cmd->n_dep_vars * rows_per_var;
-  const int nc = 2 + heading_columns;
-
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Descriptives"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
+  struct pivot_table *table = pivot_table_create (N_("Descriptives"));
+  table->omit_empty = true;
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Aspect"),
+                          N_("Statistic"), N_("Std. Error"));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"), N_("Mean"));
+  struct pivot_category *interval = pivot_category_create_group__ (
+    statistics->root,
+    pivot_value_new_text_format (N_("%g%% Confidence Interval for Mean"),
+                                 cmd->conf * 100.0));
+  pivot_category_create_leaves (interval, N_("Lower Bound"),
+                                N_("Upper Bound"));
+  pivot_category_create_leaves (
+    statistics->root, N_("5% Trimmed Mean"), N_("Median"), N_("Variance"),
+    N_("Std. Deviation"), N_("Minimum"), N_("Maximum"), N_("Range"),
+    N_("Interquartile Range"), N_("Skewness"), N_("Kurtosis"));
 
-  /* Internal Vertical lines */
-  tab_box (t, -1, -1, -1, TAL_1,
-           heading_columns, 0, nc - 1, nr - 1);
-
-  /* External Frame */
-  tab_box (t, TAL_2, TAL_2, -1, -1,
-           0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-
-  tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE,
-            _("Statistic"));
+  const struct interaction *iact = cmd->iacts[iact_idx];
+  struct pivot_footnote *missing_footnote = create_missing_footnote (table);
+  create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
 
-  tab_text (t, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE,
-            _("Std. Error"));
+  struct pivot_dimension *dep_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-  for (i = 0; i < iact->n_vars; ++i)
-    {
-      tab_text (t,
-                1 + i, 0,
-                TAT_TITLE,
-                var_to_string (iact->vars[i])
-                );
-    }
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
 
-  for (v = 0; v < cmd->n_dep_vars; ++v)
+  size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
+  for (size_t v = 0; v < cmd->n_dep_vars; ++v)
     {
-      const union value **prev_val = previous_value_alloc (iact);
-
-      int ivar_idx;
-      if ( v > 0 )
-        tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var);
+      indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
+        dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
 
-      tab_text (t,
-                0, heading_rows + v * rows_per_var,
-                TAT_TITLE | TAB_LEFT,
-                var_to_string (cmd->dep_vars[v])
-                );
-
-      for (i = 0; i < n_cats; ++i)
+      for (size_t i = 0; i < n_cats; ++i)
         {
-          const struct ccase *c =
-            categoricals_get_case_by_category_real (cmd->cats,
-                                                    iact_idx, i);
-
-          const struct exploratory_stats *ess =
-            categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
+          for (size_t j = 0; j < iact->n_vars; j++)
+            {
+              int idx = categoricals_get_value_index_by_category_real (
+                cmd->cats, iact_idx, i, j);
+              indexes[table->n_dimensions - 2 - j] = idx;
+            }
 
+          const struct exploratory_stats *ess
+            = categoricals_get_user_data_by_category_real (cmd->cats,
+                                                           iact_idx, i);
           const struct exploratory_stats *es = ess + v;
 
-          const int diff_idx = previous_value_record (iact, c, prev_val);
-
           double m0, m1, m2, m3, m4;
-         double tval;
-
           moments_calculate (es->mom, &m0, &m1, &m2, &m3, &m4);
+          double tval = gsl_cdf_tdist_Qinv ((1.0 - cmd->conf) / 2.0, m0 - 1.0);
 
-          tval = gsl_cdf_tdist_Qinv ((1.0 - cmd->conf) / 2.0, m0 - 1.0);
-
-          for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
+          struct entry
             {
-              const struct variable *ivar = iact->vars[ivar_idx];
-              const union value *val = case_data (c, ivar);
-
-              if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                  || i == 0)
-                {
-                  struct string str;
-                  ds_init_empty (&str);
-                  append_value_name (ivar, val, &str);
-
-                  tab_text (t,
-                            1 + ivar_idx,
-                            heading_rows + v * rows_per_var + i * rows_per_cat,
-                            TAT_TITLE | TAB_LEFT,
-                            ds_cstr (&str)
-                            );
-
-                  ds_destroy (&str);
-                }
+              int stat_idx;
+              int aspect_idx;
+              double x;
             }
-
-          if ( diff_idx != -1 && diff_idx < iact->n_vars)
+          entries[] = {
+            { 0, 0, m1 },
+            { 0, 1, calc_semean (m2, m0) },
+            { 1, 0, m1 - tval * calc_semean (m2, m0) },
+            { 2, 0, m1 + tval * calc_semean (m2, m0) },
+            { 3, 0, trimmed_mean_calculate (es->trimmed_mean) },
+            { 4, 0, percentile_calculate (es->quartiles[1], cmd->pc_alg) },
+            { 5, 0, m2 },
+            { 6, 0, sqrt (m2) },
+            { 7, 0, es->minima[0].val },
+            { 8, 0, es->maxima[0].val },
+            { 9, 0, es->maxima[0].val - es->minima[0].val },
+            { 10, 0, (percentile_calculate (es->quartiles[2], cmd->pc_alg) -
+                      percentile_calculate (es->quartiles[0], cmd->pc_alg)) },
+            { 11, 0, m3 },
+            { 11, 1, calc_seskew (m0) },
+            { 12, 0, m4 },
+            { 12, 1, calc_sekurt (m0) },
+          };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
             {
-              tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                         heading_rows + v * rows_per_var + i * rows_per_cat
-                         );
+              const struct entry *e = &entries[j];
+              indexes[0] = e->aspect_idx;
+              indexes[1] = e->stat_idx;
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (e->x));
             }
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat,
-                    TAB_LEFT,
-                    _("Mean")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat,
-                      0, m1, NULL, RC_OTHER);
-
-          tab_double (t,
-                      1 + iact->n_vars + 3,
-                      heading_rows + v * rows_per_var + i * rows_per_cat,
-                      0, calc_semean (m2, m0), NULL, RC_OTHER);
-
-          tab_text_format (t,
-                           1 + iact->n_vars,
-                           heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                           TAB_LEFT,
-                           _("%g%% Confidence Interval for Mean"),
-                           cmd->conf * 100.0
-                           );
-
-          tab_text (t,
-                    1 + iact->n_vars + 1,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                    TAB_LEFT,
-                    _("Lower Bound")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 1,
-                      0, m1 - tval * calc_semean (m2, m0), NULL, RC_OTHER);
-
-
-          tab_text (t,
-                    1 + iact->n_vars + 1,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 2,
-                    TAB_LEFT,
-                    _("Upper Bound")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 2,
-                      0, m1 + tval * calc_semean (m2, m0), NULL, RC_OTHER);
-
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 3,
-                    TAB_LEFT,
-                    _("5% Trimmed Mean")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 3,
-                      0,
-                      trimmed_mean_calculate (es->trimmed_mean),
-                      NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 4,
-                    TAB_LEFT,
-                    _("Median")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 4,
-                      0,
-                      percentile_calculate (es->quartiles[1], cmd->pc_alg),
-                      NULL, RC_OTHER);
-
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 5,
-                    TAB_LEFT,
-                    _("Variance")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 5,
-                      0, m2, NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 6,
-                    TAB_LEFT,
-                    _("Std. Deviation")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 6,
-                      0, sqrt (m2), NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 7,
-                    TAB_LEFT,
-                    _("Minimum")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 7,
-                      0,
-                      es->minima[0].val,
-                      NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 8,
-                    TAB_LEFT,
-                    _("Maximum")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 8,
-                      0,
-                      es->maxima[0].val,
-                      NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 9,
-                    TAB_LEFT,
-                    _("Range")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 9,
-                      0,
-                      es->maxima[0].val - es->minima[0].val,
-                      NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 10,
-                    TAB_LEFT,
-                    _("Interquartile Range")
-                    );
-
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 10,
-                      0,
-                      percentile_calculate (es->quartiles[2], cmd->pc_alg) -
-                      percentile_calculate (es->quartiles[0], cmd->pc_alg),
-                      NULL, RC_OTHER);
-
-
-
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 11,
-                    TAB_LEFT,
-                    _("Skewness")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 11,
-                      0, m3, NULL, RC_OTHER);
-
-          tab_double (t,
-                      1 + iact->n_vars + 3,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 11,
-                      0, calc_seskew (m0), NULL, RC_OTHER);
-
-          tab_text (t,
-                    1 + iact->n_vars,
-                    heading_rows + v * rows_per_var + i * rows_per_cat + 12,
-                    TAB_LEFT,
-                    _("Kurtosis")
-                    );
-
-          tab_double (t,
-                      1 + iact->n_vars + 2,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 12,
-                      0, m4, NULL, RC_OTHER);
-
-          tab_double (t,
-                      1 + iact->n_vars + 3,
-                      heading_rows + v * rows_per_var + i * rows_per_cat + 12,
-                      0, calc_sekurt (m0), NULL, RC_OTHER);
         }
-
-      free (prev_val);
     }
-  tab_submit (t);
+
+  free (indexes);
+
+  pivot_table_submit (table);
 }
 
 
 static void
 extremes_report (const struct examine *cmd, int iact_idx)
 {
-  const struct interaction *iact = cmd->iacts[iact_idx];
-  int i, v;
-  const int heading_columns = 1 + iact->n_vars + 2;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  size_t n_cats =  categoricals_n_count (cmd->cats, iact_idx);
-
-  const int rows_per_cat = 2 * cmd->disp_extremes;
-  const int rows_per_var = n_cats * rows_per_cat;
-
-  const int nr = heading_rows + cmd->n_dep_vars * rows_per_var;
-  const int nc = 2 + heading_columns;
-
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Extreme Values"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
+  struct pivot_table *table = pivot_table_create (N_("Extreme Values"));
+  table->omit_empty = true;
 
-  /* Internal Vertical lines */
-  tab_box (t, -1, -1, -1, TAL_1,
-           heading_columns, 0, nc - 1, nr - 1);
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  pivot_category_create_leaf (statistics->root,
+                              (cmd->id_var
+                               ? pivot_value_new_variable (cmd->id_var)
+                               : pivot_value_new_text (N_("Case Number"))));
+  pivot_category_create_leaves (statistics->root, N_("Value"));
 
-  /* External Frame */
-  tab_box (t, TAL_2, TAL_2, -1, -1,
-           0, 0, nc - 1, nr - 1);
+  struct pivot_dimension *order = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Order"));
+  for (size_t i = 0; i < cmd->disp_extremes; i++)
+    pivot_category_create_leaf (order->root, pivot_value_new_integer (i + 1));
 
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Extreme"),
+                          N_("Highest"), N_("Lowest"));
 
+  const struct interaction *iact = cmd->iacts[iact_idx];
+  struct pivot_footnote *missing_footnote = create_missing_footnote (table);
+  create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
 
-  if ( cmd->id_var )
-    tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE,
-              var_to_string (cmd->id_var));
-  else
-    tab_text (t, heading_columns, 0, TAB_CENTER | TAT_TITLE,
-              _("Case Number"));
-
-  tab_text (t, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE,
-            _("Value"));
+  struct pivot_dimension *dep_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-  for (i = 0; i < iact->n_vars; ++i)
-    {
-      tab_text (t,
-                1 + i, 0,
-                TAT_TITLE,
-                var_to_string (iact->vars[i])
-                );
-    }
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
 
-  for (v = 0; v < cmd->n_dep_vars; ++v)
+  size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
+  for (size_t v = 0; v < cmd->n_dep_vars; ++v)
     {
-      const union value **prev_val = previous_value_alloc (iact);
+      indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
+        dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
 
-      int ivar_idx;
-      if ( v > 0 )
-        tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var);
-
-      tab_text (t,
-                0, heading_rows + v * rows_per_var,
-                TAT_TITLE,
-                var_to_string (cmd->dep_vars[v])
-                );
-
-      for (i = 0; i < n_cats; ++i)
+      for (size_t i = 0; i < n_cats; ++i)
         {
-          int e;
-          const struct ccase *c =
-            categoricals_get_case_by_category_real (cmd->cats, iact_idx, i);
-
-          const struct exploratory_stats *ess =
-            categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
+          for (size_t j = 0; j < iact->n_vars; j++)
+            {
+              int idx = categoricals_get_value_index_by_category_real (
+                cmd->cats, iact_idx, i, j);
+              indexes[table->n_dimensions - 2 - j] = idx;
+            }
 
+          const struct exploratory_stats *ess
+            = categoricals_get_user_data_by_category_real (cmd->cats,
+                                                           iact_idx, i);
           const struct exploratory_stats *es = ess + v;
 
-          int diff_idx = previous_value_record (iact, c, prev_val);
-
-          for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
+          for (int e = 0 ; e < cmd->disp_extremes; ++e)
             {
-              const struct variable *ivar = iact->vars[ivar_idx];
-              const union value *val = case_data (c, ivar);
+              indexes[1] = e;
 
-              if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                  || i == 0)
+              for (size_t j = 0; j < 2; j++)
                 {
-                  struct string str;
-                  ds_init_empty (&str);
-                  append_value_name (ivar, val, &str);
-
-                  tab_text (t,
-                            1 + ivar_idx,
-                            heading_rows + v * rows_per_var + i * rows_per_cat,
-                            TAT_TITLE | TAB_LEFT,
-                            ds_cstr (&str)
-                            );
-
-                  ds_destroy (&str);
+                  const struct extremity *extremity
+                    = j ? &es->minima[e] : &es->maxima[e];
+                  indexes[2] = j;
+
+                  indexes[0] = 0;
+                  pivot_table_put (
+                    table, indexes, table->n_dimensions,
+                    (cmd->id_var
+                     ? new_value_with_missing_footnote (cmd->id_var,
+                                                        &extremity->identity,
+                                                        missing_footnote)
+                     : pivot_value_new_integer (extremity->identity.f)));
+
+                  indexes[0] = 1;
+                  union value val = { .f = extremity->val };
+                  pivot_table_put (
+                    table, indexes, table->n_dimensions,
+                    new_value_with_missing_footnote (cmd->dep_vars[v], &val,
+                                                     missing_footnote));
                 }
             }
-
-          if ( diff_idx != -1 && diff_idx < iact->n_vars)
-            {
-              tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                         heading_rows + v * rows_per_var + i * rows_per_cat
-                         );
-            }
-
-         tab_text (t,
-                    heading_columns - 2,
-                   heading_rows + v * rows_per_var + i * rows_per_cat,
-                   TAB_RIGHT,
-                   _("Highest"));
-
-
-          tab_hline (t, TAL_1, heading_columns - 2, nc - 1,
-                     heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes
-                     );
-
-         tab_text (t,
-                    heading_columns - 2,
-                   heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes,
-                   TAB_RIGHT,
-                   _("Lowest"));
-
-          for (e = 0 ; e < cmd->disp_extremes; ++e)
-            {
-              tab_double (t,
-                          heading_columns - 1,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                          TAB_RIGHT,
-                          e + 1,
-                          NULL, RC_INTEGER);
-
-              /* The casenumber */
-              if (cmd->id_var)
-                tab_value (t,
-                           heading_columns,
-                           heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                           TAB_RIGHT,
-                           &es->maxima[e].identity,
-                           cmd->id_var,
-                           NULL);
-              else
-                tab_double (t,
-                          heading_columns,
-                            heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                            TAB_RIGHT,
-                            es->maxima[e].identity.f,
-                            NULL, RC_INTEGER);
-
-              tab_double (t,
-                         heading_columns + 1,
-                         heading_rows + v * rows_per_var + i * rows_per_cat + e,
-                         0,
-                         es->maxima[e].val,
-                         var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
-
-
-              tab_double (t,
-                          heading_columns - 1,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
-                          TAB_RIGHT,
-                          e + 1,
-                          NULL, RC_INTEGER);
-
-              /* The casenumber */
-              if (cmd->id_var)
-                tab_value (t,
-                           heading_columns,
-                           heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
-                           TAB_RIGHT,
-                           &es->minima[e].identity,
-                           cmd->id_var,
-                           NULL);
-              else
-                tab_double (t,
-                            heading_columns,
-                            heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
-                            TAB_RIGHT,
-                            es->minima[e].identity.f,
-                            NULL, RC_INTEGER);
-
-              tab_double (t,
-                          heading_columns + 1,
-                          heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e,
-                          0,
-                          es->minima[e].val,
-                          var_get_print_format (cmd->dep_vars[v]), RC_OTHER);
-            }
         }
-      free (prev_val);
     }
+  free (indexes);
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
 static void
 summary_report (const struct examine *cmd, int iact_idx)
 {
-  const struct interaction *iact = cmd->iacts[iact_idx];
-  int i, v;
-  const int heading_columns = 1 + iact->n_vars;
-  const int heading_rows = 3;
-  struct tab_table *t;
-
-  const struct fmt_spec *wfmt = cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
-
-  size_t n_cats =  categoricals_n_count (cmd->cats, iact_idx);
-
-  const int nr = heading_rows + n_cats * cmd->n_dep_vars;
-  const int nc = 6 + heading_columns;
-
-  t = tab_create (nc, nr);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_title (t, _("Case Processing Summary"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
+  struct pivot_table *table = pivot_table_create (
+    N_("Case Processing Summary"));
+  table->omit_empty = true;
+  pivot_table_set_weight_var (table, dict_get_weight (cmd->dict));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT);
+  struct pivot_dimension *cases = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Cases"), N_("Valid"), N_("Missing"),
+    N_("Total"));
+  cases->root->show_label = true;
 
-  /* Internal Vertical lines */
-  tab_box (t, -1, -1, -1, TAL_1,
-           heading_columns, 0, nc - 1, nr - 1);
-
-  /* External Frame */
-  tab_box (t, TAL_2, TAL_2, -1, -1,
-           0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_joint_text (t, heading_columns, 0,
-                 nc - 1, 0, TAB_CENTER | TAT_TITLE, _("Cases"));
-  tab_joint_text (t,
-                  heading_columns, 1,
-                  heading_columns + 1, 1,
-                  TAB_CENTER | TAT_TITLE, _("Valid"));
-
-  tab_joint_text (t,
-                  heading_columns + 2, 1,
-                  heading_columns + 3, 1,
-                  TAB_CENTER | TAT_TITLE, _("Missing"));
+  const struct interaction *iact = cmd->iacts[iact_idx];
+  struct pivot_footnote *missing_footnote = create_missing_footnote (table);
+  create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
 
-  tab_joint_text (t,
-                  heading_columns + 4, 1,
-                  heading_columns + 5, 1,
-                  TAB_CENTER | TAT_TITLE, _("Total"));
+  struct pivot_dimension *dep_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-  for (i = 0; i < 3; ++i)
-    {
-      tab_text (t, heading_columns + i * 2, 2, TAB_CENTER | TAT_TITLE,
-               _("N"));
-      tab_text (t, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE,
-               _("Percent"));
-    }
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
 
-  for (i = 0; i < iact->n_vars; ++i)
+  size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
+  for (size_t v = 0; v < cmd->n_dep_vars; ++v)
     {
-      tab_text (t,
-                1 + i, 2,
-                TAT_TITLE,
-                var_to_string (iact->vars[i])
-                );
-    }
-
-  if (n_cats > 0)
-    for (v = 0; v < cmd->n_dep_vars; ++v)
-      {
-       int ivar_idx;
-       const union value **prev_values = previous_value_alloc (iact);
-
-       if ( v > 0 )
-         tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats);
+      indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
+        dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
 
-       tab_text (t,
-                 0, heading_rows + n_cats * v,
-                 TAT_TITLE,
-                 var_to_string (cmd->dep_vars[v])
-                 );
+      for (size_t i = 0; i < n_cats; ++i)
+        {
+          for (size_t j = 0; j < iact->n_vars; j++)
+            {
+              int idx = categoricals_get_value_index_by_category_real (
+                cmd->cats, iact_idx, i, j);
+              indexes[table->n_dimensions - 2 - j] = idx;
+            }
 
+          const struct exploratory_stats *es
+            = categoricals_get_user_data_by_category_real (
+              cmd->cats, iact_idx, i);
 
-       for (i = 0; i < n_cats; ++i)
-         {
-           double total;
-           const struct exploratory_stats *es;
-
-           const struct ccase *c =
-             categoricals_get_case_by_category_real (cmd->cats,
-                                                     iact_idx, i);
-           if (c)
-             {
-               int diff_idx = previous_value_record (iact, c, prev_values);
-
-               if ( diff_idx != -1 && diff_idx < iact->n_vars - 1)
-                 tab_hline (t, TAL_1, 1 + diff_idx, nc - 1,
-                            heading_rows + n_cats * v + i );
-
-               for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
-                 {
-                   const struct variable *ivar = iact->vars[ivar_idx];
-                   const union value *val = case_data (c, ivar);
-
-                   if (( diff_idx != -1 && diff_idx <= ivar_idx)
-                       || i == 0)
-                     {
-                       struct string str;
-                       ds_init_empty (&str);
-                       append_value_name (ivar, val, &str);
-
-                       tab_text (t,
-                                 1 + ivar_idx, heading_rows + n_cats * v + i,
-                                 TAT_TITLE | TAB_LEFT,
-                                 ds_cstr (&str)
-                                 );
-
-                       ds_destroy (&str);
-                     }
-                 }
-             }
-
-
-           es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i);
-
-
-           total = es[v].missing + es[v].non_missing;
-           tab_double (t,
-                       heading_columns + 0,
-                       heading_rows + n_cats * v + i,
-                       0,
-                       es[v].non_missing,
-                       NULL, RC_WEIGHT);
-
-
-           tab_text_format (t,
-                            heading_columns + 1,
-                            heading_rows + n_cats * v + i,
-                            0,
-                            "%g%%",
-                            100.0 * es[v].non_missing / total
-                            );
-
-
-           tab_double (t,
-                       heading_columns + 2,
-                       heading_rows + n_cats * v + i,
-                       0,
-                       es[v].missing,
-                       NULL, RC_WEIGHT);
-
-           tab_text_format (t,
-                            heading_columns + 3,
-                            heading_rows + n_cats * v + i,
-                            0,
-                            "%g%%",
-                            100.0 * es[v].missing / total
-                            );
-           tab_double (t,
-                       heading_columns + 4,
-                       heading_rows + n_cats * v + i,
-                       0,
-                       total,
-                       NULL, RC_WEIGHT);
-
-           /* This can only be 100% can't it? */
-           tab_text_format (t,
-                            heading_columns + 5,
-                            heading_rows + n_cats * v + i,
-                            0,
-                            "%g%%",
-                            100.0 * (es[v].missing + es[v].non_missing)/ total
-                            );
-         }
-       free (prev_values);
-      }
+          double total = es[v].missing + es[v].non_missing;
+          struct entry
+            {
+              int stat_idx;
+              int case_idx;
+              double x;
+            }
+          entries[] = {
+            { 0, 0, es[v].non_missing },
+            { 1, 0, 100.0 * es[v].non_missing / total },
+            { 0, 1, es[v].missing },
+            { 1, 1, 100.0 * es[v].missing / total },
+            { 0, 2, total },
+            { 1, 2, 100.0 },
+          };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            {
+              const struct entry *e = &entries[j];
+              indexes[0] = e->stat_idx;
+              indexes[1] = e->case_idx;
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (e->x));
+            }
+        }
+    }
 
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 2);
+  free (indexes);
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 /* Attempt to parse an interaction from LEXER */
index 095d98ff35c5c0c290bae9cc3c6ab45f1fdd9afb..797c5a67255eb920df2fb107bce3b8c003111aba 100644 (file)
@@ -47,7 +47,7 @@
 #include "math/moments.h"
 #include "output/chart-item.h"
 #include "output/charts/scree.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 
 #include "gettext.h"
@@ -1638,162 +1638,101 @@ static void
 show_communalities (const struct cmd_factor * factor,
                    const gsl_vector *initial, const gsl_vector *extracted)
 {
-  int i;
-  int c = 0;
-  const int heading_columns = 1;
-  int nc = heading_columns;
-  const int heading_rows = 1;
-  const int nr = heading_rows + factor->n_vars;
-  struct tab_table *t;
-
-  if (factor->print & PRINT_EXTRACTION)
-    nc++;
-
-  if (factor->print & PRINT_INITIAL)
-    nc++;
-
-  /* No point having a table with only headings */
-  if (nc <= 1)
+  if (!(factor->print & (PRINT_INITIAL | PRINT_EXTRACTION)))
     return;
 
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Communalities"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
+  struct pivot_table *table = pivot_table_create (N_("Communalities"));
 
-  c = 1;
+  struct pivot_dimension *communalities = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Communalities"));
   if (factor->print & PRINT_INITIAL)
-    tab_text (t, c++, 0, TAB_CENTER | TAT_TITLE, _("Initial"));
-
+    pivot_category_create_leaves (communalities->root, N_("Initial"));
   if (factor->print & PRINT_EXTRACTION)
-    tab_text (t, c++, 0, TAB_CENTER | TAT_TITLE, _("Extraction"));
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  for (i = 0 ; i < factor->n_vars; ++i)
+    pivot_category_create_leaves (communalities->root, N_("Extraction"));
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+
+  for (size_t i = 0 ; i < factor->n_vars; ++i)
     {
-      c = 0;
-      tab_text (t, c++, i + heading_rows, TAT_TITLE, var_to_string (factor->vars[i]));
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (factor->vars[i]));
 
+      int col = 0;
       if (factor->print & PRINT_INITIAL)
-       tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (initial, i), NULL, RC_OTHER);
-
+        pivot_table_put2 (table, col++, row, pivot_value_new_number (
+                            gsl_vector_get (initial, i)));
       if (factor->print & PRINT_EXTRACTION)
-       tab_double (t, c++, i + heading_rows, 0, gsl_vector_get (extracted, i), NULL, RC_OTHER);
+        pivot_table_put2 (table, col++, row, pivot_value_new_number (
+                            gsl_vector_get (extracted, i)));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
+static struct pivot_dimension *
+create_numeric_dimension (struct pivot_table *table,
+                          enum pivot_axis_type axis_type, const char *name,
+                          size_t n, bool show_label)
+{
+  struct pivot_dimension *d = pivot_dimension_create (table, axis_type, name);
+  d->root->show_label = show_label;
+  for (int i = 0 ; i < n; ++i)
+    pivot_category_create_leaf (d->root, pivot_value_new_integer (i + 1));
+  return d;
+}
 
 static void
 show_factor_matrix (const struct cmd_factor *factor, const struct idata *idata, const char *title, const gsl_matrix *fm)
 {
-  int i;
+  struct pivot_table *table = pivot_table_create (title);
 
   const int n_factors = idata->n_extractions;
+  create_numeric_dimension (
+    table, PIVOT_AXIS_COLUMN,
+    factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor"),
+    n_factors, true);
 
-  const int heading_columns = 1;
-  const int heading_rows = 2;
-  const int nr = heading_rows + factor->n_vars;
-  const int nc = heading_columns + n_factors;
-  gsl_permutation *perm;
-
-  struct tab_table *t = tab_create (nc, nr);
-
-  /*
-  if ( factor->extraction == EXTRACTION_PC )
-    tab_title (t, _("Component Matrix"));
-  else
-    tab_title (t, _("Factor Matrix"));
-  */
-
-  tab_title (t, "%s", title);
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  if ( factor->extraction == EXTRACTION_PC )
-    tab_joint_text (t,
-                   1, 0,
-                   nc - 1, 0,
-                   TAB_CENTER | TAT_TITLE, _("Component"));
-  else
-    tab_joint_text (t,
-                   1, 0,
-                   nc - 1, 0,
-                   TAB_CENTER | TAT_TITLE, _("Factor"));
-
-
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
-
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 1,
-          nc - 1, nr - 1);
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
   /* Initialise to the identity permutation */
-  perm = gsl_permutation_calloc (factor->n_vars);
+  gsl_permutation *perm = gsl_permutation_calloc (factor->n_vars);
 
   if ( factor->sort)
     sort_matrix_indirect (fm, perm);
 
-  for (i = 0 ; i < n_factors; ++i)
-    {
-      tab_text_format (t, heading_columns + i, 1, TAB_CENTER | TAT_TITLE, _("%d"), i + 1);
-    }
-
-  for (i = 0 ; i < factor->n_vars; ++i)
+  for (size_t i = 0 ; i < factor->n_vars; ++i)
     {
-      int j;
       const int matrix_row = perm->data[i];
-      tab_text (t, 0, i + heading_rows, TAT_TITLE, var_to_string (factor->vars[matrix_row]));
 
-      for (j = 0 ; j < n_factors; ++j)
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (factor->vars[matrix_row]));
+
+      for (size_t j = 0 ; j < n_factors; ++j)
        {
          double x = gsl_matrix_get (fm, matrix_row, j);
-
          if ( fabs (x) < factor->blank)
            continue;
 
-         tab_double (t, heading_columns + j, heading_rows + i, 0, x, NULL, RC_OTHER);
+          pivot_table_put2 (table, j, var_idx, pivot_value_new_number (x));
        }
     }
 
   gsl_permutation_free (perm);
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
+static void
+put_variance (struct pivot_table *table, int row, int phase_idx,
+              double lambda, double percent, double cum)
+{
+  double entries[] = { lambda, percent, cum };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    pivot_table_put3 (table, i, phase_idx, row,
+                      pivot_value_new_number (entries[i]));
+}
 
 static void
 show_explained_variance (const struct cmd_factor * factor,
@@ -1802,517 +1741,226 @@ show_explained_variance (const struct cmd_factor * factor,
                         const gsl_vector *extracted_eigenvalues,
                         const gsl_vector *rotated_loadings)
 {
-  size_t i;
-  int c = 0;
-  const int heading_columns = 1;
-  const int heading_rows = 2;
-  const int nr = heading_rows + factor->n_vars;
-
-  struct tab_table *t ;
-
-  double i_total = 0.0;
-  double i_cum = 0.0;
-
-  double e_total = 0.0;
-  double e_cum = 0.0;
-
-  double r_cum = 0.0;
-
-  int nc = heading_columns;
-
-  if (factor->print & PRINT_EXTRACTION)
-    nc += 3;
-
-  if (factor->print & PRINT_INITIAL)
-    nc += 3;
-
-  if (factor->print & PRINT_ROTATION)
-    {
-      nc += factor->rotation == ROT_PROMAX ? 1 : 3;
-    }
-
-  /* No point having a table with only headings */
-  if ( nc <= heading_columns)
+  if (!(factor->print & (PRINT_INITIAL | PRINT_EXTRACTION | PRINT_ROTATION)))
     return;
 
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Total Variance Explained"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-  tab_hline (t, TAL_1, 1, nc - 1, 1);
+  struct pivot_table *table = pivot_table_create (
+    N_("Total Variance Explained"));
+  table->omit_empty = true;
 
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  /* xgettext:no-c-format */
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Total"), PIVOT_RC_OTHER,
+                          N_("% of Variance"), PIVOT_RC_PERCENT,
+                          N_("Cumulative %"), PIVOT_RC_PERCENT);
 
-
-  if ( factor->extraction == EXTRACTION_PC)
-    tab_text (t, 0, 1, TAB_LEFT | TAT_TITLE, _("Component"));
-  else
-    tab_text (t, 0, 1, TAB_LEFT | TAT_TITLE, _("Factor"));
-
-  c = 1;
+  struct pivot_dimension *phase = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Phase"));
   if (factor->print & PRINT_INITIAL)
-    {
-      tab_joint_text (t, c, 0, c + 2, 0, TAB_CENTER | TAT_TITLE, _("Initial Eigenvalues"));
-      c += 3;
-    }
+    pivot_category_create_leaves (phase->root, N_("Initial Eigenvalues"));
 
   if (factor->print & PRINT_EXTRACTION)
-    {
-      tab_joint_text (t, c, 0, c + 2, 0, TAB_CENTER | TAT_TITLE, _("Extraction Sums of Squared Loadings"));
-      c += 3;
-    }
+    pivot_category_create_leaves (phase->root,
+                                  N_("Extraction Sums of Squared Loadings"));
 
   if (factor->print & PRINT_ROTATION)
-    {
-      const int width = factor->rotation == ROT_PROMAX ? 0 : 2;
-      tab_joint_text (t, c, 0, c + width, 0, TAB_CENTER | TAT_TITLE, _("Rotation Sums of Squared Loadings"));
-      c += width + 1;
-    }
-
-  for (i = 0; i < (nc - heading_columns + 2) / 3 ; ++i)
-    {
-      tab_text (t, i * 3 + 1, 1, TAB_CENTER | TAT_TITLE, _("Total"));
-
-      tab_vline (t, TAL_2, heading_columns + i * 3, 0, nr - 1);
+    pivot_category_create_leaves (phase->root,
+                                  N_("Rotation Sums of Squared Loadings"));
 
-      if (i == 2 && factor->rotation == ROT_PROMAX)
-       continue;
+  struct pivot_dimension *components = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW,
+    factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor"));
 
-      /* xgettext:no-c-format */
-      tab_text (t, i * 3 + 2, 1, TAB_CENTER | TAT_TITLE, _("% of Variance"));
-      tab_text (t, i * 3 + 3, 1, TAB_CENTER | TAT_TITLE, _("Cumulative %"));
-    }
-
-  for (i = 0 ; i < initial_eigenvalues->size; ++i)
+  double i_total = 0.0;
+  for (size_t i = 0 ; i < initial_eigenvalues->size; ++i)
     i_total += gsl_vector_get (initial_eigenvalues, i);
 
-  if ( factor->extraction == EXTRACTION_PAF)
-    {
-      e_total = factor->n_vars;
-    }
-  else
-    {
-      e_total = i_total;
-    }
+  double e_total = (factor->extraction == EXTRACTION_PAF
+                    ? factor->n_vars
+                    : i_total);
 
-  for (i = 0 ; i < factor->n_vars; ++i)
+  double i_cum = 0.0;
+  double e_cum = 0.0;
+  double r_cum = 0.0;
+  for (size_t i = 0 ; i < factor->n_vars; ++i)
     {
       const double i_lambda = gsl_vector_get (initial_eigenvalues, i);
       double i_percent = 100.0 * i_lambda / i_total ;
+      i_cum += i_percent;
 
       const double e_lambda = gsl_vector_get (extracted_eigenvalues, i);
       double e_percent = 100.0 * e_lambda / e_total ;
+      e_cum += e_percent;
 
-      c = 0;
-
-      tab_text_format (t, c++, i + heading_rows, TAB_LEFT | TAT_TITLE, _("%zu"), i + 1);
+      int row = pivot_category_create_leaf (
+        components->root, pivot_value_new_integer (i + 1));
 
-      i_cum += i_percent;
-      e_cum += e_percent;
+      int phase_idx = 0;
 
       /* Initial Eigenvalues */
       if (factor->print & PRINT_INITIAL)
-      {
-       tab_double (t, c++, i + heading_rows, 0, i_lambda, NULL, RC_OTHER);
-       tab_double (t, c++, i + heading_rows, 0, i_percent, NULL, RC_OTHER);
-       tab_double (t, c++, i + heading_rows, 0, i_cum, NULL, RC_OTHER);
-      }
-
-
-      if (factor->print & PRINT_EXTRACTION)
-       {
-         if (i < idata->n_extractions)
-           {
-             /* Sums of squared loadings */
-             tab_double (t, c++, i + heading_rows, 0, e_lambda, NULL, RC_OTHER);
-             tab_double (t, c++, i + heading_rows, 0, e_percent, NULL, RC_OTHER);
-             tab_double (t, c++, i + heading_rows, 0, e_cum, NULL, RC_OTHER);
-           }
-       }
+        put_variance (table, row, phase_idx++, i_lambda, i_percent, i_cum);
 
-      if (rotated_loadings != NULL)
+      if (i < idata->n_extractions)
         {
-          const double r_lambda = gsl_vector_get (rotated_loadings, i);
-          double r_percent = 100.0 * r_lambda / e_total ;
+          if (factor->print & PRINT_EXTRACTION)
+            put_variance (table, row, phase_idx++, e_lambda, e_percent, e_cum);
 
-          if (factor->print & PRINT_ROTATION)
+          if (rotated_loadings != NULL && factor->print & PRINT_ROTATION)
             {
-              if (i < idata->n_extractions)
-                {
-                  r_cum += r_percent;
-                  tab_double (t, c++, i + heading_rows, 0, r_lambda, NULL, RC_OTHER);
-                 if (factor->rotation != ROT_PROMAX)
-                   {
-                     tab_double (t, c++, i + heading_rows, 0, r_percent, NULL, RC_OTHER);
-                     tab_double (t, c++, i + heading_rows, 0, r_cum, NULL, RC_OTHER);
-                   }
-                }
+              double r_lambda = gsl_vector_get (rotated_loadings, i);
+              double r_percent = 100.0 * r_lambda / e_total ;
+              if (factor->rotation == ROT_PROMAX)
+                r_lambda = r_percent = SYSMIS;
+
+              r_cum += r_percent;
+              put_variance (table, row, phase_idx++, r_lambda, r_percent,
+                            r_cum);
             }
         }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
-
 static void
 show_factor_correlation (const struct cmd_factor * factor, const gsl_matrix *fcm)
 {
-  size_t i, j;
-  const int heading_columns = 1;
-  const int heading_rows = 1;
-  const int nr = heading_rows + fcm->size2;
-  const int nc = heading_columns + fcm->size1;
-  struct tab_table *t = tab_create (nc, nr);
-
-  tab_title (t, _("Factor Correlation Matrix"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-  tab_hline (t, TAL_1, 1, nc - 1, 1);
+  struct pivot_table *table = pivot_table_create (
+    N_("Factor Correlation Matrix"));
 
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  create_numeric_dimension (
+    table, PIVOT_AXIS_ROW,
+    factor->extraction == EXTRACTION_PC ? N_("Component") : N_("Factor"),
+    fcm->size2, true);
 
+  create_numeric_dimension (table, PIVOT_AXIS_COLUMN, N_("Factor 2"),
+                            fcm->size1, false);
 
-  if ( factor->extraction == EXTRACTION_PC)
-    tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Component"));
-  else
-    tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Factor"));
+  for (size_t i = 0 ; i < fcm->size1; ++i)
+    for (size_t j = 0 ; j < fcm->size2; ++j)
+      pivot_table_put2 (table, j, i,
+                        pivot_value_new_number (gsl_matrix_get (fcm, i, j)));
 
-  for (i = 0 ; i < fcm->size1; ++i)
-    {
-      tab_text_format (t, heading_columns + i, 0, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1);
-    }
+  pivot_table_submit (table);
+}
 
-  for (i = 0 ; i < fcm->size2; ++i)
+static void
+add_var_dims (struct pivot_table *table, const struct cmd_factor *factor)
+{
+  for (int i = 0; i < 2; i++)
     {
-      tab_text_format (t, 0, heading_rows + i, TAB_CENTER | TAT_TITLE, _("%zu"), i + 1);
-    }
-
+      struct pivot_dimension *d = pivot_dimension_create (
+        table, i ? PIVOT_AXIS_ROW : PIVOT_AXIS_COLUMN,
+        N_("Variables"));
 
-  for (i = 0 ; i < fcm->size1; ++i)
-    {
-      for (j = 0 ; j < fcm->size2; ++j)
-       tab_double (t, heading_columns + j,  heading_rows + i, 0,
-                   gsl_matrix_get (fcm, i, j), NULL, RC_OTHER);
+      for (size_t j = 0; j < factor->n_vars; j++)
+        pivot_category_create_leaf (
+          d->root, pivot_value_new_variable (factor->vars[j]));
     }
-
-  tab_submit (t);
 }
 
 static void
 show_aic (const struct cmd_factor *factor, const struct idata *idata)
 {
-  struct tab_table *t ;
-  size_t i;
-
-  const int heading_rows = 1;
-  const int heading_columns = 2;
-
-  const int nc = heading_columns + factor->n_vars;
-  const int nr = heading_rows + 2 * factor->n_vars;
-
   if ((factor->print & PRINT_AIC) == 0)
     return;
 
-  t = tab_create (nc, nr);
-
-  tab_title (t, _("Anti-Image Matrices"));
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
+  struct pivot_table *table = pivot_table_create (N_("Anti-Image Matrices"));
 
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
+  add_var_dims (table, factor);
 
-  tab_vline (t, TAL_2, 2, 0, nr - 1);
-
-  /* Outline the box */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          nc - 1, nr - 1);
-
-  /* Vertical lines */
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          nc - 1, nr - 1);
-
-
-  for (i = 0; i < factor->n_vars; ++i)
-    tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i]));
-
-  tab_text (t, 0, heading_rows, TAT_TITLE, _("Anti-image Covariance"));
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows + factor->n_vars);
-  tab_text (t, 0, heading_rows + factor->n_vars, TAT_TITLE, _("Anti-image Correlation"));
-
-  for (i = 0; i < factor->n_vars; ++i)
-    {
-      tab_text (t, 1, i + heading_rows, TAT_TITLE,
-               var_to_string (factor->vars[i]));
-
-      tab_text (t, 1, factor->n_vars + i + heading_rows, TAT_TITLE,
-               var_to_string (factor->vars[i]));
-    }
-
-  for (i = 0; i < factor->n_vars; ++i)
-    {
-      int j;
-      for (j = 0; j < factor->n_vars; ++j)
-       {
-         tab_double (t, heading_columns + i, heading_rows + j, 0,
-                     gsl_matrix_get (idata->ai_cov, i, j), NULL, RC_OTHER);
-       }
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("Anti-image Covariance"),
+                          N_("Anti-image Correlation"));
 
+  for (size_t i = 0; i < factor->n_vars; ++i)
+    for (size_t j = 0; j < factor->n_vars; ++j)
+      {
+        double cov = gsl_matrix_get (idata->ai_cov, i, j);
+        pivot_table_put3 (table, i, j, 0, pivot_value_new_number (cov));
 
-      for (j = 0; j < factor->n_vars; ++j)
-       {
-         tab_double (t, heading_columns + i, factor->n_vars + heading_rows + j, 0,
-                     gsl_matrix_get (idata->ai_cor, i, j), NULL, RC_OTHER);
-       }
-    }
+        double corr = gsl_matrix_get (idata->ai_cor, i, j);
+        pivot_table_put3 (table, i, j, 1, pivot_value_new_number (corr));
+      }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 static void
 show_correlation_matrix (const struct cmd_factor *factor, const struct idata *idata)
 {
-  struct tab_table *t ;
-  size_t i, j;
-  int y_pos_corr = -1;
-  int y_pos_sig = -1;
-  int suffix_rows = 0;
-
-  const int heading_rows = 1;
-  const int heading_columns = 2;
-
-  int nc = heading_columns ;
-  int nr = heading_rows ;
-  int n_data_sets = 0;
-
-  if (factor->print & PRINT_CORRELATION)
-    {
-      y_pos_corr = n_data_sets;
-      n_data_sets++;
-      nc = heading_columns + factor->n_vars;
-    }
-
-  if (factor->print & PRINT_SIG)
-    {
-      y_pos_sig = n_data_sets;
-      n_data_sets++;
-      nc = heading_columns + factor->n_vars;
-    }
-
-  nr += n_data_sets * factor->n_vars;
-
-  if (factor->print & PRINT_DETERMINANT)
-    suffix_rows = 1;
-
-  /* If the table would contain only headings, don't bother rendering it */
-  if (nr <= heading_rows && suffix_rows == 0)
+  if (!(factor->print & (PRINT_CORRELATION | PRINT_SIG | PRINT_DETERMINANT)))
     return;
 
-  t = tab_create (nc, nr + suffix_rows);
-
-  tab_title (t, _("Correlation Matrix"));
+  struct pivot_table *table = pivot_table_create (N_("Correlation Matrix"));
 
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-
-  if (nr > heading_rows)
+  if (factor->print & (PRINT_CORRELATION | PRINT_SIG))
     {
-      tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-      tab_vline (t, TAL_2, 2, 0, nr - 1);
-
-      /* Outline the box */
-      tab_box (t,
-              TAL_2, TAL_2,
-              -1, -1,
-              0, 0,
-              nc - 1, nr - 1);
-
-      /* Vertical lines */
-      tab_box (t,
-              -1, -1,
-              -1, TAL_1,
-              heading_columns, 0,
-              nc - 1, nr - 1);
-
-
-      for (i = 0; i < factor->n_vars; ++i)
-       tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i]));
-
-
-      for (i = 0 ; i < n_data_sets; ++i)
-       {
-         int y = heading_rows + i * factor->n_vars;
-         size_t v;
-         for (v = 0; v < factor->n_vars; ++v)
-           tab_text (t, 1, y + v, TAT_TITLE, var_to_string (factor->vars[v]));
-
-         tab_hline (t, TAL_1, 0, nc - 1, y);
-       }
+      add_var_dims (table, factor);
 
+      struct pivot_dimension *statistics = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Statistics"));
       if (factor->print & PRINT_CORRELATION)
-       {
-         const double y = heading_rows + y_pos_corr;
-         tab_text (t, 0, y, TAT_TITLE, _("Correlations"));
-
-         for (i = 0; i < factor->n_vars; ++i)
-           {
-             for (j = 0; j < factor->n_vars; ++j)
-               tab_double (t, heading_columns + j,  y + i, 0, gsl_matrix_get (idata->mm.corr, i, j), NULL, RC_OTHER);
-           }
-       }
-
+        pivot_category_create_leaves (statistics->root, N_("Correlation"),
+                                      PIVOT_RC_CORRELATION);
       if (factor->print & PRINT_SIG)
-       {
-         const double y = heading_rows + y_pos_sig * factor->n_vars;
-         tab_text (t, 0, y, TAT_TITLE, _("Sig. (1-tailed)"));
-
-         for (i = 0; i < factor->n_vars; ++i)
-           {
-             for (j = 0; j < factor->n_vars; ++j)
-               {
-                 double rho = gsl_matrix_get (idata->mm.corr, i, j);
-                 double w = gsl_matrix_get (idata->mm.n, i, j);
+        pivot_category_create_leaves (statistics->root, N_("Sig. (1-tailed)"),
+                                      PIVOT_RC_SIGNIFICANCE);
 
-                 if (i == j)
-                   continue;
+      int stat_idx = 0;
+      if (factor->print & PRINT_CORRELATION)
+        {
+          for (int i = 0; i < factor->n_vars; ++i)
+            for (int j = 0; j < factor->n_vars; ++j)
+              {
+                double corr = gsl_matrix_get (idata->mm.corr, i, j);
+                pivot_table_put3 (table, j, i, stat_idx,
+                                  pivot_value_new_number (corr));
+              }
+          stat_idx++;
+        }
 
-                 tab_double (t, heading_columns + j,  y + i, 0, significance_of_correlation (rho, w), NULL, RC_PVALUE);
-               }
-           }
-       }
+      if (factor->print & PRINT_SIG)
+        {
+          for (int i = 0; i < factor->n_vars; ++i)
+            for (int j = 0; j < factor->n_vars; ++j)
+              if (i != j)
+                {
+                  double rho = gsl_matrix_get (idata->mm.corr, i, j);
+                  double w = gsl_matrix_get (idata->mm.n, i, j);
+                  double sig = significance_of_correlation (rho, w);
+                  pivot_table_put3 (table, j, i, stat_idx,
+                                    pivot_value_new_number (sig));
+                }
+          stat_idx++;
+        }
     }
 
   if (factor->print & PRINT_DETERMINANT)
-    {
-      tab_text (t, 0, nr, TAB_LEFT | TAT_TITLE, _("Determinant"));
-
-      tab_double (t, 1, nr, 0, idata->detR, NULL, RC_OTHER);
-    }
+    table->caption = pivot_value_new_user_text_nocopy (
+      xasprintf ("%s: %.2f", _("Determinant"), idata->detR));
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 static void
 show_covariance_matrix (const struct cmd_factor *factor, const struct idata *idata)
 {
-  struct tab_table *t ;
-  size_t i, j;
-  int y_pos_corr = -1;
-  int suffix_rows = 0;
-
-  const int heading_rows = 1;
-  const int heading_columns = 1;
-
-  int nc = heading_columns ;
-  int nr = heading_rows ;
-  int n_data_sets = 0;
-
-  if (factor->print & PRINT_COVARIANCE)
-    {
-      y_pos_corr = n_data_sets;
-      n_data_sets++;
-      nc = heading_columns + factor->n_vars;
-    }
-
-  nr += n_data_sets * factor->n_vars;
-
-  /* If the table would contain only headings, don't bother rendering it */
-  if (nr <= heading_rows && suffix_rows == 0)
+  if (!(factor->print & PRINT_COVARIANCE))
     return;
 
-  t = tab_create (nc, nr + suffix_rows);
-
-  tab_title (t, _("Covariance Matrix"));
-
-  tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-
-  if (nr > heading_rows)
-    {
-      tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-      tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  struct pivot_table *table = pivot_table_create (N_("Covariance Matrix"));
+  add_var_dims (table, factor);
 
-      /* Outline the box */
-      tab_box (t,
-              TAL_2, TAL_2,
-              -1, -1,
-              0, 0,
-              nc - 1, nr - 1);
-
-      /* Vertical lines */
-      tab_box (t,
-              -1, -1,
-              -1, TAL_1,
-              heading_columns, 0,
-              nc - 1, nr - 1);
-
-
-      for (i = 0; i < factor->n_vars; ++i)
-       tab_text (t, heading_columns + i, 0, TAT_TITLE, var_to_string (factor->vars[i]));
-
-
-      for (i = 0 ; i < n_data_sets; ++i)
-       {
-         int y = heading_rows + i * factor->n_vars;
-         size_t v;
-         for (v = 0; v < factor->n_vars; ++v)
-           tab_text (t, heading_columns -1, y + v, TAT_TITLE, var_to_string (factor->vars[v]));
-
-         tab_hline (t, TAL_1, 0, nc - 1, y);
-       }
-
-      if (factor->print & PRINT_COVARIANCE)
-       {
-         const double y = heading_rows + y_pos_corr;
-
-         for (i = 0; i < factor->n_vars; ++i)
-           {
-             for (j = 0; j < factor->n_vars; ++j)
-               tab_double (t, heading_columns + j,  y + i, 0, gsl_matrix_get (idata->mm.cov, i, j), NULL, RC_OTHER);
-           }
-       }
-    }
+  for (int i = 0; i < factor->n_vars; ++i)
+    for (int j = 0; j < factor->n_vars; ++j)
+      {
+        double cov = gsl_matrix_get (idata->mm.cov, i, j);
+        pivot_table_put2 (table, j, i, pivot_value_new_number (cov));
+      }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
@@ -2408,116 +2056,73 @@ do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata)
 
   if ( factor->print & PRINT_UNIVARIATE)
     {
-      const struct fmt_spec *wfmt = factor->wv ? var_get_print_format (factor->wv) : & F_8_0;
-      const int nc = 4;
-      int i;
-
-      const int heading_columns = 1;
-      const int heading_rows = 1;
-
-      const int nr = heading_rows + factor->n_vars;
-
-      struct tab_table *t = tab_create (nc, nr);
-      tab_set_format (t, RC_WEIGHT, wfmt);
-      tab_title (t, _("Descriptive Statistics"));
+      struct pivot_table *table = pivot_table_create (
+        N_("Descriptive Statistics"));
+      pivot_table_set_weight_var (table, factor->wv);
 
-      tab_headers (t, heading_columns, 0, heading_rows, 0);
+      pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                              N_("Mean"), PIVOT_RC_OTHER,
+                              N_("Std. Deviation"), PIVOT_RC_OTHER,
+                              N_("Analysis N"), PIVOT_RC_COUNT);
 
-      /* Outline the box */
-      tab_box (t,
-              TAL_2, TAL_2,
-              -1, -1,
-              0, 0,
-              nc - 1, nr - 1);
-
-      /* Vertical lines */
-      tab_box (t,
-              -1, -1,
-              -1, TAL_1,
-              heading_columns, 0,
-              nc - 1, nr - 1);
-
-      tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
-      tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-      tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
-      tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-      tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Analysis N"));
+      struct pivot_dimension *variables = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Variables"));
 
       for (i = 0 ; i < factor->n_vars; ++i)
        {
          const struct variable *v = factor->vars[i];
-         tab_text (t, 0, i + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v));
 
-         tab_double (t, 1, i + heading_rows, 0, gsl_matrix_get (idata->mm.mean_matrix, i, i), NULL, RC_OTHER);
-         tab_double (t, 2, i + heading_rows, 0, sqrt (gsl_matrix_get (idata->mm.var_matrix, i, i)), NULL, RC_OTHER);
-         tab_double (t, 3, i + heading_rows, 0, gsl_matrix_get (idata->mm.n, i, i), NULL, RC_WEIGHT);
+          int row = pivot_category_create_leaf (
+            variables->root, pivot_value_new_variable (v));
+
+          double entries[] = {
+            gsl_matrix_get (idata->mm.mean_matrix, i, i),
+            sqrt (gsl_matrix_get (idata->mm.var_matrix, i, i)),
+            gsl_matrix_get (idata->mm.n, i, i),
+          };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            pivot_table_put2 (table, j, row,
+                              pivot_value_new_number (entries[j]));
        }
 
-      tab_submit (t);
+      pivot_table_submit (table);
     }
 
   if (factor->print & PRINT_KMO)
     {
-      int i;
-      double df = factor->n_vars * (factor->n_vars - 1) / 2;
-
-      double w = 0;
-
-
-      double xsq;
-
-      const int heading_columns = 2;
-      const int heading_rows = 0;
-
-      const int nr = heading_rows + 4;
-      const int nc = heading_columns + 1;
-
-
-
-      struct tab_table *t = tab_create (nc, nr);
-      tab_title (t, _("KMO and Bartlett's Test"));
-
-
-      tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-      /* Outline the box */
-      tab_box (t,
-              TAL_2, TAL_2,
-              -1, -1,
-              0, 0,
-              nc - 1, nr - 1);
-
-      tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-      tab_text (t, 0, 0, TAT_TITLE | TAB_LEFT, _("Kaiser-Meyer-Olkin Measure of Sampling Adequacy"));
-
-      tab_double (t, 2, 0, 0, sum_ssq_r /  (sum_ssq_r + sum_ssq_a), NULL, RC_OTHER);
-
-      tab_text (t, 0, 1, TAT_TITLE | TAB_LEFT, _("Bartlett's Test of Sphericity"));
-
-      tab_text (t, 1, 1, TAT_TITLE, _("Approx. Chi-Square"));
-      tab_text (t, 1, 2, TAT_TITLE, _("df"));
-      tab_text (t, 1, 3, TAT_TITLE, _("Sig."));
-
+      struct pivot_table *table = pivot_table_create (
+        N_("KMO and Bartlett's Test"));
+
+      struct pivot_dimension *statistics = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Statistics"),
+        N_("Kaiser-Meyer-Olkin Measure of Sampling Adequacy"), PIVOT_RC_OTHER);
+      pivot_category_create_group (
+        statistics->root, N_("Bartlett's Test of Sphericity"),
+        N_("Approx. Chi-Square"), PIVOT_RC_OTHER,
+        N_("df"), PIVOT_RC_INTEGER,
+        N_("Sig."), PIVOT_RC_SIGNIFICANCE);
 
       /* The literature doesn't say what to do for the value of W when
         missing values are involved.  The best thing I can think of
         is to take the mean average. */
-      w = 0;
+      double w = 0;
       for (i = 0; i < idata->mm.n->size1; ++i)
        w += gsl_matrix_get (idata->mm.n, i, i);
       w /= idata->mm.n->size1;
 
-      xsq = w - 1 - (2 * factor->n_vars + 5) / 6.0;
-      xsq *= -log (idata->detR);
-
-      tab_double (t, 2, 1, 0, xsq, NULL, RC_OTHER);
-      tab_double (t, 2, 2, 0, df, NULL, RC_INTEGER);
-      tab_double (t, 2, 3, 0, gsl_cdf_chisq_Q (xsq, df), NULL, RC_PVALUE);
-
-
-      tab_submit (t);
+      double xsq = ((w - 1 - (2 * factor->n_vars + 5) / 6.0)
+                    * -log (idata->detR));
+      double df = factor->n_vars * (factor->n_vars - 1) / 2;
+      double entries[] = {
+        sum_ssq_r / (sum_ssq_r + sum_ssq_a),
+        xsq,
+        df,
+        gsl_cdf_chisq_Q (xsq, df)
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put1 (table, i, pivot_value_new_number (entries[i]));
+
+      pivot_table_submit (table);
     }
 
   show_correlation_matrix (factor, idata);
@@ -2640,21 +2245,25 @@ do_factor_by_matrix (const struct cmd_factor *factor, struct idata *idata)
     show_scree (factor, idata);
 
     show_factor_matrix (factor, idata,
-                       factor->extraction == EXTRACTION_PC ? _("Component Matrix") : _("Factor Matrix"),
+                       (factor->extraction == EXTRACTION_PC
+                         ? N_("Component Matrix") : N_("Factor Matrix")),
                        factor_matrix);
 
     if ( factor->rotation == ROT_PROMAX)
       {
-       show_factor_matrix (factor, idata, _("Pattern Matrix"),  pattern_matrix);
+       show_factor_matrix (factor, idata, N_("Pattern Matrix"),
+                            pattern_matrix);
        gsl_matrix_free (pattern_matrix);
       }
 
     if ( factor->rotation != ROT_NONE)
       {
        show_factor_matrix (factor, idata,
-                           (factor->rotation == ROT_PROMAX) ? _("Structure Matrix") :
-                           (factor->extraction == EXTRACTION_PC ? _("Rotated Component Matrix") :
-                            _("Rotated Factor Matrix")),
+                           (factor->rotation == ROT_PROMAX
+                             ? N_("Structure Matrix")
+                             : factor->extraction == EXTRACTION_PC
+                             ? N_("Rotated Component Matrix")
+                            : N_("Rotated Factor Matrix")),
                            rotated_factors);
 
        gsl_matrix_free (rotated_factors);
index ff29b6600abf97d3e94ca24f41ad4d58183c4e0e..8bd6c600205d3fe75dc6a99dd230c2ab9591146b 100644 (file)
@@ -56,7 +56,7 @@
 #include "output/charts/barchart.h"
 #include "output/charts/piechart.h"
 #include "output/charts/plot-hist.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
@@ -211,7 +211,8 @@ struct frq_proc
 
     /* Percentiles to calculate and possibly display. */
     struct percentile *percentiles;
-    int n_percentiles, n_show_percentiles;
+    const struct percentile *median;
+    int n_percentiles;
 
     /* Frequency table display. */
     long int max_categories;         /* Maximum categories to show. */
@@ -236,7 +237,8 @@ struct freq_compare_aux
     bool ascending_value;
   };
 
-static void calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count]);
+static void calc_stats (const struct frq_proc *,
+                        const struct var_freqs *, double d[FRQ_ST_count]);
 
 static void do_piechart(const struct frq_chart *pie,
                        const struct variable *var,
@@ -247,7 +249,6 @@ static void do_barchart(const struct frq_chart *bar,
                        const struct freq_tab *frq_tab);
 
 static void dump_statistics (const struct frq_proc *frq,
-                            const struct var_freqs *vf,
                             const struct variable *wv);
 
 static int
@@ -274,89 +275,74 @@ static struct histogram *
 freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
                   const struct variable *var);
 
+static void
+put_freq_row (struct pivot_table *table, int var_idx,
+              double frequency, double percent,
+              double valid_percent, double cum_percent)
+{
+  double entries[] = { frequency, percent, valid_percent, cum_percent };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    if (entries[i] != SYSMIS)
+      pivot_table_put2 (table, i, var_idx,
+                        pivot_value_new_number (entries[i]));
+}
 
 /* Displays a full frequency table for variable V. */
 static void
 dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
 {
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : &F_8_0;
   const struct freq_tab *ft = &vf->tab;
-  int n_categories;
-  struct freq *f;
-  struct tab_table *t;
-  int r, x;
-  double cum_total = 0.0;
-  double cum_freq = 0.0;
 
-  static const char *headings[] = {
-    N_("Value Label"),
-    N_("Value"),
-    N_("Frequency"),
-    N_("Percent"),
-    N_("Valid Percent"),
-    N_("Cum Percent")
-  };
+  struct pivot_table *table = pivot_table_create__ (pivot_value_new_variable (
+                                                      vf->var));
+  pivot_table_set_weight_var (table, wv);
 
-  n_categories = ft->n_valid + ft->n_missing;
-  t = tab_create (6, n_categories + 2);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 0, 0, 1, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Frequency"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT,
+                          N_("Valid Percent"), PIVOT_RC_PERCENT,
+                          N_("Cumulative Percent"), PIVOT_RC_PERCENT);
 
-  for (x = 0; x < 6; x++)
-    tab_text (t, x, 0, TAB_CENTER | TAT_TITLE, gettext (headings[x]));
+  struct pivot_dimension *variable = pivot_dimension_create__ (
+    table, PIVOT_AXIS_ROW, pivot_value_new_variable (vf->var));
 
-  r = 1;
-  for (f = ft->valid; f < ft->missing; f++)
+  double cum_freq = 0.0;
+  double cum_percent = 0.0;
+  struct pivot_category *valid = NULL;
+  for (const struct freq *f = ft->valid; f < ft->missing; f++)
     {
-      const char *label;
-      double percent, valid_percent;
-
       cum_freq += f->count;
-
-      percent = f->count / ft->total_cases * 100.0;
-      valid_percent = f->count / ft->valid_cases * 100.0;
-      cum_total += valid_percent;
-
-      label = var_lookup_value_label (vf->var, f->values);
-      if (label != NULL)
-        tab_text (t, 0, r, TAB_LEFT, label);
-
-      tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL);
-      tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
-      tab_double (t, 3, r, TAB_NONE, percent, NULL, RC_OTHER);
-      tab_double (t, 4, r, TAB_NONE, valid_percent, NULL, RC_OTHER);
-      tab_double (t, 5, r, TAB_NONE, cum_total, NULL, RC_OTHER);
-      r++;
+      double valid_percent = f->count / ft->valid_cases * 100.0;
+      cum_percent += valid_percent;
+
+      if (!valid)
+        valid = pivot_category_create_group (variable->root, N_("Valid"));
+      int var_idx = pivot_category_create_leaf (
+        valid, pivot_value_new_var_value (vf->var, &f->values[0]));
+      put_freq_row (table, var_idx, f->count,
+                    f->count / ft->total_cases * 100.0,
+                    valid_percent, cum_percent);
     }
-  for (; f < &ft->valid[n_categories]; f++)
-    {
-      const char *label;
 
+  struct pivot_category *missing = NULL;
+  size_t n_categories = ft->n_valid + ft->n_missing;
+  for (const struct freq *f = ft->missing; f < &ft->valid[n_categories]; f++)
+    {
       cum_freq += f->count;
 
-      label = var_lookup_value_label (vf->var, f->values);
-      if (label != NULL)
-        tab_text (t, 0, r, TAB_LEFT, label);
-
-      tab_value (t, 1, r, TAB_NONE, f->values, vf->var, NULL);
-      tab_double (t, 2, r, TAB_NONE, f->count, NULL, RC_WEIGHT);
-      tab_double (t, 3, r, TAB_NONE,
-                 f->count / ft->total_cases * 100.0, NULL, RC_OTHER);
-      tab_text (t, 4, r, TAB_NONE, _("Missing"));
-      r++;
+      if (!missing)
+        missing = pivot_category_create_group (variable->root, N_("Missing"));
+      int var_idx = pivot_category_create_leaf (
+        missing, pivot_value_new_var_value (vf->var, &f->values[0]));
+      put_freq_row (table, var_idx, f->count,
+                    f->count / ft->total_cases * 100.0, SYSMIS, SYSMIS);
     }
 
-  tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, 5, r);
-  tab_hline (t, TAL_2, 0, 5, 1);
-  tab_hline (t, TAL_2, 0, 5, r);
-  tab_joint_text (t, 0, r, 1, r, TAB_RIGHT | TAT_TITLE, _("Total"));
-  tab_vline (t, TAL_0, 1, r, r);
-  tab_double (t, 2, r, TAB_NONE, cum_freq, NULL, RC_WEIGHT);
-  tab_double (t, 3, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER);
-  tab_double (t, 4, r, TAB_NONE, 100.0, &F_5_1, RC_OTHER);
-
-  tab_title (t, "%s", var_to_string (vf->var));
-  tab_submit (t);
+  int var_idx = pivot_category_create_leaf (
+    variable->root, pivot_value_new_text (N_("Total")));
+  put_freq_row (table, var_idx, cum_freq, cum_percent, SYSMIS, SYSMIS);
+
+  pivot_table_submit (table);
 }
 \f
 /* Statistical display. */
@@ -532,25 +518,28 @@ postcalc (struct frq_proc *frq, const struct dataset *ds)
   for (i = 0; i < frq->n_vars; i++)
     {
       struct var_freqs *vf = &frq->vars[i];
-
       postprocess_freq_tab (frq, vf);
+      calc_percentiles (frq, vf);
+    }
+
+  if (frq->n_stats)
+    dump_statistics (frq, wv);
+
+  for (i = 0; i < frq->n_vars; i++)
+    {
+      struct var_freqs *vf = &frq->vars[i];
 
       /* Frequencies tables. */
       if (vf->tab.n_valid + vf->tab.n_missing <= frq->max_categories)
         dump_freq_table (vf, wv);
 
-      calc_percentiles (frq, vf);
-
-      /* Statistics. */
-      if (frq->n_stats)
-       dump_statistics (frq, vf, wv);
 
       if (frq->hist && var_is_numeric (vf->var) && vf->tab.n_valid > 0)
        {
          double d[FRQ_ST_count];
          struct histogram *histogram;
 
-         calc_stats (vf, d);
+         calc_stats (frq, vf, d);
 
          histogram = freq_tab_to_hist (frq, &vf->tab, vf->var);
 
@@ -620,7 +609,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
 
   frq.percentiles = NULL;
   frq.n_percentiles = 0;
-  frq.n_show_percentiles = 0;
 
   frq.hist = NULL;
   frq.pie = NULL;
@@ -782,7 +770,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
                  frq.percentiles[frq.n_percentiles].show = true;
                  lex_get (lexer);
                  frq.n_percentiles++;
-                 frq.n_show_percentiles++;
                }
              else
                {
@@ -860,7 +847,6 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
                  frq.percentiles[frq.n_percentiles].show = true;
 
                  frq.n_percentiles++;
-                 frq.n_show_percentiles++;
                }
            }
          else
@@ -1123,10 +1109,9 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
                    * sizeof (*frq.percentiles));
 
        frq.percentiles[frq.n_percentiles].p = 0.50;
-       frq.percentiles[frq.n_percentiles].show = true;
+       frq.percentiles[frq.n_percentiles].show = false;
 
        frq.n_percentiles++;
-        frq.n_show_percentiles++;
     }
 
 
@@ -1212,27 +1197,31 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
           sizeof (*frq.percentiles),
           ptile_3way);
 
-    frq.n_show_percentiles = 0;
     for (i = o = 0; i < frq.n_percentiles; ++i)
       {
         if (frq.percentiles[i].p != previous_p)
           {
             frq.percentiles[o].p = frq.percentiles[i].p;
             frq.percentiles[o].show = frq.percentiles[i].show;
-            if (frq.percentiles[i].show)
-              frq.n_show_percentiles++;
             o++;
           }
         else if (frq.percentiles[i].show &&
                  !frq.percentiles[o].show)
           {
             frq.percentiles[o].show = true;
-            frq.n_show_percentiles++;
           }
        previous_p = frq.percentiles[i].p;
       }
 
     frq.n_percentiles = o;
+
+    frq.median = NULL;
+    for (i = 0; i < frq.n_percentiles; i++)
+      if (frq.percentiles[i].p == 0.5)
+        {
+          frq.median = &frq.percentiles[i];
+          break;
+        }
   }
 
   {
@@ -1509,7 +1498,8 @@ do_barchart(const struct frq_chart *bar, const struct variable **var,
 /* Calculates all the pertinent statistics for VF, putting them in array
    D[]. */
 static void
-calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
+calc_stats (const struct frq_proc *frq, const struct var_freqs *vf,
+            double d[FRQ_ST_count])
 {
   const struct freq_tab *ft = &vf->tab;
   double W = ft->valid_cases;
@@ -1563,88 +1553,102 @@ calc_stats (const struct var_freqs *vf, double d[FRQ_ST_count])
   d[FRQ_ST_SEMEAN] = d[FRQ_ST_STDDEV] / sqrt (W);
   d[FRQ_ST_SESKEWNESS] = calc_seskew (W);
   d[FRQ_ST_SEKURTOSIS] = calc_sekurt (W);
+  d[FRQ_ST_MEDIAN] = frq->median ? frq->median->value : SYSMIS;
 }
 
-/* Displays a table of all the statistics requested for variable V. */
-static void
-dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
-                 const struct variable *wv)
+static bool
+all_string_variables (const struct frq_proc *frq)
 {
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : &F_8_0;
-  const struct freq_tab *ft = &vf->tab;
-  double stat_value[FRQ_ST_count];
-  struct tab_table *t;
-  int i, r = 2; /* N missing and N valid are always dumped */
-
-  if (var_is_alpha (vf->var))
-    return;
+  for (size_t i = 0; i < frq->n_vars; i++)
+    if (var_is_numeric (frq->vars[i].var))
+      return false;
 
-  calc_stats (vf, stat_value);
-
-  t = tab_create (3, ((frq->stats & BIT_INDEX (FRQ_ST_MEDIAN)) ? frq->n_stats - 1 : frq->n_stats)
-                               + frq->n_show_percentiles + 2);
-
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ;
+  return true;
+}
 
-  tab_vline (t, TAL_1 , 2, 0, tab_nr(t) - 1);
+/* Displays a table of all the statistics requested. */
+static void
+dump_statistics (const struct frq_proc *frq, const struct variable *wv)
+{
+  if (all_string_variables (frq))
+    return;
 
-  for (i = 0; i < FRQ_ST_count; i++)
+  struct pivot_table *table = pivot_table_create (N_("Statistics"));
+  pivot_table_set_weight_var (table, wv);
+
+  struct pivot_dimension *variables
+    = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variables"));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"));
+  struct pivot_category *n = pivot_category_create_group (
+    statistics->root, N_("N"));
+  pivot_category_create_leaves (n,
+                                N_("Valid"), PIVOT_RC_COUNT,
+                                N_("Missing"), PIVOT_RC_COUNT);
+  for (int i = 0; i < FRQ_ST_count; i++)
+    if (frq->stats & BIT_INDEX (i))
+      pivot_category_create_leaf (statistics->root,
+                                  pivot_value_new_text (st_name[i]));
+  struct pivot_category *percentiles = NULL;
+  for (size_t i = 0; i < frq->n_percentiles; i++)
     {
-      if (FRQ_ST_MEDIAN == i)
-       continue;
-
-      if (frq->stats & BIT_INDEX (i))
-      {
-       tab_text (t, 0, r, TAB_LEFT | TAT_TITLE,
-                     gettext (st_name[i]));
-
-       if (vf->tab.n_valid <= 0 && r >= 2)
-         tab_text (t, 2, r, 0,   ".");
-       else
-         tab_double (t, 2, r, TAB_NONE, stat_value[i], NULL, RC_OTHER);
-       r++;
-      }
-    }
+      const struct percentile *pc = &frq->percentiles[i];
 
-  tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("N"));
-  tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Valid"));
-  tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Missing"));
+      if (!pc->show)
+        continue;
 
-  tab_double (t, 2, 0, TAB_NONE, ft->valid_cases, NULL, RC_WEIGHT);
-  tab_double (t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, NULL, RC_WEIGHT);
+      if (!percentiles)
+        percentiles = pivot_category_create_group (
+          statistics->root, N_("Percentiles"));
+      pivot_category_create_leaf (percentiles, pivot_value_new_integer (
+                                    pc->p * 100.0));
+    }
 
-  for (i = 0; i < frq->n_percentiles; i++)
+  for (size_t i = 0; i < frq->n_vars; i++)
     {
-      const struct percentile *pc = &frq->percentiles[i];
-
-      if (!pc->show)
+      struct var_freqs *vf = &frq->vars[i];
+      if (var_is_alpha (vf->var))
         continue;
 
-      if ( i == 0 )
-       {
-         tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Percentiles"));
-       }
+      const struct freq_tab *ft = &vf->tab;
 
-      if (vf->tab.n_valid <= 0)
-       {
-         tab_text (t, 2, r, 0,   ".");
-         ++r;
-         continue;
-       }
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (vf->var));
 
-      if (pc->p == 0.5)
-        tab_text (t, 1, r, TAB_LEFT, _("50 (Median)"));
-      else
-        tab_double (t, 1, r, TAB_LEFT, pc->p * 100, NULL, RC_INTEGER);
-      tab_double (t, 2, r, TAB_NONE, pc->value,
-                  var_get_print_format (vf->var), RC_OTHER);
+      int row = 0;
+      pivot_table_put2 (table, var_idx, row++,
+                        pivot_value_new_number (ft->valid_cases));
+      pivot_table_put2 (table, var_idx, row++,
+                        pivot_value_new_number (
+                          ft->total_cases - ft->valid_cases));
 
-      ++r;
-    }
+      double stat_values[FRQ_ST_count];
+      calc_stats (frq, vf, stat_values);
+      for (int j = 0; j < FRQ_ST_count; j++)
+        {
+          if (!(frq->stats & BIT_INDEX (j)))
+            continue;
+
+          union value v = { .f = vf->tab.n_valid ? stat_values[j] : SYSMIS };
+          struct pivot_value *pv
+            = (j == FRQ_ST_MODE || j == FRQ_ST_MINIMUM || j == FRQ_ST_MAXIMUM
+               ? pivot_value_new_var_value (vf->var, &v)
+               : pivot_value_new_number (v.f));
+          pivot_table_put2 (table, var_idx, row++, pv);
+        }
+
+      for (size_t j = 0; j < frq->n_percentiles; j++)
+        {
+          const struct percentile *pc = &frq->percentiles[j];
+          if (!pc->show)
+            continue;
 
-  tab_title (t, "%s", var_to_string (vf->var));
+          union value v = { .f = vf->tab.n_valid ? pc->value : SYSMIS };
+          pivot_table_put2 (table, var_idx, row++,
+                            pivot_value_new_var_value (vf->var, &v));
+        }
+    }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
-
index cf03c83c12d22065467ce2a38c41fc3212793749..9ea3cbc516aec69bfd91b4cba019e0859afa13f6 100644 (file)
 #include "data/variable.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -216,40 +217,24 @@ friedman_execute (const struct dataset *ds,
 static void
 show_ranks_box (const struct one_sample_test *ost, const struct friedman *fr)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 1;
-  struct tab_table *table =
-    tab_create (row_headers + 1, column_headers + ost->n_vars);
+  struct pivot_table *table = pivot_table_create (N_("Ranks"));
 
-  tab_headers (table, row_headers, 0, column_headers, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Mean Rank"),
+                          N_("Mean Rank"), PIVOT_RC_OTHER);
 
-  tab_title (table, _("Ranks"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
 
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-
-  tab_text (table, 1, 0, 0, _("Mean Rank"));
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  for (i = 0 ; i < ost->n_vars ; ++i)
+  for (size_t i = 0 ; i < ost->n_vars ; ++i)
     {
-      tab_text (table, 0, row_headers + i,
-               TAB_LEFT, var_to_string (ost->vars[i]));
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (ost->vars[i]));
 
-      tab_double (table, 1, row_headers + i,
-                 0, fr->rank_sum[i] / fr->cc, NULL, RC_OTHER);
+      pivot_table_put2 (table, 0, row,
+                        pivot_value_new_number (fr->rank_sum[i] / fr->cc));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
 
@@ -258,60 +243,33 @@ show_sig_box (const struct one_sample_test *ost, const struct friedman *fr)
 {
   const struct friedman_test *ft = UP_CAST (ost, const struct friedman_test, parent);
 
-  int row = 0;
-  const struct fmt_spec *wfmt = dict_get_weight_format (fr->dict);
-
-  const int row_headers = 1;
-  const int column_headers = 0;
-  struct tab_table *table =
-    tab_create (row_headers + 1, column_headers + (ft->kendalls_w ? 5 : 4));
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Test Statistics"));
-
-  tab_text (table,  0, column_headers + row++,
-           TAT_TITLE | TAB_LEFT , _("N"));
-
-  if ( ft->kendalls_w)
-    tab_text (table,  0, column_headers + row++,
-             TAT_TITLE | TAB_LEFT , _("Kendall's W"));
-
-  tab_text (table,  0, column_headers + row++,
-           TAT_TITLE | TAB_LEFT , _("Chi-Square"));
-
-  tab_text (table,  0, column_headers + row++,
-           TAT_TITLE | TAB_LEFT, _("df"));
-
-  tab_text (table,  0, column_headers + row++,
-           TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  row = 0;
-  tab_double (table, 1, column_headers + row++,
-             0, fr->cc, NULL, RC_WEIGHT);
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
+  pivot_table_set_weight_var (table, dict_get_weight (fr->dict));
 
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("N"), PIVOT_RC_COUNT);
   if (ft->kendalls_w)
-    tab_double (table, 1, column_headers + row++,
-               0, fr->w, NULL, RC_OTHER);
+    pivot_category_create_leaves (statistics->root, N_("Kendall's W"),
+                                  PIVOT_RC_OTHER);
+  pivot_category_create_leaves (statistics->root,
+                                N_("Chi-Square"), PIVOT_RC_OTHER,
+                                N_("df"), PIVOT_RC_INTEGER,
+                                N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_double (table, 1, column_headers + row++,
-             0, fr->chi_sq, NULL, RC_OTHER);
+  double entries[5];
+  int n = 0;
 
-  tab_double (table, 1, column_headers + row++,
-             0, ost->n_vars - 1, NULL, RC_INTEGER);
+  entries[n++] = fr->cc;
+  if (ft->kendalls_w)
+    entries[n++] = fr->w;
+  entries[n++] = fr->chi_sq;
+  entries[n++] = ost->n_vars - 1;
+  entries[n++] = gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1);
+  assert (n <= sizeof entries / sizeof *entries);
 
-  tab_double (table, 1, column_headers + row++,
-             0, gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1),
-             NULL, RC_PVALUE);
+  for (size_t i = 0; i < n; i++)
+    pivot_table_put1 (table, i, pivot_value_new_number (entries[i]));
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index 5c46b1843706722c908b0f2e5b4aa91ced0031f4..c8a3dd36e15f714b0f0b76b9d390b88396647d39 100644 (file)
 #include "math/covariance.h"
 #include "math/interaction.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 struct glm_spec
@@ -651,16 +652,14 @@ run_glm (struct glm_spec *cmd, struct casereader *input,
 
   if (cmd->dump_coding)
     {
-      struct tab_table *t =
-       covariance_dump_enc_header (cov,
-                                   1 + casereader_count_cases (input));
+      struct pivot_table *t = covariance_dump_enc_header (cov);
       for (reader = input;
           (c = casereader_read (reader)) != NULL; case_unref (c))
        {
          covariance_dump_enc (cov, c, t);
        }
-      casereader_destroy (reader);
-      tab_submit (t);
+
+      pivot_table_submit (t);
     }
 
   {
@@ -709,174 +708,120 @@ run_glm (struct glm_spec *cmd, struct casereader *input,
   taint_destroy (taint);
 }
 
-static const char *roman[] =
-  {
-    "", /* The Romans had no concept of zero */
-    "I",
-    "II",
-    "III",
-    "IV"
-  };
+static void
+put_glm_row (struct pivot_table *table, int row,
+             double a, double b, double c, double d, double e)
+{
+  double entries[] = { a, b, c, d, e };
+
+  for (size_t col = 0; col < sizeof entries / sizeof *entries; col++)
+    if (entries[col] != SYSMIS)
+      pivot_table_put2 (table, col, row,
+                        pivot_value_new_number (entries[col]));
+}
 
 static void
 output_glm (const struct glm_spec *cmd, const struct glm_workspace *ws)
 {
-  const struct fmt_spec *wfmt =
-    cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
+  struct pivot_table *table = pivot_table_create (
+    N_("Tests of Between-Subjects Effects"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          (cmd->ss_type == 1 ? N_("Type I Sum Of Squares")
+                           : cmd->ss_type == 2 ? N_("Type II Sum Of Squares")
+                           : N_("Type III Sum Of Squares")), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_COUNT,
+                          N_("Mean Square"), PIVOT_RC_OTHER,
+                          N_("F"), PIVOT_RC_OTHER,
+                          N_("Sig."), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *source = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Source"),
+    cmd->intercept ? N_("Corrected Model") : N_("Model"));
 
-  double intercept_ssq;
-  double ssq_effects;
   double n_total, mean;
-  double df_corr = 1.0;
-  double mse = 0;
-
-  int f;
-  int r;
-  const int heading_columns = 1;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  const int nc = 6;
-  int nr = heading_rows + 3 + cmd->n_interactions;
-  if (cmd->intercept)
-    nr += 2;
-
-  t = tab_create (nc, nr);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_title (t, _("Tests of Between-Subjects Effects"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source"));
-
-  /* TRANSLATORS: The parameter is a roman numeral */
-  tab_text_format (t, 1, 0, TAB_CENTER | TAT_TITLE,
-                  _("Type %s Sum of Squares"),
-                  roman[cmd->ss_type]);
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean Square"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("F"));
-  tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
-
   moments_calculate (ws->totals, &n_total, &mean, NULL, NULL, NULL);
 
-  df_corr += categoricals_df_total (ws->cats);
+  double df_corr = 1.0 + categoricals_df_total (ws->cats);
 
-  r = heading_rows;
-  if (cmd->intercept)
-    tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Corrected Model"));
-  else
-    tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Model"));
-
-  r++;
-
-  mse = gsl_vector_get (ws->ssq, 0) / (n_total - df_corr);
-
-  intercept_ssq = pow2 (mean * n_total) / n_total;
-
-  ssq_effects = 0.0;
+  double mse = gsl_vector_get (ws->ssq, 0) / (n_total - df_corr);
+  double intercept_ssq = pow2 (mean * n_total) / n_total;
   if (cmd->intercept)
     {
-      const double df = 1.0;
-      const double F = intercept_ssq / df / mse;
-      tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Intercept"));
+      int row = pivot_category_create_leaf (
+        source->root, pivot_value_new_text (N_("Intercept")));
+
       /* The intercept for unbalanced models is of limited use and
         nobody knows how to calculate it properly */
       if (categoricals_isbalanced (ws->cats))
-       {
-         tab_double (t, 1, r, 0, intercept_ssq, NULL, RC_OTHER);
-         tab_double (t, 2, r, 0, 1.00, NULL, RC_WEIGHT);
-         tab_double (t, 3, r, 0, intercept_ssq / df, NULL, RC_OTHER);
-         tab_double (t, 4, r, 0, F, NULL, RC_OTHER);
-         tab_double (t, 5, r, 0, gsl_cdf_fdist_Q (F, df, n_total - df_corr),
-                     NULL, RC_PVALUE);
-       }
-      r++;
+        {
+          const double df = 1.0;
+          const double F = intercept_ssq / df / mse;
+          put_glm_row (table, row, intercept_ssq, 1.0, intercept_ssq / df,
+                       F, gsl_cdf_fdist_Q (F, df, n_total - df_corr));
+        }
     }
 
-  for (f = 0; f < cmd->n_interactions; ++f)
+  double ssq_effects = 0.0;
+  for (int f = 0; f < cmd->n_interactions; ++f)
     {
-      struct string str = DS_EMPTY_INITIALIZER;
       double df = categoricals_df (ws->cats, f);
-
       double ssq = gsl_vector_get (ws->ssq, f + 1);
-      double F;
-
       ssq_effects += ssq;
-
-      if (! cmd->intercept)
+      if (!cmd->intercept)
        {
          df++;
          ssq += intercept_ssq;
        }
+      double F = ssq / df / mse;
 
-      F = ssq / df / mse;
+      struct string str = DS_EMPTY_INITIALIZER;
       interaction_to_string (cmd->interactions[f], &str);
-      tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, ds_cstr (&str));
-      ds_destroy (&str);
-
-      tab_double (t, 1, r, 0, ssq, NULL, RC_OTHER);
-      tab_double (t, 2, r, 0, df, NULL, RC_WEIGHT);
-      tab_double (t, 3, r, 0, ssq / df, NULL, RC_OTHER);
-      tab_double (t, 4, r, 0, F, NULL, RC_OTHER);
+      int row = pivot_category_create_leaf (
+        source->root, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
 
-      tab_double (t, 5, r, 0, gsl_cdf_fdist_Q (F, df, n_total - df_corr),
-                 NULL, RC_PVALUE);
-      r++;
+      put_glm_row (table, row, ssq, df, ssq / df, F,
+                   gsl_cdf_fdist_Q (F, df, n_total - df_corr));
     }
 
   {
     /* Model / Corrected Model */
     double df = df_corr;
     double ssq = ws->total_ssq - gsl_vector_get (ws->ssq, 0);
-    double F;
-
-    if ( cmd->intercept )
-      df --;
+    if (cmd->intercept)
+      df--;
     else
       ssq += intercept_ssq;
-
-    F = ssq / df / mse;
-    tab_double (t, 1, heading_rows, 0, ssq, NULL, RC_OTHER);
-    tab_double (t, 2, heading_rows, 0, df, NULL, RC_WEIGHT);
-    tab_double (t, 3, heading_rows, 0, ssq / df, NULL, RC_OTHER);
-    tab_double (t, 4, heading_rows, 0, F, NULL, RC_OTHER);
-
-    tab_double (t, 5, heading_rows, 0,
-               gsl_cdf_fdist_Q (F, df, n_total - df_corr), NULL, RC_PVALUE);
+    double F = ssq / df / mse;
+    put_glm_row (table, 0, ssq, df, ssq / df, F,
+                 gsl_cdf_fdist_Q (F, df, n_total - df_corr));
   }
 
   {
+    int row = pivot_category_create_leaf (source->root,
+                                          pivot_value_new_text (N_("Error")));
     const double df = n_total - df_corr;
     const double ssq = gsl_vector_get (ws->ssq, 0);
     const double mse = ssq / df;
-    tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Error"));
-    tab_double (t, 1, r, 0, ssq, NULL, RC_OTHER);
-    tab_double (t, 2, r, 0, df, NULL, RC_WEIGHT);
-    tab_double (t, 3, r++, 0, mse, NULL, RC_OTHER);
+    put_glm_row (table, row, ssq, df, mse, SYSMIS, SYSMIS);
   }
 
   {
-    tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Total"));
-    tab_double (t, 1, r, 0, ws->total_ssq + intercept_ssq, NULL, RC_OTHER);
-    tab_double (t, 2, r, 0, n_total, NULL, RC_WEIGHT);
-
-    r++;
+    int row = pivot_category_create_leaf (source->root,
+                                          pivot_value_new_text (N_("Total")));
+    put_glm_row (table, row, ws->total_ssq + intercept_ssq, n_total,
+                 SYSMIS, SYSMIS, SYSMIS);
   }
 
   if (cmd->intercept)
     {
-      tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, _("Corrected Total"));
-      tab_double (t, 1, r, 0, ws->total_ssq, NULL, RC_OTHER);
-      tab_double (t, 2, r, 0, n_total - 1.0, NULL, RC_WEIGHT);
+      int row = pivot_category_create_leaf (
+        source->root, pivot_value_new_text (N_("Corrected Total")));
+      put_glm_row (table, row, ws->total_ssq, n_total - 1.0, SYSMIS,
+                   SYSMIS, SYSMIS);
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 #if 0
index 578efc1e756feec5755582798b380e792813c05b..cc927bd10c8bb7ddd3914d89a54d363fbdbaadad 100644 (file)
@@ -58,8 +58,6 @@
 #include "language/stats/freq.h"
 #include "language/stats/chart-category.h"
 
-#include "output/tab.h"
-
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
index d7af2b070ee4912da641c69b0eb16d9ca7f6120b..7e8406f38253e3a2b687d4625886313f57e03128 100644 (file)
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "math/sort.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
 
+#include "gettext.h"
+#define N_(msgid) msgid
+#define _(msgid) gettext (msgid)
+
+
 /* Returns true iff the independent variable lies in the
    between val1 and val2. Regardless of which is the greater value.
 */
@@ -216,7 +221,8 @@ struct jt
   double stddev;
 };
 
-static void show_jt (const struct n_sample_test *nst, const struct jt *jt, const struct variable *wv);
+static void show_jt (const struct n_sample_test *, const struct jt *,
+                     const struct fmt_spec *wfmt);
 
 
 void
@@ -336,85 +342,61 @@ jonckheere_terpstra_execute (const struct dataset *ds,
 
     jt.mean = (pow2 (jt.n) - ccsq_sum) / 4.0;
 
-    show_jt (nst, &jt, dict_get_weight (dict));
+    show_jt (nst, &jt, dict_get_weight_format (dict));
   }
 
   casereader_destroy (input);
   caseproto_unref (proto);
 }
-
 \f
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
 static void
-show_jt (const struct n_sample_test *nst, const struct jt *jt, const struct variable *wv)
+show_jt (const struct n_sample_test *nst, const struct jt *jt,
+         const struct fmt_spec *wfmt)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 1;
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
-
-  struct tab_table *table =
-    tab_create (row_headers + 7, column_headers + nst->n_vars);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Jonckheere-Terpstra Test"));
-
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  tab_text_format (table, 1, 0, TAT_TITLE | TAB_CENTER,
-                   _("Number of levels in %s"),
-                   var_to_string (nst->indep_var));
-  tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, _("N"));
-  tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, _("Observed J-T Statistic"));
-  tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, _("Mean J-T Statistic"));
-  tab_text (table, 5, 0, TAT_TITLE | TAB_CENTER, _("Std. Deviation of J-T Statistic"));
-  tab_text (table, 6, 0, TAT_TITLE | TAB_CENTER, _("Std. J-T Statistic"));
-  tab_text (table, 7, 0, TAT_TITLE | TAB_CENTER, _("Asymp. Sig. (2-tailed)"));
-
-
-  for (i = 0; i < nst->n_vars; ++i)
+  struct pivot_table *table = pivot_table_create (
+    N_("Jonckheere-Terpstra Test"));
+  pivot_table_set_weight_format (table, wfmt);
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  pivot_category_create_leaf_rc (
+    statistics->root,
+    pivot_value_new_text_format (N_("Number of levels in %s"),
+                                 var_to_string (nst->indep_var)),
+    PIVOT_RC_INTEGER);
+  pivot_category_create_leaves (
+    statistics->root,
+    N_("N"), PIVOT_RC_COUNT,
+    N_("Observed J-T Statistic"), PIVOT_RC_OTHER,
+    N_("Mean J-T Statistic"), PIVOT_RC_OTHER,
+    N_("Std. Deviation of J-T Statistic"), PIVOT_RC_OTHER,
+    N_("Std. J-T Statistic"), PIVOT_RC_OTHER,
+    N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+
+  for (size_t i = 0; i < nst->n_vars; ++i)
     {
-      double std_jt;
-
-      tab_text (table, 0, i + row_headers, TAT_TITLE,
-                var_to_string (nst->vars[i]) );
-
-      tab_double (table, 1, i + row_headers, TAT_TITLE,
-                  jt[0].levels, NULL, RC_INTEGER);
-
-      tab_double (table, 2, i + row_headers, TAT_TITLE,
-                  jt[0].n, NULL, RC_WEIGHT);
-
-      tab_double (table, 3, i + row_headers, TAT_TITLE,
-                  jt[0].obs, NULL, RC_OTHER);
-
-      tab_double (table, 4, i + row_headers, TAT_TITLE,
-                  jt[0].mean, NULL, RC_OTHER);
-
-      tab_double (table, 5, i + row_headers, TAT_TITLE,
-                  jt[0].stddev, NULL, RC_OTHER);
-
-      std_jt = (jt[0].obs - jt[0].mean) / jt[0].stddev;
-      tab_double (table, 6, i + row_headers, TAT_TITLE,
-                  std_jt, NULL, RC_OTHER);
-
-      tab_double (table, 7, i + row_headers, TAT_TITLE,
-                  2.0 * ((std_jt > 0) ? gsl_cdf_ugaussian_Q (std_jt) : gsl_cdf_ugaussian_P (std_jt)), NULL, RC_PVALUE);
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (nst->vars[i]));
+
+      double std_jt = (jt[0].obs - jt[0].mean) / jt[0].stddev;
+      double sig = (2.0 * (std_jt > 0
+                           ? gsl_cdf_ugaussian_Q (std_jt)
+                           : gsl_cdf_ugaussian_P (std_jt)));
+      double entries[] = {
+        jt[0].levels,
+        jt[0].n,
+        jt[0].obs,
+        jt[0].mean,
+        jt[0].stddev,
+        std_jt,
+        sig,
+      };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, row, pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index 24c369a93b7fd69051adff5967ef9418f2bbe954..ae6fffe205118decea725ed1badc9f6e17be7034 100644 (file)
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "math/sort.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
 
+#include "gettext.h"
+#define N_(msgid) msgid
+#define _(msgid) gettext (msgid)
 
 /* Returns true iff the independent variable lies in the range [nst->val1, nst->val2] */
 static bool
@@ -113,8 +116,8 @@ struct kw
   double h;
 };
 
-static void show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_groups);
-static void show_sig_box (const struct n_sample_test *nst, const struct kw *kw);
+static void show_ranks_box (const struct n_sample_test *, const struct kw *);
+static void show_sig_box (const struct n_sample_test *, const struct kw *);
 
 void
 kruskal_wallis_execute (const struct dataset *ds,
@@ -220,7 +223,7 @@ kruskal_wallis_execute (const struct dataset *ds,
 
   casereader_destroy (input);
 
-  show_ranks_box (nst, kw, total_n_groups);
+  show_ranks_box (nst, kw);
   show_sig_box (nst, kw);
 
   /* Cleanup allocated memory */
@@ -237,140 +240,79 @@ kruskal_wallis_execute (const struct dataset *ds,
 
   free (kw);
 }
-
 \f
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-
 static void
-show_ranks_box (const struct n_sample_test *nst, const struct kw *kw, int n_groups)
+show_ranks_box (const struct n_sample_test *nst, const struct kw *kw)
 {
-  int row;
-  int i;
-  const int row_headers = 2;
-  const int column_headers = 1;
-  struct tab_table *table =
-    tab_create (row_headers + 2, column_headers + n_groups + nst->n_vars);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
+  struct pivot_table *table = pivot_table_create (N_("Ranks"));
 
-  tab_title (table, _("Ranks"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_INTEGER,
+                          N_("Mean Rank"), PIVOT_RC_OTHER);
 
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_text (table, 1, 0, TAT_TITLE,
-           var_to_string (nst->indep_var)
-           );
-
-  tab_text (table, 3, 0, 0, _("Mean Rank"));
-  tab_text (table, 2, 0, 0, _("N"));
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-
-  row = column_headers;
-  for (i = 0 ; i < nst->n_vars ; ++i)
+  for (size_t i = 0 ; i < nst->n_vars ; ++i)
     {
-      int tot = 0;
-      struct rank_entry *re_x;
-      struct bt bt;
-
-      if (i > 0)
-       tab_hline (table, TAL_1, 0, tab_nc (table) -1, row);
-
-      tab_text (table,  0, row,
-               TAT_TITLE, var_to_string (nst->vars[i]));
-
       /* Sort the rank entries, by iteratin the hash and putting the entries
          into a binary tree. */
-      bt_init (&bt, compare_rank_entries_3way, nst->vars[i]);
+      struct bt bt = BT_INITIALIZER(compare_rank_entries_3way, nst->vars[i]);
+      struct rank_entry *re_x;
       HMAP_FOR_EACH (re_x, struct rank_entry, node, &kw[i].map)
-       {
-          bt_insert (&bt, &re_x->btn);
-        }
+        bt_insert (&bt, &re_x->btn);
 
       /* Report the rank entries in sorted order. */
+      struct pivot_category *group = pivot_category_create_group__ (
+        variables->root, pivot_value_new_variable (nst->vars[i]));
+      int tot = 0;
       const struct rank_entry *re;
       BT_FOR_EACH (re, struct rank_entry, btn, &bt)
         {
-         struct string str;
-         ds_init_empty (&str);
-
+         struct string str = DS_EMPTY_INITIALIZER;
          var_append_value_name (nst->indep_var, &re->group, &str);
+          int row = pivot_category_create_leaf (
+            group, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
 
-         tab_text   (table, 1, row, TAB_LEFT, ds_cstr (&str));
-         tab_double (table, 2, row, TAB_LEFT, re->n, NULL, RC_INTEGER);
-         tab_double (table, 3, row, TAB_LEFT, re->sum_of_ranks / re->n, NULL, RC_OTHER);
+          double entries[] = { re->n, re->sum_of_ranks / re->n };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            pivot_table_put2 (table, j, row,
+                              pivot_value_new_number (entries[j]));
 
          tot += re->n;
-         row++;
-         ds_destroy (&str);
        }
 
-      tab_double (table, 2, row, TAB_LEFT,
-                 tot, NULL, RC_INTEGER);
-      tab_text (table, 1, row++, TAB_LEFT, _("Total"));
+      int row = pivot_category_create_leaves (group, N_("Total"));
+      pivot_table_put2 (table, 0, row, pivot_value_new_number (tot));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
-
 static void
 show_sig_box (const struct n_sample_test *nst, const struct kw *kw)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 1;
-  struct tab_table *table =
-    tab_create (row_headers + nst->n_vars * 2, column_headers + 3);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Test Statistics"));
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
 
-  tab_text (table,  0, column_headers,
-           TAT_TITLE | TAB_LEFT , _("Chi-Square"));
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("Chi-Square"), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_INTEGER,
+                          N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_text (table,  0, 1 + column_headers,
-           TAT_TITLE | TAB_LEFT, _("df"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Variables"));
 
-  tab_text (table,  0, 2 + column_headers,
-           TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  for (i = 0 ; i < nst->n_vars; ++i)
+  for (size_t i = 0 ; i < nst->n_vars; ++i)
     {
-      const double df = hmap_count (&kw[i].map) - 1;
-      tab_text (table, column_headers + 1 + i, 0, TAT_TITLE,
-               var_to_string (nst->vars[i])
-               );
-
-      tab_double (table, column_headers + 1 + i, 1, 0,
-                 kw[i].h, NULL, RC_OTHER);
-
-      tab_double (table, column_headers + 1 + i, 2, 0,
-                 df, NULL, RC_INTEGER);
-
-      tab_double (table, column_headers + 1 + i, 3, 0,
-                 gsl_cdf_chisq_Q (kw[i].h, df),
-                 NULL, RC_PVALUE);
+      int col = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (nst->vars[i]));
+
+      double df = hmap_count (&kw[i].map) - 1;
+      double sig = gsl_cdf_chisq_Q (kw[i].h, df);
+      double entries[] = { kw[i].h, df, sig };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, col, pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index 7e2e5bb6312cb1e6a9787682ad3245619c72a605..89559b798fe5dcc32843cd0980027693cff8771b 100644 (file)
 #include "libpspp/hash-functions.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -269,133 +270,96 @@ show_results (const struct ks *ks,
              const struct ks_one_sample_test *kst,
              const struct fmt_spec *wfmt)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 2;
-  const int nc = kst->parent.n_vars + column_headers;
-  const int nr = 8 + row_headers;
-  struct tab_table *table = tab_create (nc, nr);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-  tab_headers (table, row_headers, 0, column_headers, 0);
+  struct pivot_table *table = pivot_table_create (
+    N_("One-Sample Kolmogorov-Smirnov Test"));
+  pivot_table_set_weight_format (table, wfmt);
 
-  tab_title (table, _("One-Sample Kolmogorov-Smirnov Test"));
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, nc - 1, nr - 1 );
-
-  tab_hline (table, TAL_2, 0, nc - 1, row_headers);
-
-  tab_vline (table, TAL_1, column_headers, 0, nr - 1);
-
-  tab_text (table,  0, 1,
-           TAT_TITLE | TAB_LEFT , _("N"));
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("N"), PIVOT_RC_COUNT);
 
   switch (kst->dist)
     {
-    case KS_NORMAL:
-      tab_text (table,  0, 2,
-               TAT_TITLE | TAB_LEFT , _("Normal Parameters"));
-
-      tab_text (table,  1, 2,
-               TAT_TITLE | TAB_LEFT , _("Mean"));
-      tab_text (table,  1, 3,
-               TAT_TITLE | TAB_LEFT , _("Std. Deviation"));
-      break;
     case KS_UNIFORM:
-      tab_text (table,  0, 2,
-               TAT_TITLE | TAB_LEFT , _("Uniform Parameters"));
+      pivot_category_create_group (statistics->root, N_("Uniform Parameters"),
+                                   N_("Minimum"), N_("Maximum"));
+      break;
 
-      tab_text (table,  1, 2,
-               TAT_TITLE | TAB_LEFT , _("Minimum"));
-      tab_text (table,  1, 3,
-               TAT_TITLE | TAB_LEFT , _("Maximum"));
+    case KS_NORMAL:
+      pivot_category_create_group (statistics->root, N_("Normal Parameters"),
+                                   N_("Mean"), N_("Std. Deviation"));
       break;
-    case KS_POISSON:
-      tab_text (table,  0, 2,
-               TAT_TITLE | TAB_LEFT , _("Poisson Parameters"));
 
-      tab_text (table,  1, 2,
-               TAT_TITLE | TAB_LEFT , _("Lambda"));
+    case KS_POISSON:
+      pivot_category_create_group (statistics->root, N_("Poisson Parameters"),
+                                   N_("Lambda"));
       break;
-    case KS_EXPONENTIAL:
-      tab_text (table,  0, 2,
-               TAT_TITLE | TAB_LEFT , _("Exponential Parameters"));
 
-      tab_text (table,  1, 2,
-               TAT_TITLE | TAB_LEFT , _("Scale"));
+    case KS_EXPONENTIAL:
+      pivot_category_create_group (statistics->root,
+                                   N_("Exponential Parameters"), N_("Scale"));
       break;
 
     default:
       NOT_REACHED ();
     }
 
-  /* The variable columns */
-  for (i = 0; i < kst->parent.n_vars; ++i)
+  pivot_category_create_group (
+    statistics->root, N_("Most Extreme Differences"),
+    N_("Absolute"), N_("Positive"), N_("Negative"));
+
+  pivot_category_create_leaves (
+    statistics->root, N_("Kolmogorov-Smirnov Z"),
+    _("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Variables"));
+
+  for (size_t i = 0; i < kst->parent.n_vars; ++i)
     {
-      double abs = 0;
-      double z = 0;
-      const int col = 2 + i;
-      tab_text (table, col, 0,
-               TAT_TITLE | TAB_CENTER ,
-               var_to_string (kst->parent.vars[i]));
+      int col = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (kst->parent.vars[i]));
+
+      double values[10];
+      size_t n = 0;
+
+      values[n++] = ks[i].obs_cc;
 
       switch (kst->dist)
        {
        case KS_UNIFORM:
-         tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT);
-         tab_double (table, col, 2, 0, ks[i].test_min, NULL, RC_OTHER);
-         tab_double (table, col, 3, 0, ks[i].test_max, NULL, RC_OTHER);
+          values[n++] = ks[i].test_min;
+          values[n++] = ks[i].test_max;
          break;
 
        case KS_NORMAL:
-         tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT);
-         tab_double (table, col, 2, 0, ks[i].mu, NULL, RC_OTHER);
-         tab_double (table, col, 3, 0, ks[i].sigma, NULL, RC_OTHER);
+          values[n++] = ks[i].mu;
+          values[n++] = ks[i].sigma;
          break;
 
        case KS_POISSON:
        case KS_EXPONENTIAL:
-         tab_double (table, col, 1, 0, ks[i].obs_cc, NULL, RC_WEIGHT);
-         tab_double (table, col, 2, 0, ks[i].mu, NULL, RC_OTHER);
+          values[n++] = ks[i].mu;
          break;
 
        default:
          NOT_REACHED ();
        }
 
-      abs = ks[i].diff_pos;
+      double abs = ks[i].diff_pos;
       maximize (&abs, -ks[i].diff_neg);
 
-      z = sqrt (ks[i].obs_cc) * abs;
-
-      tab_double (table, col, 5, 0, ks[i].diff_pos, NULL, RC_OTHER);
-      tab_double (table, col, 6, 0, ks[i].diff_neg, NULL, RC_OTHER);
+      double z = sqrt (ks[i].obs_cc) * abs;
 
-      tab_double (table, col, 4, 0, abs, NULL, RC_OTHER);
+      values[n++] = abs;
+      values[n++] = ks[i].diff_pos;
+      values[n++] = ks[i].diff_neg;
+      values[n++] = z;
+      values[n++] = ks_asymp_sig (z);
 
-      tab_double (table, col, 7, 0, z, NULL, RC_OTHER);
-      tab_double (table, col, 8, 0, ks_asymp_sig (z), NULL, RC_PVALUE);
+      for (size_t j = 0; j < n; j++)
+        pivot_table_put2 (table, j, col, pivot_value_new_number (values[j]));
     }
 
-
-  tab_text (table,  0, 4,
-           TAT_TITLE | TAB_LEFT , _("Most Extreme Differences"));
-
-  tab_text (table,  1, 4,
-           TAT_TITLE | TAB_LEFT , _("Absolute"));
-
-  tab_text (table,  1, 5,
-           TAT_TITLE | TAB_LEFT , _("Positive"));
-
-  tab_text (table,  1, 6,
-           TAT_TITLE | TAB_LEFT , _("Negative"));
-
-  tab_text (table,  0, 7,
-           TAT_TITLE | TAB_LEFT , _("Kolmogorov-Smirnov Z"));
-
-  tab_text (table,  0, 8,
-           TAT_TITLE | TAB_LEFT , _("Asymp. Sig. (2-tailed)"));
-
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index 14c317ff723c68622139b1baf74771a39396ec62..6d2366518b301606e68b720c218dc769a4148e69 100644 (file)
 #include "language/lexer/value-parser.h"
 #include "language/lexer/variable-parser.h"
 #include "libpspp/assertion.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmap.h"
 #include "libpspp/ll.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "math/categoricals.h"
 #include "math/interaction.h"
-#include "libpspp/hmap.h"
-#include "libpspp/hash-functions.h"
-
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -1137,43 +1137,26 @@ cmd_logistic (struct lexer *lexer, struct dataset *ds)
 static void
 output_depvarmap (const struct lr_spec *cmd, const struct lr_result *res)
 {
-  const int heading_columns = 0;
-  const int heading_rows = 1;
-  struct tab_table *t;
-  struct string str;
-
-  const int nc = 2;
-  int nr = heading_rows + 2;
-
-  t = tab_create (nc, nr);
-  tab_title (t, _("Dependent Variable Encoding"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  struct pivot_table *table = pivot_table_create (
+    N_("Dependent Variable Encoding"));
 
-  tab_text (t,  0, 0, TAB_CENTER | TAT_TITLE, _("Original Value"));
-  tab_text (t,  1, 0, TAB_CENTER | TAT_TITLE, _("Internal Value"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Mapping"),
+                          N_("Internal Value"));
 
+  struct pivot_dimension *original = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Original Value"));
+  original->root->show_label = true;
 
+  for (int i = 0; i < 2; i++)
+    {
+      const union value *v = i ? &res->y1 : &res->y0;
+      int orig_idx = pivot_category_create_leaf (
+        original->root, pivot_value_new_var_value (cmd->dep_var, v));
+      pivot_table_put2 (table, 0, orig_idx, pivot_value_new_number (
+                          map_dependent_var (cmd, res, v)));
+    }
 
-  ds_init_empty (&str);
-  var_append_value_name (cmd->dep_var, &res->y0, &str);
-  tab_text (t,  0, 0 + heading_rows,  0, ds_cstr (&str));
-
-  ds_clear (&str);
-  var_append_value_name (cmd->dep_var, &res->y1, &str);
-  tab_text (t,  0, 1 + heading_rows,  0, ds_cstr (&str));
-
-
-  tab_double (t, 1, 0 + heading_rows, 0, map_dependent_var (cmd, res, &res->y0), NULL, RC_INTEGER);
-  tab_double (t, 1, 1 + heading_rows, 0, map_dependent_var (cmd, res, &res->y1), NULL, RC_INTEGER);
-  ds_destroy (&str);
-
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
@@ -1182,84 +1165,62 @@ static void
 output_variables (const struct lr_spec *cmd,
                  const struct lr_result *res)
 {
-  int row = 0;
-  const int heading_columns = 1;
-  int heading_rows = 1;
-  struct tab_table *t;
+  struct pivot_table *table = pivot_table_create (
+    N_("Variables in the Equation"));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("B"), PIVOT_RC_OTHER,
+    N_("S.E."), PIVOT_RC_OTHER,
+    N_("Wald"), PIVOT_RC_OTHER,
+    N_("df"), PIVOT_RC_INTEGER,
+    N_("Sig."), PIVOT_RC_SIGNIFICANCE,
+    N_("Exp(B)"), PIVOT_RC_OTHER);
+  if (cmd->print & PRINT_CI)
+    {
+      struct pivot_category *group = pivot_category_create_group__ (
+        statistics->root,
+        pivot_value_new_text_format (N_("%d%% CI for Exp(B)"),
+                                     cmd->confidence));
+      pivot_category_create_leaves (group, N_("Lower"), N_("Upper"));
+    }
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+  struct pivot_category *step1 = pivot_category_create_group (
+    variables->root, N_("Step 1"));
 
-  int nc = 8;
-  int nr ;
-  int i = 0;
   int ivar = 0;
   int idx_correction = 0;
+  int i = 0;
 
-  if (cmd->print & PRINT_CI)
-    {
-      nc += 2;
-      heading_rows += 1;
-      row++;
-    }
-  nr = heading_rows + cmd->n_predictor_vars;
+  int nr = cmd->n_predictor_vars;
   if (cmd->constant)
     nr++;
-
   if (res->cats)
     nr += categoricals_df_total (res->cats) + cmd->n_cat_predictors;
 
-  t = tab_create (nc, nr);
-  tab_title (t, _("Variables in the Equation"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_text (t,  0, row + 1, TAB_CENTER | TAT_TITLE, _("Step 1"));
-
-  tab_text (t,  2, row, TAB_CENTER | TAT_TITLE, _("B"));
-  tab_text (t,  3, row, TAB_CENTER | TAT_TITLE, _("S.E."));
-  tab_text (t,  4, row, TAB_CENTER | TAT_TITLE, _("Wald"));
-  tab_text (t,  5, row, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t,  6, row, TAB_CENTER | TAT_TITLE, _("Sig."));
-  tab_text (t,  7, row, TAB_CENTER | TAT_TITLE, _("Exp(B)"));
-
-  if (cmd->print & PRINT_CI)
-    {
-      tab_joint_text_format (t, 8, 0, 9, 0,
-                            TAB_CENTER | TAT_TITLE, _("%d%% CI for Exp(B)"), cmd->confidence);
-
-      tab_text (t,  8, row, TAB_CENTER | TAT_TITLE, _("Lower"));
-      tab_text (t,  9, row, TAB_CENTER | TAT_TITLE, _("Upper"));
-    }
-
-  for (row = heading_rows ; row < nr; ++row)
+  for (int row = 0; row < nr; row++)
     {
-      const int idx = row - heading_rows - idx_correction;
-
-      const double b = gsl_vector_get (res->beta_hat, idx);
-      const double sigma2 = gsl_matrix_get (res->hessian, idx, idx);
-      const double wald = pow2 (b) / sigma2;
-      const double df = 1;
+      const int idx = row - idx_correction;
 
+      int var_idx;
       if (idx < cmd->n_predictor_vars)
-       {
-         tab_text (t, 1, row, TAB_LEFT | TAT_TITLE,
-                   var_to_string (cmd->predictor_vars[idx]));
-       }
+        var_idx = pivot_category_create_leaf (
+          step1, pivot_value_new_variable (cmd->predictor_vars[idx]));
       else if (i < cmd->n_cat_predictors)
        {
-         double wald;
-         bool summary = false;
-         struct string str;
          const struct interaction *cat_predictors = cmd->cat_predictors[i];
-         const int df = categoricals_df (res->cats, i);
-
-         ds_init_empty (&str);
+         struct string str = DS_EMPTY_INITIALIZER;
          interaction_to_string (cat_predictors, &str);
-
-         if (ivar == 0)
+         if (ivar != 0)
+            ds_put_format (&str, "(%d)", ivar);
+          var_idx = pivot_category_create_leaf (
+            step1, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
+
+         int df = categoricals_df (res->cats, i);
+         bool summary = ivar == 0;
+          if (summary)
            {
              /* Calculate the Wald statistic,
                 which is \beta' C^-1 \beta .
@@ -1278,64 +1239,56 @@ output_variables (const struct lr_spec *cmd,
              gsl_linalg_cholesky_invert (subhessian);
 
              gsl_blas_dgemv (CblasTrans, 1.0, subhessian, &vv.vector, 0, temp);
+              double wald;
              gsl_blas_ddot (temp, &vv.vector, &wald);
 
-             tab_double (t, 4, row, 0, wald, NULL, RC_OTHER);
-             tab_double (t, 5, row, 0, df, NULL, RC_INTEGER);
-             tab_double (t, 6, row, 0, gsl_cdf_chisq_Q (wald, df), NULL, RC_PVALUE);
+              double entries[] = { wald, df, gsl_cdf_chisq_Q (wald, df) };
+              for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+                pivot_table_put2 (table, j + 2, var_idx,
+                                  pivot_value_new_number (entries[j]));
 
-             idx_correction ++;
-             summary = true;
+             idx_correction++;
              gsl_matrix_free (subhessian);
              gsl_vector_free (temp);
            }
-         else
-           {
-             ds_put_format (&str, "(%d)", ivar);
-           }
 
-         tab_text (t, 1, row, TAB_LEFT | TAT_TITLE, ds_cstr (&str));
          if (ivar++ == df)
            {
              ++i; /* next interaction */
              ivar = 0;
            }
 
-         ds_destroy (&str);
-
          if (summary)
            continue;
        }
       else
-       {
-         tab_text (t, 1, row, TAB_LEFT | TAT_TITLE, _("Constant"));
-       }
-
-      tab_double (t, 2, row, 0, b, NULL, RC_OTHER);
-      tab_double (t, 3, row, 0, sqrt (sigma2), NULL, RC_OTHER);
-      tab_double (t, 4, row, 0, wald, NULL, RC_OTHER);
-      tab_double (t, 5, row, 0, df, NULL, RC_INTEGER);
-      tab_double (t, 6, row, 0, gsl_cdf_chisq_Q (wald, df), NULL, RC_PVALUE);
-      tab_double (t, 7, row, 0, exp (b), NULL, RC_OTHER);
-
-      if (cmd->print & PRINT_CI)
-       {
-         int last_ci = nr;
-         double wc = gsl_cdf_ugaussian_Pinv (0.5 + cmd->confidence / 200.0);
-         wc *= sqrt (sigma2);
-
-         if (cmd->constant)
-           last_ci--;
-
-         if (row < last_ci)
-           {
-             tab_double (t, 8, row, 0, exp (b - wc), NULL, RC_OTHER);
-             tab_double (t, 9, row, 0, exp (b + wc), NULL, RC_OTHER);
-           }
-       }
+        var_idx = pivot_category_create_leaves (step1, N_("Constant"));
+
+      double b = gsl_vector_get (res->beta_hat, idx);
+      double sigma2 = gsl_matrix_get (res->hessian, idx, idx);
+      double wald = pow2 (b) / sigma2;
+      double df = 1;
+      double wc = (gsl_cdf_ugaussian_Pinv (0.5 + cmd->confidence / 200.0)
+                   * sqrt (sigma2));
+      bool show_ci = cmd->print & PRINT_CI && row < nr - cmd->constant;
+
+      double entries[] = {
+        b,
+        sqrt (sigma2),
+        wald,
+        df,
+        gsl_cdf_chisq_Q (wald, df),
+        exp (b),
+        show_ci ? exp (b - wc) : SYSMIS,
+        show_ci ? exp (b + wc) : SYSMIS,
+      };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        if (entries[j] != SYSMIS)
+          pivot_table_put2 (table, j, var_idx,
+                            pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
@@ -1344,105 +1297,79 @@ static void
 output_model_summary (const struct lr_result *res,
                      double initial_log_likelihood, double log_likelihood)
 {
-  const int heading_columns = 0;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  const int nc = 4;
-  int nr = heading_rows + 1;
-  double cox;
-
-  t = tab_create (nc, nr);
-  tab_title (t, _("Model Summary"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_text (t,  0, 0, TAB_LEFT | TAT_TITLE, _("Step 1"));
-  tab_text (t,  1, 0, TAB_CENTER | TAT_TITLE, _("-2 Log likelihood"));
-  tab_double (t,  1, 1, 0, -2 * log_likelihood, NULL, RC_OTHER);
-
-
-  tab_text (t,  2, 0, TAB_CENTER | TAT_TITLE, _("Cox & Snell R Square"));
-  cox =  1.0 - exp((initial_log_likelihood - log_likelihood) * (2 / res->cc));
-  tab_double (t,  2, 1, 0, cox, NULL, RC_OTHER);
-
-  tab_text (t,  3, 0, TAB_CENTER | TAT_TITLE, _("Nagelkerke R Square"));
-  tab_double (t,  3, 1, 0, cox / ( 1.0 - exp(initial_log_likelihood * (2 / res->cc))), NULL, RC_OTHER);
-
-
-  tab_submit (t);
+  struct pivot_table *table = pivot_table_create (N_("Model Summary"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("-2 Log likelihood"), PIVOT_RC_OTHER,
+                          N_("Cox & Snell R Square"), PIVOT_RC_OTHER,
+                          N_("Nagelkerke R Square"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *step = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Step"));
+  step->root->show_label = true;
+  pivot_category_create_leaf (step->root, pivot_value_new_integer (1));
+
+  double cox = (1.0 - exp ((initial_log_likelihood - log_likelihood)
+                           * (2 / res->cc)));
+  double entries[] = {
+    -2 * log_likelihood,
+    cox,
+    cox / ( 1.0 - exp(initial_log_likelihood * (2 / res->cc)))
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    pivot_table_put2 (table, i, 0, pivot_value_new_number (entries[i]));
+
+  pivot_table_submit (table);
 }
 
 /* Show the case processing summary box */
 static void
 case_processing_summary (const struct lr_result *res)
 {
-  const int heading_columns = 1;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  const int nc = 3;
-  const int nr = heading_rows + 3;
-  casenumber total;
-
-  t = tab_create (nc, nr);
-  tab_title (t, _("Case Processing Summary"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
+  struct pivot_table *table = pivot_table_create (
+    N_("Case Processing Summary"));
 
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT);
 
-  tab_text (t,  0, 0, TAB_LEFT | TAT_TITLE, _("Unweighted Cases"));
-  tab_text (t,  1, 0, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text (t,  2, 0, TAB_CENTER | TAT_TITLE, _("Percent"));
+  struct pivot_dimension *cases = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Unweighted Cases"),
+    N_("Included in Analysis"), N_("Missing Cases"), N_("Total"));
+  cases->root->show_label = true;
 
-
-  tab_text (t,  0, 1, TAB_LEFT | TAT_TITLE, _("Included in Analysis"));
-  tab_text (t,  0, 2, TAB_LEFT | TAT_TITLE, _("Missing Cases"));
-  tab_text (t,  0, 3, TAB_LEFT | TAT_TITLE, _("Total"));
-
-  tab_double (t,  1, 1, 0, res->n_nonmissing, NULL, RC_INTEGER);
-  tab_double (t,  1, 2, 0, res->n_missing, NULL, RC_INTEGER);
-
-  total = res->n_nonmissing + res->n_missing;
-  tab_double (t,  1, 3, 0, total , NULL, RC_INTEGER);
-
-  tab_double (t,  2, 1, 0, 100 * res->n_nonmissing / (double) total, NULL, RC_OTHER);
-  tab_double (t,  2, 2, 0, 100 * res->n_missing / (double) total, NULL, RC_OTHER);
-  tab_double (t,  2, 3, 0, 100 * total / (double) total, NULL, RC_OTHER);
-
-  tab_submit (t);
+  double total = res->n_nonmissing + res->n_missing;
+  struct entry
+    {
+      int stat_idx;
+      int case_idx;
+      double x;
+    }
+  entries[] = {
+    { 0, 0, res->n_nonmissing },
+    { 0, 1, res->n_missing },
+    { 0, 2, total },
+    { 1, 0, 100.0 * res->n_nonmissing / total },
+    { 1, 1, 100.0 * res->n_missing / total },
+    { 1, 2, 100.0 },
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    pivot_table_put2 (table, entries[i].stat_idx, entries[i].case_idx,
+                      pivot_value_new_number (entries[i].x));
+
+  pivot_table_submit (table);
 }
 
 static void
 output_categories (const struct lr_spec *cmd, const struct lr_result *res)
 {
-  const struct fmt_spec *wfmt =
-    cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
-
-  int cumulative_df;
-  int i = 0;
-  const int heading_columns = 2;
-  const int heading_rows = 2;
-  struct tab_table *t;
-
-  int nc ;
-  int nr ;
-
-  int v;
-  int r = 0;
+  struct pivot_table *table = pivot_table_create (
+    N_("Categorical Variables' Codings"));
+  pivot_table_set_weight_var (table, dict_get_weight (cmd->dict));
 
   int max_df = 0;
   int total_cats = 0;
-  for (i = 0; i < cmd->n_cat_predictors; ++i)
+  for (int i = 0; i < cmd->n_cat_predictors; ++i)
     {
       size_t n = categoricals_n_count (res->cats, i);
       size_t df = categoricals_df (res->cats, i);
@@ -1451,164 +1378,121 @@ output_categories (const struct lr_spec *cmd, const struct lr_result *res)
       total_cats += n;
     }
 
-  nc = heading_columns + 1 + max_df;
-  nr = heading_rows + total_cats;
-
-  t = tab_create (nc, nr);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-
-  tab_title (t, _("Categorical Variables' Codings"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-
-  tab_text (t, heading_columns, 1, TAB_CENTER | TAT_TITLE, _("Frequency"));
-
-  tab_joint_text_format (t, heading_columns + 1, 0, nc - 1, 0,
-                        TAB_CENTER | TAT_TITLE, _("Parameter coding"));
-
-
-  for (i = 0; i < max_df; ++i)
-    {
-      int c = heading_columns + 1 + i;
-      tab_text_format (t,  c, 1, TAB_CENTER | TAT_TITLE, _("(%d)"), i + 1);
-    }
-
-  cumulative_df = 0;
-  for (v = 0; v < cmd->n_cat_predictors; ++v)
+  struct pivot_dimension *codings = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Codings"),
+    N_("Frequency"), PIVOT_RC_COUNT);
+  struct pivot_category *coding_group = pivot_category_create_group (
+    codings->root, N_("Parameter coding"));
+  for (int i = 0; i < max_df; ++i)
+    pivot_category_create_leaf_rc (
+      coding_group,
+      pivot_value_new_user_text_nocopy (xasprintf ("(%d)", i + 1)),
+      PIVOT_RC_INTEGER);
+
+  struct pivot_dimension *categories = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Categories"));
+
+  int cumulative_df = 0;
+  for (int v = 0; v < cmd->n_cat_predictors; ++v)
     {
       int cat;
       const struct interaction *cat_predictors = cmd->cat_predictors[v];
-      int df =  categoricals_df (res->cats, v);
-      struct string str;
-      ds_init_empty (&str);
+      int df = categoricals_df (res->cats, v);
 
+      struct string str = DS_EMPTY_INITIALIZER;
       interaction_to_string (cat_predictors, &str);
-
-      tab_text (t, 0, heading_rows + r, TAB_LEFT | TAT_TITLE, ds_cstr (&str) );
-
-      ds_destroy (&str);
+      struct pivot_category *var_group = pivot_category_create_group__ (
+        categories->root,
+        pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
 
       for (cat = 0; cat < categoricals_n_count (res->cats, v) ; ++cat)
        {
-         struct string str;
-         const struct ccase *c = categoricals_get_case_by_category_real (res->cats, v, cat);
-         const double *freq = categoricals_get_user_data_by_category_real (res->cats, v, cat);
-
-         int x;
-         ds_init_empty (&str);
-
-         for (x = 0; x < cat_predictors->n_vars; ++x)
+         const struct ccase *c = categoricals_get_case_by_category_real (
+            res->cats, v, cat);
+          struct string label = DS_EMPTY_INITIALIZER;
+         for (int x = 0; x < cat_predictors->n_vars; ++x)
            {
-             const union value *val = case_data (c, cat_predictors->vars[x]);
-             var_append_value_name (cat_predictors->vars[x], val, &str);
+              if (!ds_is_empty (&label))
+                ds_put_byte (&label, ' ');
 
-             if (x < cat_predictors->n_vars - 1)
-               ds_put_cstr (&str, " ");
+             const union value *val = case_data (c, cat_predictors->vars[x]);
+             var_append_value_name (cat_predictors->vars[x], val, &label);
            }
+          int cat_idx = pivot_category_create_leaf (
+            var_group,
+            pivot_value_new_user_text_nocopy (ds_steal_cstr (&label)));
 
-         tab_text   (t, 1, heading_rows + r, 0, ds_cstr (&str));
-         ds_destroy (&str);
-                 tab_double (t, 2, heading_rows + r, 0, *freq, NULL, RC_WEIGHT);
+         double *freq = categoricals_get_user_data_by_category_real (
+            res->cats, v, cat);
+          pivot_table_put2 (table, 0, cat_idx, pivot_value_new_number (*freq));
 
-         for (x = 0; x < df; ++x)
-           {
-             tab_double (t, heading_columns + 1 + x, heading_rows + r, 0, (cat == x), NULL, RC_INTEGER);
-           }
-         ++r;
+         for (int x = 0; x < df; ++x)
+            pivot_table_put2 (table, x + 1, cat_idx,
+                              pivot_value_new_number (cat == x));
        }
       cumulative_df += df;
     }
 
-  tab_submit (t);
-
+  pivot_table_submit (table);
 }
 
+static void
+create_classification_dimension (const struct lr_spec *cmd,
+                                 const struct lr_result *res,
+                                 struct pivot_table *table,
+                                 enum pivot_axis_type axis_type,
+                                 const char *label, const char *total)
+{
+  struct pivot_dimension *d = pivot_dimension_create (
+    table, axis_type, label);
+  d->root->show_label = true;
+  struct pivot_category *pred_group = pivot_category_create_group__ (
+    d->root, pivot_value_new_variable (cmd->dep_var));
+  for (int i = 0; i < 2; i++)
+    {
+      const union value *y = i ? &res->y1 : &res->y0;
+      pivot_category_create_leaf_rc (
+        pred_group, pivot_value_new_var_value (cmd->dep_var, y),
+        PIVOT_RC_COUNT);
+    }
+  pivot_category_create_leaves (d->root, total, PIVOT_RC_PERCENT);
+}
 
 static void
 output_classification_table (const struct lr_spec *cmd, const struct lr_result *res)
 {
-  const struct fmt_spec *wfmt =
-    cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
-
-  const int heading_columns = 3;
-  const int heading_rows = 3;
-
-  struct string sv0, sv1;
-
-  const int nc = heading_columns + 3;
-  const int nr = heading_rows + 3;
-
-  struct tab_table *t = tab_create (nc, nr);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-
-  ds_init_empty (&sv0);
-  ds_init_empty (&sv1);
-
-  tab_title (t, _("Classification Table"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, nc - 1, nr - 1);
-  tab_box (t, -1, -1, -1, TAL_1, heading_columns, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  tab_text (t,  0, heading_rows, TAB_CENTER | TAT_TITLE, _("Step 1"));
-
-
-  tab_joint_text (t, heading_columns, 0, nc - 1, 0,
-                 TAB_CENTER | TAT_TITLE, _("Predicted"));
-
-  tab_joint_text (t, heading_columns, 1, heading_columns + 1, 1,
-                 0, var_to_string (cmd->dep_var) );
+  struct pivot_table *table = pivot_table_create (N_("Classification Table"));
+  pivot_table_set_weight_var (table, cmd->wv);
 
-  tab_joint_text (t, 1, 2, 2, 2,
-                 TAB_LEFT | TAT_TITLE, _("Observed"));
+  create_classification_dimension (cmd, res, table, PIVOT_AXIS_COLUMN,
+                                   N_("Predicted"), N_("Percentage Correct"));
+  create_classification_dimension (cmd, res, table, PIVOT_AXIS_ROW,
+                                   N_("Observed"), N_("Overall Percentage"));
 
-  tab_text (t, 1, 3, TAB_LEFT, var_to_string (cmd->dep_var) );
-
-
-  tab_joint_text (t, nc - 1, 1, nc - 1, 2,
-                 TAB_CENTER | TAT_TITLE, _("Percentage\nCorrect"));
-
-
-  tab_joint_text (t, 1, nr - 1, 2, nr - 1,
-                 TAB_LEFT | TAT_TITLE, _("Overall Percentage"));
-
-
-  tab_hline (t, TAL_1, 1, nc - 1, nr - 1);
-
-  var_append_value_name (cmd->dep_var, &res->y0, &sv0);
-  var_append_value_name (cmd->dep_var, &res->y1, &sv1);
-
-  tab_text (t, 2, heading_rows,     TAB_LEFT,  ds_cstr (&sv0));
-  tab_text (t, 2, heading_rows + 1, TAB_LEFT,  ds_cstr (&sv1));
-
-  tab_text (t, heading_columns,     2, 0,  ds_cstr (&sv0));
-  tab_text (t, heading_columns + 1, 2, 0,  ds_cstr (&sv1));
-
-  ds_destroy (&sv0);
-  ds_destroy (&sv1);
-
-  tab_double (t, heading_columns, 3,     0, res->tn, NULL, RC_WEIGHT);
-  tab_double (t, heading_columns + 1, 4, 0, res->tp, NULL, RC_WEIGHT);
-
-  tab_double (t, heading_columns + 1, 3, 0, res->fp, NULL, RC_WEIGHT);
-  tab_double (t, heading_columns,     4, 0, res->fn, NULL, RC_WEIGHT);
-
-  tab_double (t, heading_columns + 2, 3, 0, 100 * res->tn / (res->tn + res->fp), NULL, RC_OTHER);
-  tab_double (t, heading_columns + 2, 4, 0, 100 * res->tp / (res->tp + res->fn), NULL, RC_OTHER);
-
-  tab_double (t, heading_columns + 2, 5, 0,
-             100 * (res->tp + res->tn) / (res->tp  + res->tn + res->fp + res->fn), NULL, RC_OTHER);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Step"), N_("Step 1"));
 
+  struct entry
+    {
+      int pred_idx;
+      int obs_idx;
+      double x;
+    }
+  entries[] = {
+    { 0, 0, res->tn },
+    { 0, 1, res->fn },
+    { 1, 0, res->fp },
+    { 1, 1, res->tp },
+    { 2, 0, 100 * res->tn / (res->tn + res->fp) },
+    { 2, 1, 100 * res->tp / (res->tp + res->fn) },
+    { 2, 2,
+      100 * (res->tp + res->tn) / (res->tp  + res->tn + res->fp + res->fn)},
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    {
+      const struct entry *e = &entries[i];
+      pivot_table_put3 (table, e->pred_idx, e->obs_idx, 0,
+                        pivot_value_new_number (e->x));
+    }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
index e117cc366cbfd24aefacd5631eca45a1a81c2e0c..ad3a95733ed76ff35b9b10e6c7530461a9c8fc52 100644 (file)
 #include "libpspp/cast.h"
 #include "libpspp/misc.h"
 #include "math/sort.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
+
+#include "gettext.h"
+#define N_(msgid) msgid
+#define _(msgid) gettext (msgid)
 
 /* Calculates the adjustment necessary for tie compensation */
 static void
@@ -50,8 +54,9 @@ struct mw
   double z;
 };
 
-static void show_ranks_box (const struct n_sample_test *nst, const struct mw *mw);
-static void show_statistics_box (const struct n_sample_test *nst, const struct mw *mw, bool exact);
+static void show_ranks_box (const struct n_sample_test *, const struct mw *);
+static void show_statistics_box (const struct n_sample_test *,
+                                 const struct mw *);
 
 
 
@@ -79,7 +84,7 @@ mann_whitney_execute (const struct dataset *ds,
                      struct casereader *input,
                      enum mv_class exclude,
                      const struct npar_test *test,
-                     bool exact,
+                     bool exact UNUSED,
                      double timer UNUSED)
 {
   int i;
@@ -166,157 +171,104 @@ mann_whitney_execute (const struct dataset *ds,
   casereader_destroy (input);
 
   show_ranks_box (nst, mw);
-  show_statistics_box (nst, mw, exact);
+  show_statistics_box (nst, mw);
 
   free (mw);
 }
-
 \f
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
 static void
 show_ranks_box (const struct n_sample_test *nst, const struct mw *mwv)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 2;
-  struct tab_table *table =
-    tab_create (row_headers + 7, column_headers + nst->n_vars);
-
-  struct string g1str, g2str;;
-  ds_init_empty (&g1str);
-  var_append_value_name (nst->indep_var, &nst->val1, &g1str);
-
-  ds_init_empty (&g2str);
-  var_append_value_name (nst->indep_var, &nst->val2, &g2str);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Ranks"));
-
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  tab_hline (table, TAL_1, row_headers, tab_nc (table) -1, 1);
-
-  tab_text (table, 1, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
-  tab_text (table, 2, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
-  tab_text (table, 3, 1, TAT_TITLE | TAB_CENTER, _("Total"));
-  tab_joint_text (table, 1, 0, 3, 0,
-                 TAT_TITLE | TAB_CENTER, _("N"));
-  tab_vline (table, TAL_2, 4, 0, tab_nr (table) - 1);
-
-  tab_text (table, 4, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
-  tab_text (table, 5, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
-  tab_joint_text (table, 4, 0, 5, 0,
-                 TAT_TITLE | TAB_CENTER, _("Mean Rank"));
-  tab_vline (table, TAL_2, 6, 0, tab_nr (table) - 1);
-
-  tab_text (table, 6, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
-  tab_text (table, 7, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
-  tab_joint_text (table, 6, 0, 7, 0,
-                 TAT_TITLE | TAB_CENTER, _("Sum of Ranks"));
-
-  ds_destroy (&g1str);
-  ds_destroy (&g2str);
-
-  for (i = 0 ; i < nst->n_vars ; ++i)
+  struct pivot_table *table = pivot_table_create (N_("Ranks"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Mean Rank"), PIVOT_RC_OTHER,
+                          N_("Sum of Ranks"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *indep = pivot_dimension_create__ (
+    table, PIVOT_AXIS_ROW, pivot_value_new_variable (nst->indep_var));
+  pivot_category_create_leaf (indep->root,
+                              pivot_value_new_var_value (nst->indep_var,
+                                                         &nst->val1));
+  pivot_category_create_leaf (indep->root,
+                              pivot_value_new_var_value (nst->indep_var,
+                                                         &nst->val2));
+  pivot_category_create_leaves (indep->root, N_("Total"));
+
+  struct pivot_dimension *dep = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
+
+  for (size_t i = 0 ; i < nst->n_vars ; ++i)
     {
       const struct mw *mw = &mwv[i];
-      tab_text (table, 0, column_headers + i, TAT_TITLE,
-               var_to_string (nst->vars[i]));
-
-      tab_double (table, 1, column_headers + i, 0,
-                 mw->n[0], NULL, RC_OTHER);
-
-      tab_double (table, 2, column_headers + i, 0,
-                 mw->n[1], NULL, RC_OTHER);
-
-      tab_double (table, 3, column_headers + i, 0,
-                 mw->n[1] + mw->n[0], NULL, RC_OTHER);
 
-      /* Mean Ranks */
-      tab_double (table, 4, column_headers + i, 0,
-                 mw->rank_sum[0] / mw->n[0], NULL, RC_OTHER);
-
-      tab_double (table, 5, column_headers + i, 0,
-                 mw->rank_sum[1] / mw->n[1], NULL, RC_OTHER);
-
-      /* Sum of Ranks */
-      tab_double (table, 6, column_headers + i, 0,
-                 mw->rank_sum[0], NULL, RC_OTHER);
-
-      tab_double (table, 7, column_headers + i, 0,
-                 mw->rank_sum[1], NULL, RC_OTHER);
+      int dep_idx = pivot_category_create_leaf (
+        dep->root, pivot_value_new_variable (nst->vars[i]));
+
+      struct entry
+        {
+          int stat_idx;
+          int indep_idx;
+          double x;
+        }
+      entries[] = {
+        /* N. */
+        { 0, 0, mw->n[0] },
+        { 0, 1, mw->n[1] },
+        { 0, 2, mw->n[0] + mw->n[1] },
+
+        /* Mean Rank. */
+        { 1, 0, mw->rank_sum[0] / mw->n[0] },
+        { 1, 1, mw->rank_sum[1] / mw->n[1] },
+
+        /* Sum of Ranks. */
+        { 2, 0, mw->rank_sum[0] },
+        { 2, 1, mw->rank_sum[1] },
+      };
+
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        {
+          const struct entry *e = &entries[j];
+          pivot_table_put3 (table, e->stat_idx, e->indep_idx, dep_idx,
+                            pivot_value_new_number (e->x));
+        }
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
 static void
-show_statistics_box (const struct n_sample_test *nst, const struct mw *mwv, bool exact)
+show_statistics_box (const struct n_sample_test *nst, const struct mw *mwv)
 {
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 1;
-  struct tab_table *table =
-    tab_create (row_headers + (exact ? 6 : 4), column_headers + nst->n_vars);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
 
-  tab_title (table, _("Test Statistics"));
+  pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    _("Mann-Whitney U"), PIVOT_RC_OTHER,
+    _("Wilcoxon W"), PIVOT_RC_OTHER,
+    _("Z"), PIVOT_RC_OTHER,
+    _("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
 
-  /* Vertical lines inside the box */
-  tab_box (table, 1, 0, -1, TAL_1,
-          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  /* Box around the table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  tab_text (table, 1, 0, TAT_TITLE | TAB_CENTER, _("Mann-Whitney U"));
-  tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, _("Wilcoxon W"));
-  tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, _("Z"));
-  tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, _("Asymp. Sig. (2-tailed)"));
-
-  if (exact)
-    {
-      tab_text (table, 5, 0, TAT_TITLE | TAB_CENTER, _("Exact Sig. (2-tailed)"));
-      tab_text (table, 6, 0, TAT_TITLE | TAB_CENTER, _("Point Probability"));
-    }
-
-  for (i = 0 ; i < nst->n_vars ; ++i)
+  for (size_t i = 0 ; i < nst->n_vars ; ++i)
     {
       const struct mw *mw = &mwv[i];
 
-      tab_text (table, 0, column_headers + i, TAT_TITLE,
-               var_to_string (nst->vars[i]));
-
-      tab_double (table, 1, column_headers + i, 0,
-                 mw->u, NULL, RC_OTHER);
-
-      tab_double (table, 2, column_headers + i, 0,
-                 mw->w, NULL, RC_OTHER);
-
-      tab_double (table, 3, column_headers + i, 0,
-                 mw->z, NULL, RC_OTHER);
-
-      tab_double (table, 4, column_headers + i, 0,
-                 2.0 * gsl_cdf_ugaussian_P (mw->z), NULL, RC_PVALUE);
+      int row = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (nst->vars[i]));
+
+      double entries[] = {
+        mw->u,
+        mw->w,
+        mw->z,
+        2.0 * gsl_cdf_ugaussian_P (mw->z),
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index d3f48192fa9f9a91c20c026cdda398f277a99115..0456b909c59a75688d97ada4a109ec71775caab8 100644 (file)
@@ -29,7 +29,7 @@
 #include "data/variable.h"
 #include "language/stats/npar.h"
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "libpspp/message.h"
 
 #include "gl/minmax.h"
@@ -38,6 +38,7 @@
 #include "data/value.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -155,142 +156,93 @@ mcnemar_execute (const struct dataset *ds,
   free (mc);
 }
 
+static char *
+make_pair_name (const variable_pair *pair)
+{
+  return xasprintf ("%s & %s", var_to_string ((*pair)[0]),
+                    var_to_string ((*pair)[1]));
+}
 
 static void
 output_freq_table (variable_pair *vp,
                   const struct mcnemar *param,
                   const struct dictionary *dict)
 {
-  const int header_rows = 2;
-  const int header_cols = 1;
-
-  struct tab_table *table = tab_create (header_cols + 2, header_rows + 2);
-
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-
-  struct string pair_name;
-  struct string val1str ;
-  struct string val0str ;
-
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  ds_init_empty (&val0str);
-  ds_init_empty (&val1str);
-
-  var_append_value_name ((*vp)[0], &param->val0, &val0str);
-  var_append_value_name ((*vp)[1], &param->val1, &val1str);
-
-  ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-  ds_put_cstr (&pair_name, " & ");
-  ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
-
-  tab_title (table, "%s", ds_cstr (&pair_name));
-
-  ds_destroy (&pair_name);
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_user_text_nocopy (make_pair_name (vp)));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-  tab_headers (table, header_cols, 0, header_rows, 0);
-
-  /* Vertical lines inside the box */
-  tab_box (table, 0, 0, -1, TAL_1,
-          1, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_vline (table, TAL_2, header_cols, 0, tab_nr (table) - 1);
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, header_rows);
-
-  tab_text (table,  0, 0,  TAB_CENTER, var_to_string ((*vp)[0]));
-
-  tab_joint_text (table,  1, 0,  2, 0, TAB_CENTER, var_to_string ((*vp)[1]));
-  tab_hline (table, TAL_1, 1, tab_nc (table) - 1, 1);
-
-
-  tab_text (table, 0, header_rows + 0, TAB_LEFT, ds_cstr (&val0str));
-  tab_text (table, 0, header_rows + 1, TAB_LEFT, ds_cstr (&val1str));
-
-  tab_text (table, header_cols + 0, 1, TAB_LEFT, ds_cstr (&val0str));
-  tab_text (table, header_cols + 1, 1, TAB_LEFT, ds_cstr (&val1str));
-
-  tab_double (table, header_cols + 0, header_rows + 0, TAB_RIGHT, param->n00, NULL, RC_WEIGHT);
-  tab_double (table, header_cols + 0, header_rows + 1, TAB_RIGHT, param->n01, NULL, RC_WEIGHT);
-  tab_double (table, header_cols + 1, header_rows + 0, TAB_RIGHT, param->n10, NULL, RC_WEIGHT);
-  tab_double (table, header_cols + 1, header_rows + 1, TAB_RIGHT, param->n11, NULL, RC_WEIGHT);
+  struct pivot_dimension *vars[2];
+  for (int i = 0; i < 2; i++)
+    {
+      vars[i] = pivot_dimension_create__ (
+        table, i ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW,
+        pivot_value_new_variable ((*vp)[i]));
+      vars[i]->root->show_label = true;
+
+      for (int j = 0; j < 2; j++)
+        {
+          const union value *val = j ? &param->val1 : &param->val0;
+          pivot_category_create_leaf_rc (
+            vars[i]->root, pivot_value_new_var_value ((*vp)[0], val),
+            PIVOT_RC_COUNT);
+        }
+    }
 
-  tab_submit (table);
+  struct entry
+    {
+      int idx0;
+      int idx1;
+      double x;
+    }
+  entries[] = {
+    { 0, 0, param->n00 },
+    { 1, 0, param->n01 },
+    { 0, 1, param->n10 },
+    { 1, 1, param->n11 },
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    {
+      const struct entry *e = &entries[i];
+      pivot_table_put2 (table, e->idx0, e->idx1,
+                        pivot_value_new_number (e->x));
+    }
 
-  ds_destroy (&val0str);
-  ds_destroy (&val1str);
+  pivot_table_submit (table);
 }
 
-
 static void
 output_statistics_table (const struct two_sample_test *t2s,
                         const struct mcnemar *mc,
                         const struct dictionary *dict)
 {
-  int i;
-
-  struct tab_table *table = tab_create (5, t2s->n_pairs + 1);
-
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-  tab_title (table, _("Test Statistics"));
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, 0, 1,  0, 1);
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
-  tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+                          N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE,
+                          N_("Point Probability"), PIVOT_RC_OTHER);
 
-  /* Vertical lines inside the box */
-  tab_box (table, -1, -1, -1, TAL_1,
-          0, 0,
-          tab_nc (table) - 1, tab_nr (table) - 1);
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Pairs"));
 
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1,
-          tab_nr (table) - 1);
-
-  tab_text (table,  1, 0, TAT_TITLE | TAB_CENTER,
-           _("N"));
-
-  tab_text (table,  2, 0, TAT_TITLE | TAB_CENTER,
-           _("Exact Sig. (2-tailed)"));
-
-  tab_text (table,  3, 0, TAT_TITLE | TAB_CENTER,
-           _("Exact Sig. (1-tailed)"));
-
-  tab_text (table,  4, 0, TAT_TITLE | TAB_CENTER,
-           _("Point Probability"));
-
-  for (i = 0 ; i < t2s->n_pairs; ++i)
+  for (size_t i = 0 ; i < t2s->n_pairs; ++i)
     {
-      double sig;
       variable_pair *vp = &t2s->pairs[i];
-
-      struct string pair_name;
-      ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-      ds_put_cstr (&pair_name, " & ");
-      ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
-
-      tab_text (table,  0, 1 + i, TAB_LEFT, ds_cstr (&pair_name));
-      ds_destroy (&pair_name);
-
-      tab_double (table, 1, 1 + i, TAB_RIGHT, mc[i].n00 + mc[i].n01 + mc[i].n10 + mc[i].n11, NULL, RC_WEIGHT);
-
-      sig = gsl_cdf_binomial_P (mc[i].n01,  0.5,  mc[i].n01 + mc[i].n10);
-
-      tab_double (table, 2, 1 + i, TAB_RIGHT, 2 * sig, NULL, RC_PVALUE);
-      tab_double (table, 3, 1 + i, TAB_RIGHT, sig, NULL, RC_PVALUE);
-
-      tab_double (table, 4, 1 + i, TAB_RIGHT, gsl_ran_binomial_pdf (mc[i].n01, 0.5, mc[i].n01 + mc[i].n10),
-                 NULL, RC_OTHER);
+      int pair_idx = pivot_category_create_leaf (
+        pairs->root, pivot_value_new_user_text_nocopy (make_pair_name (vp)));
+
+      double n = mc[i].n00 + mc[i].n01 + mc[i].n10 + mc[i].n11;
+      double sig = gsl_cdf_binomial_P (mc[i].n01, 0.5, mc[i].n01 + mc[i].n10);
+      double point = gsl_ran_binomial_pdf (mc[i].n01, 0.5,
+                                           mc[i].n01 + mc[i].n10);
+      double entries[] = { n, 2.0 * sig, sig, point };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, pair_idx,
+                          pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index df747fb5d038b4db3a0273d8032fadc4440daa19..7e7642adf1fd2ff1a51c0492330e5a792e19b790 100644 (file)
@@ -35,7 +35,7 @@
 #include "math/interaction.h"
 #include "math/moments.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include <math.h>
 
@@ -834,7 +834,8 @@ is_missing (const struct means *cmd,
   return false;
 }
 
-static void output_case_processing_summary (const struct mtable *);
+static void output_case_processing_summary (const struct mtable *,
+                                            const struct variable *wv);
 
 static void output_report (const struct means *, int, const struct mtable *);
 
@@ -1033,7 +1034,7 @@ run_means (struct means *cmd, struct casereader *input,
       int i;
       const struct mtable *table = &cmd->table[t];
 
-      output_case_processing_summary (table);
+      output_case_processing_summary (table, wv);
 
       for (i = 0; i < table->n_layers; ++i)
        {
@@ -1047,201 +1048,143 @@ run_means (struct means *cmd, struct casereader *input,
 
 
 static void
-output_case_processing_summary (const struct mtable *table)
+output_case_processing_summary (const struct mtable *mt,
+                                const struct variable *wv)
 {
-  int i, v;
-  const int heading_columns = 1;
-  const int heading_rows = 3;
-  struct tab_table *t;
-
-  const int nr = heading_rows + table->n_layers * table->n_dep_vars;
-  const int nc = 7;
-
-  t = tab_create (nc, nr);
-  tab_title (t, _("Case Processing Summary"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-
-  tab_joint_text (t, heading_columns, 0,
-                 nc - 1, 0, TAB_CENTER | TAT_TITLE, _("Cases"));
-
-  tab_joint_text (t, 1, 1, 2, 1, TAB_CENTER | TAT_TITLE, _("Included"));
-  tab_joint_text (t, 3, 1, 4, 1, TAB_CENTER | TAT_TITLE, _("Excluded"));
-  tab_joint_text (t, 5, 1, 6, 1, TAB_CENTER | TAT_TITLE, _("Total"));
+  struct pivot_table *table = pivot_table_create (
+    N_("Case Processing Summary"));
+  pivot_table_set_weight_var (table, wv);
 
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 1);
-  tab_hline (t, TAL_1, heading_columns, nc - 1, 2);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Cases"),
+                          N_("Included"), N_("Excluded"), N_("Total"))
+    ->root->show_label = true;
 
+  struct pivot_dimension *tables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Tables"));
 
-  for (i = 0; i < 3; ++i)
-    {
-      tab_text (t, heading_columns + i * 2, 2, TAB_CENTER | TAT_TITLE,
-               _("N"));
-      tab_text (t, heading_columns + i * 2 + 1, 2, TAB_CENTER | TAT_TITLE,
-               _("Percent"));
-    }
-
-  for (v = 0; v < table->n_dep_vars; ++v)
+  for (size_t v = 0; v < mt->n_dep_vars; ++v)
     {
-      const struct variable *var = table->dep_vars[v];
-      const char *dv_name = var_to_string (var);
-      for (i = 0; i < table->n_layers; ++i)
+      const struct variable *var = mt->dep_vars[v];
+      for (size_t i = 0; i < mt->n_layers; ++i)
        {
-         const int row = v * table->n_layers + i;
-         const struct interaction *iact = table->interactions[i];
-         casenumber n_total;
-
-         struct string str;
-         ds_init_cstr (&str, dv_name);
-         ds_put_cstr (&str, ": ");
+         const int row = v * mt->n_layers + i;
+         const struct interaction *iact = mt->interactions[i];
 
+         struct string str = DS_EMPTY_INITIALIZER;
+          ds_put_format (&str, "%s: ", var_to_string (var));
          interaction_to_string (iact, &str);
-
-         tab_text (t, 0, row + heading_rows,
-                   TAB_LEFT | TAT_TITLE, ds_cstr (&str));
-
-
-         n_total = table->summary[row].missing +
-           table->summary[row].non_missing;
-
-         tab_double (t, 1, row + heading_rows,
-                     0, table->summary[row].non_missing, NULL, RC_INTEGER);
-
-         tab_text_format (t, 2, row + heading_rows,
-                          0, _("%g%%"),
-                          table->summary[row].non_missing / (double) n_total * 100.0);
-
-
-         tab_double (t, 3, row + heading_rows,
-                     0, table->summary[row].missing, NULL, RC_INTEGER);
-
-
-         tab_text_format (t, 4, row + heading_rows,
-                          0, _("%g%%"),
-                          table->summary[row].missing / (double) n_total * 100.0);
-
-
-         tab_double (t, 5, row + heading_rows,
-                     0, table->summary[row].missing +
-                     table->summary[row].non_missing, NULL, RC_INTEGER);
-
-         tab_text_format (t, 6, row + heading_rows,
-                          0, _("%g%%"),
-                          n_total / (double) n_total * 100.0);
-
-
-         ds_destroy (&str);
+          int table_idx = pivot_category_create_leaf (
+            tables->root, pivot_value_new_user_text_nocopy (
+              ds_steal_cstr (&str)));
+
+          const struct summary *s = &mt->summary[row];
+         double n_total = s->missing + s->non_missing;
+          struct entry
+            {
+              int stat_idx;
+              int case_idx;
+              double x;
+            }
+          entries[] =
+            {
+              { 0, 0, s->non_missing },
+              { 1, 0, s->non_missing / n_total * 100.0 },
+              { 0, 1, s->missing },
+              { 1, 1, s->missing / n_total * 100.0 },
+              { 0, 2, n_total },
+              { 1, 2, 100.0 },
+            };
+
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            {
+              const struct entry *e = &entries[j];
+              pivot_table_put3 (table, e->stat_idx, e->case_idx, table_idx,
+                                pivot_value_new_number (e->x));
+            }
        }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
-
 static void
-output_report (const struct means *cmd,  int iact_idx,
-              const struct mtable *table)
+create_interaction_dimensions (struct pivot_table *table,
+                               const struct categoricals *cats,
+                               const struct interaction *iact)
 {
-  int grp;
-  int i;
-
-  const struct interaction *iact = table->interactions[iact_idx];
-
-  const int heading_columns = 1 + iact->n_vars;
-  const int heading_rows = 1;
-  struct tab_table *t;
-
-  const int n_cats = categoricals_n_count (table->cats, iact_idx);
-
-  const int nr = n_cats * table->n_dep_vars + heading_rows;
-
-  const int nc = heading_columns + cmd->n_cells;
-
-  t = tab_create (nc, nr);
-  tab_title (t, _("Report"));
-
-  tab_headers (t, heading_columns, 0, heading_rows, 0);
-
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, nc - 1, nr - 1);
-
-  tab_hline (t, TAL_2, 0, nc - 1, heading_rows);
-  tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
-
-  for (i = 0; i < iact->n_vars; ++i)
-    {
-      tab_text (t, 1 + i, 0, TAB_CENTER | TAT_TITLE,
-               var_to_string (iact->vars[i]));
-    }
-
-  for (i = 0; i < cmd->n_cells; ++i)
+  for (size_t i = iact->n_vars; i-- > 0; )
     {
-      tab_text (t, heading_columns + i, 0,
-               TAB_CENTER | TAT_TITLE,
-               gettext (cell_spec[cmd->cells[i]].title));
+      const struct variable *var = iact->vars[i];
+      struct pivot_dimension *d = pivot_dimension_create__ (
+        table, PIVOT_AXIS_ROW, pivot_value_new_variable (var));
+      d->root->show_label = true;
+
+      size_t n;
+      union value *values = categoricals_get_var_values (cats, var, &n);
+      for (size_t j = 0; j < n; j++)
+        pivot_category_create_leaf (
+          d->root, pivot_value_new_var_value (var, &values[j]));
     }
+}
 
+static void
+output_report (const struct means *cmd,  int iact_idx,
+              const struct mtable *mt)
+{
+  struct pivot_table *table = pivot_table_create (N_("Report"));
+  table->omit_empty = true;
 
-  for (i = 0; i < n_cats; ++i)
-    {
-      int v, dv;
-      const struct ccase *c =
-       categoricals_get_case_by_category_real (table->cats, iact_idx, i);
-
-      for (dv = 0; dv < table->n_dep_vars; ++dv)
-       {
-         tab_text (t, 0,
-                   heading_rows + dv * n_cats,
-                   TAB_RIGHT | TAT_TITLE,
-                   var_to_string (table->dep_vars[dv])
-                   );
-
-         if ( dv > 0)
-           tab_hline (t, TAL_1, 0, nc - 1, heading_rows + dv * n_cats);
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  for (int i = 0; i < cmd->n_cells; ++i)
+    pivot_category_create_leaf (
+      statistics->root, pivot_value_new_text (cell_spec[cmd->cells[i]].title));
 
-         for (v = 0; v < iact->n_vars; ++v)
-           {
-             const struct variable *var = iact->vars[v];
-             const union value *val = case_data (c, var);
-             struct string str;
-             ds_init_empty (&str);
-             var_append_value_name (var, val, &str);
+  const struct interaction *iact = mt->interactions[iact_idx];
+  create_interaction_dimensions (table, mt->cats, iact);
 
-             tab_text (t, 1 + v, heading_rows + dv * n_cats + i,
-                       TAB_RIGHT | TAT_TITLE, ds_cstr (&str));
+  struct pivot_dimension *dep_dim = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-             ds_destroy (&str);
-           }
-       }
-    }
+  size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
 
-  for (grp = 0; grp < n_cats; ++grp)
+  size_t n_cats = categoricals_n_count (mt->cats, iact_idx);
+  for (size_t v = 0; v < mt->n_dep_vars; ++v)
     {
-      int dv;
-      struct per_cat_data *per_cat_data =
-       categoricals_get_user_data_by_category_real (table->cats, iact_idx, grp);
-
-      for (dv = 0; dv < table->n_dep_vars; ++dv)
-       {
-         const struct per_var_data *pvd = &per_cat_data->pvd[dv];
-         for (i = 0; i < cmd->n_cells; ++i)
-           {
-             const int csi = cmd->cells[i];
-             const struct cell_spec *cs = &cell_spec[csi];
-
-             double result = cs->sd (pvd, pvd->cell_stats[i]);
-
-             tab_double (t, heading_columns + i,
-                         heading_rows + grp + dv * n_cats,
-                         0, result, NULL, RC_OTHER);
-           }
-       }
+      indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
+        dep_dim->root, pivot_value_new_variable (mt->dep_vars[v]));
+
+      for (size_t i = 0; i < n_cats; ++i)
+        {
+          for (size_t j = 0; j < iact->n_vars; j++)
+            {
+              int idx = categoricals_get_value_index_by_category_real (
+                mt->cats, iact_idx, i, j);
+              indexes[table->n_dimensions - 2 - j] = idx;
+            }
+
+          struct per_cat_data *per_cat_data
+            = categoricals_get_user_data_by_category_real (
+              mt->cats, iact_idx, i);
+
+          const struct per_var_data *pvd = &per_cat_data->pvd[v];
+          for (int stat_idx = 0; stat_idx < cmd->n_cells; ++stat_idx)
+            {
+              indexes[0] = stat_idx;
+              const int csi = cmd->cells[stat_idx];
+              const struct cell_spec *cs = &cell_spec[csi];
+
+              double result = cs->sd (pvd, pvd->cell_stats[stat_idx]);
+              pivot_table_put (table, indexes, table->n_dimensions,
+                               pivot_value_new_number (result));
+            }
+        }
     }
+  free (indexes);
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
+
index 7bb87f92f299eddc5c07741b2e1e9ea1e3db6554..0f1ecd29482f542c592ccd743c50bd186016b816 100644 (file)
 #include "libpspp/str.h"
 #include "libpspp/misc.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -301,157 +302,85 @@ median_execute (const struct dataset *ds,
 static void
 show_frequencies (const struct n_sample_test *nst, const struct results *results,  int n_vals, const struct dictionary *dict)
 {
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-  int i;
-  int v;
-
-  const int row_headers = 2;
-  const int column_headers = 2;
-  const int nc = row_headers + n_vals;
-  const int nr = column_headers + nst->n_vars * 2;
-
-  struct tab_table *table = tab_create (nc, nr);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Frequencies"));
-
-  /* Box around the table and vertical lines inside*/
-  tab_box (table, TAL_2, TAL_2, -1, TAL_1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  tab_joint_text (table,
-                 row_headers, 0, row_headers + n_vals - 1, 0,
-                 TAT_TITLE | TAB_CENTER, var_to_string (nst->indep_var));
-
-
-  tab_hline (table, TAL_1, row_headers, tab_nc (table) - 1, 1);
-
-
-  for (i = 0; i < n_vals; ++i)
-    {
-      const struct results *rs = results + 0;
-      struct string label;
-      ds_init_empty (&label);
-
-      var_append_value_name (nst->indep_var, &rs->sorted_array[i]->val,
-                           &label);
-
-      tab_text (table, row_headers + i, 1,
-               TAT_TITLE | TAB_LEFT, ds_cstr (&label));
-
-      ds_destroy (&label);
-    }
-
-  for (v = 0; v < nst->n_vars; ++v)
+  struct pivot_table *table = pivot_table_create (N_("Frequencies"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
+
+  struct pivot_dimension *indep = pivot_dimension_create__ (
+    table, PIVOT_AXIS_COLUMN, pivot_value_new_variable (nst->indep_var));
+  indep->root->show_label = true;
+  for (int i = 0; i < n_vals; ++i)
+    pivot_category_create_leaf_rc (
+      indep->root, pivot_value_new_var_value (
+        nst->indep_var, &results->sorted_array[i]->val), PIVOT_RC_COUNT);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("> Median"), N_("≤ Median"));
+
+  struct pivot_dimension *dep = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
+
+  for (int v = 0; v < nst->n_vars; ++v)
     {
       const struct results *rs = &results[v];
-      tab_text (table,  0, column_headers + v * 2,
-               TAT_TITLE | TAB_LEFT, var_to_string (rs->var) );
-
-      tab_text (table,  1, column_headers + v * 2,
-               TAT_TITLE | TAB_LEFT, _("> Median") );
-
-      tab_text (table,  1, column_headers + v * 2 + 1,
-               TAT_TITLE | TAB_LEFT, _("≤ Median") );
 
-      if ( v > 0)
-       tab_hline (table, TAL_1, 0, tab_nc (table) - 1, column_headers + v * 2);
-    }
-
-  for (v = 0; v < nst->n_vars; ++v)
-    {
-      int i;
-      const struct results *rs = &results[v];
+      int dep_idx = pivot_category_create_leaf (
+        dep->root, pivot_value_new_variable (rs->var));
 
-      for (i = 0; i < n_vals; ++i)
+      for (int indep_idx = 0; indep_idx < n_vals; indep_idx++)
        {
-         const struct val_node *vn = rs->sorted_array[i];
-         tab_double (table, row_headers + i, column_headers + v * 2,
-                     0, vn->gt, NULL, RC_WEIGHT);
-
-         tab_double (table, row_headers + i, column_headers + v * 2 + 1,
-                     0, vn->le, NULL, RC_WEIGHT);
+         const struct val_node *vn = rs->sorted_array[indep_idx];
+          pivot_table_put3 (table, indep_idx, 0, dep_idx,
+                            pivot_value_new_number (vn->gt));
+          pivot_table_put3 (table, indep_idx, 1, dep_idx,
+                            pivot_value_new_number (vn->le));
        }
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
-
 static void
 show_test_statistics (const struct n_sample_test *nst,
                      const struct results *results,
                      int n_vals,
                      const struct dictionary *dict)
 {
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-  int v;
-
-  const int row_headers = 1;
-  const int column_headers = 1;
-  const int nc = row_headers + 5;
-  const int nr = column_headers + nst->n_vars;
-
-  struct tab_table *table = tab_create (nc, nr);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Test Statistics"));
-
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-  tab_box (table, TAL_2, TAL_2, -1, TAL_1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Median"),
+                          N_("Chi-Square"), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_COUNT,
+                          N_("Asymp. Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  tab_text (table, row_headers + 0, 0,
-           TAT_TITLE | TAB_CENTER, _("N"));
-
-  tab_text (table, row_headers + 1, 0,
-           TAT_TITLE | TAB_CENTER, _("Median"));
-
-  tab_text (table, row_headers + 2, 0,
-           TAT_TITLE | TAB_CENTER, _("Chi-Square"));
-
-  tab_text (table, row_headers + 3, 0,
-           TAT_TITLE | TAB_CENTER, _("df"));
-
-  tab_text (table, row_headers + 4, 0,
-           TAT_TITLE | TAB_CENTER, _("Asymp. Sig."));
-
-
-  for (v = 0; v < nst->n_vars; ++v)
+  for (int v = 0; v < nst->n_vars; ++v)
     {
       double df = n_vals - 1;
       const struct results *rs = &results[v];
-      tab_text (table,  0, column_headers + v,
-               TAT_TITLE | TAB_LEFT, var_to_string (rs->var));
-
-
-      tab_double (table, row_headers + 0, column_headers + v,
-                 0, rs->n, NULL, RC_WEIGHT);
-
-      tab_double (table, row_headers + 1, column_headers + v,
-                 0, rs->median, NULL, RC_OTHER);
-
-      tab_double (table, row_headers + 2, column_headers + v,
-                 0, rs->chisq, NULL, RC_OTHER);
-
-      tab_double (table, row_headers + 3, column_headers + v,
-                 0, df, NULL, RC_WEIGHT);
 
-      tab_double (table, row_headers + 4, column_headers + v,
-                 0, gsl_cdf_chisq_Q (rs->chisq, df), NULL, RC_PVALUE);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (rs->var));
+
+      double entries[] = {
+        rs->n,
+        rs->median,
+        rs->chisq,
+        df,
+        gsl_cdf_chisq_Q (rs->chisq, df),
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        {
+          struct pivot_value *value
+            = pivot_value_new_number (entries[i]);
+          if (i == 1)
+            value->numeric.format = *var_get_print_format (rs->var);
+          pivot_table_put2 (table, i, var_idx, value);
+        }
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index 332486adc8debc2626a5565d09971eb4d4c9115e..e45879565bee88d38cffb18fa25f990f48a87e86 100644 (file)
 #include "data/format.h"
 #include "data/variable.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -91,87 +92,42 @@ npar_summary_calc_descriptives (struct descriptives *desc,
 void
 do_summary_box (const struct descriptives *desc,
                const struct variable *const *vv,
-               int n_vars)
+               int n_vars,
+                const struct fmt_spec *wfmt)
 {
-  int v;
-  bool quartiles = false;
+  if (!desc)
+    return;
 
-  int col;
-  int columns = 1 ;
-  struct tab_table *table ;
+  struct pivot_table *table = pivot_table_create (
+    N_("Descriptive Statistics"));
+  pivot_table_set_weight_format (table, wfmt);
 
-  if ( desc ) columns += 5;
-  if ( quartiles ) columns += 3;
+  pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("N"), PIVOT_RC_COUNT,
+    N_("Mean"), PIVOT_RC_OTHER,
+    N_("Std. Deviation"), PIVOT_RC_OTHER,
+    N_("Minimum"), N_("Maximum"));
 
-  table = tab_create (columns, 2 + n_vars);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
 
-
-  tab_title (table, _("Descriptive Statistics"));
-
-  tab_headers (table, 1, 0, 1, 0);
-
-  tab_box (table, TAL_1, TAL_1, -1, TAL_1,
-          0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, 2);
-  tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
-
-  col = 1;
-  if ( desc )
+  for (int v = 0; v < n_vars; ++v)
     {
-      tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER,
-                     _("N"));
-      col++;
-      tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER,
-                     _("Mean"));
-      col++;
-      tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER,
-                     _("Std. Deviation"));
-      col++;
-      tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER,
-                     _("Minimum"));
-      col++;
-      tab_joint_text (table, col, 0, col, 1, TAT_TITLE | TAB_CENTER,
-                     _("Maximum"));
-      col++;
-    }
+      const struct variable *var = vv[v];
 
-  if ( quartiles )
-    {
-      tab_joint_text (table, col, 0, col + 2, 0, TAT_TITLE | TAB_CENTER,
-                     _("Percentiles"));
-      tab_hline (table, TAL_1, col, col + 2, 1);
-
-      tab_text (table, col, 1, TAT_TITLE | TAB_CENTER,
-               _("25th"));
-      col++;
-      tab_text (table, col, 1, TAT_TITLE | TAB_CENTER,
-               _("50th (Median)"));
-      col++;
-      tab_text (table, col, 1, TAT_TITLE | TAB_CENTER,
-               _("75th"));
-      col++;
-    }
+      int row = pivot_category_create_leaf (variables->root,
+                                            pivot_value_new_variable (var));
 
+      double entries[] = { desc[v].n, desc[v].mean, desc[v].std_dev };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, row, pivot_value_new_number (entries[j]));
 
-  for ( v = 0 ; v < n_vars ; ++v )
-    {
-      const struct variable *var = vv[v];
-      const struct fmt_spec *fmt = var_get_print_format (var);
-
-      tab_text (table, 0, 2 + v, 0, var_to_string (var));
-
-      col = 1;
-      if (desc != NULL)
-        {
-          tab_double (table, col++, 2 + v, 0, desc[v].n, fmt, RC_OTHER);
-          tab_double (table, col++, 2 + v, 0, desc[v].mean, fmt, RC_OTHER);
-          tab_double (table, col++, 2 + v, 0, desc[v].std_dev, fmt, RC_OTHER);
-          tab_double (table, col++, 2 + v, 0, desc[v].min, fmt, RC_OTHER);
-          tab_double (table, col++, 2 + v, 0, desc[v].max, fmt, RC_OTHER);
-        }
+      union value extrema[2] = { { .f = desc[v].min }, { .f = desc[v].max } };
+      for (size_t j = 0; j < 2; j++)
+        pivot_table_put2 (table, 3 + j, row,
+                          pivot_value_new_var_value (var, &extrema[j]));
     }
 
-
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index a78d1b7e2a22c7241f84b37d74b4fe85100b401d..3955bd64119d054ff6318b7b97849fce14b5edb0 100644 (file)
@@ -22,6 +22,7 @@
 struct variable ;
 struct casereader ;
 struct dictionary;
+struct fmt_spec;
 
 struct descriptives
 {
@@ -35,7 +36,8 @@ struct descriptives
 void
 do_summary_box (const struct descriptives *desc,
                const struct variable *const *vv,
-               int n_vars);
+               int n_vars,
+                const struct fmt_spec *wfmt);
 
 void npar_summary_calc_descriptives (struct descriptives *desc,
                                     struct casereader *input,
index 071a02ee16a53ddd243e8197d41486b1c4f085cb..1d369eca44a6b091451762c1dd16a61ce1ca576f 100644 (file)
@@ -553,7 +553,8 @@ npar_execute (struct casereader *input,
 
   if ( (specs->descriptives || specs->quartiles)
        && !taint_has_tainted_successor (casereader_get_taint (input)) )
-    do_summary_box (summary_descriptives, specs->vv, specs->n_vars );
+    do_summary_box (summary_descriptives, specs->vv, specs->n_vars,
+                    dict_get_weight_format (dataset_dict (ds)));
 
   free (summary_descriptives);
   casereader_destroy (input);
index d0a6e5d7860180571d5fcab9773fe70ddeaacdb8..ef20cbafbf1135810df8bf1bfdd0d5dbe714aa46 100644 (file)
@@ -44,7 +44,7 @@
 #include "math/covariance.h"
 #include "math/levene.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -143,6 +143,7 @@ struct oneway_spec
 
   /* The weight variable */
   const struct variable *wv;
+  const struct fmt_spec *wfmt;
 
   /* The confidence level for multiple comparisons */
   double alpha;
@@ -429,6 +430,7 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds)
   oneway.missing_type = MISS_ANALYSIS;
   oneway.exclude = MV_ANY;
   oneway.wv = dict_get_weight (dict);
+  oneway.wfmt = dict_get_weight_format (dict);
   oneway.alpha = 0.05;
   oneway.posthoc = NULL;
   oneway.n_posthoc = 0;
@@ -963,306 +965,220 @@ output_oneway (const struct oneway_spec *cmd, struct oneway_workspace *ws)
 static void
 show_anova_table (const struct oneway_spec *cmd, const struct oneway_workspace *ws)
 {
-  size_t i;
-  int n_cols =7;
-  size_t n_rows = cmd->n_vars * 3 + 1;
+  struct pivot_table *table = pivot_table_create (N_("ANOVA"));
 
-  struct tab_table *t = tab_create (n_cols, n_rows);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Sum of Squares"), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_INTEGER,
+                          N_("Mean Square"), PIVOT_RC_OTHER,
+                          N_("F"), PIVOT_RC_OTHER,
+                          N_("Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_headers (t, 2, 0, 1, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Type"),
+                          N_("Between Groups"), N_("Within Groups"),
+                          N_("Total"));
 
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1 );
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-  tab_vline (t, TAL_0, 1, 0, 0);
-
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Sum of Squares"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Mean Square"));
-  tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("F"));
-  tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
-
-
-  for (i = 0; i < cmd->n_vars; ++i)
+  for (size_t i = 0; i < cmd->n_vars; ++i)
     {
-      double n;
-      double df1, df2;
-      double msa;
-      const char *s = var_to_string (cmd->vars[i]);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (cmd->vars[i]));
+
       const struct per_var_ws *pvw = &ws->vws[i];
 
+      double n;
       moments1_calculate (ws->dd_total[i]->mom, &n, NULL, NULL, NULL, NULL);
 
-      df1 = pvw->n_groups - 1;
-      df2 = n - pvw->n_groups;
-      msa = pvw->ssa / df1;
-
-      tab_text (t, 0, i * 3 + 1, TAB_LEFT | TAT_TITLE, s);
-      tab_text (t, 1, i * 3 + 1, TAB_LEFT | TAT_TITLE, _("Between Groups"));
-      tab_text (t, 1, i * 3 + 2, TAB_LEFT | TAT_TITLE, _("Within Groups"));
-      tab_text (t, 1, i * 3 + 3, TAB_LEFT | TAT_TITLE, _("Total"));
-
-      if (i > 0)
-       tab_hline (t, TAL_1, 0, n_cols - 1, i * 3 + 1);
-
-
-      /* Sums of Squares */
-      tab_double (t, 2, i * 3 + 1, 0, pvw->ssa, NULL, RC_OTHER);
-      tab_double (t, 2, i * 3 + 3, 0, pvw->sst, NULL, RC_OTHER);
-      tab_double (t, 2, i * 3 + 2, 0, pvw->sse, NULL, RC_OTHER);
-
-
-      /* Degrees of freedom */
-      tab_double (t, 3, i * 3 + 1, 0, df1, NULL, RC_INTEGER);
-      tab_double (t, 3, i * 3 + 2, 0, df2,  NULL, RC_INTEGER);
-      tab_double (t, 3, i * 3 + 3, 0, n - 1, NULL, RC_INTEGER);
+      double df1 = pvw->n_groups - 1;
+      double df2 = n - pvw->n_groups;
+      double msa = pvw->ssa / df1;
+      double F = msa / pvw->mse ;
 
-      /* Mean Squares */
-      tab_double (t, 4, i * 3 + 1, TAB_RIGHT, msa, NULL, RC_OTHER);
-      tab_double (t, 4, i * 3 + 2, TAB_RIGHT, pvw->mse, NULL, RC_OTHER);
-
-      {
-       const double F = msa / pvw->mse ;
-
-       /* The F value */
-       tab_double (t, 5, i * 3 + 1, 0,  F, NULL, RC_OTHER);
-
-       /* The significance */
-       tab_double (t, 6, i * 3 + 1, 0, gsl_cdf_fdist_Q (F, df1, df2), NULL, RC_PVALUE);
-      }
+      struct entry
+        {
+          int stat_idx;
+          int type_idx;
+          double x;
+        }
+      entries[] = {
+        /* Sums of Squares. */
+        { 0, 0, pvw->ssa },
+        { 0, 1, pvw->sse },
+        { 0, 2, pvw->sst },
+        /* Degrees of Freedom. */
+        { 1, 0, df1 },
+        { 1, 1, df2 },
+        { 1, 2, n - 1 },
+        /* Mean Squares. */
+        { 2, 0, msa },
+        { 2, 1, pvw->mse },
+        /* F. */
+        { 3, 0, F },
+        /* Significance. */
+        { 4, 0, gsl_cdf_fdist_Q (F, df1, df2) },
+      };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        {
+          const struct entry *e = &entries[j];
+          pivot_table_put3 (table, e->stat_idx, e->type_idx, var_idx,
+                            pivot_value_new_number (e->x));
+        }
     }
 
-  tab_title (t, _("ANOVA"));
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
-
 /* Show the descriptives table */
 static void
 show_descriptives (const struct oneway_spec *cmd, const struct oneway_workspace *ws)
 {
-  size_t v;
-  int n_cols = 10;
-  struct tab_table *t;
-  int row;
-
-  const double confidence = 0.95;
-  const double q = (1.0 - confidence) / 2.0;
-
-  const struct fmt_spec *wfmt = cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
-
-  int n_rows = 2;
-
-  for (v = 0; v < cmd->n_vars; ++v)
-    n_rows += ws->actual_number_of_groups + 1;
-
-  t = tab_create (n_cols, n_rows);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 2, 0, 2, 0);
-
-  /* Put a frame around the entire box, and vertical lines inside */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
-
-  /* Underline headers */
-  tab_hline (t, TAL_2, 0, n_cols - 1, 2);
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-
-  tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Mean"));
-  tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("Std. Error"));
+  if (!cmd->n_vars)
+    return;
+  const struct categoricals *cats = covariance_get_categoricals (
+    ws->vws[0].cov);
 
+  struct pivot_table *table = pivot_table_create (N_("Descriptives"));
+  pivot_table_set_weight_format (table, cmd->wfmt);
 
-  tab_vline (t, TAL_0, 7, 0, 0);
-  tab_hline (t, TAL_1, 6, 7, 1);
-  tab_joint_text_format (t, 6, 0, 7, 0, TAB_CENTER | TAT_TITLE,
-                         _("%g%% Confidence Interval for Mean"),
-                         confidence*100.0);
-
-  tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound"));
-  tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound"));
-
-  tab_text (t, 8, 1, TAB_CENTER | TAT_TITLE, _("Minimum"));
-  tab_text (t, 9, 1, TAB_CENTER | TAT_TITLE, _("Maximum"));
+  const double confidence = 0.95;
 
-  tab_title (t, _("Descriptives"));
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("N"), PIVOT_RC_COUNT, N_("Mean"), N_("Std. Deviation"),
+    N_("Std. Error"));
+  struct pivot_category *interval = pivot_category_create_group__ (
+    statistics->root,
+    pivot_value_new_text_format (N_("%g%% Confidence Interval for Mean"),
+                                 confidence * 100.0));
+  pivot_category_create_leaves (interval, N_("Lower Bound"),
+                                N_("Upper Bound"));
+  pivot_category_create_leaves (statistics->root,
+                                N_("Minimum"), N_("Maximum"));
+
+  struct pivot_dimension *indep_var = pivot_dimension_create__ (
+    table, PIVOT_AXIS_ROW, pivot_value_new_variable (cmd->indep_var));
+  indep_var->root->show_label = true;
+  size_t n;
+  union value *values = categoricals_get_var_values (cats, cmd->indep_var, &n);
+  for (size_t j = 0; j < n; j++)
+    pivot_category_create_leaf (
+      indep_var->root, pivot_value_new_var_value (cmd->indep_var, &values[j]));
+  pivot_category_create_leaf (
+    indep_var->root, pivot_value_new_text_format (N_("Total")));
+
+  struct pivot_dimension *dep_var = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variable"));
 
-  row = 2;
-  for (v = 0; v < cmd->n_vars; ++v)
+  const double q = (1.0 - confidence) / 2.0;
+  for (int v = 0; v < cmd->n_vars; ++v)
     {
-      const char *s = var_to_string (cmd->vars[v]);
-      const struct fmt_spec *fmt = var_get_print_format (cmd->vars[v]);
-
-      int count = 0;
+      int dep_var_idx = pivot_category_create_leaf (
+        dep_var->root, pivot_value_new_variable (cmd->vars[v]));
 
       struct per_var_ws *pvw = &ws->vws[v];
       const struct categoricals *cats = covariance_get_categoricals (pvw->cov);
 
-      tab_text (t, 0, row, TAB_LEFT | TAT_TITLE, s);
-      if ( v > 0)
-       tab_hline (t, TAL_1, 0, n_cols - 1, row);
-
+      int count;
       for (count = 0; count < categoricals_n_total (cats); ++count)
        {
-         double T;
-         double n, mean, variance;
-         double std_dev, std_error ;
-
-         struct string vstr;
-
-         const struct ccase *gcc = categoricals_get_case_by_category (cats, count);
-         const struct descriptive_data *dd = categoricals_get_user_data_by_category (cats, count);
+         const struct descriptive_data *dd
+            = categoricals_get_user_data_by_category (cats, count);
 
+         double n, mean, variance;
          moments1_calculate (dd->mom, &n, &mean, &variance, NULL, NULL);
 
-         std_dev = sqrt (variance);
-         std_error = std_dev / sqrt (n) ;
-
-         ds_init_empty (&vstr);
-
-         var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr);
-
-         tab_text (t, 1, row + count,
-                   TAB_LEFT | TAT_TITLE,
-                   ds_cstr (&vstr));
-
-         ds_destroy (&vstr);
-
-         /* Now fill in the numbers ... */
-
-         tab_double (t, 2, row + count, 0, n, NULL, RC_WEIGHT);
-
-         tab_double (t, 3, row + count, 0, mean, NULL, RC_OTHER);
-
-         tab_double (t, 4, row + count, 0, std_dev, NULL, RC_OTHER);
-
-
-         tab_double (t, 5, row + count, 0, std_error, NULL, RC_OTHER);
-
-         /* Now the confidence interval */
-
-         T = gsl_cdf_tdist_Qinv (q, n - 1);
-
-         tab_double (t, 6, row + count, 0,
-                     mean - T * std_error, NULL, RC_OTHER);
-
-         tab_double (t, 7, row + count, 0,
-                     mean + T * std_error, NULL, RC_OTHER);
-
-         /* Min and Max */
-
-         tab_double (t, 8, row + count, 0,  dd->minimum, fmt, RC_OTHER);
-         tab_double (t, 9, row + count, 0,  dd->maximum, fmt, RC_OTHER);
+         double std_dev = sqrt (variance);
+         double std_error = std_dev / sqrt (n) ;
+         double T = gsl_cdf_tdist_Qinv (q, n - 1);
+
+          double entries[] = {
+            n,
+            mean,
+            std_dev,
+            std_error,
+            mean - T * std_error,
+            mean + T * std_error,
+            dd->minimum,
+            dd->maximum,
+          };
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            pivot_table_put3 (table, i, count, dep_var_idx,
+                              pivot_value_new_number (entries[i]));
        }
 
       if (categoricals_is_complete (cats))
-      {
-       double T;
-       double n, mean, variance;
-       double std_dev;
-       double std_error;
-
-       moments1_calculate (ws->dd_total[v]->mom, &n, &mean, &variance, NULL, NULL);
-
-       std_dev = sqrt (variance);
-       std_error = std_dev / sqrt (n) ;
-
-       tab_text (t, 1, row + count,
-                 TAB_LEFT | TAT_TITLE, _("Total"));
-
-       tab_double (t, 2, row + count, 0, n, NULL, RC_WEIGHT);
-
-       tab_double (t, 3, row + count, 0, mean, NULL, RC_OTHER);
-
-       tab_double (t, 4, row + count, 0, std_dev, NULL, RC_OTHER);
-
-       tab_double (t, 5, row + count, 0, std_error, NULL, RC_OTHER);
-
-       /* Now the confidence interval */
-       T = gsl_cdf_tdist_Qinv (q, n - 1);
-
-       tab_double (t, 6, row + count, 0,
-                   mean - T * std_error, NULL, RC_OTHER);
-
-       tab_double (t, 7, row + count, 0,
-                   mean + T * std_error, NULL, RC_OTHER);
-
-
-       /* Min and Max */
-       tab_double (t, 8, row + count, 0,  ws->dd_total[v]->minimum, fmt, RC_OTHER);
-       tab_double (t, 9, row + count, 0,  ws->dd_total[v]->maximum, fmt, RC_OTHER);
-      }
-
-      row += categoricals_n_total (cats) + 1;
+        {
+          double n, mean, variance;
+          moments1_calculate (ws->dd_total[v]->mom, &n, &mean, &variance,
+                              NULL, NULL);
+
+          double std_dev = sqrt (variance);
+          double std_error = std_dev / sqrt (n) ;
+          double T = gsl_cdf_tdist_Qinv (q, n - 1);
+
+          double entries[] = {
+            n,
+            mean,
+            std_dev,
+            std_error,
+            mean - T * std_error,
+            mean + T * std_error,
+            ws->dd_total[v]->minimum,
+            ws->dd_total[v]->maximum,
+          };
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            pivot_table_put3 (table, i, count, dep_var_idx,
+                              pivot_value_new_number (entries[i]));
+        }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 /* Show the homogeneity table */
 static void
 show_homogeneity (const struct oneway_spec *cmd, const struct oneway_workspace *ws)
 {
-  size_t v;
-  int n_cols = 5;
-  size_t n_rows = cmd->n_vars + 1;
-
-  struct tab_table *t = tab_create (n_cols, n_rows);
-  tab_headers (t, 1, 0, 1, 0);
-
-  /* Put a frame around the entire box, and vertical lines inside */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
+  struct pivot_table *table = pivot_table_create (
+    N_("Test of Homogeneity of Variances"));
 
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Levene Statistic"), PIVOT_RC_OTHER,
+                          N_("df1"), PIVOT_RC_INTEGER,
+                          N_("df2"), PIVOT_RC_INTEGER,
+                          N_("Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1);
-  tab_vline (t, TAL_2, 1, 0, n_rows - 1);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Levene Statistic"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("df1"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df2"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
-
-  tab_title (t, _("Test of Homogeneity of Variances"));
-
-  for (v = 0; v < cmd->n_vars; ++v)
+  for (int v = 0; v < cmd->n_vars; ++v)
     {
-      double n;
-      const struct per_var_ws *pvw = &ws->vws[v];
-      double F = levene_calculate (pvw->nl);
-
-      const struct variable *var = cmd->vars[v];
-      const char *s = var_to_string (var);
-      double df1, df2;
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (cmd->vars[v]));
 
+      double n;
       moments1_calculate (ws->dd_total[v]->mom, &n, NULL, NULL, NULL, NULL);
 
-      df1 = pvw->n_groups - 1;
-      df2 = n - pvw->n_groups;
-
-      tab_text (t, 0, v + 1, TAB_LEFT | TAT_TITLE, s);
-
-      tab_double (t, 1, v + 1, TAB_RIGHT, F, NULL, RC_OTHER);
-      tab_double (t, 2, v + 1, TAB_RIGHT, df1, NULL, RC_INTEGER);
-      tab_double (t, 3, v + 1, TAB_RIGHT, df2, NULL, RC_INTEGER);
+      const struct per_var_ws *pvw = &ws->vws[v];
+      double df1 = pvw->n_groups - 1;
+      double df2 = n - pvw->n_groups;
+      double F = levene_calculate (pvw->nl);
 
-      /* Now the significance */
-      tab_double (t, 4, v + 1, TAB_RIGHT, gsl_cdf_fdist_Q (F, df1, df2), NULL, RC_PVALUE);
+      double entries[] =
+        {
+          F,
+          df1,
+          df2,
+          gsl_cdf_fdist_Q (F, df1, df2),
+        };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, var_idx,
+                          pivot_value_new_number (entries[i]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
@@ -1270,155 +1186,87 @@ show_homogeneity (const struct oneway_spec *cmd, const struct oneway_workspace *
 static void
 show_contrast_coeffs (const struct oneway_spec *cmd, const struct oneway_workspace *ws)
 {
-  int c_num = 0;
-  struct ll *cli;
-
-  int n_contrasts = ll_count (&cmd->contrast_list);
-  int n_cols = 2 + ws->actual_number_of_groups;
-  int n_rows = 2 + n_contrasts;
-
-  struct tab_table *t;
-
-  const struct covariance *cov = ws->vws[0].cov ;
-
-  t = tab_create (n_cols, n_rows);
-  tab_headers (t, 2, 0, 2, 0);
+  struct pivot_table *table = pivot_table_create (N_("Contrast Coefficients"));
 
-  /* Put a frame around the entire box, and vertical lines inside */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
+  struct pivot_dimension *indep_var = pivot_dimension_create__ (
+    table, PIVOT_AXIS_COLUMN, pivot_value_new_variable (cmd->indep_var));
+  indep_var->root->show_label = true;
 
-  tab_box (t,
-          -1, -1,
-          TAL_0, TAL_0,
-          2, 0,
-          n_cols - 1, 0);
+  struct pivot_dimension *contrast = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Contrast"));
+  contrast->root->show_label = true;
 
-  tab_box (t,
-          -1, -1,
-          TAL_0, TAL_0,
-          0, 0,
-          1, 1);
+  const struct covariance *cov = ws->vws[0].cov;
 
-  tab_hline (t, TAL_1, 2, n_cols - 1, 1);
-  tab_hline (t, TAL_2, 0, n_cols - 1, 2);
-
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-
-  tab_title (t, _("Contrast Coefficients"));
-
-  tab_text (t,  0, 2, TAB_LEFT | TAT_TITLE, _("Contrast"));
-
-
-  tab_joint_text (t, 2, 0, n_cols - 1, 0, TAB_CENTER | TAT_TITLE,
-                 var_to_string (cmd->indep_var));
-
-  for ( cli = ll_head (&cmd->contrast_list);
-       cli != ll_null (&cmd->contrast_list);
-       cli = ll_next (cli))
+  const struct contrasts_node *cn;
+  int c_num = 1;
+  ll_for_each (cn, struct contrasts_node, ll, &cmd->contrast_list)
     {
-      int count = 0;
-      struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll);
-      struct ll *coeffi ;
+      int contrast_idx = pivot_category_create_leaf (
+        contrast->root, pivot_value_new_integer (c_num++));
 
-      tab_text_format (t, 1, c_num + 2, TAB_CENTER, "%d", c_num + 1);
-
-      for (coeffi = ll_head (&cn->coefficient_list);
-          coeffi != ll_null (&cn->coefficient_list);
-          ++count, coeffi = ll_next (coeffi))
+      const struct coeff_node *coeffn;
+      int indep_idx = 0;
+      ll_for_each (coeffn, struct coeff_node, ll, &cn->coefficient_list)
        {
          const struct categoricals *cats = covariance_get_categoricals (cov);
-         const struct ccase *gcc = categoricals_get_case_by_category (cats, count);
-         struct coeff_node *coeffn = ll_data (coeffi, struct coeff_node, ll);
-         struct string vstr;
-
-         ds_init_empty (&vstr);
-
-         var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr);
+         const struct ccase *gcc = categoricals_get_case_by_category (
+            cats, indep_idx);
 
-         tab_text (t, count + 2, 1, TAB_CENTER | TAT_TITLE, ds_cstr (&vstr));
+          if (!contrast_idx)
+            pivot_category_create_leaf (
+              indep_var->root, pivot_value_new_var_value (
+                cmd->indep_var, case_data (gcc, cmd->indep_var)));
 
-         ds_destroy (&vstr);
-
-         tab_text_format (t, count + 2, c_num + 2, TAB_RIGHT, "%.*g",
-                           DBL_DIG + 1, coeffn->coeff);
+          pivot_table_put2 (table, indep_idx++, contrast_idx,
+                            pivot_value_new_integer (coeffn->coeff));
        }
-      ++c_num;
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
-
 /* Show the results of the contrast tests */
 static void
 show_contrast_tests (const struct oneway_spec *cmd, const struct oneway_workspace *ws)
 {
+  struct pivot_table *table = pivot_table_create (N_("Contrast Tests"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Value of Contrast"), PIVOT_RC_OTHER,
+                          N_("Std. Error"), PIVOT_RC_OTHER,
+                          N_("t"), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_OTHER,
+                          N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *contrasts = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Contrast"));
+  contrasts->root->show_label = true;
   int n_contrasts = ll_count (&cmd->contrast_list);
-  size_t v;
-  int n_cols = 8;
-  size_t n_rows = 1 + cmd->n_vars * 2 * n_contrasts;
-
-  struct tab_table *t;
+  for (int i = 1; i <= n_contrasts; i++)
+    pivot_category_create_leaf (contrasts->root, pivot_value_new_integer (i));
 
-  t = tab_create (n_cols, n_rows);
-  tab_headers (t, 3, 0, 1, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Assumption"),
+                          N_("Assume equal variances"),
+                          N_("Does not assume equal variances"));
 
-  /* Put a frame around the entire box, and vertical lines inside */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variable"));
 
-  tab_box (t,
-          -1, -1,
-          TAL_0, TAL_0,
-          0, 0,
-          2, 0);
-
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1);
-  tab_vline (t, TAL_2, 3, 0, n_rows - 1);
-
-  tab_title (t, _("Contrast Tests"));
-
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Contrast"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Value of Contrast"));
-  tab_text (t,  4, 0, TAB_CENTER | TAT_TITLE, _("Std. Error"));
-  tab_text (t,  5, 0, TAB_CENTER | TAT_TITLE, _("t"));
-  tab_text (t,  6, 0, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t,  7, 0, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
-
-  for (v = 0; v < cmd->n_vars; ++v)
+  for (int v = 0; v < cmd->n_vars; ++v)
     {
       const struct per_var_ws *pvw = &ws->vws[v];
       const struct categoricals *cats = covariance_get_categoricals (pvw->cov);
       if (!categoricals_is_complete (cats))
        continue;
-      struct ll *cli;
-      int i = 0;
-      int lines_per_variable = 2 * n_contrasts;
 
-      tab_text (t,  0, (v * lines_per_variable) + 1, TAB_LEFT | TAT_TITLE,
-               var_to_string (cmd->vars[v]));
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (cmd->vars[v]));
 
-      for ( cli = ll_head (&cmd->contrast_list);
-           cli != ll_null (&cmd->contrast_list);
-           ++i, cli = ll_next (cli))
+      struct contrasts_node *cn;
+      int contrast_idx = 0;
+      ll_for_each (cn, struct contrasts_node, ll, &cmd->contrast_list)
        {
-         struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll);
-         struct ll *coeffi ;
-         int ci = 0;
-         double contrast_value = 0.0;
-         double coef_msq = 0.0;
-
-         double T;
-         double std_error_contrast;
-         double df;
-         double sec_vneq = 0.0;
 
          /* Note: The calculation of the degrees of freedom in the
             "variances not equal" case is painfull!!
@@ -1431,254 +1279,174 @@ show_contrast_tests (const struct oneway_spec *cmd, const struct oneway_workspac
             }
          */
 
-         double df_denominator = 0.0;
-         double df_numerator = 0.0;
-
          double grand_n;
-         moments1_calculate (ws->dd_total[v]->mom, &grand_n, NULL, NULL, NULL, NULL);
-         df = grand_n - pvw->n_groups;
+         moments1_calculate (ws->dd_total[v]->mom, &grand_n, NULL, NULL,
+                              NULL, NULL);
+         double df = grand_n - pvw->n_groups;
 
-         if ( i == 0 )
+         double contrast_value = 0.0;
+         double coef_msq = 0.0;
+         double sec_vneq = 0.0;
+         double df_denominator = 0.0;
+         double df_numerator = 0.0;
+          struct coeff_node *coeffn;
+         int ci = 0;
+          ll_for_each (coeffn, struct coeff_node, ll, &cn->coefficient_list)
            {
-             tab_text (t,  1, (v * lines_per_variable) + i + 1,
-                       TAB_LEFT | TAT_TITLE,
-                       _("Assume equal variances"));
-
-             tab_text (t,  1, (v * lines_per_variable) + i + 1 + n_contrasts,
-                       TAB_LEFT | TAT_TITLE,
-                       _("Does not assume equal"));
-           }
-
-         tab_text_format (t,  2, (v * lines_per_variable) + i + 1,
-                           TAB_CENTER | TAT_TITLE, "%d", i + 1);
-
+             const struct descriptive_data *dd
+                = categoricals_get_user_data_by_category (cats, ci);
+             const double coef = coeffn->coeff;
 
-         tab_text_format (t,  2,
-                           (v * lines_per_variable) + i + 1 + n_contrasts,
-                           TAB_CENTER | TAT_TITLE, "%d", i + 1);
-
-         for (coeffi = ll_head (&cn->coefficient_list);
-              coeffi != ll_null (&cn->coefficient_list);
-              ++ci, coeffi = ll_next (coeffi))
-           {
              double n, mean, variance;
-             const struct descriptive_data *dd = categoricals_get_user_data_by_category (cats, ci);
-             struct coeff_node *cn = ll_data (coeffi, struct coeff_node, ll);
-             const double coef = cn->coeff;
-             double winv ;
-
              moments1_calculate (dd->mom, &n, &mean, &variance, NULL, NULL);
 
-             winv = variance / n;
-
+             double winv = variance / n;
              contrast_value += coef * mean;
+             coef_msq += pow2 (coef) / n;
+             sec_vneq += pow2 (coef) * variance / n;
+             df_numerator += pow2 (coef) * winv;
+             df_denominator += pow2(pow2 (coef) * winv) / (n - 1);
 
-             coef_msq += (pow2 (coef)) / n;
-
-             sec_vneq += (pow2 (coef)) * variance / n;
-
-             df_numerator += (pow2 (coef)) * winv;
-             df_denominator += pow2((pow2 (coef)) * winv) / (n - 1);
+              ci++;
            }
-
          sec_vneq = sqrt (sec_vneq);
-
          df_numerator = pow2 (df_numerator);
 
-         tab_double (t,  3, (v * lines_per_variable) + i + 1,
-                     TAB_RIGHT, contrast_value, NULL, RC_OTHER);
-
-         tab_double (t,  3, (v * lines_per_variable) + i + 1 +
-                     n_contrasts,
-                     TAB_RIGHT, contrast_value, NULL, RC_OTHER);
-
-         std_error_contrast = sqrt (pvw->mse * coef_msq);
-
-         /* Std. Error */
-         tab_double (t,  4, (v * lines_per_variable) + i + 1,
-                     TAB_RIGHT, std_error_contrast,
-                     NULL, RC_OTHER);
+         double std_error_contrast = sqrt (pvw->mse * coef_msq);
+         double T = fabs (contrast_value / std_error_contrast);
+         double T_ne = contrast_value / sec_vneq;
+         double df_ne = df_numerator / df_denominator;
+          double p_ne = gsl_cdf_tdist_P (T_ne, df_ne);
+          double q_ne = gsl_cdf_tdist_Q (T_ne, df_ne);
 
-         T = fabs (contrast_value / std_error_contrast);
-
-         /* T Statistic */
-
-         tab_double (t,  5, (v * lines_per_variable) + i + 1,
-                     TAB_RIGHT, T,
-                     NULL, RC_OTHER);
-
-
-         /* Degrees of Freedom */
-         tab_double (t,  6, (v * lines_per_variable) + i + 1,
-                    TAB_RIGHT,  df, NULL, RC_INTEGER);
-
-
-         /* Significance TWO TAILED !!*/
-         tab_double (t,  7, (v * lines_per_variable) + i + 1,
-                     TAB_RIGHT,  2 * gsl_cdf_tdist_Q (T, df),
-                     NULL, RC_PVALUE);
-
-         /* Now for the Variances NOT Equal case */
-
-         /* Std. Error */
-         tab_double (t,  4,
-                     (v * lines_per_variable) + i + 1 + n_contrasts,
-                     TAB_RIGHT, sec_vneq,
-                     NULL, RC_OTHER);
-
-         T = contrast_value / sec_vneq;
-         tab_double (t,  5,
-                     (v * lines_per_variable) + i + 1 + n_contrasts,
-                     TAB_RIGHT, T,
-                     NULL, RC_OTHER);
-
-         df = df_numerator / df_denominator;
-
-         tab_double (t,  6,
-                     (v * lines_per_variable) + i + 1 + n_contrasts,
-                     TAB_RIGHT, df,
-                     NULL, RC_OTHER);
-
-         {
-           double p = gsl_cdf_tdist_P (T, df);
-           double q = gsl_cdf_tdist_Q (T, df);
+          struct entry
+            {
+              int stat_idx;
+              int assumption_idx;
+              double x;
+            }
+          entries[] =
+            {
+              /* Assume equal. */
+              { 0, 0, contrast_value },
+              { 1, 0, std_error_contrast },
+              { 2, 0, T },
+              { 3, 0, df },
+              { 4, 0, 2 * gsl_cdf_tdist_Q (T, df) },
+              /* Do not assume equal. */
+              { 0, 1, contrast_value },
+              { 1, 1, sec_vneq },
+              { 2, 1, T_ne },
+              { 3, 1, df_ne },
+              { 4, 1, 2 * (T > 0 ? q_ne : p_ne) },
+            };
+
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            {
+              const struct entry *e = &entries[i];
+              pivot_table_put4 (
+                table, e->stat_idx, contrast_idx, e->assumption_idx, var_idx,
+                pivot_value_new_number (e->x));
+            }
 
-           /* The Significance */
-           tab_double (t, 7, (v * lines_per_variable) + i + 1 + n_contrasts,
-                       TAB_RIGHT,  2 * ((T > 0) ? q : p),
-                       NULL, RC_PVALUE);
-         }
+          contrast_idx++;
        }
-
-      if ( v > 0 )
-       tab_hline (t, TAL_1, 0, n_cols - 1, (v * lines_per_variable) + 1);
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
-
-
 static void
 show_comparisons (const struct oneway_spec *cmd, const struct oneway_workspace *ws, int v)
 {
-  const int n_cols = 8;
-  const int heading_rows = 2;
-  const int heading_cols = 3;
-
-  int p;
-  int r = heading_rows ;
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_user_text_nocopy (xasprintf (
+                                        _("Multiple Comparisons (%s)"),
+                                        var_to_string (cmd->vars[v]))));
+  table->omit_empty = true;
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("Mean Difference (I - J)"), PIVOT_RC_OTHER,
+    N_("Std. Error"), PIVOT_RC_OTHER,
+    N_("Sig."), PIVOT_RC_SIGNIFICANCE);
+  struct pivot_category *interval = pivot_category_create_group__ (
+    statistics->root,
+    pivot_value_new_text_format (N_("%g%% Confidence Interval"),
+                                 (1 - cmd->alpha) * 100.0));
+  pivot_category_create_leaves (interval,
+                                N_("Lower Bound"), PIVOT_RC_OTHER,
+                                N_("Upper Bound"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *j_family = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("(J) Family"));
+  j_family->root->show_label = true;
+
+  struct pivot_dimension *i_family = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("(J) Family"));
+  i_family->root->show_label = true;
 
   const struct per_var_ws *pvw = &ws->vws[v];
   const struct categoricals *cat = pvw->cat;
-  const int n_rows = heading_rows + cmd->n_posthoc * pvw->n_groups * (pvw->n_groups - 1);
-
-  struct tab_table *t = tab_create (n_cols, n_rows);
-
-  tab_headers (t, heading_cols, 0, heading_rows, 0);
-
-  /* Put a frame around the entire box, and vertical lines inside */
-  tab_box (t,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
-
-  tab_box (t,
-          -1, -1,
-          -1, TAL_1,
-          heading_cols, 0,
-          n_cols - 1, n_rows - 1);
-
-  tab_vline (t, TAL_2, heading_cols, 0, n_rows - 1);
-
-  tab_title (t, _("Multiple Comparisons (%s)"), var_to_string (cmd->vars[v]));
-
-  tab_text_format (t,  1, 1, TAB_LEFT | TAT_TITLE, _("(I) %s"), var_to_string (cmd->indep_var));
-  tab_text_format (t,  2, 1, TAB_LEFT | TAT_TITLE, _("(J) %s"), var_to_string (cmd->indep_var));
-  tab_text (t,  3, 0, TAB_CENTER | TAT_TITLE, _("Mean Difference"));
-  tab_text (t,  3, 1, TAB_CENTER | TAT_TITLE, _("(I - J)"));
-  tab_text (t,  4, 1, TAB_CENTER | TAT_TITLE, _("Std. Error"));
-  tab_text (t,  5, 1, TAB_CENTER | TAT_TITLE, _("Sig."));
-
-  tab_joint_text_format (t, 6, 0, 7, 0, TAB_CENTER | TAT_TITLE,
-                         _("%g%% Confidence Interval"),
-                         (1 - cmd->alpha) * 100.0);
-
-  tab_text (t,  6, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound"));
-  tab_text (t,  7, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound"));
+  for (int i = 0; i < pvw->n_groups; i++)
+    {
+      const struct ccase *gcc = categoricals_get_case_by_category (cat, i);
+      for (int j = 0; j < 2; j++)
+        pivot_category_create_leaf (
+          j ? j_family->root : i_family->root,
+          pivot_value_new_var_value (cmd->indep_var,
+                                     case_data (gcc, cmd->indep_var)));
+    }
 
+  struct pivot_dimension *test = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Test"));
 
-  for (p = 0; p < cmd->n_posthoc; ++p)
+  for (int p = 0; p < cmd->n_posthoc; ++p)
     {
-      int i;
       const struct posthoc *ph = &ph_tests[cmd->posthoc[p]];
 
-      tab_hline (t, TAL_2, 0, n_cols - 1, r);
-
-      tab_text (t, 0, r, TAB_LEFT | TAT_TITLE, gettext (ph->label));
+      int test_idx = pivot_category_create_leaf (
+        test->root, pivot_value_new_text (ph->label));
 
-      for (i = 0; i < pvw->n_groups ; ++i)
+      for (int i = 0; i < pvw->n_groups ; ++i)
        {
+         struct descriptive_data *dd_i
+            = categoricals_get_user_data_by_category (cat, i);
          double weight_i, mean_i, var_i;
-         int rx = 0;
-         struct string vstr;
-         int j;
-         struct descriptive_data *dd_i = categoricals_get_user_data_by_category (cat, i);
-         const struct ccase *gcc = categoricals_get_case_by_category (cat, i);
-
-
-         ds_init_empty (&vstr);
-         var_append_value_name (cmd->indep_var, case_data (gcc, cmd->indep_var), &vstr);
-
-         if ( i != 0)
-           tab_hline (t, TAL_1, 1, n_cols - 1, r);
-         tab_text (t, 1, r, TAB_LEFT | TAT_TITLE, ds_cstr (&vstr));
-
          moments1_calculate (dd_i->mom, &weight_i, &mean_i, &var_i, 0, 0);
 
-         for (j = 0 ; j < pvw->n_groups; ++j)
+         for (int j = 0 ; j < pvw->n_groups; ++j)
            {
-             double std_err;
-             double weight_j, mean_j, var_j;
-             double half_range;
-             const struct ccase *cc;
-             struct descriptive_data *dd_j = categoricals_get_user_data_by_category (cat, j);
              if (j == i)
                continue;
 
-             ds_clear (&vstr);
-             cc = categoricals_get_case_by_category (cat, j);
-             var_append_value_name (cmd->indep_var, case_data (cc, cmd->indep_var), &vstr);
-             tab_text (t, 2, r + rx, TAB_LEFT | TAT_TITLE, ds_cstr (&vstr));
-
+             struct descriptive_data *dd_j
+                = categoricals_get_user_data_by_category (cat, j);
+             double weight_j, mean_j, var_j;
              moments1_calculate (dd_j->mom, &weight_j, &mean_j, &var_j, 0, 0);
 
-             tab_double  (t, 3, r + rx, 0, mean_i - mean_j, NULL, RC_OTHER);
-
-             std_err = pvw->mse;
+             double std_err = pvw->mse;
              std_err *= weight_i + weight_j;
              std_err /= weight_i * weight_j;
              std_err = sqrt (std_err);
 
-             tab_double  (t, 4, r + rx, 0, std_err, NULL, RC_OTHER);
-
-             tab_double (t, 5, r + rx, 0, 2 * multiple_comparison_sig (std_err, pvw, dd_i, dd_j, ph), NULL, RC_PVALUE);
-
-             half_range = mc_half_range (cmd, pvw, std_err, dd_i, dd_j, ph);
-
-             tab_double (t, 6, r + rx, 0,
-                         (mean_i - mean_j) - half_range, NULL, RC_OTHER);
-
-             tab_double (t, 7, r + rx, 0,
-                         (mean_i - mean_j) + half_range, NULL, RC_OTHER);
-
-             rx++;
+              double sig = 2 * multiple_comparison_sig (std_err, pvw,
+                                                        dd_i, dd_j, ph);
+             double half_range = mc_half_range (cmd, pvw, std_err,
+                                                 dd_i, dd_j, ph);
+              double entries[] = {
+                mean_i - mean_j,
+                std_err,
+                sig,
+                (mean_i - mean_j) - half_range,
+                (mean_i - mean_j) + half_range,
+              };
+              for (size_t k = 0; k < sizeof entries / sizeof *entries; k++)
+                pivot_table_put4 (table, k, j, i, test_idx,
+                                  pivot_value_new_number (entries[k]));
            }
-         ds_destroy (&vstr);
-         r += pvw->n_groups - 1;
        }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
index b171951557f95c1a464aacc9e1dfcfabc8576dd6..a3387bb630b53a717ea4f72603fcfc11d92c308d 100644 (file)
@@ -39,7 +39,7 @@
 #include "libpspp/assertion.h"
 #include "libpspp/str.h"
 #include "math/random.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "output/text-item.h"
 
 #include "gettext.h"
@@ -514,97 +514,69 @@ kmeans_cluster (struct Kmeans *kmeans, struct casereader *reader, const struct q
 static void
 quick_cluster_show_centers (struct Kmeans *kmeans, bool initial, const struct qc *qc)
 {
-  struct tab_table *t;
-  int nc, nr, currow;
-  int i, j;
-  nc = qc->ngroups + 1;
-  nr = qc->n_vars + 4;
-  t = tab_create (nc, nr);
-  tab_headers (t, 0, nc - 1, 0, 1);
-  currow = 0;
-  if (!initial)
-    {
-      tab_title (t, _("Final Cluster Centers"));
-    }
-  else
-    {
-      tab_title (t, _("Initial Cluster Centers"));
-    }
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1);
-  tab_joint_text (t, 1, 0, nc - 1, 0, TAB_CENTER, _("Cluster"));
-  tab_hline (t, TAL_1, 1, nc - 1, 2);
-  currow += 2;
-
-  for (i = 0; i < qc->ngroups; i++)
-    {
-      tab_text_format (t, (i + 1), currow, TAB_CENTER, "%d", (i + 1));
-    }
-  currow++;
-  tab_hline (t, TAL_1, 1, nc - 1, currow);
-  currow++;
-  for (i = 0; i < qc->n_vars; i++)
-    {
-      tab_text (t, 0, currow + i, TAB_LEFT,
-               var_to_string (qc->vars[i]));
+  struct pivot_table *table = pivot_table_create (
+    initial ? N_("Initial Cluster Centers") : N_("Final Cluster Centers"));
+
+  struct pivot_dimension *clusters = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Cluster"));
+  clusters->root->show_label = true;
+  for (size_t i = 0; i < qc->ngroups; i++)
+    pivot_category_create_leaf (clusters->root,
+                                pivot_value_new_integer (i + 1));
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable"));
+  for (size_t i = 0; i < qc->n_vars; i++)
+    pivot_category_create_leaf (variables->root,
+                                pivot_value_new_variable (qc->vars[i]));
+
+  const gsl_matrix *matrix = (initial
+                              ? kmeans->initial_centers
+                              : kmeans->centers);
+  for (size_t i = 0; i < qc->ngroups; i++)
+    for (size_t j = 0; j < qc->n_vars; j++)
+      {
+        double x = gsl_matrix_get (matrix, kmeans->group_order->data[i], j);
+        union value v = { .f = x };
+        pivot_table_put2 (table, i, j,
+                          pivot_value_new_var_value (qc->vars[j], &v));
     }
 
-  for (i = 0; i < qc->ngroups; i++)
-    {
-      for (j = 0; j < qc->n_vars; j++)
-       {
-         if (!initial)
-           {
-             tab_double (t, i + 1, j + 4, TAB_CENTER,
-                         gsl_matrix_get (kmeans->centers,
-                                         kmeans->group_order->data[i], j),
-                         var_get_print_format (qc->vars[j]), RC_OTHER);
-           }
-         else
-           {
-             tab_double (t, i + 1, j + 4, TAB_CENTER,
-                         gsl_matrix_get (kmeans->initial_centers,
-                                         kmeans->group_order->data[i], j),
-                         var_get_print_format (qc->vars[j]), RC_OTHER);
-           }
-       }
-    }
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 /* Reports cluster membership for each case. */
 static void
 quick_cluster_show_membership (struct Kmeans *kmeans, const struct casereader *reader, const struct qc *qc)
 {
-  struct tab_table *t;
-  int nc, nr, i;
+  struct pivot_table *table = pivot_table_create (N_("Cluster Membership"));
 
-  struct ccase *c;
-  struct casereader *cs = casereader_clone (reader);
-  nc = 2;
-  nr = kmeans->n + 1;
-  t = tab_create (nc, nr);
-  tab_headers (t, 0, nc - 1, 0, 0);
-  tab_title (t, _("Cluster Membership"));
-  tab_text (t, 0, 0, TAB_CENTER, _("Case Number"));
-  tab_text (t, 1, 0, TAB_CENTER, _("Cluster"));
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1);
-  tab_hline (t, TAL_1, 0, nc - 1, 1);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Cluster"),
+                          N_("Cluster"));
+
+  struct pivot_dimension *cases = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Case Number"));
+  cases->root->show_label = true;
 
   gsl_permutation *ip = gsl_permutation_alloc (qc->ngroups);
   gsl_permutation_inverse (ip, kmeans->group_order);
 
-  for (i = 0; (c = casereader_read (cs)) != NULL; i++, case_unref (c))
+  struct casereader *cs = casereader_clone (reader);
+  struct ccase *c;
+  for (int i = 0; (c = casereader_read (cs)) != NULL; i++, case_unref (c))
     {
-      int clust = -1;
       assert (i < kmeans->n);
+      int clust;
       kmeans_get_nearest_group (kmeans, c, qc, &clust, NULL, NULL, NULL);
-      clust = ip->data[clust];
-      tab_text_format (t, 0, i+1, TAB_CENTER, "%d", (i + 1));
-      tab_text_format (t, 1, i+1, TAB_CENTER, "%d", (clust + 1));
+      int cluster = ip->data[clust];
+
+      int case_idx = pivot_category_create_leaf (
+        cases->root, pivot_value_new_integer (i + 1));
+      pivot_table_put2 (table, 0, case_idx,
+                        pivot_value_new_integer (cluster + 1));
     }
   gsl_permutation_free (ip);
-  assert (i == kmeans->n);
-  tab_submit (t);
+  pivot_table_submit (table);
   casereader_destroy (cs);
 }
 
@@ -613,31 +585,33 @@ quick_cluster_show_membership (struct Kmeans *kmeans, const struct casereader *r
 static void
 quick_cluster_show_number_cases (struct Kmeans *kmeans, const struct qc *qc)
 {
-  struct tab_table *t;
-  int nc, nr;
-  int i, numelem;
-  long int total;
-  nc = 3;
-  nr = qc->ngroups + 1;
-  t = tab_create (nc, nr);
-  tab_headers (t, 0, nc - 1, 0, 0);
-  tab_title (t, _("Number of Cases in each Cluster"));
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1);
-  tab_text (t, 0, 0, TAB_LEFT, _("Cluster"));
-
-  total = 0;
-  for (i = 0; i < qc->ngroups; i++)
+  struct pivot_table *table = pivot_table_create (
+    N_("Number of Cases in each Cluster"));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Count"));
+
+  struct pivot_dimension *clusters = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Clusters"));
+  struct pivot_category *group = pivot_category_create_group (
+    clusters->root, N_("Cluster"));
+
+  long int total = 0;
+  for (int i = 0; i < qc->ngroups; i++)
     {
-      tab_text_format (t, 1, i, TAB_CENTER, "%d", (i + 1));
-      numelem =
-       kmeans->num_elements_groups->data[kmeans->group_order->data[i]];
-      tab_text_format (t, 2, i, TAB_CENTER, "%d", numelem);
-      total += numelem;
+      int cluster_idx = pivot_category_create_leaf (
+        group, pivot_value_new_integer (i + 1));
+      int count = kmeans->num_elements_groups->data[
+        kmeans->group_order->data[i]];
+      pivot_table_put2 (table, 0, cluster_idx,
+                        pivot_value_new_integer (count));
+      total += count;
     }
 
-  tab_text (t, 0, qc->ngroups, TAB_LEFT, _("Valid"));
-  tab_text_format (t, 2, qc->ngroups, TAB_LEFT, "%ld", total);
-  tab_submit (t);
+  int cluster_idx = pivot_category_create_leaf (
+    clusters->root, pivot_value_new_text (N_("Valid")));
+  pivot_table_put2 (table, 0, cluster_idx, pivot_value_new_integer (total));
+  pivot_table_submit (table);
 }
 
 /* Reports. */
index 65a0fb8b574a9fb66b75031ed65332c7514e0ceb..cd3833dbba7a78583ad0aa5016754c8990ad863c 100644 (file)
@@ -41,8 +41,7 @@
 #include "libpspp/pool.h"
 #include "libpspp/string-set.h"
 #include "libpspp/taint.h"
-
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -650,7 +649,6 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
   struct string_set new_names;
   struct rank rank;
   struct rank_spec *rs;
-  int i;
 
   subcase_init_empty (&rank.sc);
 
@@ -802,11 +800,9 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
      created with INTO. */
   for (rs = rank.rs; rs < &rank.rs[rank.n_rs]; rs++)
     {
-      int v;
-
       rs->dest_labels = pool_calloc (rank.pool, rank.n_vars,
                                      sizeof *rs->dest_labels);
-      for ( v = 0 ; v < rank.n_vars ;  v ++ )
+      for (int v = 0 ; v < rank.n_vars ;  v ++ )
         {
           const char **dst_name = &rs->dest_names[v];
           if ( *dst_name == NULL )
@@ -825,72 +821,54 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
 
   if ( rank.print )
     {
-      int v;
+      struct pivot_table *table = pivot_table_create (
+        N_("Variables Created by RANK"));
+      table->omit_empty = true;
 
-      tab_output_text_format (0, _("Variables Created By %s"), "RANK");
-      tab_output_text (0, "");
+      pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("New Variable"),
+                              N_("New Variable"), N_("Function"),
+                              N_("Fraction"), N_("Grouping Variables"));
 
-      for (i = 0 ; i <  rank.n_rs ; ++i )
+      struct pivot_dimension *variables = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Existing Variable"),
+        N_("Existing Variable"));
+      variables->root->show_label = true;
+
+      for (size_t i = 0 ; i <  rank.n_rs ; ++i )
        {
-         for ( v = 0 ; v < rank.n_vars ;  v ++ )
+         for (size_t v = 0 ; v < rank.n_vars ;  v ++ )
            {
-             if ( rank.n_group_vars > 0 )
-               {
-                 struct string varlist;
-                 int g;
-
-                 ds_init_empty (&varlist);
-                 for ( g = 0 ; g < rank.n_group_vars ; ++g )
-                   {
-                     ds_put_cstr (&varlist, var_get_name (rank.group_vars[g]));
-
-                     if ( g < rank.n_group_vars - 1)
-                       ds_put_cstr (&varlist, " ");
-                   }
-
-                 if ( rank.rs[i].rfunc == NORMAL ||
-                      rank.rs[i].rfunc == PROPORTION )
-                   tab_output_text_format (0,
-                                            _("%s into %s(%s of %s using %s BY %s)"),
-                                            var_get_name (rank.vars[v]),
-                                            rank.rs[i].dest_names[v],
-                                            function_name[rank.rs[i].rfunc],
-                                            var_get_name (rank.vars[v]),
-                                            fraction_name (&rank),
-                                            ds_cstr (&varlist));
-
-                 else
-                   tab_output_text_format (0,
-                                            _("%s into %s(%s of %s BY %s)"),
-                                            var_get_name (rank.vars[v]),
-                                            rank.rs[i].dest_names[v],
-                                            function_name[rank.rs[i].rfunc],
-                                            var_get_name (rank.vars[v]),
-                                            ds_cstr (&varlist));
-                 ds_destroy (&varlist);
-               }
-             else
-               {
-                 if ( rank.rs[i].rfunc == NORMAL ||
-                      rank.rs[i].rfunc == PROPORTION )
-                   tab_output_text_format (0,
-                                            _("%s into %s(%s of %s using %s)"),
-                                            var_get_name (rank.vars[v]),
-                                            rank.rs[i].dest_names[v],
-                                            function_name[rank.rs[i].rfunc],
-                                            var_get_name (rank.vars[v]),
-                                            fraction_name (&rank));
-
-                 else
-                   tab_output_text_format (0,
-                                            _("%s into %s(%s of %s)"),
-                                            var_get_name (rank.vars[v]),
-                                            rank.rs[i].dest_names[v],
-                                            function_name[rank.rs[i].rfunc],
-                                            var_get_name (rank.vars[v]));
-               }
+              int row_idx = pivot_category_create_leaf (
+                variables->root, pivot_value_new_variable (rank.vars[v]));
+
+              struct string group_vars = DS_EMPTY_INITIALIZER;
+              for (int g = 0 ; g < rank.n_group_vars ; ++g )
+                {
+                  if (g)
+                    ds_put_byte (&group_vars, ' ');
+                  ds_put_cstr (&group_vars, var_get_name (rank.group_vars[g]));
+                }
+
+              enum rank_func rfunc = rank.rs[i].rfunc;
+              bool has_fraction = rfunc == NORMAL || rfunc == PROPORTION;
+              const char *entries[] =
+                {
+                  rank.rs[i].dest_names[v],
+                  function_name[rank.rs[i].rfunc],
+                  has_fraction ? fraction_name (&rank) : NULL,
+                  rank.n_group_vars ? ds_cstr (&group_vars) : NULL,
+                };
+              for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+                {
+                  const char *entry = entries[j];
+                  if (entry)
+                    pivot_table_put2 (table, j, row_idx,
+                                      pivot_value_new_user_text (entry, -1));
+                }
            }
        }
+
+      pivot_table_submit (table);
     }
 
   /* Do the ranking */
index 72649ba4ac633667d678f188927cbf0cb339dc6e..ecc2279b45b879ddf68e8e81354f17cc1ab5c9a2 100644 (file)
 #include "libpspp/message.h"
 #include "libpspp/taint.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
+
+#include "gl/intprops.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 
-#include <gl/intprops.h>
-
 #define STATS_R      1
 #define STATS_COEFF  2
 #define STATS_ANOVA  4
@@ -782,35 +783,27 @@ run_regression (const struct regression *cmd,
 static void
 reg_stats_r (const struct linreg * c, const struct variable *var)
 {
-  struct tab_table *t;
-  int n_rows = 2;
-  int n_cols = 5;
-  double rsq;
-  double adjrsq;
-  double std_error;
-
-  assert (c != NULL);
-  rsq = linreg_ssreg (c) / linreg_sst (c);
-  adjrsq = rsq -
-    (1.0 - rsq) * linreg_n_coeffs (c) / (linreg_n_obs (c) -
-                                         linreg_n_coeffs (c) - 1);
-  std_error = sqrt (linreg_mse (c));
-  t = tab_create (n_cols, n_rows);
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1);
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-  tab_vline (t, TAL_0, 1, 0, 0);
-
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("R"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("R Square"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Adjusted R Square"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Error of the Estimate"));
-  tab_double (t, 1, 1, TAB_RIGHT, sqrt (rsq), NULL, RC_OTHER);
-  tab_double (t, 2, 1, TAB_RIGHT, rsq, NULL, RC_OTHER);
-  tab_double (t, 3, 1, TAB_RIGHT, adjrsq, NULL, RC_OTHER);
-  tab_double (t, 4, 1, TAB_RIGHT, std_error, NULL, RC_OTHER);
-  tab_title (t, _("Model Summary (%s)"), var_to_string (var));
-  tab_submit (t);
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("Model Summary (%s)"),
+                                 var_to_string (var)));
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("R"), N_("R Square"), N_("Adjusted R Square"),
+                          N_("Std. Error of the Estimate"));
+
+  double rsq = linreg_ssreg (c) / linreg_sst (c);
+  double adjrsq = (rsq -
+                   (1.0 - rsq) * linreg_n_coeffs (c)
+                   / (linreg_n_obs (c) - linreg_n_coeffs (c) - 1));
+  double std_error = sqrt (linreg_mse (c));
+
+  double entries[] = {
+    sqrt (rsq), rsq, adjrsq, std_error
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    pivot_table_put1 (table, i, pivot_value_new_number (entries[i]));
+
+  pivot_table_submit (table);
 }
 
 /*
@@ -819,128 +812,82 @@ reg_stats_r (const struct linreg * c, const struct variable *var)
 static void
 reg_stats_coeff (const struct linreg * c, const gsl_matrix *cov, const struct variable *var, const struct regression *cmd)
 {
-  size_t j;
-  int n_cols = 7;
-  const int heading_rows = 2;
-  int n_rows;
-  int this_row = heading_rows;
-  double pval;
-  double std_err;
-  double beta;
-  const char *label;
-
-  const struct variable *v;
-  struct tab_table *t;
-
-  const double df = linreg_n_obs (c) - linreg_n_coeffs (c) - 1;
-  double q = (1 - cmd->ci) / 2.0;  /* 2-tailed test */
-  double tval = gsl_cdf_tdist_Qinv (q, df);
-
-  assert (c != NULL);
-  n_rows = linreg_n_coeffs (c) + heading_rows + 1;
-
-  if (cmd->stats & STATS_CI)
-    n_cols += 2;
-
-  t = tab_create (n_cols, n_rows);
-  tab_headers (t, 2, 0, 1, 0);
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
-  tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows);
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-  tab_vline (t, TAL_0, 1, 0, 0);
-
-
-  tab_hline (t, TAL_1, 2, 4, 1);
-  tab_joint_text (t, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE, _("Unstandardized Coefficients"));
-  tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("B"));
-  tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Std. Error"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Standardized Coefficients"));
-  tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Beta"));
-  tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("t"));
-  tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Sig."));
-
-  std_err = sqrt (gsl_matrix_get (linreg_cov (c), 0, 0));
-
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("Coefficients (%s)"),
+                                 var_to_string (var)));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  pivot_category_create_group (statistics->root,
+                               N_("Unstandardized Coefficients"),
+                               N_("B"), N_("Std. Error"));
+  pivot_category_create_group (statistics->root,
+                               N_("Standardized Coefficients"), N_("Beta"));
+  pivot_category_create_leaves (statistics->root, N_("t"),
+                                N_("Sig."), PIVOT_RC_SIGNIFICANCE);
   if (cmd->stats & STATS_CI)
     {
-      double lower = linreg_intercept (c) - tval * std_err ;
-      double upper = linreg_intercept (c) + tval * std_err ;
-      tab_double (t, 7, heading_rows, 0, lower, NULL, RC_OTHER);
-      tab_double (t, 8, heading_rows, 0, upper, NULL, RC_OTHER);
-
-      tab_joint_text_format (t, 7, 0, 8, 0, TAB_CENTER | TAT_TITLE, _("%g%% Confidence Interval for B"), cmd->ci * 100);
-      tab_hline (t, TAL_1, 7, 8, 1);
-      tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound"));
-      tab_text (t, 8, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound"));
+      struct pivot_category *interval = pivot_category_create_group__ (
+        statistics->root, pivot_value_new_text_format (
+          N_("%g%% Confidence Interval for B"),
+          cmd->ci * 100.0));
+      pivot_category_create_leaves (interval, N_("Lower Bound"),
+                                    N_("Upper Bound"));
     }
 
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+
+  double df = linreg_n_obs (c) - linreg_n_coeffs (c) - 1;
+  double q = (1 - cmd->ci) / 2.0;  /* 2-tailed test */
+  double tval = gsl_cdf_tdist_Qinv (q, df);
+
   if (!cmd->origin)
     {
-      tab_text (t, 1, this_row, TAB_LEFT | TAT_TITLE, _("(Constant)"));
-      tab_double (t, 2, this_row, 0, linreg_intercept (c), NULL, RC_OTHER);
-      tab_double (t, 3, this_row, 0, std_err, NULL, RC_OTHER);
-      tab_double (t, 4, this_row, 0, 0.0, NULL, RC_OTHER);
-      double t_stat = linreg_intercept (c) / std_err;
-      tab_double (t, 5, this_row, 0, t_stat, NULL, RC_OTHER);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_text (N_("(Constant)")));
 
-      double pval =
-       2 * gsl_cdf_tdist_Q (fabs (t_stat),
-                            (double) (linreg_n_obs (c) - linreg_n_coeffs (c)));
-      tab_double (t, 6, this_row, 0, pval, NULL, RC_PVALUE);
-      this_row++;
+      double std_err = sqrt (gsl_matrix_get (linreg_cov (c), 0, 0));
+      double t_stat = linreg_intercept (c) / std_err;
+      double entries[] = {
+        linreg_intercept (c),
+        std_err,
+        0.0,
+        t_stat,
+        2.0 * gsl_cdf_tdist_Q (fabs (t_stat),
+                               linreg_n_obs (c) - linreg_n_coeffs (c)),
+        linreg_intercept (c) - tval * std_err,
+        linreg_intercept (c) + tval * std_err,
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, var_idx,
+                          pivot_value_new_number (entries[i]));
     }
 
-  for (j = 0; j < linreg_n_coeffs (c); j++, this_row++)
+  for (size_t j = 0; j < linreg_n_coeffs (c); j++)
     {
-      struct string tstr;
-      ds_init_empty (&tstr);
-
-      v = linreg_indep_var (c, j);
-      label = var_to_string (v);
-      /* Do not overwrite the variable's name. */
-      ds_put_cstr (&tstr, label);
-      tab_text (t, 1, this_row, TAB_LEFT, ds_cstr (&tstr));
-      /*
-         Regression coefficients.
-       */
-      tab_double (t, 2, this_row, 0, linreg_coeff (c, j), NULL, RC_OTHER);
-      /*
-         Standard error of the coefficients.
-       */
-      std_err = sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1));
-      tab_double (t, 3, this_row, 0, std_err, NULL, RC_OTHER);
-      /*
-         Standardized coefficient, i.e., regression coefficient
-         if all variables had unit variance.
-       */
-      beta = sqrt (gsl_matrix_get (cov, j, j));
-      beta *= linreg_coeff (c, j) /
-        sqrt (gsl_matrix_get (cov, cov->size1 - 1, cov->size2 - 1));
-      tab_double (t, 4, this_row, 0, beta, NULL, RC_OTHER);
+      const struct variable *v = linreg_indep_var (c, j);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (v));
 
-      /*
-         Test statistic for H0: coefficient is 0.
-       */
+      double std_err = sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1));
       double t_stat = linreg_coeff (c, j) / std_err;
-      tab_double (t, 5, this_row, 0, t_stat, NULL, RC_OTHER);
-      /*
-         P values for the test statistic above.
-       */
-      pval = 2 * gsl_cdf_tdist_Q (fabs (t_stat), df);
-      tab_double (t, 6, this_row, 0, pval, NULL, RC_PVALUE);
-      ds_destroy (&tstr);
-
-      if (cmd->stats & STATS_CI)
-       {
-         double lower = linreg_coeff (c, j)  - tval * std_err ;
-         double upper = linreg_coeff (c, j)  + tval * std_err ;
-
-         tab_double (t, 7, this_row, 0, lower, NULL, RC_OTHER);
-         tab_double (t, 8, this_row, 0, upper, NULL, RC_OTHER);
-       }
+      double entries[] = {
+        linreg_coeff (c, j),
+        sqrt (gsl_matrix_get (linreg_cov (c), j + 1, j + 1)),
+        (sqrt (gsl_matrix_get (cov, j, j)) * linreg_coeff (c, j) /
+         sqrt (gsl_matrix_get (cov, cov->size1 - 1, cov->size2 - 1))),
+        t_stat,
+        2 * gsl_cdf_tdist_Q (fabs (t_stat), df),
+        linreg_coeff (c, j)  - tval * std_err,
+        linreg_coeff (c, j)  + tval * std_err,
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, var_idx,
+                          pivot_value_new_number (entries[i]));
     }
-  tab_title (t, _("Coefficients (%s)"), var_to_string (var));
-  tab_submit (t);
+
+  pivot_table_submit (table);
 }
 
 /*
@@ -949,98 +896,84 @@ reg_stats_coeff (const struct linreg * c, const gsl_matrix *cov, const struct va
 static void
 reg_stats_anova (const struct linreg * c, const struct variable *var)
 {
-  int n_cols = 7;
-  int n_rows = 4;
-  const double msm = linreg_ssreg (c) / linreg_dfmodel (c);
-  const double mse = linreg_mse (c);
-  const double F = msm / mse;
-  const double pval = gsl_cdf_fdist_Q (F, linreg_dfmodel (c),
-                                      linreg_dferror (c));
-
-  struct tab_table *t;
-
-  assert (c != NULL);
-  t = tab_create (n_cols, n_rows);
-  tab_headers (t, 2, 0, 1, 0);
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("ANOVA (%s)"), var_to_string (var)));
 
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Sum of Squares"), PIVOT_RC_OTHER,
+                          N_("df"), PIVOT_RC_INTEGER,
+                          N_("Mean Square"), PIVOT_RC_OTHER,
+                          N_("F"), PIVOT_RC_OTHER,
+                          N_("Sig."), PIVOT_RC_SIGNIFICANCE);
 
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1);
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-  tab_vline (t, TAL_0, 1, 0, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Source"),
+                          N_("Regression"), N_("Residual"), N_("Total"));
 
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Sum of Squares"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Mean Square"));
-  tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("F"));
-  tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
+  double msm = linreg_ssreg (c) / linreg_dfmodel (c);
+  double mse = linreg_mse (c);
+  double F = msm / mse;
 
-  tab_text (t, 1, 1, TAB_LEFT | TAT_TITLE, _("Regression"));
-  tab_text (t, 1, 2, TAB_LEFT | TAT_TITLE, _("Residual"));
-  tab_text (t, 1, 3, TAB_LEFT | TAT_TITLE, _("Total"));
-
-  /* Sums of Squares */
-  tab_double (t, 2, 1, 0, linreg_ssreg (c), NULL, RC_OTHER);
-  tab_double (t, 2, 3, 0, linreg_sst (c), NULL, RC_OTHER);
-  tab_double (t, 2, 2, 0, linreg_sse (c), NULL, RC_OTHER);
-
-
-  /* Degrees of freedom */
-  tab_text_format (t, 3, 1, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dfmodel (c));
-  tab_text_format (t, 3, 2, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dferror (c));
-  tab_text_format (t, 3, 3, TAB_RIGHT, "%.*g", DBL_DIG + 1, linreg_dftotal (c));
-
-  /* Mean Squares */
-  tab_double (t, 4, 1, TAB_RIGHT, msm, NULL, RC_OTHER);
-  tab_double (t, 4, 2, TAB_RIGHT, mse, NULL, RC_OTHER);
-
-  tab_double (t, 5, 1, 0, F, NULL, RC_OTHER);
-
-  tab_double (t, 6, 1, 0, pval, NULL, RC_PVALUE);
+  struct entry
+    {
+      int stat_idx;
+      int source_idx;
+      double x;
+    }
+  entries[] = {
+    /* Sums of Squares. */
+    { 0, 0, linreg_ssreg (c) },
+    { 0, 1, linreg_sse (c) },
+    { 0, 2, linreg_sst (c) },
+    /* Degrees of freedom. */
+    { 1, 0, linreg_dfmodel (c) },
+    { 1, 1, linreg_dferror (c) },
+    { 1, 2, linreg_dftotal (c) },
+    /* Mean Squares. */
+    { 2, 0, msm },
+    { 2, 1, mse },
+    /* F */
+    { 3, 0, F },
+    /* Significance. */
+    { 4, 0, gsl_cdf_fdist_Q (F, linreg_dfmodel (c), linreg_dferror (c)) },
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    {
+      const struct entry *e = &entries[i];
+      pivot_table_put2 (table, e->stat_idx, e->source_idx,
+                        pivot_value_new_number (e->x));
+    }
 
-  tab_title (t, _("ANOVA (%s)"), var_to_string (var));
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
 static void
 reg_stats_bcov (const struct linreg * c, const struct variable *var)
 {
-  int n_cols;
-  int n_rows;
-  int i;
-  int k;
-  int row;
-  int col;
-  const char *label;
-  struct tab_table *t;
-
-  assert (c != NULL);
-  n_cols = linreg_n_indeps (c) + 1 + 2;
-  n_rows = 2 * (linreg_n_indeps (c) + 1);
-  t = tab_create (n_cols, n_rows);
-  tab_headers (t, 2, 0, 1, 0);
-  tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
-  tab_hline (t, TAL_2, 0, n_cols - 1, 1);
-  tab_vline (t, TAL_2, 2, 0, n_rows - 1);
-  tab_vline (t, TAL_0, 1, 0, 0);
-  tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Model"));
-  tab_text (t, 1, 1, TAB_CENTER | TAT_TITLE, _("Covariances"));
-  for (i = 0; i < linreg_n_coeffs (c); i++)
+  struct pivot_table *table = pivot_table_create__ (
+    pivot_value_new_text_format (N_("Coefficient Correlations (%s)"),
+                                 var_to_string (var)));
+
+  for (size_t i = 0; i < 2; i++)
     {
-      const struct variable *v = linreg_indep_var (c, i);
-      label = var_to_string (v);
-      tab_text (t, 2, i, TAB_CENTER, label);
-      tab_text (t, i + 2, 0, TAB_CENTER, label);
-      for (k = 1; k < linreg_n_coeffs (c); k++)
-        {
-          col = (i <= k) ? k : i;
-          row = (i <= k) ? i : k;
-          tab_double (t, k + 2, i, TAB_CENTER,
-                      gsl_matrix_get (linreg_cov (c), row, col), NULL, RC_OTHER);
-        }
+      struct pivot_dimension *models = pivot_dimension_create (
+        table, i ? PIVOT_AXIS_ROW : PIVOT_AXIS_COLUMN, N_("Models"));
+      for (size_t j = 0; j < linreg_n_coeffs (c); j++)
+        pivot_category_create_leaf (
+          models->root, pivot_value_new_variable (
+            linreg_indep_var (c, j)));
     }
-  tab_title (t, _("Coefficient Correlations (%s)"), var_to_string (var));
-  tab_submit (t);
+
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("Covariances"));
+
+  for (size_t i = 0; i < linreg_n_coeffs (c); i++)
+    for (size_t k = 0; k < linreg_n_coeffs (c); k++)
+      {
+        double cov = gsl_matrix_get (linreg_cov (c), MIN (i, k), MAX (i, k));
+        pivot_table_put3 (table, k, i, 0, pivot_value_new_number (cov));
+      }
+
+  pivot_table_submit (table);
 }
 
index 27a4656723ab28920710943d6f53184a388d0517..756932ba89545c7188246af3c3f3343cbde9c416 100644 (file)
@@ -31,7 +31,7 @@
 #include "libpspp/misc.h"
 #include "libpspp/str.h"
 #include "math/moments.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "output/text-item.h"
 
 #include "gettext.h"
@@ -536,345 +536,161 @@ static void
 case_processing_summary (casenumber n_valid, casenumber n_missing,
                         const struct dictionary *dict)
 {
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
+  struct pivot_table *table = pivot_table_create (
+    N_("Case Processing Summary"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-  casenumber total;
-  int n_cols = 4;
-  int n_rows = 4;
-  int heading_columns = 2;
-  int heading_rows = 1;
-  struct tab_table *tbl;
-  tbl = tab_create (n_cols, n_rows);
-  tab_set_format (tbl, RC_WEIGHT, wfmt);
-  tab_headers (tbl, heading_columns, 0, heading_rows, 0);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Percent"), PIVOT_RC_PERCENT);
 
-  tab_title (tbl, _("Case Processing Summary"));
+  struct pivot_dimension *cases = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Cases"), N_("Valid"), N_("Excluded"),
+    N_("Total"));
+  cases->root->show_label = true;
 
-  /* Vertical lines for the data only */
-  tab_box (tbl,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          n_cols - 1, n_rows - 1);
+  casenumber total = n_missing + n_valid;
 
-  /* Box around table */
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
-
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
-
-  tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
-
-
-  tab_text (tbl, 0, heading_rows, TAB_LEFT | TAT_TITLE,
-               _("Cases"));
-
-  tab_text (tbl, 1, heading_rows, TAB_LEFT | TAT_TITLE,
-               _("Valid"));
-
-  tab_text (tbl, 1, heading_rows + 1, TAB_LEFT | TAT_TITLE,
-               _("Excluded"));
-
-  tab_text (tbl, 1, heading_rows + 2, TAB_LEFT | TAT_TITLE,
-               _("Total"));
-
-  tab_text (tbl, heading_columns, 0, TAB_CENTER | TAT_TITLE,
-               _("N"));
-
-  tab_text (tbl, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, _("%"));
-
-  total = n_missing + n_valid;
-
-  tab_double (tbl, 2, heading_rows, TAB_RIGHT,
-            n_valid, NULL, RC_WEIGHT);
-
-
-  tab_double (tbl, 2, heading_rows + 1, TAB_RIGHT,
-            n_missing, NULL, RC_WEIGHT);
-
-
-  tab_double (tbl, 2, heading_rows + 2, TAB_RIGHT,
-            total, NULL, RC_WEIGHT);
-
-
-  tab_double (tbl, 3, heading_rows, TAB_RIGHT,
-             100 * n_valid / (double) total, NULL, RC_OTHER);
-
-
-  tab_double (tbl, 3, heading_rows + 1, TAB_RIGHT,
-             100 * n_missing / (double) total, NULL, RC_OTHER);
-
-
-  tab_double (tbl, 3, heading_rows + 2, TAB_RIGHT,
-             100 * total / (double) total, NULL, RC_OTHER);
+  struct entry
+    {
+      int stat_idx;
+      int case_idx;
+      double x;
+    }
+  entries[] = {
+    { 0, 0, n_valid },
+    { 0, 1, n_missing },
+    { 0, 2, total },
+    { 1, 0, 100.0 * n_valid / total },
+    { 1, 1, 100.0 * n_missing / total },
+    { 1, 2, 100.0 }
+  };
 
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    {
+      const struct entry *e = &entries[i];
+      pivot_table_put2 (table, e->stat_idx, e->case_idx,
+                        pivot_value_new_number (e->x));
+    }
 
-  tab_submit (tbl);
+  pivot_table_submit (table);
 }
 
-
-
 static void
 reliability_summary_total (const struct reliability *rel)
 {
-  int i;
-  const int n_cols = 5;
-  const int heading_columns = 1;
-  const int heading_rows = 1;
-  const int n_rows = rel->sc[0].n_items + heading_rows ;
-  const struct variable *wv = rel->wv;
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
-  struct tab_table *tbl = tab_create (n_cols, n_rows);
-  tab_set_format (tbl, RC_WEIGHT, wfmt);
-  tab_headers (tbl, heading_columns, 0, heading_rows, 0);
-
-  tab_title (tbl, _("Item-Total Statistics"));
-
-  /* Vertical lines for the data only */
-  tab_box (tbl,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          n_cols - 1, n_rows - 1);
-
-  /* Box around table */
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
-
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
-
-  tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
-
-  tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
-           _("Scale Mean if Item Deleted"));
+  struct pivot_table *table = pivot_table_create (N_("Item-Total Statistics"));
 
-  tab_text (tbl, 2, 0, TAB_CENTER | TAT_TITLE,
-           _("Scale Variance if Item Deleted"));
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Scale Mean if Item Deleted"),
+                          N_("Scale Variance if Item Deleted"),
+                          N_("Corrected Item-Total Correlation"),
+                          N_("Cronbach's Alpha if Item Deleted"));
 
-  tab_text (tbl, 3, 0, TAB_CENTER | TAT_TITLE,
-           _("Corrected Item-Total Correlation"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
 
-  tab_text (tbl, 4, 0, TAB_CENTER | TAT_TITLE,
-           _("Cronbach's Alpha if Item Deleted"));
-
-
-  for (i = 0 ; i < rel->sc[0].n_items; ++i)
+  for (size_t i = 0 ; i < rel->sc[0].n_items; ++i)
     {
-      double cov, item_to_total_r;
-      double mean, weight, var;
-
       const struct cronbach *s = &rel->sc[rel->total_start + i];
-      tab_text (tbl, 0, heading_rows + i, TAB_LEFT| TAT_TITLE,
-               var_to_string (rel->sc[0].items[i]));
-
-      moments1_calculate (s->total, &weight, &mean, &var, 0, 0);
-
-      tab_double (tbl, 1, heading_rows + i, TAB_RIGHT,
-                 mean, NULL, RC_OTHER);
-
-      tab_double (tbl, 2, heading_rows + i, TAB_RIGHT,
-                 s->variance_of_sums, NULL, RC_OTHER);
-
-      tab_double (tbl, 4, heading_rows + i, TAB_RIGHT,
-                 s->alpha, NULL, RC_OTHER);
 
-
-      moments1_calculate (rel->sc[0].m[i], &weight, &mean, &var, 0,0);
-      cov = rel->sc[0].variance_of_sums + var - s->variance_of_sums;
-      cov /= 2.0;
-
-      item_to_total_r = (cov - var) / (sqrt(var) * sqrt (s->variance_of_sums));
-
-
-      tab_double (tbl, 3, heading_rows + i, TAB_RIGHT,
-                 item_to_total_r, NULL, RC_OTHER);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (rel->sc[0].items[i]));
+
+      double mean;
+      moments1_calculate (s->total, NULL, &mean, NULL, NULL, NULL);
+
+      double var;
+      moments1_calculate (rel->sc[0].m[i], NULL, NULL, &var, NULL, NULL);
+      double cov
+        = (rel->sc[0].variance_of_sums + var - s->variance_of_sums) / 2.0;
+
+      double entries[] = {
+        mean,
+        s->variance_of_sums,
+        (cov - var) / sqrt (var * s->variance_of_sums),
+        s->alpha,
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, var_idx,
+                          pivot_value_new_number (entries[i]));
     }
 
-
-  tab_submit (tbl);
+  pivot_table_submit (table);
 }
 
 
-static void reliability_statistics_model_alpha (struct tab_table *tbl,
-                                               const struct reliability *rel);
-
-static void reliability_statistics_model_split (struct tab_table *tbl,
-                                               const struct reliability *rel);
-
-
-struct reliability_output_table
-{
-  int n_cols;
-  int n_rows;
-  int heading_cols;
-  int heading_rows;
-  void (*populate) (struct tab_table *, const struct reliability *);
-};
-
-
-static struct reliability_output_table rol[2] =
-  {
-    { 2, 2, 1, 1, reliability_statistics_model_alpha},
-    { 4, 9, 3, 0, reliability_statistics_model_split}
-  };
-
 static void
 reliability_statistics (const struct reliability *rel)
 {
-  int n_cols = rol[rel->model].n_cols;
-  int n_rows = rol[rel->model].n_rows;
-  int heading_columns = rol[rel->model].heading_cols;
-  int heading_rows = rol[rel->model].heading_rows;
-  const struct variable *wv = rel->wv;
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
-  struct tab_table *tbl = tab_create (n_cols, n_rows);
-  tab_set_format (tbl, RC_WEIGHT, wfmt);
-
-  tab_headers (tbl, heading_columns, 0, heading_rows, 0);
-
-  tab_title (tbl, _("Reliability Statistics"));
-
-  /* Vertical lines for the data only */
-  tab_box (tbl,
-          -1, -1,
-          -1, TAL_1,
-          heading_columns, 0,
-          n_cols - 1, n_rows - 1);
-
-  /* Box around table */
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          n_cols - 1, n_rows - 1);
-
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
-
-  tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
-
-  if ( rel->model == MODEL_ALPHA )
-    reliability_statistics_model_alpha (tbl, rel);
-  else if (rel->model == MODEL_SPLIT )
-    reliability_statistics_model_split (tbl, rel);
-
-  tab_submit (tbl);
-}
-
-
-static void
-reliability_statistics_model_alpha (struct tab_table *tbl,
-                                   const struct reliability *rel)
-{
-  const struct cronbach *s = &rel->sc[0];
-
-  tab_text (tbl, 0, 0, TAB_CENTER | TAT_TITLE,
-               _("Cronbach's Alpha"));
-
-  tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
-               _("N of Items"));
-
-  tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL, RC_OTHER);
-
-  tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, NULL, RC_WEIGHT);
-}
-
-
-static void
-reliability_statistics_model_split (struct tab_table *tbl,
-                                   const struct reliability *rel)
-{
-  tab_text (tbl, 0, 0, TAB_LEFT,
-           _("Cronbach's Alpha"));
-
-  tab_text (tbl, 1, 0, TAB_LEFT,
-           _("Part 1"));
-
-  tab_text (tbl, 2, 0, TAB_LEFT,
-           _("Value"));
-
-  tab_text (tbl, 2, 1, TAB_LEFT,
-           _("N of Items"));
-
-  tab_text (tbl, 1, 2, TAB_LEFT,
-           _("Part 2"));
-
-  tab_text (tbl, 2, 2, TAB_LEFT,
-           _("Value"));
+  struct pivot_table *table = pivot_table_create (
+    N_("Reliability Statistics"));
+  pivot_table_set_weight_var (table, rel->wv);
 
-  tab_text (tbl, 2, 3, TAB_LEFT,
-           _("N of Items"));
-
-  tab_text (tbl, 1, 4, TAB_LEFT,
-           _("Total N of Items"));
-
-  tab_text (tbl, 0, 5, TAB_LEFT,
-           _("Correlation Between Forms"));
-
-  tab_text (tbl, 0, 6, TAB_LEFT,
-           _("Spearman-Brown Coefficient"));
-
-  tab_text (tbl, 1, 6, TAB_LEFT,
-           _("Equal Length"));
-
-  tab_text (tbl, 1, 7, TAB_LEFT,
-           _("Unequal Length"));
-
-
-  tab_text (tbl, 0, 8, TAB_LEFT,
-           _("Guttman Split-Half Coefficient"));
-
-
-
-  tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL, RC_OTHER);
-  tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL, RC_OTHER);
-
-  tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, NULL, RC_WEIGHT);
-  tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, NULL, RC_WEIGHT);
-
-  tab_double (tbl, 3, 4, TAB_RIGHT,
-            rel->sc[1].n_items + rel->sc[2].n_items, NULL, RC_WEIGHT);
-
-  {
-    /* R is the correlation between the two parts */
-    double r = rel->sc[0].variance_of_sums -
-      rel->sc[1].variance_of_sums -
-      rel->sc[2].variance_of_sums ;
-
-    /* Guttman Split Half Coefficient */
-    double g = 2 * r / rel->sc[0].variance_of_sums;
-
-    /* Unequal Length Spearman Brown Coefficient, and
-     intermediate value used in the computation thereof */
-    double uly, tmp;
-
-    r /= sqrt (rel->sc[1].variance_of_sums);
-    r /= sqrt (rel->sc[2].variance_of_sums);
-    r /= 2.0;
-
-    tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL, RC_OTHER);
-
-    /* Equal length Spearman-Brown Coefficient */
-    tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL, RC_OTHER);
-
-    tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL, RC_OTHER);
-
-    tmp = (1.0 - r*r) * rel->sc[1].n_items * rel->sc[2].n_items /
-      pow2 (rel->sc[0].n_items);
-
-    uly = sqrt( pow4 (r) + 4 * pow2 (r) * tmp);
-    uly -= pow2 (r);
-    uly /= 2 * tmp;
+  if (rel->model == MODEL_ALPHA)
+    {
+      pivot_dimension_create (table, PIVOT_AXIS_COLUMN,
+                              N_("Statistics"),
+                              N_("Cronbach's Alpha"), PIVOT_RC_OTHER,
+                              N_("N of Items"), PIVOT_RC_COUNT);
+
+      const struct cronbach *s = &rel->sc[0];
+      pivot_table_put1 (table, 0, pivot_value_new_number (s->alpha));
+      pivot_table_put1 (table, 1, pivot_value_new_number (s->n_items));
+    }
+  else
+    {
+      struct pivot_dimension *statistics = pivot_dimension_create (
+        table, PIVOT_AXIS_ROW, N_("Statistics"));
+      struct pivot_category *alpha = pivot_category_create_group (
+        statistics->root, N_("Cronbach's Alpha"));
+      pivot_category_create_group (alpha, N_("Part 1"),
+                                   N_("Value"), PIVOT_RC_OTHER,
+                                   N_("N of Items"), PIVOT_RC_COUNT);
+      pivot_category_create_group (alpha, N_("Part 2"),
+                                   N_("Value"), PIVOT_RC_OTHER,
+                                   N_("N of Items"), PIVOT_RC_COUNT);
+      pivot_category_create_leaves (alpha,
+                                    N_("Total N of Items"), PIVOT_RC_COUNT);
+      pivot_category_create_leaves (statistics->root,
+                                    N_("Correlation Between Forms"),
+                                    PIVOT_RC_OTHER);
+      pivot_category_create_group (statistics->root,
+                                   N_("Spearman-Brown Coefficient"),
+                                   N_("Equal Length"), PIVOT_RC_OTHER,
+                                   N_("Unequal Length"), PIVOT_RC_OTHER);
+      pivot_category_create_leaves (statistics->root,
+                                    N_("Guttman Split-Half Coefficient"),
+                                    PIVOT_RC_OTHER);
+
+      /* R is the correlation between the two parts */
+      double r0 = rel->sc[0].variance_of_sums -
+        rel->sc[1].variance_of_sums -
+        rel->sc[2].variance_of_sums ;
+      double r1 = (r0 / sqrt (rel->sc[1].variance_of_sums)
+                   / sqrt (rel->sc[2].variance_of_sums)
+                   / 2.0);
+
+      /* Guttman Split Half Coefficient */
+      double g = 2 * r0 / rel->sc[0].variance_of_sums;
+
+      double tmp = (1.0 - r1*r1) * rel->sc[1].n_items * rel->sc[2].n_items /
+        pow2 (rel->sc[0].n_items);
+
+      double entries[] = {
+        rel->sc[1].alpha,
+        rel->sc[1].n_items,
+        rel->sc[2].alpha,
+        rel->sc[2].n_items,
+        rel->sc[1].n_items + rel->sc[2].n_items,
+        r1,
+        2 * r1 / (1.0 + r1),
+        (sqrt ( pow4 (r1) + 4 * pow2 (r1) * tmp) - pow2 (r1)) / (2 * tmp),
+        g,
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put1 (table, i, pivot_value_new_number (entries[i]));
+    }
 
-    tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL, RC_OTHER);
-  }
+  pivot_table_submit (table);
 }
-
index 7d13c2c2cb7cf32c13c9d5c5051cf1328441517a..eb2430a2541efc29e52e1101b0e7ff1e631d1ee1 100644 (file)
@@ -35,7 +35,7 @@
 #include "math/sort.h"
 #include "output/chart-item.h"
 #include "output/charts/roc-chart.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -963,229 +963,161 @@ do_roc (struct cmd_roc *roc, struct casereader *reader, struct dictionary *dict)
 static void
 show_auc  (struct roc_state *rs, const struct cmd_roc *roc)
 {
-  int i;
-  const int n_fields = roc->print_se ? 5 : 1;
-  const int n_cols = roc->n_vars > 1 ? n_fields + 1: n_fields;
-  const int n_rows = 2 + roc->n_vars;
-  struct tab_table *tbl = tab_create (n_cols, n_rows);
-
-  if ( roc->n_vars > 1)
-    tab_title (tbl, _("Area Under the Curve"));
-  else
-    tab_title (tbl, _("Area Under the Curve (%s)"), var_to_string (roc->vars[0]));
-
-  tab_headers (tbl, n_cols - n_fields, 0, 1, 0);
-
-
-  tab_text (tbl, n_cols - n_fields, 1, TAT_TITLE, _("Area"));
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, 2);
+  struct pivot_table *table = pivot_table_create (N_("Area Under the Curve"));
 
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1,
-          n_rows - 1);
-
-  if ( roc->print_se )
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+    N_("Area"), PIVOT_RC_OTHER);
+  if (roc->print_se)
     {
-      tab_text (tbl, n_cols - 4, 1, TAT_TITLE, _("Std. Error"));
-      tab_text (tbl, n_cols - 3, 1, TAT_TITLE, _("Asymptotic Sig."));
-
-      tab_text (tbl, n_cols - 2, 1, TAT_TITLE, _("Lower Bound"));
-      tab_text (tbl, n_cols - 1, 1, TAT_TITLE, _("Upper Bound"));
-
-      tab_joint_text_format (tbl, n_cols - 2, 0, 4, 0,
-                            TAT_TITLE | TAB_CENTER,
-                            _("Asymp. %g%% Confidence Interval"), roc->ci);
-      tab_vline (tbl, 0, n_cols - 1, 0, 0);
-      tab_hline (tbl, TAL_1, n_cols - 2, n_cols - 1, 1);
+      pivot_category_create_leaves (
+        statistics->root,
+        N_("Std. Error"), PIVOT_RC_OTHER,
+        N_("Asymptotic Sig."), PIVOT_RC_SIGNIFICANCE);
+      struct pivot_category *interval = pivot_category_create_group__ (
+        statistics->root,
+        pivot_value_new_text_format (N_("Asymp. %g%% Confidence Interval"),
+                                     roc->ci));
+      pivot_category_create_leaves (interval,
+                                    N_("Lower Bound"), PIVOT_RC_OTHER,
+                                    N_("Upper Bound"), PIVOT_RC_OTHER);
     }
 
-  if ( roc->n_vars > 1)
-    tab_text (tbl, 0, 1, TAT_TITLE, _("Variable under test"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variable under test"));
+  variables->root->show_label = true;
 
-  if ( roc->n_vars > 1)
-    tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
-
-
-  for ( i = 0 ; i < roc->n_vars ; ++i )
+  for (size_t i = 0 ; i < roc->n_vars ; ++i )
     {
-      tab_text (tbl, 0, 2 + i, TAT_TITLE, var_to_string (roc->vars[i]));
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (roc->vars[i]));
 
-      tab_double (tbl, n_cols - n_fields, 2 + i, 0, rs[i].auc, NULL, RC_OTHER);
+      pivot_table_put2 (table, 0, var_idx, pivot_value_new_number (rs[i].auc));
 
       if ( roc->print_se )
        {
-         double se ;
-         const double sd_0_5 = sqrt ((rs[i].n1 + rs[i].n2 + 1) /
-                                     (12 * rs[i].n1 * rs[i].n2));
-         double ci ;
-         double yy ;
-
-         se = rs[i].auc * (1 - rs[i].auc) + (rs[i].n1 - 1) * (rs[i].q1hat - pow2 (rs[i].auc)) +
-           (rs[i].n2 - 1) * (rs[i].q2hat - pow2 (rs[i].auc));
-
+         double se = (rs[i].auc * (1 - rs[i].auc)
+                       + (rs[i].n1 - 1) * (rs[i].q1hat - pow2 (rs[i].auc))
+                       + (rs[i].n2 - 1) * (rs[i].q2hat - pow2 (rs[i].auc)));
          se /= rs[i].n1 * rs[i].n2;
-
          se = sqrt (se);
 
-         tab_double (tbl, n_cols - 4, 2 + i, 0,
-                     se,
-                     NULL, RC_OTHER);
-
-         ci = 1 - roc->ci / 100.0;
-         yy = gsl_cdf_gaussian_Qinv (ci, se) ;
-
-         tab_double (tbl, n_cols - 2, 2 + i, 0,
-                     rs[i].auc - yy,
-                     NULL, RC_OTHER);
-
-         tab_double (tbl, n_cols - 1, 2 + i, 0,
-                     rs[i].auc + yy,
-                     NULL, RC_OTHER);
-
-         tab_double (tbl, n_cols - 3, 2 + i, 0,
-                     2.0 * gsl_cdf_ugaussian_Q (fabs ((rs[i].auc - 0.5 ) / sd_0_5)),
-                     NULL, RC_PVALUE);
+         double ci = 1 - roc->ci / 100.0;
+         double yy = gsl_cdf_gaussian_Qinv (ci, se);
+
+         double sd_0_5 = sqrt ((rs[i].n1 + rs[i].n2 + 1) /
+                                (12 * rs[i].n1 * rs[i].n2));
+          double sig = 2.0 * gsl_cdf_ugaussian_Q (fabs ((rs[i].auc - 0.5)
+                                                        / sd_0_5));
+          double entries[] = { se, sig, rs[i].auc - yy, rs[i].auc + yy };
+          for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+            pivot_table_put2 (table, i + 1, var_idx,
+                              pivot_value_new_number (entries[i]));
        }
     }
 
-  tab_submit (tbl);
+  pivot_table_submit (table);
 }
 
 
 static void
 show_summary (const struct cmd_roc *roc)
 {
-  const int n_cols = 3;
-  const int n_rows = 4;
-  struct tab_table *tbl = tab_create (n_cols, n_rows);
-
-  tab_title (tbl, _("Case Summary"));
-
-  tab_headers (tbl, 1, 0, 2, 0);
-
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, -1,
-          0, 0,
-          n_cols - 1,
-          n_rows - 1);
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, 2);
-  tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
-
-
-  tab_hline (tbl, TAL_2, 1, n_cols - 1, 1);
-  tab_vline (tbl, TAL_1, 2, 1, n_rows - 1);
-
+  struct pivot_table *table = pivot_table_create (N_("Case Summary"));
 
-  tab_text (tbl, 0, 1, TAT_TITLE | TAB_LEFT, var_to_string (roc->state_var));
-  tab_text (tbl, 1, 1, TAT_TITLE, _("Unweighted"));
-  tab_text (tbl, 2, 1, TAT_TITLE, _("Weighted"));
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Valid N (listwise)"),
+    N_("Unweighted"), PIVOT_RC_INTEGER,
+    N_("Weighted"), PIVOT_RC_OTHER);
+  statistics->root->show_label = true;
 
-  tab_joint_text (tbl, 1, 0, 2, 0,
-                 TAT_TITLE | TAB_CENTER,
-                 _("Valid N (listwise)"));
+  struct pivot_dimension *cases = pivot_dimension_create__ (
+    table, PIVOT_AXIS_ROW, pivot_value_new_variable (roc->state_var));
+  cases->root->show_label = true;
+  pivot_category_create_leaves (cases->root, N_("Positive"), N_("Negative"));
 
-
-  tab_text (tbl, 0, 2, TAB_LEFT, _("Positive"));
-  tab_text (tbl, 0, 3, TAB_LEFT, _("Negative"));
-
-
-  tab_double (tbl, 1, 2, 0, roc->pos, NULL, RC_INTEGER);
-  tab_double (tbl, 1, 3, 0, roc->neg, NULL, RC_INTEGER);
-
-  tab_double (tbl, 2, 2, 0, roc->pos_weighted, NULL, RC_OTHER);
-  tab_double (tbl, 2, 3, 0, roc->neg_weighted, NULL, RC_OTHER);
-
-  tab_submit (tbl);
+  struct entry
+    {
+      int stat_idx;
+      int case_idx;
+      double x;
+    }
+  entries[] = {
+    { 0, 0, roc->pos },
+    { 0, 1, roc->neg },
+    { 1, 0, roc->pos_weighted },
+    { 1, 1, roc->neg_weighted },
+  };
+  for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+    {
+      const struct entry *e = &entries[i];
+      pivot_table_put2 (table, e->stat_idx, e->case_idx,
+                        pivot_value_new_number (e->x));
+    }
+  pivot_table_submit (table);
 }
 
-
 static void
 show_coords (struct roc_state *rs, const struct cmd_roc *roc)
 {
-  int x = 1;
-  int i;
-  const int n_cols = roc->n_vars > 1 ? 4 : 3;
-  int n_rows = 1;
-  struct tab_table *tbl ;
-
-  for (i = 0; i < roc->n_vars; ++i)
-    n_rows += casereader_count_cases (rs[i].cutpoint_rdr);
-
-  tbl = tab_create (n_cols, n_rows);
+  struct pivot_table *table = pivot_table_create (
+    N_("Coordinates of the Curve"));
+  table->omit_empty = true;
 
-  if ( roc->n_vars > 1)
-    tab_title (tbl, _("Coordinates of the Curve"));
-  else
-    tab_title (tbl, _("Coordinates of the Curve (%s)"), var_to_string (roc->vars[0]));
-
-
-  tab_headers (tbl, 1, 0, 1, 0);
-
-  tab_hline (tbl, TAL_2, 0, n_cols - 1, 1);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("Positive if greater than or equal to"),
+                          N_("Sensitivity"), N_("1 - Specificity"));
 
-  if ( roc->n_vars > 1)
-    tab_text (tbl, 0, 0, TAT_TITLE, _("Test variable"));
+  struct pivot_dimension *coordinates = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Coordinates"));
+  coordinates->hide_all_labels = true;
 
-  tab_text (tbl, n_cols - 3, 0, TAT_TITLE, _("Positive if greater than or equal to"));
-  tab_text (tbl, n_cols - 2, 0, TAT_TITLE, _("Sensitivity"));
-  tab_text (tbl, n_cols - 1, 0, TAT_TITLE, _("1 - Specificity"));
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Test variable"));
+  variables->root->show_label = true;
 
-  tab_box (tbl,
-          TAL_2, TAL_2,
-          -1, TAL_1,
-          0, 0,
-          n_cols - 1,
-          n_rows - 1);
 
-  if ( roc->n_vars > 1)
-    tab_vline (tbl, TAL_2, 1, 0, n_rows - 1);
-
-  for (i = 0; i < roc->n_vars; ++i)
+  int n_coords = 0;
+  for (size_t i = 0; i < roc->n_vars; ++i)
     {
-      struct ccase *cc;
       struct casereader *r = casereader_clone (rs[i].cutpoint_rdr);
 
-      if ( roc->n_vars > 1)
-       tab_text (tbl, 0, x, TAT_TITLE, var_to_string (roc->vars[i]));
-
-      if ( i > 0)
-       tab_hline (tbl, TAL_1, 0, n_cols - 1, x);
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (roc->vars[i]));
 
-
-      for (; (cc = casereader_read (r)) != NULL;
-          case_unref (cc), x++)
+      struct ccase *cc;
+      int coord_idx = 0;
+      for (; (cc = casereader_read (r)) != NULL; case_unref (cc))
        {
          const double se = case_data_idx (cc, ROC_TP)->f /
-           (
-            case_data_idx (cc, ROC_TP)->f
-            +
-            case_data_idx (cc, ROC_FN)->f
-            );
+           (case_data_idx (cc, ROC_TP)->f + case_data_idx (cc, ROC_FN)->f);
 
          const double sp = case_data_idx (cc, ROC_TN)->f /
-           (
-            case_data_idx (cc, ROC_TN)->f
-            +
-            case_data_idx (cc, ROC_FP)->f
-            );
-
-         tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, ROC_CUTPOINT)->f,
-                     var_get_print_format (roc->vars[i]), RC_OTHER);
-
-         tab_double (tbl, n_cols - 2, x, 0, se, NULL, RC_OTHER);
-         tab_double (tbl, n_cols - 1, x, 0, 1 - sp, NULL, RC_OTHER);
+           (case_data_idx (cc, ROC_TN)->f + case_data_idx (cc, ROC_FP)->f);
+
+          pivot_table_put3 (
+            table, 0, coord_idx, var_idx,
+            pivot_value_new_var_value (roc->vars[i],
+                                       case_data_idx (cc, ROC_CUTPOINT)));
+
+          pivot_table_put3 (table, 1, coord_idx, var_idx,
+                            pivot_value_new_number (se));
+          pivot_table_put3 (table, 2, coord_idx, var_idx,
+                            pivot_value_new_number (1 - sp));
+          coord_idx++;
        }
 
+      if (coord_idx > n_coords)
+        n_coords = coord_idx;
+
       casereader_destroy (r);
     }
 
-  tab_submit (tbl);
+  for (size_t i = 0; i < n_coords; i++)
+    pivot_category_create_leaf (coordinates->root,
+                                pivot_value_new_integer (i + 1));
+
+  pivot_table_submit (table);
 }
 
 
index 9a32a530e836744f827ff39e524f43a3c9b85f4e..eb95372ae81d8573b1c294341f1752b7a10ca2b6 100644 (file)
 #include "libpspp/misc.h"
 #include "math/percentiles.h"
 #include "math/sort.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -308,99 +309,49 @@ runs_execute (const struct dataset *ds,
 static void
 show_runs_result (const struct runs_test *rt, const struct run_state *rs, const struct dictionary *dict)
 {
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
   const struct one_sample_test *otp = &rt->parent;
 
-  int i;
-  const int row_headers = 1;
-  const int column_headers = 1;
-  struct tab_table *table =
-    tab_create (row_headers + otp->n_vars, column_headers + 7);
-  tab_set_format (table, RC_WEIGHT, wfmt);
-
-  tab_headers (table, row_headers, 0, column_headers, 0);
-
-  tab_title (table, _("Runs Test"));
-
-  /* Box around the table and vertical lines inside*/
-  tab_box (table, TAL_2, TAL_2, -1, TAL_1,
-          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
-  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
-
-  for (i = 0 ; i < otp->n_vars; ++i)
+  struct pivot_table *table = pivot_table_create (N_("Runs Test"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
+
+  pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    (rt->cp_mode == CP_CUSTOM ? N_("Test Value")
+     : rt->cp_mode == CP_MODE ? N_("Test Value (mode)")
+     : rt->cp_mode == CP_MEAN ? N_("Test Value (mean)")
+     : N_("Test Value (median)")), PIVOT_RC_OTHER,
+    N_("Cases < Test Value"), PIVOT_RC_COUNT,
+    N_("Cases ≥ Test Value"), PIVOT_RC_COUNT,
+    N_("Total Cases"), PIVOT_RC_COUNT,
+    N_("Number of Runs"), PIVOT_RC_INTEGER,
+    N_("Z"), PIVOT_RC_OTHER,
+    N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Variable"));
+
+  for (size_t i = 0 ; i < otp->n_vars; ++i)
     {
       const struct run_state *run = &rs[i];
 
-      double z = runs_statistic (run);
-
-      tab_text (table,  row_headers + i, 0,
-               TAT_TITLE | TAB_CENTER ,
-               var_to_string (otp->vars[i]));
-
-      tab_double (table, row_headers +i, 1, 0,
-                 run->cutpoint, NULL, RC_OTHER);
+      int col = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (otp->vars[i]));
 
-      tab_double (table, row_headers +i, 2, 0,
-                 run->nn, NULL, RC_WEIGHT);
-
-      tab_double (table, row_headers +i, 3, 0,
-                 run->np, NULL, RC_WEIGHT);
-
-      tab_double (table, row_headers +i, 4, 0,
-                 run->n, NULL, RC_WEIGHT);
-
-      tab_double (table, row_headers +i, 5, 0,
-                 run->runs, NULL, RC_INTEGER);
-
-      tab_double (table, row_headers +i, 6, 0,
-                 z, NULL, RC_OTHER);
-
-      tab_double (table, row_headers +i, 7, 0,
-                 2.0 * (1.0 - gsl_cdf_ugaussian_P (z)), NULL, RC_PVALUE);
-    }
+      double z = runs_statistic (run);
 
-  switch  ( rt->cp_mode)
-    {
-    case CP_CUSTOM:
-      tab_text (table,  0, column_headers ,
-               TAT_TITLE | TAB_LEFT , _("Test Value"));
-      break;
-    case CP_MODE:
-      tab_text (table,  0, column_headers ,
-               TAT_TITLE | TAB_LEFT , _("Test Value (mode)"));
-      break;
-    case CP_MEAN:
-      tab_text (table,  0, column_headers ,
-               TAT_TITLE | TAB_LEFT , _("Test Value (mean)"));
-      break;
-    case CP_MEDIAN:
-      tab_text (table,  0, column_headers ,
-               TAT_TITLE | TAB_LEFT , _("Test Value (median)"));
-      break;
+      double rows[] = {
+        run->cutpoint,
+        run->nn,
+        run->np,
+        run->n,
+        run->runs,
+        z,
+        2.0 * (1.0 - gsl_cdf_ugaussian_P (z)),
+      };
+
+      for (int row = 0; row < sizeof rows / sizeof *rows; row++)
+        pivot_table_put2 (table, row, col, pivot_value_new_number (rows[row]));
     }
 
-  tab_text (table,  0, column_headers + 1,
-           TAT_TITLE | TAB_LEFT , _("Cases < Test Value"));
-
-  tab_text (table,  0, column_headers + 2,
-           TAT_TITLE | TAB_LEFT , _("Cases ≥ Test Value"));
-
-  tab_text (table,  0, column_headers + 3,
-           TAT_TITLE | TAB_LEFT , _("Total Cases"));
-
-  tab_text (table,  0, column_headers + 4,
-           TAT_TITLE | TAB_LEFT , _("Number of Runs"));
-
-  tab_text (table,  0, column_headers + 5,
-           TAT_TITLE | TAB_LEFT , _("Z"));
-
-  tab_text (table,  0, column_headers + 6,
-           TAT_TITLE | TAB_LEFT , _("Asymp. Sig. (2-tailed)"));
-
-  tab_submit (table);
+  pivot_table_submit (table);
 }
-
-
index e16298a6baf5501ce5cecae732b2c5d1c29c27b7..30de7d1e9bdfdaccf18c01772c387c2ee9ea463e 100644 (file)
 #include "data/variable.h"
 #include "language/stats/npar.h"
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 struct sign_test_params
@@ -47,117 +48,80 @@ struct sign_test_params
   double point_prob;
 };
 
+static int
+add_pair_leaf (struct pivot_dimension *dimension, variable_pair *pair)
+{
+  char *label = xasprintf ("%s - %s", var_to_string ((*pair)[0]),
+                           var_to_string ((*pair)[1]));
+  return pivot_category_create_leaf (
+    dimension->root,
+    pivot_value_new_user_text_nocopy (label));
+}
 
 static void
 output_frequency_table (const struct two_sample_test *t2s,
                        const struct sign_test_params *param,
                        const struct dictionary *dict)
 {
-  int i;
-  struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs);
-
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
-
-  tab_set_format (table, RC_WEIGHT, wfmt);
-  tab_title (table, _("Frequencies"));
-
-  tab_headers (table, 2, 0, 1, 0);
+  struct pivot_table *table = pivot_table_create (N_("Frequencies"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-  /* Vertical lines inside the box */
-  tab_box (table, 0, 0, -1, TAL_1,
-          1, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("N"),
+                          N_("N"), PIVOT_RC_COUNT);
 
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Differences"),
+                          N_("Negative Differences"),
+                          N_("Positive Differences"),
+                          N_("Ties"), N_("Total"));
 
-  tab_text (table,  2, 0,  TAB_CENTER, _("N"));
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Pairs"));
 
-  for (i = 0 ; i < t2s->n_pairs; ++i)
+  for (size_t i = 0 ; i < t2s->n_pairs; ++i)
     {
       variable_pair *vp = &t2s->pairs[i];
 
-      struct string pair_name;
-      ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-      ds_put_cstr (&pair_name, " - ");
-      ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
+      int pair_idx = add_pair_leaf (pairs, vp);
 
-
-      tab_text (table, 0, 1 + i * 4, TAB_LEFT, ds_cstr (&pair_name));
-
-      ds_destroy (&pair_name);
-
-      tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4);
-
-      tab_text (table,  1, 1 + i * 4,  TAB_LEFT, _("Negative Differences"));
-      tab_text (table,  1, 2 + i * 4,  TAB_LEFT, _("Positive Differences"));
-      tab_text (table,  1, 3 + i * 4,  TAB_LEFT, _("Ties"));
-      tab_text (table,  1, 4 + i * 4,  TAB_LEFT, _("Total"));
-
-      tab_double (table, 2, 1 + i * 4, TAB_RIGHT, param[i].neg, NULL, RC_WEIGHT);
-      tab_double (table, 2, 2 + i * 4, TAB_RIGHT, param[i].pos, NULL, RC_WEIGHT);
-      tab_double (table, 2, 3 + i * 4, TAB_RIGHT, param[i].ties, NULL, RC_WEIGHT);
-      tab_double (table, 2, 4 + i * 4, TAB_RIGHT,
-                 param[i].ties + param[i].neg + param[i].pos, NULL, RC_WEIGHT);
+      const struct sign_test_params *p = &param[i];
+      double values[] = { p->neg, p->pos, p->ties, p->ties + p->neg + p->pos };
+      for (size_t j = 0; j < sizeof values / sizeof *values; j++)
+        pivot_table_put3 (table, 0, j, pair_idx,
+                          pivot_value_new_number (values[j]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
 static void
 output_statistics_table (const struct two_sample_test *t2s,
                         const struct sign_test_params *param)
 {
-  int i;
-  struct tab_table *table = tab_create (1 + t2s->n_pairs, 4);
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
 
-  tab_title (table, _("Test Statistics"));
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
+                          N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+                          N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE,
+                          N_("Point Probability"), PIVOT_RC_SIGNIFICANCE);
 
-  tab_headers (table, 0, 1,  0, 1);
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Pairs"));
 
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
-  tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
-
-
-  /* Vertical lines inside the box */
-  tab_box (table, -1, -1, -1, TAL_1,
-          0, 0,
-          tab_nc (table) - 1, tab_nr (table) - 1);
-
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1,
-          tab_nr (table) - 1);
-
-  tab_text (table,  0, 1, TAT_TITLE | TAB_LEFT,
-           _("Exact Sig. (2-tailed)"));
-
-  tab_text (table,  0, 2, TAT_TITLE | TAB_LEFT,
-           _("Exact Sig. (1-tailed)"));
-
-  tab_text (table,  0, 3, TAT_TITLE | TAB_LEFT,
-           _("Point Probability"));
-
-  for (i = 0 ; i < t2s->n_pairs; ++i)
+  for (size_t i = 0 ; i < t2s->n_pairs; ++i)
     {
       variable_pair *vp = &t2s->pairs[i];
-
-      struct string pair_name;
-      ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-      ds_put_cstr (&pair_name, " - ");
-      ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
-
-      tab_text (table,  1 + i, 0, TAB_LEFT, ds_cstr (&pair_name));
-      ds_destroy (&pair_name);
-
-      tab_double (table, 1 + i, 1, TAB_RIGHT,
-                 param[i].one_tailed_sig * 2, NULL, RC_PVALUE);
-
-      tab_double (table, 1 + i, 2, TAB_RIGHT, param[i].one_tailed_sig, NULL, RC_PVALUE);
-      tab_double (table, 1 + i, 3, TAB_RIGHT, param[i].point_prob, NULL, RC_PVALUE);
+      int pair_idx = add_pair_leaf (pairs, vp);
+
+      const struct sign_test_params *p = &param[i];
+      double values[] = { p->one_tailed_sig * 2,
+                          p->one_tailed_sig,
+                          p->point_prob };
+      for (size_t j = 0; j < sizeof values / sizeof *values; j++)
+        pivot_table_put2 (table, j, pair_idx,
+                          pivot_value_new_number (values[j]));
     }
 
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
 void
index e4e42433080389534e7782154dbb0775e83cc846..fff8c968c5f99405451ff3e06f961387e00acac0 100644 (file)
 #include "data/dictionary.h"
 #include "data/format.h"
 #include "data/variable.h"
-
 #include "math/moments.h"
 #include "math/levene.h"
+#include "output/pivot-table.h"
 
-#include <output/tab.h>
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -187,207 +187,170 @@ indep_run (struct tt *tt, const struct variable *gvar,
 static void
 indep_summary (const struct tt *tt, struct indep_samples *is, const struct pair_stats *ps)
 {
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-
-  int v;
-  int cols = 6;
-  const int heading_rows = 1;
-  int rows = tt->n_vars * 2 + heading_rows;
-
-  struct string vallab0 ;
-  struct string vallab1 ;
-  struct tab_table *t = tab_create (cols, rows);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  ds_init_empty (&vallab0);
-  ds_init_empty (&vallab1);
-
-  tab_headers (t, 0, 0, 1, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
-  tab_hline (t, TAL_2, 0, cols - 1, 1);
-
-  tab_title (t, _("Group Statistics"));
-  tab_text  (t, 1, 0, TAB_CENTER | TAT_TITLE, var_to_string (is->gvar));
-  tab_text  (t, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text  (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
-  tab_text  (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text  (t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
-
+  struct pivot_table *table = pivot_table_create (N_("Group Statistics"));
+  pivot_table_set_weight_var (table, tt->wv);
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Mean"), PIVOT_RC_OTHER,
+                          N_("Std. Deviation"), PIVOT_RC_OTHER,
+                          N_("S.E. Mean"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *group = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Group"));
+  group->root->show_label = true;
   if (is->cut)
     {
+      struct string vallab0 = DS_EMPTY_INITIALIZER;
       ds_put_cstr (&vallab0, "≥");
-      ds_put_cstr (&vallab1, "<");
-
       var_append_value_name (is->gvar, is->gval0, &vallab0);
+      pivot_category_create_leaf (group->root,
+                                  pivot_value_new_user_text_nocopy (
+                                    ds_steal_cstr (&vallab0)));
+
+      struct string vallab1 = DS_EMPTY_INITIALIZER;
+      ds_put_cstr (&vallab1, "<");
       var_append_value_name (is->gvar, is->gval0, &vallab1);
+      pivot_category_create_leaf (group->root,
+                                  pivot_value_new_user_text_nocopy (
+                                    ds_steal_cstr (&vallab1)));
     }
   else
     {
-      var_append_value_name (is->gvar, is->gval0, &vallab0);
-      var_append_value_name (is->gvar, is->gval1, &vallab1);
+      pivot_category_create_leaf (
+        group->root, pivot_value_new_var_value (is->gvar, is->gval0));
+      pivot_category_create_leaf (
+        group->root, pivot_value_new_var_value (is->gvar, is->gval1));
     }
 
-  tab_vline (t, TAL_1, 1, heading_rows,  rows - 1);
+  struct pivot_dimension *dep_vars = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
 
-  for (v = 0; v < tt->n_vars; ++v)
+  for (size_t v = 0; v < tt->n_vars; ++v)
     {
-      int i;
       const struct variable *var = tt->vars[v];
 
-      tab_text (t, 0, v * 2 + heading_rows, TAB_LEFT,
-                var_to_string (var));
-
-      tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT,
-                       ds_cstr (&vallab0));
+      int dep_var_idx = pivot_category_create_leaf (
+        dep_vars->root, pivot_value_new_variable (var));
 
-      tab_text (t, 1, v * 2 + 1 + heading_rows, TAB_LEFT,
-                       ds_cstr (&vallab1));
-
-      for (i = 0 ; i < 2; ++i)
+      for (int i = 0 ; i < 2; ++i)
        {
          double cc, mean, sigma;
          moments_calculate (ps[v].mom[i], &cc, &mean, &sigma, NULL, NULL);
 
-         tab_double (t, 2, v * 2 + i + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT);
-         tab_double (t, 3, v * 2 + i + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER);
-         tab_double (t, 4, v * 2 + i + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER);
-         tab_double (t, 5, v * 2 + i + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER);
+          double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            pivot_table_put3 (table, j, i, dep_var_idx,
+                              pivot_value_new_number (entries[j]));
        }
     }
 
-  tab_submit (t);
-
-  ds_destroy (&vallab0);
-  ds_destroy (&vallab1);
+  pivot_table_submit (table);
 }
 
 
 static void
 indep_test (const struct tt *tt, const struct pair_stats *ps)
 {
-  int v;
-  const int heading_rows = 3;
-  const int rows= tt->n_vars * 2 + heading_rows;
-
-  const size_t cols = 11;
-
-  struct tab_table *t = tab_create (cols, rows);
-  tab_headers (t, 0, 0, 3, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
-  tab_hline (t, TAL_2, 0, cols - 1, 3);
-
-  tab_title (t, _("Independent Samples Test"));
-
-  tab_hline (t, TAL_1, 2, cols - 1, 1);
-  tab_vline (t, TAL_2, 2, 0, rows - 1);
-  tab_vline (t, TAL_1, 4, 0, rows - 1);
-  tab_box (t, -1, -1, -1, TAL_1, 2, 1, cols - 2, rows - 1);
-  tab_hline (t, TAL_1, cols - 2, cols - 1, 2);
-  tab_box (t, -1, -1, -1, TAL_1, cols - 2, 2, cols - 1, rows - 1);
-  tab_joint_text (t, 2, 0, 3, 0, TAB_CENTER, _("Levene's Test for Equality of Variances"));
-  tab_joint_text (t, 4, 0, cols - 1, 0, TAB_CENTER, _("t-test for Equality of Means"));
-
-  tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("F"));
-  tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig."));
-  tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("t"));
-  tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
-  tab_text (t, 7, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference"));
-  tab_text (t, 8, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Difference"));
-  tab_text (t, 9, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
-  tab_text (t, 10, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
-
-  tab_joint_text_format (t, 9, 1, 10, 1, TAB_CENTER,
-                         _("%g%% Confidence Interval of the Difference"),
-                         tt->confidence * 100.0);
-
-  tab_vline (t, TAL_1, 1, heading_rows,  rows - 1);
-
-  for (v = 0; v < tt->n_vars; ++v)
+  struct pivot_table *table = pivot_table_create (
+    N_("Independent Samples Test"));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  pivot_category_create_group (
+    statistics->root, N_("Levene's Test for Equality of Variances"),
+    N_("F"), PIVOT_RC_OTHER,
+    N_("Sig."), PIVOT_RC_SIGNIFICANCE);
+  struct pivot_category *group = pivot_category_create_group (
+    statistics->root, N_("T-Test for Equality of Means"),
+    N_("t"), PIVOT_RC_OTHER,
+    N_("df"), PIVOT_RC_OTHER,
+    N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+    N_("Mean Difference"), PIVOT_RC_OTHER,
+    N_("Std. Error Difference"), PIVOT_RC_OTHER);
+  pivot_category_create_group (
+    group, N_("95% Confidence Interval of the Difference"),
+    N_("Lower"), PIVOT_RC_OTHER,
+    N_("Upper"), PIVOT_RC_OTHER);
+
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Assumptions"),
+                          N_("Equal variances assumed"),
+                          N_("Equal variances not assumed"));
+
+  struct pivot_dimension *dep_vars = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
+
+  for (size_t v = 0; v < tt->n_vars; ++v)
   {
-    double df, pooled_variance, mean_diff, tval;
-    double se2, std_err_diff;
-    double p, q;
+    int dep_var_idx = pivot_category_create_leaf (
+      dep_vars->root, pivot_value_new_variable (tt->vars[v]));
+
     double cc0, mean0, sigma0;
     double cc1, mean1, sigma1;
     moments_calculate (ps[v].mom[0], &cc0, &mean0, &sigma0, NULL, NULL);
     moments_calculate (ps[v].mom[1], &cc1, &mean1, &sigma1, NULL, NULL);
 
-    tab_text (t, 0, v * 2 + heading_rows, TAB_LEFT, var_to_string (tt->vars[v]));
-    tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT, _("Equal variances assumed"));
-
-    df = cc0 + cc1 - 2.0;
-    tab_double (t, 5, v * 2 + heading_rows, TAB_RIGHT, df, NULL, RC_OTHER);
-
-    pooled_variance = ((cc0 - 1)* sigma0 + (cc1 - 1) * sigma1) / df ;
-
-    tval = (mean0 - mean1) / sqrt (pooled_variance);
-    tval /= sqrt ((cc0 + cc1) / (cc0 * cc1));
-
-    tab_double (t, 4, v * 2 + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER);
+    double mean_diff = mean0 - mean1;
 
-    p = gsl_cdf_tdist_P (tval, df);
-    q = gsl_cdf_tdist_Q (tval, df);
 
-    mean_diff = mean0 - mean1;
-
-    tab_double (t, 6, v * 2 + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p),   NULL, RC_PVALUE);
-    tab_double (t, 7, v * 2 + heading_rows, TAB_RIGHT, mean_diff, NULL, RC_OTHER);
-
-    std_err_diff = sqrt (pooled_variance * (1.0/cc0 + 1.0/cc1));
-    tab_double (t, 8, v * 2 + heading_rows, TAB_RIGHT, std_err_diff, NULL, RC_OTHER);
-
-
-    /* Now work out the confidence interval */
-    q = (1 - tt->confidence)/2.0;  /* 2-tailed test */
-
-    tval = gsl_cdf_tdist_Qinv (q, df);
-    tab_double (t,  9, v * 2 + heading_rows, TAB_RIGHT, mean_diff - tval * std_err_diff, NULL, RC_OTHER);
-    tab_double (t, 10, v * 2 + heading_rows, TAB_RIGHT, mean_diff + tval * std_err_diff, NULL, RC_OTHER);
+    /* Equal variances assumed. */
+    double e_df = cc0 + cc1 - 2.0;
+    double e_pooled_variance = ((cc0 - 1)* sigma0 + (cc1 - 1) * sigma1) / e_df;
+    double e_tval = ((mean0 - mean1) / sqrt (e_pooled_variance)
+                     / sqrt ((cc0 + cc1) / (cc0 * cc1)));
+    double e_p = gsl_cdf_tdist_P (e_tval, e_df);
+    double e_q = gsl_cdf_tdist_Q (e_tval, e_df);
+    double e_sig = 2.0 * (e_tval > 0 ? e_q : e_p);
+    double e_std_err_diff = sqrt (e_pooled_variance * (1.0/cc0 + 1.0/cc1));
+    double e_tval_qinv = gsl_cdf_tdist_Qinv ((1 - tt->confidence) / 2.0, e_df);
 
     /* Equal variances not assumed */
-    tab_text (t, 1, v * 2 + heading_rows + 1,  TAB_LEFT, _("Equal variances not assumed"));
-    std_err_diff = sqrt ((sigma0 / cc0) + (sigma1 / cc1));
-
-    se2 = sigma0 / cc0 + sigma1 / cc1;
-    tval = mean_diff / sqrt (se2);
-    tab_double (t, 4, v * 2 + heading_rows + 1, TAB_RIGHT, tval, NULL, RC_OTHER);
-
-    {
-      double p, q;
-      const double s0 = sigma0 / (cc0);
-      const double s1 = sigma1 / (cc1);
-      double df = pow2 (s0 + s1) ;
-      df /= pow2 (s0) / (cc0 - 1) + pow2 (s1) / (cc1 - 1);
-
-      tab_double (t, 5, v * 2 + heading_rows + 1, TAB_RIGHT, df, NULL, RC_OTHER);
-
-      p = gsl_cdf_tdist_P (tval, df);
-      q = gsl_cdf_tdist_Q (tval, df);
-
-      tab_double (t, 6, v * 2 + heading_rows + 1, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE);
-
-      /* Now work out the confidence interval */
-      q = (1 - tt->confidence) / 2.0;  /* 2-tailed test */
-
-      tval = gsl_cdf_tdist_Qinv (q, df);
-    }
-
-    tab_double (t, 7, v * 2 + heading_rows + 1, TAB_RIGHT, mean_diff, NULL, RC_OTHER);
-    tab_double (t, 8, v * 2 + heading_rows + 1, TAB_RIGHT, std_err_diff, NULL, RC_OTHER);
-    tab_double (t, 9, v * 2 + heading_rows + 1, TAB_RIGHT,  mean_diff - tval * std_err_diff, NULL, RC_OTHER);
-    tab_double (t, 10, v * 2 + heading_rows + 1, TAB_RIGHT, mean_diff + tval * std_err_diff, NULL, RC_OTHER);
-
-    tab_double (t, 2, v * 2 + heading_rows, TAB_CENTER, ps[v].lev, NULL, RC_OTHER);
-
-
-    {
-      /* Now work out the significance of the Levene test */
-      double df1 = 1;
-      double df2 = cc0 + cc1 - 2;
-      double q = gsl_cdf_fdist_Q (ps[v].lev, df1, df2);
-      tab_double (t, 3, v * 2 + heading_rows, TAB_CENTER, q, NULL, RC_PVALUE);
-    }
+    const double s0 = sigma0 / cc0;
+    const double s1 = sigma1 / cc1;
+    double d_df = (pow2 (s0 + s1) / (pow2 (s0) / (cc0 - 1)
+                                   + pow2 (s1) / (cc1 - 1)));
+    double d_tval = mean_diff / sqrt (sigma0 / cc0 + sigma1 / cc1);
+    double d_p = gsl_cdf_tdist_P (d_tval, d_df);
+    double d_q = gsl_cdf_tdist_Q (d_tval, d_df);
+    double d_sig = 2.0 * (d_tval > 0 ? d_q : d_p);
+    double d_std_err_diff = sqrt ((sigma0 / cc0) + (sigma1 / cc1));
+    double d_tval_qinv = gsl_cdf_tdist_Qinv ((1 - tt->confidence) / 2.0, d_df);
+
+    struct entry
+      {
+        int assumption_idx;
+        int stat_idx;
+        double x;
+      }
+    entries[] =
+      {
+        { 0, 0, ps[v].lev },
+        { 0, 1, gsl_cdf_fdist_Q (ps[v].lev, 1, cc0 + cc1 - 2) },
+
+        { 0, 2, e_tval },
+        { 0, 3, e_df },
+        { 0, 4, e_sig },
+        { 0, 5, mean_diff },
+        { 0, 6, e_std_err_diff },
+        { 0, 7, mean_diff - e_tval_qinv * e_std_err_diff },
+        { 0, 8, mean_diff + e_tval_qinv * e_std_err_diff },
+
+        { 1, 2, d_tval },
+        { 1, 3, d_df },
+        { 1, 4, d_sig },
+        { 1, 5, mean_diff },
+        { 1, 6, d_std_err_diff },
+        { 1, 7, mean_diff - d_tval_qinv * d_std_err_diff },
+        { 1, 8, mean_diff + d_tval_qinv * d_std_err_diff },
+      };
+
+    for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+      {
+        const struct entry *e = &entries[i];
+        pivot_table_put3 (table, e->stat_idx, e->assumption_idx,
+                          dep_var_idx, pivot_value_new_number (e->x));
+      }
   }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
index fdcef55937f5faf20a67e49e7e5c37fdbe485aaa..20914c9223fa2bc67eefc72ffb730377b5727a66 100644 (file)
 #include "libpspp/hmapx.h"
 #include "math/moments.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
@@ -41,9 +42,6 @@ struct per_var_stats
 {
   const struct variable *var;
 
-  /* The position for reporting purposes */
-  int posn;
-
   /* N, Mean, Variance */
   struct moments *mom;
 
@@ -54,7 +52,8 @@ struct per_var_stats
 
 struct one_samp
 {
-  struct hmapx hmap;
+  struct per_var_stats *stats;
+  size_t n_stats;
   double testval;
 };
 
@@ -62,154 +61,118 @@ struct one_samp
 static void
 one_sample_test (const struct tt *tt, const struct one_samp *os)
 {
-  struct hmapx_node *node;
-  struct per_var_stats *per_var_stats;
-
-  const int heading_rows = 3;
-  const size_t rows = heading_rows + tt->n_vars;
-  const size_t cols = 7;
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-
-  struct tab_table *t = tab_create (cols, rows);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-
-  tab_headers (t, 0, 0, heading_rows, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
-  tab_hline (t, TAL_2, 0, cols - 1, 3);
-
-  tab_title (t, _("One-Sample Test"));
-  tab_hline (t, TAL_1, 1, cols - 1, 1);
-  tab_vline (t, TAL_2, 1, 0, rows - 1);
-
-  tab_joint_text_format (t, 1, 0, cols - 1, 0, TAB_CENTER,
-                         _("Test Value = %f"), os->testval);
-
-  tab_box (t, -1, -1, -1, TAL_1, 1, 1, cols - 1, rows - 1);
-
-  tab_joint_text_format (t, 5, 1, 6, 1, TAB_CENTER,
-                         _("%g%% Confidence Interval of the Difference"),
-                         tt->confidence * 100.0);
-
-  tab_hline (t, TAL_1, 5, 6, 2);
-  tab_text (t, 1, 2, TAB_CENTER | TAT_TITLE, _("t"));
-  tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
-  tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("Mean Difference"));
-  tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
-  tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
-
-  HMAPX_FOR_EACH (per_var_stats, node, &os->hmap)
+  struct pivot_table *table = pivot_table_create (N_("One-Sample Test"));
+  pivot_table_set_weight_var (table, tt->wv);
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  struct pivot_category *group = pivot_category_create_group__ (
+    statistics->root, pivot_value_new_user_text_nocopy (
+      xasprintf (_("Test Value = %.*g"), DBL_DIG + 1, os->testval)));
+  pivot_category_create_leaves (
+    group,
+    N_("t"), PIVOT_RC_OTHER,
+    N_("df"), PIVOT_RC_COUNT,
+    N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+    N_("Mean Difference"), PIVOT_RC_OTHER);
+  struct pivot_category *subgroup = pivot_category_create_group__ (
+    group, pivot_value_new_user_text_nocopy (
+      xasprintf (_("%g%% Confidence Interval of the Difference"),
+                 tt->confidence * 100.0)));
+  pivot_category_create_leaves (subgroup,
+                                N_("Lower"), PIVOT_RC_OTHER,
+                                N_("Upper"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *dep_vars = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
+
+  for (size_t i = 0; i < os->n_stats; i++)
     {
+      const struct per_var_stats *per_var_stats = &os->stats[i];
       const struct moments *m = per_var_stats->mom;
-      double cc, mean, sigma;
-      double tval, df;
-      double p, q;
-      double mean_diff;
-      double se_mean ;
-      const int v = per_var_stats->posn;
-
-      moments_calculate (m, &cc, &mean, &sigma, NULL, NULL);
-
-      tval = (mean - os->testval) * sqrt (cc / sigma);
-
-      mean_diff = per_var_stats->sum_diff / cc;
-      se_mean = sqrt (sigma / cc);
-      df = cc - 1.0;
-      p = gsl_cdf_tdist_P (tval, df);
-      q = gsl_cdf_tdist_Q (tval, df);
-
-      tab_text (t, 0, v + heading_rows, TAB_LEFT, var_to_string (per_var_stats->var));
-      tab_double (t, 1, v + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER);
-      tab_double (t, 2, v + heading_rows, TAB_RIGHT, df, NULL, RC_WEIGHT);
 
-      /* Multiply by 2 to get 2-tailed significance, makeing sure we've got
-        the correct tail*/
-      tab_double (t, 3, v + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE);
+      int dep_var_idx = pivot_category_create_leaf (
+        dep_vars->root, pivot_value_new_variable (per_var_stats->var));
 
-      tab_double (t, 4, v + heading_rows, TAB_RIGHT, mean_diff,  NULL, RC_OTHER);
-
-      tval = gsl_cdf_tdist_Qinv ( (1.0 - tt->confidence) / 2.0, df);
-
-      tab_double (t, 5, v + heading_rows, TAB_RIGHT, mean_diff - tval * se_mean, NULL, RC_OTHER);
-      tab_double (t, 6, v + heading_rows, TAB_RIGHT, mean_diff + tval * se_mean, NULL, RC_OTHER);
+      double cc, mean, sigma;
+      moments_calculate (m, &cc, &mean, &sigma, NULL, NULL);
+      double tval = (mean - os->testval) * sqrt (cc / sigma);
+      double mean_diff = per_var_stats->sum_diff / cc;
+      double se_mean = sqrt (sigma / cc);
+      double df = cc - 1.0;
+      double p = gsl_cdf_tdist_P (tval, df);
+      double q = gsl_cdf_tdist_Q (tval, df);
+      double sig = 2.0 * (tval > 0 ? q : p);
+      double tval_qinv = gsl_cdf_tdist_Qinv ((1.0 - tt->confidence) / 2.0, df);
+      double lower = mean_diff - tval_qinv * se_mean;
+      double upper = mean_diff + tval_qinv * se_mean;
+
+      double entries[] = { tval, df, sig, mean_diff, lower, upper };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, dep_var_idx,
+                          pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 static void
 one_sample_summary (const struct tt *tt, const struct one_samp *os)
 {
-  struct hmapx_node *node;
-  struct per_var_stats *per_var_stats;
-
-  const int cols = 5;
-  const int heading_rows = 1;
-  const int rows = tt->n_vars + heading_rows;
-  struct tab_table *t = tab_create (cols, rows);
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 0, 0, heading_rows, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
-  tab_hline (t, TAL_2, 0, cols - 1, 1);
-
-  tab_title (t, _("One-Sample Statistics"));
-  tab_vline (t, TAL_2, 1, 0, rows - 1);
-  tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
-
-  HMAPX_FOR_EACH (per_var_stats, node, &os->hmap)
+  struct pivot_table *table = pivot_table_create (N_("One-Sample Statistics"));
+  pivot_table_set_weight_var (table, tt->wv);
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Mean"), PIVOT_RC_OTHER,
+                          N_("Std. Deviation"), PIVOT_RC_OTHER,
+                          N_("S.E. Mean"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+
+  for (size_t i = 0; i < os->n_stats; i++)
     {
+      const struct per_var_stats *per_var_stats = &os->stats[i];
       const struct moments *m = per_var_stats->mom;
-      const int v = per_var_stats->posn;
+
+      int var_idx = pivot_category_create_leaf (
+        variables->root, pivot_value_new_variable (per_var_stats->var));
+
       double cc, mean, sigma;
       moments_calculate (m, &cc, &mean, &sigma, NULL, NULL);
 
-      tab_text (t, 0, v + heading_rows, TAB_LEFT, var_to_string (per_var_stats->var));
-      tab_double (t, 1, v + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT);
-      tab_double (t, 2, v + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER);
-      tab_double (t, 3, v + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER);
-      tab_double (t, 4, v + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER);
+      double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) };
+      for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+        pivot_table_put2 (table, j, var_idx,
+                          pivot_value_new_number (entries[j]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 void
 one_sample_run (const struct tt *tt, double testval, struct casereader *reader)
 {
-  int i;
-  struct ccase *c;
   struct one_samp os;
-  struct casereader *r;
-  struct hmapx_node *node;
-  struct per_var_stats *per_var_stats;
-
   os.testval = testval;
-  hmapx_init (&os.hmap);
-
-  /* Insert all the variables into the map */
-  for (i = 0; i < tt->n_vars; ++i)
+  os.stats = xcalloc (tt->n_vars, sizeof *os.stats);
+  os.n_stats = tt->n_vars;
+  for (size_t i = 0; i < tt->n_vars; ++i)
     {
-      struct per_var_stats *per_var_stats = xzalloc (sizeof (*per_var_stats));
-
-      per_var_stats->posn = i;
+      struct per_var_stats *per_var_stats = &os.stats[i];
       per_var_stats->var = tt->vars[i];
       per_var_stats->mom = moments_create (MOMENT_VARIANCE);
-
-      hmapx_insert (&os.hmap, per_var_stats, hash_pointer (per_var_stats->var, 0));
     }
 
-  r = casereader_clone (reader);
+  struct casereader *r = casereader_clone (reader);
+  struct ccase *c;
   for ( ; (c = casereader_read (r) ); case_unref (c))
     {
       double w = dict_get_case_weight (tt->dict, c, NULL);
-      struct hmapx_node *node;
-      struct per_var_stats *per_var_stats;
-      HMAPX_FOR_EACH (per_var_stats, node, &os.hmap)
-       {
+      for (size_t i = 0; i < os.n_stats; i++)
+        {
+          const struct per_var_stats *per_var_stats = &os.stats[i];
          const struct variable *var = per_var_stats->var;
          const union value *val = case_data (c, var);
          if (var_is_value_missing (var, val, tt->exclude))
@@ -224,10 +187,9 @@ one_sample_run (const struct tt *tt, double testval, struct casereader *reader)
   for ( ; (c = casereader_read (r) ); case_unref (c))
     {
       double w = dict_get_case_weight (tt->dict, c, NULL);
-      struct hmapx_node *node;
-      struct per_var_stats *per_var_stats;
-      HMAPX_FOR_EACH (per_var_stats, node, &os.hmap)
-       {
+      for (size_t i = 0; i < os.n_stats; i++)
+        {
+          struct per_var_stats *per_var_stats = &os.stats[i];
          const struct variable *var = per_var_stats->var;
          const union value *val = case_data (c, var);
          if (var_is_value_missing (var, val, tt->exclude))
@@ -242,12 +204,11 @@ one_sample_run (const struct tt *tt, double testval, struct casereader *reader)
   one_sample_summary (tt, &os);
   one_sample_test (tt, &os);
 
-  HMAPX_FOR_EACH (per_var_stats, node, &os.hmap)
+  for (size_t i = 0; i < os.n_stats; i++)
     {
+      const struct per_var_stats *per_var_stats = &os.stats[i];
       moments_destroy (per_var_stats->mom);
-      free (per_var_stats);
     }
-
-  hmapx_destroy (&os.hmap);
+  free (os.stats);
 }
 
index 4935e9a8cb866bd112d5d6118050af97f016ce46..921233b68e52b8364c3c9e14e3496c8046cd88fd 100644 (file)
 #include "data/dictionary.h"
 #include "data/format.h"
 #include "data/variable.h"
-#include "libpspp/hmapx.h"
-#include "libpspp/hash-functions.h"
 
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gettext.h"
+#define N_(msgid) msgid
 #define _(msgid) gettext (msgid)
 
 
 struct pair_stats
 {
-  int posn;
   double sum_of_prod;
   struct moments *mom0;
   const struct variable *var0;
@@ -51,7 +49,8 @@ struct pair_stats
 
 struct paired_samp
 {
-  struct hmapx hmap;
+  struct pair_stats *ps;
+  size_t n_ps;
 };
 
 static void paired_summary (const struct tt *tt, struct paired_samp *os);
@@ -61,31 +60,21 @@ static void paired_test (const struct tt *tt, const struct paired_samp *os);
 void
 paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *reader)
 {
-  int i;
   struct ccase *c;
   struct paired_samp ps;
   struct casereader *r;
-  struct hmapx_node *node;
-  struct pair_stats *pp = NULL;
 
-  hmapx_init (&ps.hmap);
-
-  for (i = 0; i < n_pairs; ++i)
+  ps.ps = xcalloc (n_pairs, sizeof *ps.ps);
+  ps.n_ps = n_pairs;
+  for (size_t i = 0; i < n_pairs; ++i)
     {
       vp *pair = &pairs[i];
-      unsigned int hash;
-      struct pair_stats *pp = xzalloc (sizeof *pp);
-      pp->posn = i;
+      struct pair_stats *pp = &ps.ps[i];
       pp->var0 = (*pair)[0];
       pp->var1 = (*pair)[1];
       pp->mom0 = moments_create (MOMENT_VARIANCE);
       pp->mom1 = moments_create (MOMENT_VARIANCE);
       pp->mom_diff = moments_create (MOMENT_VARIANCE);
-
-      hash = hash_pointer ((*pair)[0], 0);
-      hash = hash_pointer ((*pair)[1], hash);
-
-      hmapx_insert (&ps.hmap, pp, hash);
     }
 
   r = casereader_clone (reader);
@@ -93,10 +82,9 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r
     {
       double w = dict_get_case_weight (tt->dict, c, NULL);
 
-      struct hmapx_node *node;
-      struct pair_stats *pp = NULL;
-      HMAPX_FOR_EACH (pp, node, &ps.hmap)
+      for (int i = 0; i < ps.n_ps; i++)
        {
+          struct pair_stats *pp = &ps.ps[i];
          const union value *val0 = case_data (c, pp->var0);
          const union value *val1 = case_data (c, pp->var1);
           if (var_is_value_missing (pp->var0, val0, tt->exclude))
@@ -117,10 +105,9 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r
     {
       double w = dict_get_case_weight (tt->dict, c, NULL);
 
-      struct hmapx_node *node;
-      struct pair_stats *pp = NULL;
-      HMAPX_FOR_EACH (pp, node, &ps.hmap)
+      for (int i = 0; i < ps.n_ps; i++)
        {
+          struct pair_stats *pp = &ps.ps[i];
          const union value *val0 = case_data (c, pp->var0);
          const union value *val1 = case_data (c, pp->var1);
           if (var_is_value_missing (pp->var0, val0, tt->exclude))
@@ -142,214 +129,172 @@ paired_run (const struct tt *tt, size_t n_pairs, vp *pairs, struct casereader *r
   paired_test (tt, &ps);
 
   /* Clean up */
-  HMAPX_FOR_EACH (pp, node, &ps.hmap)
+
+  for (int i = 0; i < ps.n_ps; i++)
     {
+      struct pair_stats *pp = &ps.ps[i];
       moments_destroy (pp->mom0);
       moments_destroy (pp->mom1);
       moments_destroy (pp->mom_diff);
-      free (pp);
     }
-
-  hmapx_destroy (&ps.hmap);
+  free (ps.ps);
 }
 
 static void
 paired_summary (const struct tt *tt, struct paired_samp *os)
 {
-  size_t n_pairs = hmapx_count (&os->hmap);
-  struct hmapx_node *node;
-  struct pair_stats *pp = NULL;
-
-  const int heading_rows = 1;
-  const int heading_cols = 2;
-
-  const int cols = 4 + heading_cols;
-  const int rows = n_pairs * 2 + heading_rows;
-  struct tab_table *t = tab_create (cols, rows);
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 0, 0, heading_rows, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
-  tab_box (t, -1, -1,       TAL_0, TAL_1, heading_cols, 0, cols - 1, rows - 1);
-
-  tab_hline (t, TAL_2, 0, cols - 1, 1);
-
-  tab_title (t, _("Paired Sample Statistics"));
-  tab_vline (t, TAL_2, heading_cols, 0, rows - 1);
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
-
-  HMAPX_FOR_EACH (pp, node, &os->hmap)
-    {
-      int v = pp->posn;
-      double cc, mean, sigma;
+  struct pivot_table *table = pivot_table_create (
+    N_("Paired Sample Statistics"));
+  pivot_table_set_weight_var (table, tt->wv);
 
-      tab_text_format (t, 0, v * 2 + heading_rows, TAB_LEFT, _("Pair %d"), pp->posn + 1);
-
-      /* first var */
-      moments_calculate (pp->mom0, &cc, &mean, &sigma, NULL, NULL);
-      tab_text (t, 1, v * 2 + heading_rows, TAB_LEFT, var_to_string (pp->var0));
-      tab_double (t, 3, v * 2 + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT);
-      tab_double (t, 2, v * 2 + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER);
-      tab_double (t, 4, v * 2 + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER);
-      tab_double (t, 5, v * 2 + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER);
-
-      /* second var */
-      moments_calculate (pp->mom1, &cc, &mean, &sigma, NULL, NULL);
-      tab_text (t, 1, v * 2 + 1 + heading_rows, TAB_LEFT, var_to_string (pp->var1));
-      tab_double (t, 3, v * 2 + 1 + heading_rows, TAB_RIGHT, cc, NULL, RC_WEIGHT);
-      tab_double (t, 2, v * 2 + 1 + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER);
-      tab_double (t, 4, v * 2 + 1 + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER);
-      tab_double (t, 5, v * 2 + 1 + heading_rows, TAB_RIGHT, sqrt (sigma / cc), NULL, RC_OTHER);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Mean"), PIVOT_RC_OTHER,
+                          N_("Std. Deviation"), PIVOT_RC_OTHER,
+                          N_("S.E. Mean"), PIVOT_RC_OTHER);
+
+  struct pivot_dimension *variables = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Variables"));
+
+  for (size_t i = 0; i < os->n_ps; i++)
+    {
+      struct pair_stats *pp = &os->ps[i];
+      struct pivot_category *pair = pivot_category_create_group__ (
+        variables->root, pivot_value_new_text_format (N_("Pair %d"), i + 1));
+
+      for (int j = 0; j < 2; j++)
+        {
+          const struct variable *var = j ? pp->var1 : pp->var0;
+          const struct moments *mom = j ? pp->mom1 : pp->mom0;
+          double cc, mean, sigma;
+          moments_calculate (mom, &cc, &mean, &sigma, NULL, NULL);
+
+          int var_idx = pivot_category_create_leaf (
+            pair, pivot_value_new_variable (var));
+
+          double entries[] = { cc, mean, sqrt (sigma), sqrt (sigma / cc) };
+          for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
+            pivot_table_put2 (table, j, var_idx,
+                              pivot_value_new_number (entries[j]));
+        }
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
 static void
 paired_correlations (const struct tt *tt, struct paired_samp *os)
 {
-  size_t n_pairs = hmapx_count (&os->hmap);
-  struct hmapx_node *node;
-  struct pair_stats *pp = NULL;
-  const int heading_rows = 1;
-  const int heading_cols = 2;
-
-  const int cols = 5;
-  const int rows = n_pairs + heading_rows;
-  struct tab_table *t = tab_create (cols, rows);
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 0, 0, heading_rows, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
-
-  tab_hline (t, TAL_2, 0, cols - 1, 1);
-
-  tab_title (t, _("Paired Samples Correlations"));
-  tab_vline (t, TAL_2, heading_cols, 0, rows - 1);
-  tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
-  tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Correlation"));
-  tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
-
-  HMAPX_FOR_EACH (pp, node, &os->hmap)
-    {
-      double corr;
-      double cc0, mean0, sigma0;
-      double cc1, mean1, sigma1;
-      int v = pp->posn;
+  struct pivot_table *table = pivot_table_create (
+    N_("Paired Samples Correlations"));
+  pivot_table_set_weight_var (table, tt->wv);
+
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Correlation"), PIVOT_RC_CORRELATION,
+                          N_("Sig."), PIVOT_RC_SIGNIFICANCE);
 
-      tab_text_format (t, 0, v + heading_rows, TAB_LEFT, _("Pair %d"), pp->posn + 1);
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Pairs"));
 
-      tab_text_format (t, 1, v + heading_rows, TAB_LEFT, _("%s & %s"),
-                      var_to_string (pp->var0),
-                      var_to_string (pp->var1));
+  for (size_t i = 0; i < os->n_ps; i++)
+    {
+      struct pair_stats *pp = &os->ps[i];
+      struct pivot_category *group = pivot_category_create_group__ (
+        pairs->root, pivot_value_new_text_format (N_("Pair %d"), i + 1));
+
+      int row = pivot_category_create_leaf (
+        group, pivot_value_new_text_format (N_("%s & %s"),
+                                            var_to_string (pp->var0),
+                                            var_to_string (pp->var1)));
 
+      double cc0, mean0, sigma0;
+      double cc1, mean1, sigma1;
       moments_calculate (pp->mom0, &cc0, &mean0, &sigma0, NULL, NULL);
       moments_calculate (pp->mom1, &cc1, &mean1, &sigma1, NULL, NULL);
-
       /* If this fails, then we're not dealing with missing values properly */
       assert (cc0 == cc1);
 
-      tab_double (t, 2, v + heading_rows, TAB_RIGHT, cc0, NULL, RC_WEIGHT);
-
-      corr = pp->sum_of_prod / cc0  - (mean0 * mean1);
-      corr /= sqrt (sigma0 * sigma1);
-      corr *= cc0 / (cc0 - 1);
-
-      tab_double (t, 3, v + heading_rows, TAB_RIGHT, corr, NULL, RC_OTHER);
-      tab_double (t, 4, v + heading_rows, TAB_RIGHT,
-                 2.0 * significance_of_correlation (corr, cc0), NULL, RC_PVALUE);
+      double corr = ((pp->sum_of_prod / cc0 - mean0 * mean1)
+                     / sqrt (sigma0 * sigma1) * cc0 / (cc0 - 1));
+      double sig = 2.0 * significance_of_correlation (corr, cc0);
+      double entries[] = { cc0, corr, sig };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i]));
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
 
 
 static void
 paired_test (const struct tt *tt, const struct paired_samp *os)
 {
-  size_t n_pairs = hmapx_count (&os->hmap);
-  struct hmapx_node *node;
-  struct pair_stats *pp = NULL;
-
-  const int heading_rows = 3;
-  const int heading_cols = 2;
-  const size_t rows = heading_rows + n_pairs;
-  const size_t cols = 10;
-  const struct fmt_spec *wfmt = tt->wv ? var_get_print_format (tt->wv) : & F_8_0;
-
-  struct tab_table *t = tab_create (cols, rows);
-  tab_set_format (t, RC_WEIGHT, wfmt);
-  tab_headers (t, 0, 0, heading_rows, 0);
-  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
-  tab_hline (t, TAL_2, 0, cols - 1, 3);
-
-  tab_title (t, _("Paired Samples Test"));
-  tab_hline (t, TAL_1, heading_cols, 6, 1);
-  tab_vline (t, TAL_2, heading_cols, 0, rows - 1);
-
-  tab_box (t, -1, -1, -1, TAL_1, heading_cols, 0, cols - 1, rows - 1);
-
-  tab_joint_text (t, 2, 0, 6, 0, TAB_CENTER,
-                 _("Paired Differences"));
-
-  tab_joint_text_format (t, 5, 1, 6, 1, TAB_CENTER,
-                         _("%g%% Confidence Interval of the Difference"),
-                         tt->confidence * 100.0);
-
-  tab_hline (t, TAL_1, 5, 6, 2);
-  tab_text (t, 7, 2, TAB_CENTER | TAT_TITLE, _("t"));
-  tab_text (t, 8, 2, TAB_CENTER | TAT_TITLE, _("df"));
-  tab_text (t, 9, 2, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
-  tab_text (t, 4, 2, TAB_CENTER | TAT_TITLE, _("Std. Error Mean"));
-  tab_text (t, 3, 2, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-  tab_text (t, 2, 2, TAB_CENTER | TAT_TITLE, _("Mean"));
-
-  tab_text (t, 5, 2, TAB_CENTER | TAT_TITLE, _("Lower"));
-  tab_text (t, 6, 2, TAB_CENTER | TAT_TITLE, _("Upper"));
-
-  HMAPX_FOR_EACH (pp, node, &os->hmap)
+  struct pivot_table *table = pivot_table_create (N_("Paired Samples Test"));
+  pivot_table_set_weight_var (table, tt->wv);
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Statistics"));
+  struct pivot_category *group = pivot_category_create_group (
+    statistics->root, N_("Paired Differences"),
+    N_("Mean"), PIVOT_RC_OTHER,
+    N_("Std. Deviation"), PIVOT_RC_OTHER,
+    N_("S.E. Mean"), PIVOT_RC_OTHER);
+  struct pivot_category *interval = pivot_category_create_group__ (
+    group, pivot_value_new_text_format (
+      N_("%g%% Confidence Interval of the Difference"),
+      tt->confidence * 100.0));
+  pivot_category_create_leaves (interval,
+                                N_("Lower"), PIVOT_RC_OTHER,
+                                N_("Upper"), PIVOT_RC_OTHER);
+  pivot_category_create_leaves (statistics->root,
+                                N_("t"), PIVOT_RC_OTHER,
+                                N_("df"), PIVOT_RC_COUNT,
+                                N_("Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Pairs"));
+
+  for (size_t i = 0; i < os->n_ps; i++)
     {
-      int v = pp->posn;
-      double cc, mean, sigma;
-      double df ;
-      double tval;
-      double p, q;
-      double se_mean;
-
-      moments_calculate (pp->mom_diff, &cc, &mean, &sigma, NULL, NULL);
-
-      df = cc - 1.0;
-      tab_text_format (t, 0, v + heading_rows, TAB_LEFT, _("Pair %d"), v + 1);
+      struct pair_stats *pp = &os->ps[i];
+      struct pivot_category *group = pivot_category_create_group__ (
+        pairs->root, pivot_value_new_text_format (N_("Pair %d"), i + 1));
 
-      tab_text_format (t, 1, v + heading_rows, TAB_LEFT, _("%s - %s"),
-                      var_to_string (pp->var0),
-                      var_to_string (pp->var1));
+      int row = pivot_category_create_leaf (
+        group, pivot_value_new_text_format (N_("%s - %s"),
+                                            var_to_string (pp->var0),
+                                            var_to_string (pp->var1)));
 
-      tval = mean * sqrt (cc / sigma);
-      se_mean = sqrt (sigma / cc);
-
-      tab_double (t, 2, v + heading_rows, TAB_RIGHT, mean, NULL, RC_OTHER);
-      tab_double (t, 3, v + heading_rows, TAB_RIGHT, sqrt (sigma), NULL, RC_OTHER);
-      tab_double (t, 4, v + heading_rows, TAB_RIGHT, se_mean, NULL, RC_OTHER);
+      double cc, mean, sigma;
+      moments_calculate (pp->mom_diff, &cc, &mean, &sigma, NULL, NULL);
 
-      tab_double (t, 7, v + heading_rows, TAB_RIGHT, tval, NULL, RC_OTHER);
-      tab_double (t, 8, v + heading_rows, TAB_RIGHT, df, NULL, RC_WEIGHT);
+      double df = cc - 1.0;
 
+      double t = mean * sqrt (cc / sigma);
+      double se_mean = sqrt (sigma / cc);
 
-      p = gsl_cdf_tdist_P (tval, df);
-      q = gsl_cdf_tdist_Q (tval, df);
+      double p = gsl_cdf_tdist_P (t, df);
+      double q = gsl_cdf_tdist_Q (t, df);
+      double sig = 2.0 * (t > 0 ? q : p);
 
-      tab_double (t, 9, v + heading_rows, TAB_RIGHT, 2.0 * (tval > 0 ? q : p), NULL, RC_PVALUE);
+      double t_qinv = gsl_cdf_tdist_Qinv ((1.0 - tt->confidence) / 2.0, df);
 
-      tval = gsl_cdf_tdist_Qinv ( (1.0 - tt->confidence) / 2.0, df);
+      double entries[] = {
+        mean,
+        sqrt (sigma),
+        se_mean,
+        mean - t_qinv * se_mean,
+        mean + t_qinv * se_mean,
+        t,
+        df,
+        sig,
+      };
+      for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
+        pivot_table_put2 (table, i, row, pivot_value_new_number (entries[i]));
 
-      tab_double (t, 5, v + heading_rows, TAB_RIGHT, mean - tval * se_mean, NULL, RC_OTHER);
-      tab_double (t, 6, v + heading_rows, TAB_RIGHT, mean + tval * se_mean, NULL, RC_OTHER);
     }
 
-  tab_submit (t);
+  pivot_table_submit (table);
 }
index 2c58962047cba5a7ee662a93aa612145e6c9ace9..230e97df57f74ac51be8f7967c7f7ef74ee79d5e 100644 (file)
 #include "libpspp/misc.h"
 #include "math/sort.h"
 #include "math/wilcoxon-sig.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
 
+#include "gettext.h"
+#define N_(msgid) msgid
+#define _(msgid) gettext (msgid)
+
 static double
 append_difference (const struct ccase *c, casenumber n UNUSED, void *aux)
 {
@@ -203,91 +207,65 @@ wilcoxon_execute (const struct dataset *ds,
 
   free (ws);
 }
-
-
 \f
+static void
+put_row (struct pivot_table *table, int var_idx, int sign_idx,
+         double n, double sum)
+{
+  pivot_table_put3 (table, 0, sign_idx, var_idx, pivot_value_new_number (n));
+  if (sum != SYSMIS)
+    {
+      pivot_table_put3 (table, 1, sign_idx, var_idx,
+                        pivot_value_new_number (sum / n));
+      pivot_table_put3 (table, 2, sign_idx, var_idx,
+                        pivot_value_new_number (sum));
+    }
+}
 
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
+static int
+add_pair_leaf (struct pivot_dimension *dimension, variable_pair *pair)
+{
+  char *label = xasprintf ("%s - %s", var_to_string ((*pair)[0]),
+                           var_to_string ((*pair)[1]));
+  return pivot_category_create_leaf (
+    dimension->root,
+    pivot_value_new_user_text_nocopy (label));
+}
 
 static void
 show_ranks_box (const struct wilcoxon_state *ws,
                const struct two_sample_test *t2s,
                const struct dictionary *dict)
 {
-  size_t i;
-
-  const struct fmt_spec *wfmt = dict_get_weight_format (dict);
+  struct pivot_table *table = pivot_table_create (N_("Ranks"));
+  pivot_table_set_weight_var (table, dict_get_weight (dict));
 
-  struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs);
-  tab_set_format (table, RC_WEIGHT, wfmt);
+  pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
+                          N_("N"), PIVOT_RC_COUNT,
+                          N_("Mean Rank"), PIVOT_RC_OTHER,
+                          N_("Sum of Ranks"), PIVOT_RC_OTHER);
 
-  tab_title (table, _("Ranks"));
+  pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Sign"),
+                          N_("Negative Ranks"), N_("Positive Ranks"),
+                          N_("Ties"), N_("Total"));
 
-  tab_headers (table, 2, 0, 1, 0);
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Pairs"));
 
-  /* Vertical lines inside the box */
-  tab_box (table, 0, 0, -1, TAL_1,
-          1, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-
-  tab_text (table,  2, 0,  TAB_CENTER, _("N"));
-  tab_text (table,  3, 0,  TAB_CENTER, _("Mean Rank"));
-  tab_text (table,  4, 0,  TAB_CENTER, _("Sum of Ranks"));
-
-
-  for (i = 0 ; i < t2s->n_pairs; ++i)
+  for (size_t i = 0 ; i < t2s->n_pairs; ++i)
     {
       variable_pair *vp = &t2s->pairs[i];
-
-      struct string pair_name;
-      ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-      ds_put_cstr (&pair_name, " - ");
-      ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
-
-      tab_text (table, 1, 1 + i * 4, TAB_LEFT, _("Negative Ranks"));
-      tab_text (table, 1, 2 + i * 4, TAB_LEFT, _("Positive Ranks"));
-      tab_text (table, 1, 3 + i * 4, TAB_LEFT, _("Ties"));
-      tab_text (table, 1, 4 + i * 4, TAB_LEFT, _("Total"));
-
-      tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4);
-
-
-      tab_text (table, 0, 1 + i * 4, TAB_LEFT, ds_cstr (&pair_name));
-      ds_destroy (&pair_name);
-
-
-      /* N */
-      tab_double (table, 2, 1 + i * 4, TAB_RIGHT, ws[i].negatives.n, NULL, RC_WEIGHT);
-      tab_double (table, 2, 2 + i * 4, TAB_RIGHT, ws[i].positives.n, NULL, RC_WEIGHT);
-      tab_double (table, 2, 3 + i * 4, TAB_RIGHT, ws[i].n_zeros, NULL, RC_WEIGHT);
-
-      tab_double (table, 2, 4 + i * 4, TAB_RIGHT,
-                 ws[i].n_zeros + ws[i].positives.n + ws[i].negatives.n, NULL, RC_WEIGHT);
-
-      /* Sums */
-      tab_double (table, 4, 1 + i * 4, TAB_RIGHT, ws[i].negatives.sum, NULL, RC_OTHER);
-      tab_double (table, 4, 2 + i * 4, TAB_RIGHT, ws[i].positives.sum, NULL, RC_OTHER);
-
-
-      /* Means */
-      tab_double (table, 3, 1 + i * 4, TAB_RIGHT,
-                 ws[i].negatives.sum / (double) ws[i].negatives.n, NULL, RC_OTHER);
-
-      tab_double (table, 3, 2 + i * 4, TAB_RIGHT,
-                 ws[i].positives.sum / (double) ws[i].positives.n, NULL, RC_OTHER);
-
+      int pair_idx = add_pair_leaf (pairs, vp);
+
+      const struct wilcoxon_state *w = &ws[i];
+      put_row (table, pair_idx, 0, w->negatives.n, w->negatives.sum);
+      put_row (table, pair_idx, 1, w->positives.n, w->positives.sum);
+      put_row (table, pair_idx, 2, w->n_zeros, SYSMIS);
+      put_row (table, pair_idx, 3,
+               w->n_zeros + w->positives.n + w->negatives.n, SYSMIS);
     }
 
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
-  tab_vline (table, TAL_2, 2, 0, tab_nr (table) - 1);
-
-
-  tab_submit (table);
+  pivot_table_submit (table);
 }
 
 
@@ -298,79 +276,64 @@ show_tests_box (const struct wilcoxon_state *ws,
                double timer UNUSED
                )
 {
-  size_t i;
-  struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3);
-
-  tab_title (table, _("Test Statistics"));
-
-  tab_headers (table, 1, 0, 1, 0);
-
-  /* Vertical lines inside the box */
-  tab_box (table, 0, 0, -1, TAL_1,
-          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-  /* Box around entire table */
-  tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
-
-
-  tab_text (table,  0, 1,  TAB_LEFT, _("Z"));
-  tab_text (table,  0, 2,  TAB_LEFT, _("Asymp. Sig. (2-tailed)"));
-
-  if ( exact )
+  struct pivot_table *table = pivot_table_create (N_("Test Statistics"));
+
+  struct pivot_dimension *statistics = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Statistics"),
+    N_("Z"), PIVOT_RC_OTHER,
+    N_("Asymp. Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE);
+  if (exact)
+    pivot_category_create_leaves (
+      statistics->root,
+      N_("Exact Sig. (2-tailed)"), PIVOT_RC_SIGNIFICANCE,
+      N_("Exact Sig. (1-tailed)"), PIVOT_RC_SIGNIFICANCE);
+
+  struct pivot_dimension *pairs = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, N_("Pairs"));
+
+  struct pivot_footnote *too_many_pairs = pivot_table_create_footnote (
+    table, pivot_value_new_text (
+      N_("Too many pairs to calculate exact significance")));
+
+  for (size_t i = 0 ; i < t2s->n_pairs; ++i)
     {
-      tab_text (table,  0, 3,  TAB_LEFT, _("Exact Sig. (2-tailed)"));
-      tab_text (table,  0, 4,  TAB_LEFT, _("Exact Sig. (1-tailed)"));
-
-#if 0
-      tab_text (table,  0, 5,  TAB_LEFT, _("Point Probability"));
-#endif
-    }
-
-  for (i = 0 ; i < t2s->n_pairs; ++i)
-    {
-      double z;
-      double n = ws[i].positives.n + ws[i].negatives.n;
       variable_pair *vp = &t2s->pairs[i];
+      int pair_idx = add_pair_leaf (pairs, vp);
 
-      struct string pair_name;
-      ds_init_cstr (&pair_name, var_to_string ((*vp)[0]));
-      ds_put_cstr (&pair_name, " - ");
-      ds_put_cstr (&pair_name, var_to_string ((*vp)[1]));
-
-
-      tab_text (table, 1 + i, 0, TAB_CENTER, ds_cstr (&pair_name));
-      ds_destroy (&pair_name);
-
-      z = MIN (ws[i].positives.sum, ws[i].negatives.sum);
+      double n = ws[i].positives.n + ws[i].negatives.n;
+      double z = MIN (ws[i].positives.sum, ws[i].negatives.sum);
       z -= n * (n + 1)/ 4.0;
-
       z /= sqrt (n * (n + 1) * (2*n + 1)/24.0 - ws[i].tiebreaker / 48.0);
 
-      tab_double (table, 1 + i, 1, TAB_RIGHT, z, NULL, RC_OTHER);
-
-      tab_double (table, 1 + i, 2, TAB_RIGHT,
-                2.0 * gsl_cdf_ugaussian_P (z),
-                 NULL, RC_PVALUE);
+      double entries[4];
+      int n_entries = 0;
+      entries[n_entries++] = z;
+      entries[n_entries++] = 2.0 * gsl_cdf_ugaussian_P (z);
 
+      int footnote_idx = -1;
       if (exact)
        {
          double p = LevelOfSignificanceWXMPSR (ws[i].positives.sum, n);
          if (p < 0)
            {
-             msg (MW, _("Too many pairs to calculate exact significance."));
+              footnote_idx = n_entries;
+              entries[n_entries++] = SYSMIS;
            }
          else
-           {
-             tab_double (table, 1 + i, 3, TAB_RIGHT, p, NULL, RC_PVALUE);
-             tab_double (table, 1 + i, 4, TAB_RIGHT, p / 2.0, NULL, RC_PVALUE);
-           }
-       }
+            {
+              entries[n_entries++] = p;
+              entries[n_entries++] = p / 2.0;
+            }
+        }
+
+      for (int j = 0; j < n_entries; j++)
+        {
+          struct pivot_value *value = pivot_value_new_number (entries[j]);
+          if (j == footnote_idx)
+            pivot_value_add_footnote (value, too_many_pairs);
+          pivot_table_put2 (table, j, pair_idx, value);
+        }
     }
 
-  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
-  tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
-
-
-  tab_submit (table);
+  pivot_table_submit (table);
 }
index a2e630d79173b8fa763ab71d63822c637bc849b5..a699fdf5f5e4ef9968f14bdb24c4bf180bd4ada9 100644 (file)
 #include "language/lexer/lexer.h"
 #include "language/lexer/format-parser.h"
 #include "libpspp/message.h"
+#include "libpspp/string-set.h"
 #include "libpspp/version.h"
-#include "output/tab.h"
+#include "output/pivot-table.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;
+  struct string_set rc_names = STRING_SET_INITIALIZER (rc_names);
 
   if (!lex_force_match_id (lexer, "MODIFY"))
     {
@@ -88,12 +60,8 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED)
        }
       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;
-         bool format = false;
+          string_set_clear (&rc_names);
+         struct fmt_spec fmt = { 0, 0, 0 };
 
          while (lex_token (lexer) != T_SLASH &&
                 lex_token (lexer) != T_ENDCMD)
@@ -106,31 +74,17 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED)
                  if (! lex_force_match (lexer, T_LBRACK))
                    goto error;
 
-                 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;
-                       }
-                   }
+                 while (lex_token (lexer) == T_ID)
+                    {
+                      string_set_insert (&rc_names, lex_tokcstr (lexer));
+                      lex_get (lexer);
+                    }
+
                  if (! lex_force_match (lexer, T_RBRACK))
                    goto error;
                }
              else if (lex_match_id (lexer, "FORMAT"))
                {
-                 struct fmt_spec fmt;
                  char type[FMT_TYPE_LEN_MAX + 1];
                  int width = -1;
                  int decimals = -1;
@@ -157,9 +111,6 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED)
 
                  fmt.w = width;
                  fmt.d = decimals;
-
-                 os->fmt = fmt;
-                 format = true;
                }
              else
                {
@@ -167,8 +118,15 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED)
                  goto error;
                }
            }
-         if (!format)
-           goto error;
+
+          if (fmt.w)
+            {
+              const struct string_set_node *node;
+              const char *s;
+              STRING_SET_FOR_EACH (s, node, &rc_names)
+                if (!pivot_result_class_change (s, &fmt))
+                  lex_error (lexer, _("Unknown cell class %s."), s);
+            }
        }
       else
        {
@@ -177,23 +135,9 @@ cmd_output (struct lexer *lexer, struct dataset *ds UNUSED)
        }
     }
 
-  /* 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);
+ error:
+  string_set_destroy (&rc_names);
   return CMD_SUCCESS;
 }
index 710bc2f44e44d5372e960bc7a1433109427dd1e4..8b06448fe474fd9f2540d7036fe5aabb5e8d556f 100644 (file)
@@ -346,17 +346,11 @@ stc_custom_tnumbers (struct lexer *lexer,
   lex_match (lexer, T_EQUALS);
 
   if (lex_match_id (lexer, "VALUES"))
-    {
-      settings_set_value_style (SETTINGS_VAL_STYLE_VALUES);
-    }
+    settings_set_show_values (SETTINGS_VALUE_SHOW_VALUE);
   else if (lex_match_id (lexer, "LABELS"))
-    {
-      settings_set_value_style (SETTINGS_VAL_STYLE_LABELS);
-    }
+    settings_set_show_values (SETTINGS_VALUE_SHOW_LABEL);
   else if (lex_match_id (lexer, "BOTH"))
-    {
-      settings_set_value_style (SETTINGS_VAL_STYLE_BOTH);
-    }
+    settings_set_show_values (SETTINGS_VALUE_SHOW_BOTH);
   else
     {
       lex_error_expecting (lexer, "VALUES", "LABELS", "BOTH", NULL_SENTINEL);
@@ -375,17 +369,11 @@ stc_custom_tvars (struct lexer *lexer,
   lex_match (lexer, T_EQUALS);
 
   if (lex_match_id (lexer, "NAMES"))
-    {
-      settings_set_var_style (SETTINGS_VAR_STYLE_NAMES);
-    }
+    settings_set_show_variables (SETTINGS_VALUE_SHOW_VALUE);
   else if (lex_match_id (lexer, "LABELS"))
-    {
-      settings_set_var_style (SETTINGS_VAR_STYLE_LABELS);
-    }
+    settings_set_show_variables (SETTINGS_VALUE_SHOW_LABEL);
   else if (lex_match_id (lexer, "BOTH"))
-    {
-      settings_set_var_style (SETTINGS_VAR_STYLE_BOTH);
-    }
+    settings_set_show_variables (SETTINGS_VALUE_SHOW_BOTH);
   else
     {
       lex_error_expecting (lexer, "NAMES", "LABELS", "BOTH", NULL_SENTINEL);
index 92bb3d1d3270bfa4878ed2498d72fce799c6c2d6..30c4c567ce607bc1baaeaceeab599c86ba2fd1f5 100644 (file)
@@ -59,6 +59,7 @@ struct variable_node
     struct hmap_node node;      /* In struct categorical's 'varmap'. */
     const struct variable *var; /* The variable. */
     struct hmap valmap;         /* Contains "struct value_node"s. */
+    union value *values;        /* Values in valmap, as a sorted array. */
   };
 
 static int
@@ -74,10 +75,11 @@ compare_value_node_3way (const void *vn1_, const void *vn2_, const void *aux)
 }
 
 static struct variable_node *
-lookup_variable (const struct hmap *map, const struct variable *var, unsigned int hash)
+lookup_variable (const struct hmap *map, const struct variable *var)
 {
   struct variable_node *vn;
-  HMAP_FOR_EACH_WITH_HASH (vn, struct variable_node, node, hash, map)
+  HMAP_FOR_EACH_WITH_HASH (vn, struct variable_node, node,
+                           hash_pointer (var, 0), map)
     if (vn->var == var)
       return vn;
   return NULL;
@@ -339,14 +341,14 @@ categoricals_create (struct interaction *const *inter, size_t n_inter,
       for (size_t v = 0; v < inter[i]->n_vars; ++v)
         {
           const struct variable *var = inter[i]->vars[v];
-          unsigned int hash = hash_pointer (var, 0);
-          struct variable_node *vn = lookup_variable (&cat->varmap, var, hash);
+          struct variable_node *vn = lookup_variable (&cat->varmap, var);
           if (!vn)
             {
               vn = pool_malloc (cat->pool, sizeof *vn);
               vn->var = var;
+              vn->values = NULL;
               hmap_init (&vn->valmap);
-              hmap_insert (&cat->varmap, &vn->node,  hash);
+              hmap_insert (&cat->varmap, &vn->node, hash_pointer (var, 0));
             }
           iap->varnodes[v] = vn;
         }
@@ -577,6 +579,23 @@ categoricals_done (const struct categoricals *cat_)
   cat->sane = true;
 }
 
+union value *
+categoricals_get_var_values (const struct categoricals *cat,
+                             const struct variable *var, size_t *np)
+{
+  struct variable_node *vn = lookup_variable (&cat->varmap, var);
+  *np = hmap_count (&vn->valmap);
+  if (!vn->values)
+    {
+      vn->values = pool_nalloc (cat->pool, *np, sizeof *vn->values);
+
+      struct value_node *valnd;
+      HMAP_FOR_EACH (valnd, struct value_node, node, &vn->valmap)
+        vn->values[valnd->index] = valnd->val;
+    }
+  return vn->values;
+}
+
 static struct interact_params *
 df_to_iap (const struct categoricals *cat, int subscript)
 {
@@ -704,6 +723,21 @@ categoricals_get_user_data_by_category_real (const struct categoricals *cat,
   return n < hmap_count (&iap->ivmap) ? iap->ivs[n]->user_data : NULL;
 }
 
+int
+categoricals_get_value_index_by_category_real (const struct categoricals *cat,
+                                               int iact_idx, int cat_idx,
+                                               int var_idx)
+{
+  const struct interact_params *iap = &cat->iap[iact_idx];
+  const struct interaction_value *ivn = iap->ivs[cat_idx];
+  const struct variable *var = iap->iact->vars[var_idx];
+  const struct variable_node *vn = iap->varnodes[var_idx];
+  const union value *val = case_data (ivn->ccase, var);
+  int width = var_get_width (var);
+  unsigned int hash = value_hash (val, width, 0);
+  return lookup_value (&vn->valmap, val, hash, width)->index;
+}
+
 /* Return a case containing the set of values corresponding to CAT_INDEX. */
 const struct ccase *
 categoricals_get_case_by_category (const struct categoricals *cat,
index 4ab17299a7a1ad427103afd23023aee1de5e664b..5e49b4504ab1b9338c19fe089b861fa8d82a328f 100644 (file)
@@ -62,7 +62,7 @@ void categoricals_update (struct categoricals *, const struct ccase *);
 void categoricals_done (const struct categoricals *);
 bool categoricals_is_complete (const struct categoricals *);
 
-/* Counting categories.
+/* Categories.
 
    A variable's number of categories is the number of unique values observed in
    the data passed to categoricals_update().
@@ -76,6 +76,9 @@ bool categoricals_is_complete (const struct categoricals *);
 size_t categoricals_n_count (const struct categoricals *, size_t idx);
 size_t categoricals_n_total (const struct categoricals *);
 
+union value *categoricals_get_var_values (const struct categoricals *,
+                                          const struct variable *, size_t *n);
+
 /* Degrees of freedom.
 
    A categorical variable with N_CATS categories has N_CATS - 1 degrees of
@@ -142,6 +145,9 @@ const struct ccase *categoricals_get_case_by_category_real (
 void *categoricals_get_user_data_by_category_real (
   const struct categoricals *, int iact, int n);
 
+int categoricals_get_value_index_by_category_real (
+  const struct categoricals *, int iact_idx, int cat_idx, int var_idx);
+
 void *categoricals_get_user_data_by_category (const struct categoricals *,
                                               int category);
 const struct ccase *categoricals_get_case_by_category (
index 66b44c12c10859cd5a882db66e7c22407ce47d84..8aa652b5bded81924b6f9317b9353043168a1c5f 100644 (file)
@@ -754,62 +754,46 @@ covariance_dim (const struct covariance * cov)
 */
 
 #include "libpspp/str.h"
-#include "output/tab.h"
+#include "output/pivot-table.h"
 #include "data/format.h"
 
 
 /* Create a table which can be populated with the encodings for
    the covariance matrix COV */
-struct tab_table *
-covariance_dump_enc_header (const struct covariance *cov, int length)
+struct pivot_table *
+covariance_dump_enc_header (const struct covariance *cov)
 {
-  struct tab_table *t = tab_create (cov->dim,  length);
-  int n;
-  int i;
-
-  tab_title (t, "Covariance Encoding");
-
-  tab_box (t,
-          TAL_2, TAL_2, 0, 0,
-          0, 0,   tab_nc (t) - 1,   tab_nr (t) - 1);
-
-  tab_hline (t, TAL_2, 0, tab_nc (t) - 1, 1);
-
-
-  for (i = 0 ; i < cov->n_vars; ++i)
-    {
-      tab_text (t, i, 0, TAT_TITLE, var_get_name (cov->vars[i]));
-      tab_vline (t, TAL_1, i + 1, 0, tab_nr (t) - 1);
-    }
-
-  n = 0;
-  while (i < cov->dim)
+  struct pivot_table *table = pivot_table_create ("Covariance Encoding");
+
+  struct pivot_dimension *factors = pivot_dimension_create (
+    table, PIVOT_AXIS_COLUMN, "Factor");
+  for (size_t i = 0 ; i < cov->n_vars; ++i)
+    pivot_category_create_leaf (factors->root,
+                                pivot_value_new_variable (cov->vars[i]));
+  for (size_t i = 0, n = 0; i < cov->dim - cov->n_vars; n++)
     {
-      struct string str;
-      int idx = i - cov->n_vars;
       const struct interaction *iact =
-       categoricals_get_interaction_by_subscript (cov->categoricals, idx);
-      int df;
+       categoricals_get_interaction_by_subscript (cov->categoricals, i);
 
-      ds_init_empty (&str);
+      struct string str = DS_EMPTY_INITIALIZER;
       interaction_to_string (iact, &str);
+      struct pivot_category *group = pivot_category_create_group__ (
+        factors->root,
+        pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
 
-      df = categoricals_df (cov->categoricals, n);
-
-      tab_joint_text (t,
-                     i, 0,
-                     i + df - 1, 0,
-                     TAT_TITLE, ds_cstr (&str));
-
-      if (i + df < tab_nr (t) - 1)
-       tab_vline (t, TAL_1, i + df, 0, tab_nr (t) - 1);
+      int df = categoricals_df (cov->categoricals, n);
+      for (int j = 0; j < df; j++)
+        pivot_category_create_leaf_rc (group, pivot_value_new_integer (j),
+                                       PIVOT_RC_INTEGER);
 
       i += df;
-      n++;
-      ds_destroy (&str);
     }
 
-  return t;
+  struct pivot_dimension *matrix = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, "Matrix", "Matrix");
+  matrix->hide_all_labels = true;
+
+  return table;
 }
 
 
@@ -819,14 +803,13 @@ covariance_dump_enc_header (const struct covariance *cov, int length)
  */
 void
 covariance_dump_enc (const struct covariance *cov, const struct ccase *c,
-                    struct tab_table *t)
+                    struct pivot_table *table)
 {
-  static int row = 0;
-  int i;
-  ++row;
-  for (i = 0 ; i < cov->dim; ++i)
-    {
-      double v = get_val (cov, i, c);
-      tab_double (t, i, row, 0, v, i < cov->n_vars ? NULL : &F_8_0, RC_OTHER);
-    }
+  int row = pivot_category_create_leaf (
+    table->dimensions[1]->root,
+    pivot_value_new_integer (table->dimensions[1]->n_leaves));
+
+  for (int i = 0 ; i < cov->dim; ++i)
+    pivot_table_put2 (
+      table, i, row, pivot_value_new_number (get_val (cov, i, c)));
 }
index 18f1137a79cc6e82d04db5448c3130fcfb81efa6..eef6019ddfe4259b58f9f049ba6bd40bcd153bc9 100644 (file)
@@ -49,14 +49,8 @@ const gsl_matrix *covariance_moments (const struct covariance *cov, int m);
 const struct categoricals * covariance_get_categoricals (const struct covariance *cov);
 size_t covariance_dim (const struct covariance * cov);
 
-struct tab_table ;
-void
-covariance_dump_enc (const struct covariance *cov, const struct ccase *c,
-                    struct tab_table *t);
-
-struct tab_table *
-covariance_dump_enc_header (const struct covariance *cov, int length);
-
-
+struct pivot_table *covariance_dump_enc_header (const struct covariance *);
+void covariance_dump_enc (const struct covariance *, const struct ccase *,
+                          struct pivot_table *);
 
 #endif
index 5dfabe99dd6c0e1ee3aba9d95626cabdf7b6babd..909ce0de6343d0b31f7b8ebfc5bd92361dcc4e7f 100644 (file)
@@ -137,7 +137,7 @@ interaction_to_string (const struct interaction *iact, struct string *str)
     {
       ds_put_cstr (str, var_to_string (iact->vars[v]));
       if (v + 1 < iact->n_vars)
-        ds_put_cstr (str, " * ");
+        ds_put_cstr (str, " × ");
     }
 }
 
index c0218e6626232fbfced7122e8d65d2af0e163528..1df08c40674dab03cb05b02d5fa6cb85a4847578 100644 (file)
@@ -45,7 +45,6 @@
 #include "output/message-item.h"
 #include "output/options.h"
 #include "output/render.h"
-#include "output/tab.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
 
@@ -909,11 +908,11 @@ ascii_test_write (struct output_driver *driver,
     return;
 
   struct area_style style = {
+    .cell_style.halign = TABLE_HALIGN_LEFT,
     .font_style.bold = bold,
     .font_style.underline = underline,
   };
   struct table_cell cell = {
-    .options = TAB_LEFT,
     .text = CONST_CAST (char *, s),
     .style = &style,
   };
index 5753d59a0f9ab8aa84b0ea3da0579ed534d9efab..636e9a798052d1c57a40f026183df396c7175fb4 100644 (file)
@@ -67,11 +67,13 @@ src_output_liboutput_la_SOURCES = \
        src/output/output-item.h \
        src/output/page-setup-item.c \
        src/output/page-setup-item.h \
+       src/output/pivot-output.c \
+       src/output/pivot-table.c \
+       src/output/pivot-table.h \
        src/output/render.c \
        src/output/render.h \
        src/output/tab.c \
        src/output/tab.h \
-       src/output/table-casereader.c \
        src/output/table-item.c \
        src/output/table-item.h \
        src/output/table-paste.c \
index e7cb59f0d7b36b640e3dd71c5ca2e0df9f5f8023..975779bfa99f9555236dc292214bd553d874b283 100644 (file)
@@ -44,7 +44,6 @@
 #include "output/options.h"
 #include "output/page-setup-item.h"
 #include "output/render.h"
-#include "output/tab.h"
 #include "output/table-item.h"
 #include "output/table.h"
 #include "output/text-item.h"
@@ -1233,7 +1232,6 @@ xr_layout_cell_text (struct xr_driver *xr, const struct table_cell *cell,
   int R = options & TAB_ROTATE ? 0 : 1;
 
   struct xr_font *font = (options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED]
-                          : options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS]
                           : &xr->fonts[XR_FONT_PROPORTIONAL]);
   struct xr_font local_font;
   if (font_style->typeface)
@@ -1485,7 +1483,7 @@ xr_layout_cell_text (struct xr_driver *xr, const struct table_cell *cell,
             dump_line (xr, -xr->left_margin, best,
                        xr->width + xr->right_margin, best,
                        RENDER_LINE_SINGLE,
-                       &(struct cell_color) CELL_COLOR (0, 255, 0));
+                       &CELL_COLOR (0, 255, 0));
         }
     }
 
index 05fc08eb62f55dbfe407140a634d82fd4c8748f7..f41a984cf7898f32dee9482de3393eb282546d56 100644 (file)
@@ -561,8 +561,6 @@ html_output_table (struct html_driver *html, const struct table_item *item)
 
           /* Output cell contents. */
           const char *s = cell.text;
-          if (cell.options & TAB_EMPH)
-            fputs ("<EM>", html->file);
           if (cell.options & TAB_FIX)
             {
               fputs ("<TT>", html->file);
@@ -574,8 +572,6 @@ html_output_table (struct html_driver *html, const struct table_item *item)
               s += strspn (s, CC_SPACES);
               escape_string (html->file, s, strlen (s), " ", "<BR>");
             }
-          if (cell.options & TAB_EMPH)
-            fputs ("</EM>", html->file);
 
           html_put_footnote_markers (html, cell.footnotes, cell.n_footnotes);
 
index 60a5b7fd4b337f257c1d6258960cbffdc5809188..56b26bb1ac6db335c8227d651e8bb7b7087b2e43 100644 (file)
@@ -40,7 +40,6 @@
 #include "output/driver-provider.h"
 #include "output/message-item.h"
 #include "output/options.h"
-#include "output/tab.h"
 #include "output/table-item.h"
 #include "output/table-provider.h"
 #include "output/text-item.h"
diff --git a/src/output/pivot-output.c b/src/output/pivot-output.c
new file mode 100644 (file)
index 0000000..b1bfa31
--- /dev/null
@@ -0,0 +1,509 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2018 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include "output/pivot-table.h"
+
+#include "data/settings.h"
+#include "libpspp/assertion.h"
+#include "libpspp/pool.h"
+#include "output/tab.h"
+#include "output/table.h"
+#include "output/table-item.h"
+#include "output/text-item.h"
+#include "output/table-provider.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+#define H TABLE_HORZ
+#define V TABLE_VERT
+
+static const struct pivot_category *
+find_category (const struct pivot_dimension *d, int dim_index,
+               const size_t *indexes, int row_ofs)
+{
+  size_t index = indexes[dim_index];
+  assert (index < d->n_leaves);
+  for (const struct pivot_category *c = d->presentation_leaves[index];
+       c; c = c->parent)
+    {
+      if (!row_ofs)
+        return c;
+
+      row_ofs -= 1 + c->extra_depth;
+      if (row_ofs < 0)
+        return NULL;
+    }
+  return NULL;
+}
+
+static struct area_style *
+area_style_override (struct pool *pool,
+                     const struct area_style *in,
+                     const struct cell_style *cell_,
+                     const struct font_style *font_)
+{
+  const struct cell_style *cell = cell_ ? cell_ : &in->cell_style;
+  const struct font_style *font = font_ ? font_ : &in->font_style;
+
+  struct area_style *out = (pool
+                            ? pool_alloc (pool, sizeof *out)
+                            : xmalloc (sizeof *out));
+  *out = (struct area_style) {
+    .cell_style.halign = cell->halign,
+    .cell_style.valign = cell->valign,
+    .cell_style.decimal_offset = cell->decimal_offset,
+    .cell_style.margin[H][0] = cell->margin[H][0],
+    .cell_style.margin[H][1] = cell->margin[H][1],
+    .cell_style.margin[V][0] = cell->margin[V][0],
+    .cell_style.margin[V][1] = cell->margin[V][1],
+    .font_style.fg[0] = font->fg[0],
+    .font_style.fg[1] = font->fg[1],
+    .font_style.bg[0] = font->bg[0],
+    .font_style.bg[1] = font->bg[1],
+    .font_style.typeface = (font->typeface
+                            ? pool_strdup (pool, font->typeface)
+                            : NULL),
+    .font_style.size = font->size,
+    .font_style.bold = font->bold,
+    .font_style.italic = font->italic,
+    .font_style.underline = font->underline,
+    .font_style.markup = font->markup,
+  };
+  return out;
+}
+
+static void
+fill_cell (struct tab_table *t, int x1, int y1, int x2, int y2,
+           const struct area_style *style, int style_idx,
+           const struct pivot_value *value, struct footnote **footnotes,
+           enum settings_value_show show_values,
+           enum settings_value_show show_variables,
+           bool rotate_label)
+{
+
+  struct string s = DS_EMPTY_INITIALIZER;
+  int opts = style_idx << TAB_STYLE_SHIFT;
+  if (value)
+    {
+      bool numeric = pivot_value_format_body (value, show_values,
+                                              show_variables, &s);
+      if (numeric)
+        opts |= TAB_NUMERIC;
+      if (value->font_style && value->font_style->markup)
+        opts |= TAB_MARKUP;
+      if (rotate_label)
+        opts |= TAB_ROTATE;
+    }
+  tab_joint_text (t, x1, y1, x2, y2, opts, ds_cstr (&s));
+  ds_destroy (&s);
+
+  if (value)
+    {
+      if (value->cell_style || value->font_style)
+        tab_add_style (t, x1, y1,
+                       area_style_override (t->container, style,
+                                            value->cell_style,
+                                            value->font_style));
+
+      for (size_t i = 0; i < value->n_footnotes; i++)
+        tab_add_footnote (t, x1, y1, footnotes[value->footnotes[i]->idx]);
+    }
+}
+
+static struct table_item_text *
+pivot_value_to_table_item_text (const struct pivot_value *value,
+                                const struct area_style *area,
+                                struct footnote **footnotes,
+                                enum settings_value_show show_values,
+                                enum settings_value_show show_variables)
+{
+  if (!value)
+    return NULL;
+
+  struct string s = DS_EMPTY_INITIALIZER;
+  pivot_value_format_body (value, show_values, show_variables, &s);
+
+  struct table_item_text *text = xmalloc (sizeof *text);
+  *text = (struct table_item_text) {
+    .content = ds_steal_cstr (&s),
+    .footnotes = xnmalloc (value->n_footnotes, sizeof *text->footnotes),
+    .n_footnotes = value->n_footnotes,
+    .style = area_style_override (
+      NULL, area, value->cell_style, value->font_style),
+  };
+
+  for (size_t i = 0; i < value->n_footnotes; i++)
+    text->footnotes[i] = footnotes[value->footnotes[i]->idx];
+
+  return text;
+}
+
+static int
+get_table_rule (const struct table_border_style *styles,
+                enum pivot_border style_idx)
+{
+  return styles[style_idx].stroke | (style_idx << TAB_RULE_STYLE_SHIFT);
+}
+
+static void
+draw_line (struct tab_table *t, const struct table_border_style *styles,
+           enum pivot_border style_idx,
+           enum table_axis axis, int a, int b0, int b1)
+{
+  int rule = get_table_rule (styles, style_idx);
+  if (axis == H)
+    tab_hline (t, rule, b0, b1, a);
+  else
+    tab_vline (t, rule, a, b0, b1);
+}
+
+static void
+compose_headings (struct tab_table *t,
+                  const struct pivot_axis *a_axis, enum table_axis a,
+                  const struct pivot_axis *b_axis,
+                  const struct table_border_style *borders,
+                  enum pivot_border dim_col_horz,
+                  enum pivot_border dim_col_vert,
+                  enum pivot_border cat_col_horz,
+                  enum pivot_border cat_col_vert,
+                  const size_t *column_enumeration, size_t n_columns,
+                  const struct area_style *label_style, int label_style_idx,
+                  const struct area_style *corner_style,
+                  struct footnote **footnotes,
+                  enum settings_value_show show_values,
+                  enum settings_value_show show_variables,
+                  bool rotate_inner_labels, bool rotate_outer_labels)
+{
+  enum table_axis b = !a;
+  int b_size = a_axis->label_depth;
+  int a_ofs = b_axis->label_depth;
+
+  if (!a_axis->n_dimensions || !n_columns || !b_size)
+    return;
+
+  int bottom_row = b_size - 1;
+  const int stride = MAX (1, a_axis->n_dimensions);
+  for (int dim_index = 0; dim_index < a_axis->n_dimensions; dim_index++)
+    {
+      const struct pivot_dimension *d = a_axis->dimensions[dim_index];
+      if (d->hide_all_labels)
+        continue;
+
+      for (int row_ofs = 0; row_ofs < d->label_depth; row_ofs++)
+        {
+          for (size_t x1 = 0; x1 < n_columns; )
+            {
+              const struct pivot_category *c = find_category (
+                d, dim_index, column_enumeration + x1 * stride, row_ofs);
+              if (!c)
+                {
+                  x1++;
+                  continue;
+                }
+
+              size_t x2;
+              for (x2 = x1 + 1; x2 < n_columns; x2++)
+                {
+                  const struct pivot_category *c2 = find_category (
+                    d, dim_index, column_enumeration + x2 * stride, row_ofs);
+                  if (c != c2)
+                    break;
+                }
+
+              int y1 = bottom_row - row_ofs - c->extra_depth;
+              int y2 = bottom_row - row_ofs + 1;
+              bool is_outer_row = y1 == 0;
+              bool is_inner_row = y2 == b_size;
+              if (pivot_category_is_leaf (c) || c->show_label)
+                {
+                  int bb[TABLE_N_AXES][2];
+                  bb[a][0] = x1 + a_ofs;
+                  bb[a][1] = x2 + a_ofs - 1;
+                  bb[b][0] = y1;
+                  bb[b][1] = y2 - 1;
+                  bool rotate = ((rotate_inner_labels && is_inner_row)
+                                 || (rotate_outer_labels && is_outer_row));
+                  fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
+                             label_style, label_style_idx, c->name, footnotes,
+                             show_values, show_variables, rotate);
+
+                  if (pivot_category_is_leaf (c) && x2 + 1 <= n_columns)
+                    {
+                      enum pivot_border style
+                        = (y1 == 0 && a_axis->label_depth > d->label_depth
+                           ? dim_col_vert
+                           : cat_col_vert);
+                      draw_line (t, borders, style, b, x2 + a_ofs, y1,
+                                 t->table.n[b] - 1);
+                    }
+                  if (pivot_category_is_leaf (c) && x1 > 0)
+                    {
+                      enum pivot_border style
+                        = (y1 == 0 && a_axis->label_depth > d->label_depth
+                           ? dim_col_vert
+                           : cat_col_vert);
+                      draw_line (t, borders, style, b, x1 + a_ofs, y1,
+                                 t->table.n[b] - 1);
+                    }
+                }
+              if (c->parent && c->parent->show_label)
+                draw_line (t, borders, cat_col_horz, a, y1,
+                           x1 + a_ofs, x2 + a_ofs - 1);
+
+              x1 = x2;
+            }
+        }
+
+      if (d->root->show_label_in_corner && a_ofs > 0)
+        {
+          int bb[TABLE_N_AXES][2];
+          bb[a][0] = a_ofs - 1;
+          bb[a][1] = a_ofs - 1;
+          bb[b][0] = bottom_row - d->label_depth + 1;
+          bb[b][1] = bottom_row;
+          fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
+                     corner_style, PIVOT_AREA_CORNER, d->root->name, footnotes,
+                     show_values, show_variables, false);
+        }
+
+      if (dim_index > 1)
+        draw_line (t, borders, dim_col_horz, a, bottom_row + 1, a_ofs,
+                   t->table.n[a] - 1);
+
+      bottom_row -= d->label_depth;
+    }
+}
+
+static void
+pivot_table_submit_layer (const struct pivot_table *st,
+                          const size_t *layer_indexes)
+{
+  const size_t *pindexes[PIVOT_N_AXES]
+    = { [PIVOT_AXIS_LAYER] = layer_indexes };
+
+  struct string layer_label = DS_EMPTY_INITIALIZER;
+  const struct pivot_axis *layer_axis = &st->axes[PIVOT_AXIS_LAYER];
+  for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+    {
+      const struct pivot_dimension *d = layer_axis->dimensions[i];
+      if (d->n_leaves)
+        {
+          if (!ds_is_empty (&layer_label))
+            ds_put_byte (&layer_label, '\n');
+          pivot_value_format (d->root->name, st->show_values,
+                              st->show_variables, &layer_label);
+          ds_put_cstr (&layer_label, ": ");
+          pivot_value_format (d->data_leaves[layer_indexes[i]]->name,
+                              st->show_values, st->show_variables,
+                              &layer_label);
+        }
+    }
+
+  size_t body[TABLE_N_AXES];
+  size_t *column_enumeration = pivot_table_enumerate_axis (
+    st, PIVOT_AXIS_COLUMN, layer_indexes, st->omit_empty, &body[H]);
+  size_t *row_enumeration = pivot_table_enumerate_axis (
+    st, PIVOT_AXIS_ROW, layer_indexes, st->omit_empty, &body[V]);
+
+  int stub[TABLE_N_AXES] = {
+    [H] = st->axes[PIVOT_AXIS_ROW].label_depth,
+    [V] = st->axes[PIVOT_AXIS_COLUMN].label_depth,
+  };
+  struct tab_table *table = tab_create (body[H] + stub[H],
+                                        body[V] + stub[V]);
+  tab_headers (table, stub[H], 0, stub[V], 0);
+
+  for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+    table->styles[i] = area_style_override (table->container, &st->areas[i],
+                                            NULL, NULL);
+
+  for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
+    {
+      const struct table_border_style *in = &st->borders[i];
+      table->rule_colors[i] = pool_alloc (table->container,
+                                          sizeof *table->rule_colors[i]);
+      struct cell_color *out = table->rule_colors[i];
+      out->alpha = in->color.alpha;
+      out->r = in->color.r;
+      out->g = in->color.g;
+      out->b = in->color.b;
+    }
+
+  struct footnote **footnotes = xcalloc (st->n_footnotes, sizeof *footnotes);
+  for (size_t i = 0; i < st->n_footnotes; i++)
+    footnotes[i] = tab_create_footnote (
+      table, i,
+      pivot_value_to_string (st->footnotes[i]->content,
+                             st->show_values, st->show_variables),
+      pivot_value_to_string (st->footnotes[i]->marker,
+                             st->show_values, st->show_variables),
+      area_style_override (table->container, &st->areas[PIVOT_AREA_FOOTER],
+                           st->footnotes[i]->content->cell_style,
+                           st->footnotes[i]->content->font_style));
+
+  compose_headings (table,
+                    &st->axes[PIVOT_AXIS_COLUMN], H, &st->axes[PIVOT_AXIS_ROW],
+                    st->borders,
+                    PIVOT_BORDER_DIM_COL_HORZ,
+                    PIVOT_BORDER_DIM_COL_VERT,
+                    PIVOT_BORDER_CAT_COL_HORZ,
+                    PIVOT_BORDER_CAT_COL_VERT,
+                    column_enumeration, body[H],
+                    &st->areas[PIVOT_AREA_COLUMN_LABELS],
+                    PIVOT_AREA_COLUMN_LABELS,
+                    &st->areas[PIVOT_AREA_CORNER], footnotes,
+                    st->rotate_inner_column_labels,
+                    st->show_values, st->show_variables, false);
+
+  compose_headings (table,
+                    &st->axes[PIVOT_AXIS_ROW], V, &st->axes[PIVOT_AXIS_COLUMN],
+                    st->borders,
+                    PIVOT_BORDER_DIM_ROW_VERT,
+                    PIVOT_BORDER_DIM_ROW_HORZ,
+                    PIVOT_BORDER_CAT_ROW_VERT,
+                    PIVOT_BORDER_CAT_ROW_HORZ,
+                    row_enumeration, body[V],
+                    &st->areas[PIVOT_AREA_ROW_LABELS],
+                    PIVOT_AREA_ROW_LABELS,
+                    &st->areas[PIVOT_AREA_CORNER], footnotes,
+                    false, st->show_values, st->show_variables,
+                    st->rotate_outer_row_labels);
+
+  size_t *dindexes = xcalloc (st->n_dimensions, sizeof *dindexes);
+  size_t y = 0;
+  PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
+                              &st->axes[PIVOT_AXIS_ROW])
+    {
+      size_t x = 0;
+      PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
+                                  column_enumeration,
+                                  &st->axes[PIVOT_AXIS_COLUMN])
+        {
+          pivot_table_convert_indexes_ptod (st, pindexes, dindexes);
+          const struct pivot_value *value = pivot_table_get (st, dindexes);
+          fill_cell (table,
+                     x + stub[H], y + stub[V],
+                     x + stub[H], y + stub[V],
+                     &st->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA,
+                     value, footnotes,
+                     st->show_values, st->show_variables, false);
+
+          x++;
+        }
+
+      y++;
+    }
+  free (dindexes);
+
+  if (st->corner_text && stub[H] && stub[V])
+    fill_cell (table, 0, 0, stub[H] - 1, stub[V] - 1,
+               &st->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER,
+               st->corner_text, footnotes,
+               st->show_values, st->show_variables, false);
+
+  if (tab_nc (table) && tab_nr (table))
+    {
+      tab_hline (
+        table, get_table_rule (st->borders, PIVOT_BORDER_INNER_TOP),
+        0, tab_nc (table) - 1, 0);
+      tab_hline (
+        table, get_table_rule (st->borders, PIVOT_BORDER_INNER_BOTTOM),
+        0, tab_nc (table) - 1, tab_nr (table));
+      tab_vline (
+        table, get_table_rule (st->borders, PIVOT_BORDER_INNER_LEFT),
+        0, 0, tab_nr (table) - 1);
+      tab_vline (
+        table, get_table_rule (st->borders, PIVOT_BORDER_INNER_RIGHT),
+        tab_nc (table), 0, tab_nr (table) - 1);
+
+      if (stub[V])
+        tab_hline (
+          table, get_table_rule (st->borders, PIVOT_BORDER_DATA_TOP),
+          0, tab_nc (table) - 1, stub[V]);
+      if (stub[H])
+        tab_vline (
+          table, get_table_rule (st->borders, PIVOT_BORDER_DATA_LEFT),
+          stub[H], 0, tab_nr (table) - 1);
+
+    }
+  free (column_enumeration);
+  free (row_enumeration);
+
+  struct table_item *ti = table_item_create (&table->table, NULL, NULL);
+
+  if (st->title)
+    {
+      struct table_item_text *title = pivot_value_to_table_item_text (
+        st->title, &st->areas[PIVOT_AREA_TITLE], footnotes,
+        st->show_values, st->show_variables);
+      table_item_set_title (ti, title);
+      table_item_text_destroy (title);
+    }
+
+  if (!ds_is_empty (&layer_label))
+    {
+      struct table_item_text *layers = table_item_text_create (
+        ds_cstr (&layer_label));
+      layers->style = area_style_override (NULL, &st->areas[PIVOT_AREA_LAYERS],
+                                           NULL, NULL);
+      table_item_set_layers (ti, layers);
+      table_item_text_destroy (layers);
+
+      ds_destroy (&layer_label);
+    }
+
+  if (st->caption)
+    {
+      struct table_item_text *caption = pivot_value_to_table_item_text (
+        st->caption, &st->areas[PIVOT_AREA_CAPTION], footnotes,
+        st->show_values, st->show_variables);
+      table_item_set_caption (ti, caption);
+      table_item_text_destroy (caption);
+    }
+
+  table_item_submit (ti);
+}
+
+void
+pivot_table_submit (const struct pivot_table *st)
+{
+  pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, st));
+
+  int old_decimal = settings_get_decimal_char (FMT_COMMA);
+  if (st->decimal == '.' || st->decimal == ',')
+    settings_set_decimal_char (st->decimal);
+
+  if (st->print_all_layers)
+    {
+      size_t *layer_indexes;
+
+      PIVOT_AXIS_FOR_EACH (layer_indexes, &st->axes[PIVOT_AXIS_LAYER])
+        {
+          if (st->paginate_layers)
+            text_item_submit (text_item_create (TEXT_ITEM_EJECT_PAGE, ""));
+          pivot_table_submit_layer (st, layer_indexes);
+        }
+    }
+  else
+    pivot_table_submit_layer (st, st->current_layer);
+
+  settings_set_decimal_char (old_decimal);
+}
diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c
new file mode 100644 (file)
index 0000000..0b4f0fb
--- /dev/null
@@ -0,0 +1,2076 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2017, 2018 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "output/pivot-table.h"
+
+#include <stdlib.h>
+
+#include "data/data-out.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
+
+#include "gl/c-ctype.h"
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
+#include "gl/xsize.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+static const struct fmt_spec *pivot_table_get_format (
+  const struct pivot_table *, const char *s);
+\f
+/* Pivot table display styling. */
+
+/* Returns the name of AREA. */
+const char *
+pivot_area_to_string (enum pivot_area area)
+{
+  switch (area)
+    {
+    case PIVOT_AREA_TITLE: return "title";
+    case PIVOT_AREA_CAPTION: return "caption";
+    case PIVOT_AREA_FOOTER: return "footer";
+    case PIVOT_AREA_CORNER: return "corner";
+    case PIVOT_AREA_COLUMN_LABELS: return "column labels";
+    case PIVOT_AREA_ROW_LABELS: return "row labels";
+    case PIVOT_AREA_DATA: return "data";
+    case PIVOT_AREA_LAYERS: return "layers";
+    case PIVOT_N_AREAS: default: return "**error**";
+    }
+}
+
+/* Returns the name of BORDER. */
+const char *
+pivot_border_to_string (enum pivot_border border)
+{
+  switch (border)
+    {
+    case PIVOT_BORDER_TITLE:
+      return "title";
+
+    case PIVOT_BORDER_OUTER_LEFT:
+      return "left outer frame";
+    case PIVOT_BORDER_OUTER_TOP:
+      return "top outer frame";
+    case PIVOT_BORDER_OUTER_RIGHT:
+      return "right outer frame";
+    case PIVOT_BORDER_OUTER_BOTTOM:
+      return "bottom outer frame";
+
+    case PIVOT_BORDER_INNER_LEFT:
+      return "left inner frame";
+    case PIVOT_BORDER_INNER_TOP:
+      return "top inner frame";
+    case PIVOT_BORDER_INNER_RIGHT:
+      return "right inner frame";
+    case PIVOT_BORDER_INNER_BOTTOM:
+      return "bottom inner frame";
+
+    case PIVOT_BORDER_DATA_LEFT:
+      return "data area left";
+    case PIVOT_BORDER_DATA_TOP:
+      return "data area top";
+
+    case PIVOT_BORDER_DIM_ROW_HORZ:
+      return "row label horizontal dimension border";
+    case PIVOT_BORDER_DIM_ROW_VERT:
+      return "row label vertical dimension border";
+    case PIVOT_BORDER_DIM_COL_HORZ:
+      return "column label horizontal dimension border";
+    case PIVOT_BORDER_DIM_COL_VERT:
+      return "column label vertical dimension border";
+
+    case PIVOT_BORDER_CAT_ROW_HORZ:
+      return "row label horizontal category border";
+    case PIVOT_BORDER_CAT_ROW_VERT:
+      return "row label vertical category border";
+    case PIVOT_BORDER_CAT_COL_HORZ:
+      return "column label horizontal category border";
+    case PIVOT_BORDER_CAT_COL_VERT:
+      return "column label vertical category border";
+
+    case PIVOT_N_BORDERS:
+    default:
+      return "**error**";
+    }
+}
+
+void
+pivot_table_sizing_uninit (struct pivot_table_sizing *sizing)
+{
+  if (sizing)
+    {
+      free (sizing->widths);
+      free (sizing->breaks);
+      free (sizing->keeps);
+    }
+}
+\f
+/* Axes. */
+
+/* Returns the name of AXIS_TYPE. */
+const char *
+pivot_axis_type_to_string (enum pivot_axis_type axis_type)
+{
+  switch (axis_type)
+    {
+    case PIVOT_AXIS_LAYER:
+      return "layer";
+
+    case PIVOT_AXIS_ROW:
+      return "row";
+
+    case PIVOT_AXIS_COLUMN:
+      return "column";
+
+    default:
+      return "<error>";
+    }
+}
+
+static enum pivot_axis_type
+pivot_axis_type_transpose (enum pivot_axis_type axis_type)
+{
+  assert (axis_type == PIVOT_AXIS_ROW || axis_type == PIVOT_AXIS_COLUMN);
+  return (axis_type == PIVOT_AXIS_ROW ? PIVOT_AXIS_COLUMN : PIVOT_AXIS_ROW);
+}
+
+/* Implementation of PIVOT_AXIS_FOR_EACH. */
+size_t *
+pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *axis)
+{
+  if (!indexes)
+    {
+      if (axis->n_dimensions)
+        for (size_t i = 0; i < axis->n_dimensions; i++)
+          if (axis->dimensions[i]->n_leaves == 0)
+            return NULL;
+
+      return xcalloc (axis->n_dimensions, sizeof *indexes);
+    }
+
+  for (size_t i = 0; i < axis->n_dimensions; i++)
+    {
+      const struct pivot_dimension *d = axis->dimensions[i];
+      if (++indexes[i] < d->n_leaves)
+        return indexes;
+
+      indexes[i] = 0;
+    }
+
+  free (indexes);
+  return NULL;
+}
+\f
+/* Dimensions. */
+
+static void
+pivot_category_set_rc (struct pivot_category *category, const char *s)
+{
+  const struct fmt_spec *format = pivot_table_get_format (
+    category->dimension->table, s);
+  if (format)
+    category->format = *format;
+}
+
+static void
+pivot_category_create_leaves_valist (struct pivot_category *parent,
+                                     va_list args)
+{
+  const char *s;
+  while ((s = va_arg (args, const char *)))
+    {
+      if (!strncmp (s, "RC_", 3))
+        {
+          assert (parent->n_subs);
+          pivot_category_set_rc (parent->subs[parent->n_subs - 1], s);
+        }
+      else
+        pivot_category_create_leaf (parent, pivot_value_new_text (s));
+    }
+}
+
+/* Creates a new dimension with the given NAME in TABLE and returns it.  The
+   dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
+   that axis.
+
+   NAME should be a translatable name, but not actually translated yet,
+   e.g. enclosed in N_().  To use a different kind of value for a name, use
+   pivot_dimension_create__() instead.
+
+   The optional varargs parameters may be used to add an initial set of
+   categories to the dimension.  Each string should be a translatable category
+   name, but not actually translated yet, e.g. enclosed in N_().  Each string
+   may optionally be followod by a PIVOT_RC_* string that specifies the default
+   numeric format for cells in this category. */
+struct pivot_dimension * SENTINEL (0)
+(pivot_dimension_create) (struct pivot_table *table,
+                          enum pivot_axis_type axis_type,
+                          const char *name, ...)
+{
+  struct pivot_dimension *d = pivot_dimension_create__ (
+    table, axis_type, pivot_value_new_text (name));
+
+  va_list args;
+  va_start (args, name);
+  pivot_category_create_leaves_valist (d->root, args);
+  va_end (args);
+
+  return d;
+}
+
+/* Creates a new dimension with the given NAME in TABLE and returns it.  The
+   dimension is added to axis AXIS_TYPE, becoming the outermost dimension on
+   that axis. */
+struct pivot_dimension *
+pivot_dimension_create__ (struct pivot_table *table,
+                          enum pivot_axis_type axis_type,
+                          struct pivot_value *name)
+{
+  assert (pivot_table_is_empty (table));
+
+  struct pivot_dimension *d = xmalloc (sizeof *d);
+  *d = (struct pivot_dimension) {
+    .table = table,
+    .axis_type = axis_type,
+    .level = table->axes[axis_type].n_dimensions,
+    .top_index = table->n_dimensions,
+    .root = xmalloc (sizeof *d->root),
+  };
+
+  struct pivot_category *root = d->root;
+  *root = (struct pivot_category) {
+    .name = name,
+    .parent = NULL,
+    .dimension = d,
+    .show_label = false,
+    .data_index = SIZE_MAX,
+    .presentation_index = SIZE_MAX,
+  };
+
+  table->dimensions = xrealloc (
+    table->dimensions, (table->n_dimensions + 1) * sizeof *table->dimensions);
+  table->dimensions[table->n_dimensions++] = d;
+
+  struct pivot_axis *axis = &table->axes[axis_type];
+  axis->dimensions = xrealloc (
+    axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
+  axis->dimensions[axis->n_dimensions++] = d;
+
+  /* XXX extent and label_depth need to be calculated later. */
+
+  return d;
+}
+
+void
+pivot_dimension_destroy (struct pivot_dimension *d)
+{
+  if (!d)
+    return;
+
+  pivot_category_destroy (d->root);
+  free (d->data_leaves);
+  free (d->presentation_leaves);
+}
+
+/* Returns the first leaf node in an in-order traversal that is a child of
+   CAT. */
+static const struct pivot_category * UNUSED
+pivot_category_first_leaf (const struct pivot_category *cat)
+{
+  if (pivot_category_is_leaf (cat))
+    return cat;
+
+  for (size_t i = 0; i < cat->n_subs; i++)
+    {
+      const struct pivot_category *first
+        = pivot_category_first_leaf (cat->subs[i]);
+      if (first)
+        return first;
+    }
+
+  return NULL;
+}
+
+/* Returns the next leaf node in an in-order traversal starting at CAT, which
+   must be a leaf. */
+static const struct pivot_category * UNUSED
+pivot_category_next_leaf (const struct pivot_category *cat)
+{
+  assert (pivot_category_is_leaf (cat));
+
+  for (;;)
+    {
+      const struct pivot_category *parent = cat->parent;
+      if (!parent)
+        return NULL;
+      for (size_t i = cat->group_index + 1; i < parent->n_subs; i++)
+        {
+          const struct pivot_category *next
+            = pivot_category_first_leaf (parent->subs[i]);
+          if (next)
+            return next;
+        }
+
+      cat = cat->parent;
+    }
+}
+
+static void
+pivot_category_add_child (struct pivot_category *child)
+{
+  struct pivot_category *parent = child->parent;
+
+  assert (pivot_category_is_group (parent));
+  if (parent->n_subs >= parent->allocated_subs)
+    parent->subs = x2nrealloc (parent->subs, &parent->allocated_subs,
+                               sizeof *parent->subs);
+  parent->subs[parent->n_subs++] = child;
+}
+
+/* Adds leaf categories as a child of PARENT.  To create top-level categories
+   within dimension 'd', pass 'd->root' for PARENT.
+
+   Each of the varargs parameters should be a string, each of which should be a
+   translatable category name, but not actually translated yet, e.g. enclosed
+   in N_().  Each string may optionally be followod by a PIVOT_RC_* string that
+   specifies the default numeric format for cells in this category.
+
+   Returns the category index, which is just a 0-based array index, for the
+   first new category.
+
+   Leaves have to be created in in-order, that is, don't create a group and add
+   some leaves, then add leaves outside the group and try to add more leaves
+   inside it. */
+int SENTINEL (0)
+(pivot_category_create_leaves) (struct pivot_category *parent, ...)
+{
+  int retval = parent->dimension->n_leaves;
+
+  va_list args;
+  va_start (args, parent);
+  pivot_category_create_leaves_valist (parent, args);
+  va_end (args);
+
+  return retval;
+}
+
+/* Creates a new leaf category with the given NAME as a child of PARENT.  To
+   create a top-level category within dimension 'd', pass 'd->root' for PARENT.
+   Returns the category index, which is just a 0-based array index, for the new
+   category.
+
+   Leaves have to be created in in-order, that is, don't create a group and add
+   some leaves, then add leaves outside the group and try to add more leaves
+   inside it. */
+int
+pivot_category_create_leaf (struct pivot_category *parent,
+                            struct pivot_value *name)
+{
+  return pivot_category_create_leaf_rc (parent, name, NULL);
+}
+
+/* Creates a new leaf category with the given NAME as a child of PARENT.  To
+   create a top-level category within dimension 'd', pass 'd->root' for PARENT.
+   Returns the category index, which is just a 0-based array index, for the new
+   category.
+
+   If RC is nonnull and the name of a result category, the category is assigned
+   that result category.
+
+   Leaves have to be created in in-order, that is, don't create a group and add
+   some leaves, then add leaves outside the group and try to add more leaves
+   inside it. */
+int
+pivot_category_create_leaf_rc (struct pivot_category *parent,
+                               struct pivot_value *name, const char *rc)
+{
+  struct pivot_dimension *d = parent->dimension;
+
+  struct pivot_category *leaf = xmalloc (sizeof *leaf);
+  *leaf = (struct pivot_category) {
+    .name = name,
+    .parent = parent,
+    .dimension = d,
+    .group_index = parent->n_subs,
+    .data_index = d->n_leaves,
+    .presentation_index = d->n_leaves,
+  };
+
+  if (d->n_leaves >= d->allocated_leaves)
+    {
+      d->data_leaves = x2nrealloc (d->data_leaves, &d->allocated_leaves,
+                                   sizeof *d->data_leaves);
+      d->presentation_leaves = xrealloc (
+        d->presentation_leaves,
+        d->allocated_leaves * sizeof *d->presentation_leaves);
+    }
+
+  d->data_leaves[d->n_leaves] = leaf;
+  d->presentation_leaves[d->n_leaves] = leaf;
+  d->n_leaves++;
+
+  pivot_category_add_child (leaf);
+
+  /* Make sure that the new child is the last in in-order. */
+  assert (!pivot_category_next_leaf (leaf));
+
+  pivot_category_set_rc (leaf, rc);
+
+  return leaf->data_index;
+}
+
+/* Adds a new category group named NAME as a child of PARENT.  To create a
+   top-level group within dimension 'd', pass 'd->root' for PARENT.
+
+   NAME should be a translatable name, but not actually translated yet,
+   e.g. enclosed in N_().  To use a different kind of value for a name, use
+   pivot_category_create_group__() instead.
+
+   The optional varargs parameters may be used to add an initial set of
+   categories to the group.  Each string should be a translatable category
+   name, but not actually translated yet, e.g. enclosed in N_().  Each string
+   may optionally be followod by a PIVOT_RC_* string that specifies the default
+   numeric format for cells in this category.
+
+   Returns the new group. */
+struct pivot_category * SENTINEL (0)
+(pivot_category_create_group) (struct pivot_category *parent,
+                               const char *name, ...)
+{
+  struct pivot_category *group = pivot_category_create_group__ (
+    parent, pivot_value_new_text (name));
+
+  va_list args;
+  va_start (args, name);
+  pivot_category_create_leaves_valist (group, args);
+  va_end (args);
+
+  return group;
+}
+
+/* Adds a new category group named NAME as a child of PARENT.  To create a
+   top-level group within dimension 'd', pass 'd->root' for PARENT.  Returns
+   the new group. */
+struct pivot_category *
+pivot_category_create_group__ (struct pivot_category *parent,
+                               struct pivot_value *name)
+{
+  struct pivot_dimension *d = parent->dimension;
+
+  struct pivot_category *group = xmalloc (sizeof *group);
+  *group = (struct pivot_category) {
+    .name = name,
+    .parent = parent,
+    .dimension = d,
+    .show_label = true,
+    .group_index = parent->n_subs,
+    .data_index = SIZE_MAX,
+    .presentation_index = SIZE_MAX,
+  };
+
+  pivot_category_add_child (group);
+
+  return group;
+}
+
+void
+pivot_category_destroy (struct pivot_category *c)
+{
+  if (!c)
+    return;
+
+  pivot_value_destroy (c->name);
+  for (size_t i = 0; i < c->n_subs; i++)
+    pivot_category_destroy (c->subs[i]);
+  free (c);
+}
+\f
+/* Result classes.
+
+   These are usually the easiest way to control the formatting of numeric data
+   in a pivot table.  See pivot_dimension_create() for an explanation of their
+   use.  */
+struct result_class
+  {
+    const char *name;           /* "RC_*". */
+    struct fmt_spec format;
+  };
+
+/* Formats for most of the result classes. */
+static struct result_class result_classes[] =
+  {
+    { PIVOT_RC_INTEGER,      { FMT_F,   40, 0 } },
+    { PIVOT_RC_PERCENT,      { FMT_PCT, 40, 1 } },
+    { PIVOT_RC_CORRELATION,  { FMT_F,   40, 3 } },
+    { PIVOT_RC_SIGNIFICANCE, { FMT_F,   40, 3 } },
+    { PIVOT_RC_RESIDUAL,     { FMT_F,   40, 2 } },
+    { PIVOT_RC_COUNT,        { 0, 0, 0 } },
+    { PIVOT_RC_OTHER,        { 0, 0, 0 } },
+  };
+
+/* Has PIVOT_RC_COUNT been overridden by the user? */
+static bool overridden_count_format;
+
+static struct result_class *
+pivot_result_class_find (const char *s)
+{
+  for (size_t i = 0; i < sizeof result_classes / sizeof *result_classes; i++)
+    if (!strcmp (s, result_classes[i].name))
+      return &result_classes[i];
+  return NULL;
+}
+
+static const struct fmt_spec *
+pivot_table_get_format (const struct pivot_table *table, const char *s)
+{
+  if (!s)
+    return NULL;
+  else if (!strcmp (s, PIVOT_RC_OTHER))
+    return settings_get_format ();
+  else if (!strcmp (s, PIVOT_RC_COUNT) && !overridden_count_format)
+    return &table->weight_format;
+  else
+    {
+      const struct result_class *rc = pivot_result_class_find (s);
+      return rc ? &rc->format : NULL;
+    }
+}
+
+/* Sets the format specification for the result class named S (which should not
+   include the RC_ prefix) to *FORMAT.  Returns true if successful, false if S
+   does not name a known result class. */
+bool
+pivot_result_class_change (const char *s_, const struct fmt_spec *format)
+{
+  char *s = xasprintf ("RC_%s", s_);
+  struct result_class *rc = pivot_result_class_find (s);
+  if (rc)
+    {
+      rc->format = *format;
+      if (!strcmp (s, PIVOT_RC_COUNT))
+        overridden_count_format = true;
+    }
+  free (s);
+
+  return rc != NULL;
+}
+\f
+/* One piece of data within a pivot table. */
+struct pivot_cell
+  {
+    struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
+    struct pivot_value *value;
+    unsigned int idx[];         /* One index per table dimension. */
+  };
+
+/* Pivot tables. */
+
+/* Creates and returns a new pivot table with the given TITLE.  TITLE should be
+   a text string marked for translation but not actually translated yet,
+   e.g. N_("Descriptive Statistics").
+
+   Operations commonly performed on the new pivot_table:
+
+   - If empty rows or columns should not be displayed, set ->omit_empty to
+     true.
+
+   - Set the format to use for "count" values with pivot_table_set_weight_var()
+     or pivot_table_set_weight_format().
+
+   This function is a shortcut for pivot_table_create__() for the most common
+   case.  Use pivot_table_create__() directly if the title should be some kind
+   of value other than an ordinary text string.
+
+   See the large comment at the top of pivot-table.h for general advice on
+   creating pivot tables. */
+struct pivot_table *
+pivot_table_create (const char *title)
+{
+  return pivot_table_create__ (pivot_value_new_text (title));
+}
+
+/* Creates and returns a new pivot table with the given TITLE.
+
+   Operations commonly performed on the new pivot_table:
+
+   - If empty rows or columns should not be displayed, set ->omit_empty to
+     true.
+
+   - Set the format to use for "count" values with pivot_table_set_weight_var()
+     or pivot_table_set_weight_format().
+
+   See the large comment at the top of pivot-table.h for general advice on
+   creating pivot tables. */
+struct pivot_table *
+pivot_table_create__ (struct pivot_value *title)
+{
+  struct pivot_table *table = xzalloc (sizeof *table);
+  table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
+  table->title = title;
+
+  /* Set default area styles. */
+#define STYLE(BOLD, H, V, L, R, T, B) {                         \
+    .cell_style = {                                             \
+      .halign = TABLE_HALIGN_##H,                               \
+      .valign = TABLE_VALIGN_##V,                               \
+      .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R,     \
+                  [TABLE_VERT][0] = T, [TABLE_VERT][1] = B },   \
+    },                                                          \
+      .font_style = {                                           \
+      .bold = BOLD,                                             \
+      .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK},  \
+      .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE},  \
+    },                                                          \
+         }
+  static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
+    [PIVOT_AREA_TITLE]         = STYLE( true, CENTER, CENTER,  8,11,1,8),
+    [PIVOT_AREA_CAPTION]       = STYLE(false, LEFT,   TOP,     8,11,1,1),
+    [PIVOT_AREA_FOOTER]        = STYLE(false, LEFT,   TOP,    11, 8,2,3),
+    [PIVOT_AREA_CORNER]        = STYLE(false, LEFT,   BOTTOM,  8,11,1,1),
+    [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM,  8,11,1,3),
+    [PIVOT_AREA_ROW_LABELS]    = STYLE(false, LEFT,   TOP,     8,11,1,3),
+    [PIVOT_AREA_DATA]          = STYLE(false, MIXED,  TOP,     8,11,1,1),
+    [PIVOT_AREA_LAYERS]        = STYLE(false, LEFT,   BOTTOM,  8,11,1,3),
+    };
+#undef STYLE
+  for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+    table->areas[i] = default_area_styles[i];
+
+  /* Set default border styles. */
+  static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
+    [PIVOT_BORDER_TITLE]        = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_OUTER_LEFT]   = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_OUTER_TOP]    = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_OUTER_RIGHT]  = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_INNER_LEFT]   = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_INNER_TOP]    = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_INNER_RIGHT]  = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_DATA_LEFT]    = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_DATA_TOP]     = TABLE_STROKE_THICK,
+    [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
+    [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
+    [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
+    [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
+    [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
+    [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
+  };
+  for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
+    table->borders[i] = (struct table_border_style) {
+      .stroke = default_strokes[i],
+      .color = CELL_COLOR_BLACK,
+    };
+
+  table->row_labels_in_corner = true;
+  hmap_init (&table->cells);
+
+  return table;
+}
+
+/* Creates and returns a new pivot table with the given TITLE and a single cell
+   with the given CONTENT.
+
+   This is really just for error handling. */
+struct pivot_table *
+pivot_table_create_for_text (struct pivot_value *title,
+                             struct pivot_value *content)
+{
+  struct pivot_table *table = pivot_table_create__ (title);
+
+  struct pivot_dimension *d = pivot_dimension_create (
+    table, PIVOT_AXIS_ROW, N_("Error"));
+  d->hide_all_labels = true;
+  pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
+
+  pivot_table_put1 (table, 0, content);
+
+  return table;
+}
+
+/* Destroys TABLE and frees everything it points to. */
+void
+pivot_table_destroy (struct pivot_table *table)
+{
+  if (!table)
+    return;
+
+  free (table->current_layer);
+  free (table->table_look);
+
+  for (int i = 0; i < TABLE_N_AXES; i++)
+    pivot_table_sizing_uninit (&table->sizing[i]);
+
+  free (table->continuation);
+
+  for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
+    free (table->ccs[i]);
+
+  free (table->command_local);
+  free (table->command_c);
+  free (table->language);
+  free (table->locale);
+
+  free (table->dataset);
+  free (table->datafile);
+
+  for (size_t i = 0; i < table->n_footnotes; i++)
+    pivot_footnote_destroy (table->footnotes[i]);
+  free (table->footnotes);
+
+  pivot_value_destroy (table->title);
+  pivot_value_destroy (table->subtype);
+  pivot_value_destroy (table->corner_text);
+  pivot_value_destroy (table->caption);
+
+  for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+    area_style_uninit (&table->areas[i]);
+
+  for (size_t i = 0; i < table->n_dimensions; i++)
+    pivot_dimension_destroy (table->dimensions[i]);
+  free (table->dimensions);
+
+  for (size_t i = 0; i < PIVOT_N_AXES; i++)
+    free (table->axes[i].dimensions);
+
+  struct pivot_cell *cell, *next_cell;
+  HMAP_FOR_EACH_SAFE (cell, next_cell, struct pivot_cell, hmap_node,
+                      &table->cells)
+    {
+      hmap_delete (&table->cells, &cell->hmap_node);
+      pivot_value_destroy (cell->value);
+      free (cell);
+    }
+  hmap_destroy (&table->cells);
+
+  free (table);
+}
+
+/* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
+   WV, which should be the weight variable for the dictionary whose data or
+   statistics are being put into TABLE.
+
+   This has no effect if WV is NULL. */
+void
+pivot_table_set_weight_var (struct pivot_table *table,
+                            const struct variable *wv)
+{
+  if (wv)
+    pivot_table_set_weight_format (table, var_get_print_format (wv));
+}
+
+/* Sets the format used for PIVOT_RC_COUNT cells to WFMT, which should be the
+   format for the dictionary whose data or statistics are being put into TABLE.
+
+   This has no effect if WFMT is NULL. */
+void
+pivot_table_set_weight_format (struct pivot_table *table,
+                               const struct fmt_spec *wfmt)
+{
+  if (wfmt)
+    table->weight_format = *wfmt;
+}
+
+/* Returns true if TABLE has no cells, false otherwise. */
+bool
+pivot_table_is_empty (const struct pivot_table *table)
+{
+  return hmap_is_empty (&table->cells);
+}
+
+static unsigned int
+pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
+{
+  return hash_bytes (indexes, n_idx * sizeof *indexes, 0);
+}
+
+static bool
+equal_indexes (const size_t *a, const size_t *b, size_t n)
+{
+  for (size_t i = 0; i < n; i++)
+    if (a[i] != b[i])
+      return false;
+
+  return true;
+}
+
+static struct pivot_cell *
+pivot_table_lookup_cell__ (const struct pivot_table *table,
+                            const size_t *dindexes, unsigned int hash)
+{
+  struct pivot_cell *cell;
+  HMAP_FOR_EACH_WITH_HASH (cell, struct pivot_cell, hmap_node, hash,
+                           &table->cells)
+    if (equal_indexes (dindexes, cell->idx, table->n_dimensions))
+      return cell;
+  return false;
+}
+
+static struct pivot_cell *
+pivot_cell_allocate (size_t n_idx)
+{
+  struct pivot_cell *cell UNUSED;
+  return xmalloc (sizeof *cell + n_idx * sizeof *cell->idx);
+}
+
+static struct pivot_cell *
+pivot_table_insert_cell (struct pivot_table *table, const size_t *dindexes)
+{
+  unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
+  struct pivot_cell *cell = pivot_table_lookup_cell__ (table, dindexes, hash);
+  if (!cell)
+    {
+      cell = pivot_cell_allocate (table->n_dimensions);
+      for (size_t i = 0; i < table->n_dimensions; i++)
+        cell->idx[i] = dindexes[i];
+      cell->value = NULL;
+      hmap_insert (&table->cells, &cell->hmap_node, hash);
+    }
+  return cell;
+}
+
+/* Puts VALUE in the cell in TABLE whose indexes are given by the N indexes in
+   DINDEXES.  N must be the number of dimensions in TABLE.  Takes ownership of
+   VALUE.
+
+   If VALUE is a numeric value without a specified format, this function checks
+   each of the categories designated by DINDEXES[] and takes the format from
+   the first category with a result class.  If none has a result class, uses
+   the overall default numeric format. */
+void
+pivot_table_put (struct pivot_table *table, const size_t *dindexes, size_t n,
+                 struct pivot_value *value)
+{
+  assert (n == table->n_dimensions);
+
+  if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
+    {
+      for (size_t i = 0; i < table->n_dimensions; i++)
+        {
+          const struct pivot_dimension *d = table->dimensions[i];
+          if (dindexes[i] < d->n_leaves)
+            {
+              const struct pivot_category *c = d->data_leaves[dindexes[i]];
+              if (c->format.w)
+                {
+                  value->numeric.format = c->format;
+                  goto done;
+                }
+            }
+        }
+      value->numeric.format = *settings_get_format ();
+
+    done:;
+    }
+
+  struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
+  pivot_value_destroy (cell->value);
+  cell->value = value;
+}
+
+/* Puts VALUE in the cell in TABLE with index IDX1.  TABLE must have 1
+   dimension.  Takes ownership of VALUE.  */
+void
+pivot_table_put1 (struct pivot_table *table, size_t idx1,
+                  struct pivot_value *value)
+{
+  size_t dindexes[] = { idx1 };
+  pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
+}
+
+/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2).  TABLE must have 2
+   dimensions.  Takes ownership of VALUE.  */
+void
+pivot_table_put2 (struct pivot_table *table, size_t idx1, size_t idx2,
+                  struct pivot_value *value)
+{
+  size_t dindexes[] = { idx1, idx2 };
+  pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
+}
+
+/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3).  TABLE must
+   have 3 dimensions.  Takes ownership of VALUE.  */
+void
+pivot_table_put3 (struct pivot_table *table, size_t idx1, size_t idx2,
+                  size_t idx3, struct pivot_value *value)
+{
+  size_t dindexes[] = { idx1, idx2, idx3 };
+  pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
+}
+
+/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4).  TABLE
+   must have 4 dimensions.  Takes ownership of VALUE.  */
+void
+pivot_table_put4 (struct pivot_table *table, size_t idx1, size_t idx2,
+                  size_t idx3, size_t idx4, struct pivot_value *value)
+{
+  size_t dindexes[] = { idx1, idx2, idx3, idx4 };
+  pivot_table_put (table, dindexes, sizeof dindexes / sizeof *dindexes, value);
+}
+
+/* Creates and returns a new footnote in TABLE with the given CONTENT and an
+   automatically assigned marker.
+
+   The footnote will only appear in output if it is referenced.  Use
+   pivot_value_add_footnote() to add a reference to the footnote. */
+struct pivot_footnote *
+pivot_table_create_footnote (struct pivot_table *table,
+                             struct pivot_value *content)
+{
+  return pivot_table_create_footnote__ (table, table->n_footnotes,
+                                        NULL, content);
+}
+
+static struct pivot_value *
+pivot_make_default_footnote_marker (int idx, bool show_numeric_markers)
+{
+  char text[INT_BUFSIZE_BOUND (size_t)];
+  if (show_numeric_markers)
+    snprintf (text, sizeof text, "%d", idx + 1);
+  else
+    str_format_26adic (idx + 1, false, text, sizeof text);
+  return pivot_value_new_user_text (text, -1);
+}
+
+/* Creates or modifies a footnote in TABLE with 0-based number IDX.  If MARKER
+   is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
+   footnote's content. */
+struct pivot_footnote *
+pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
+                               struct pivot_value *marker,
+                               struct pivot_value *content)
+{
+  if (idx >= table->n_footnotes)
+    {
+      while (idx >= table->allocated_footnotes)
+        table->footnotes = x2nrealloc (table->footnotes,
+                                       &table->allocated_footnotes,
+                                       sizeof *table->footnotes);
+      while (idx >= table->n_footnotes)
+        {
+          struct pivot_footnote *f = xmalloc (sizeof *f);
+          f->idx = table->n_footnotes;
+          f->marker = pivot_make_default_footnote_marker (
+            f->idx, table->show_numeric_markers);
+          f->content = NULL;
+
+          table->footnotes[table->n_footnotes++] = f;
+        }
+    }
+
+  struct pivot_footnote *f = table->footnotes[idx];
+  if (marker)
+    {
+      pivot_value_destroy (f->marker);
+      f->marker = marker;
+    }
+  if (content)
+    {
+      pivot_value_destroy (f->content);
+      f->content = content;
+    }
+  return f;
+}
+
+/* Frees the data owned by F. */
+void
+pivot_footnote_destroy (struct pivot_footnote *f)
+{
+  if (f)
+    {
+      pivot_value_destroy (f->content);
+      pivot_value_destroy (f->marker);
+      free (f);
+    }
+}
+
+/* Converts per-axis presentation-order indexes, given in PINDEXES, into data
+   indexes for each dimension in TABLE in DINDEXES[]. */
+void
+pivot_table_convert_indexes_ptod (const struct pivot_table *table,
+                                  const size_t *pindexes[PIVOT_N_AXES],
+                                  size_t dindexes[/* table->n_dimensions */])
+{
+  for (size_t i = 0; i < PIVOT_N_AXES; i++)
+    {
+      const struct pivot_axis *axis = &table->axes[i];
+
+      for (size_t j = 0; j < axis->n_dimensions; j++)
+        {
+          const struct pivot_dimension *d = axis->dimensions[j];
+          dindexes[d->top_index]
+            = d->presentation_leaves[pindexes[i][j]]->data_index;
+        }
+    }
+}
+
+size_t *
+pivot_table_enumerate_axis (const struct pivot_table *table,
+                            enum pivot_axis_type axis_type,
+                            const size_t *layer_indexes, bool omit_empty,
+                            size_t *n)
+{
+  const struct pivot_axis *axis = &table->axes[axis_type];
+  if (!axis->n_dimensions)
+    {
+      size_t *enumeration = xnmalloc (2, sizeof *enumeration);
+      enumeration[0] = 0;
+      enumeration[1] = SIZE_MAX;
+      if (n)
+        *n = 1;
+      return enumeration;
+    }
+  else if (!axis->extent)
+    {
+      size_t *enumeration = xmalloc (sizeof *enumeration);
+      *enumeration = SIZE_MAX;
+      if (n)
+        *n = 0;
+      return enumeration;
+    }
+
+  size_t *enumeration = xnmalloc (xsum (xtimes (axis->extent,
+                                                axis->n_dimensions), 1),
+                                  sizeof *enumeration);
+  size_t *p = enumeration;
+  size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
+
+  size_t *axis_indexes;
+  PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
+    {
+      if (omit_empty)
+        {
+          enum pivot_axis_type axis2_type
+            = pivot_axis_type_transpose (axis_type);
+
+          size_t *axis2_indexes;
+          PIVOT_AXIS_FOR_EACH (axis2_indexes, &table->axes[axis2_type])
+            {
+              const size_t *pindexes[PIVOT_N_AXES];
+              pindexes[PIVOT_AXIS_LAYER] = layer_indexes;
+              pindexes[axis_type] = axis_indexes;
+              pindexes[axis2_type] = axis2_indexes;
+              pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
+              if (pivot_table_get (table, dindexes))
+                goto found;
+            }
+          continue;
+
+        found:
+          free (axis2_indexes);
+        }
+
+      memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
+      p += axis->n_dimensions;
+    }
+  *p = SIZE_MAX;
+  if (n)
+    *n = (p - enumeration) / axis->n_dimensions;
+
+  free (dindexes);
+  return enumeration;
+}
+
+static const struct pivot_cell *
+pivot_table_lookup_cell (const struct pivot_table *table,
+                          const size_t *dindexes)
+{
+  unsigned int hash = pivot_cell_hash_indexes (dindexes, table->n_dimensions);
+  return pivot_table_lookup_cell__ (table, dindexes, hash);
+}
+
+const struct pivot_value *
+pivot_table_get (const struct pivot_table *table, const size_t *dindexes)
+{
+  const struct pivot_cell *cell = pivot_table_lookup_cell (table, dindexes);
+  return cell ? cell->value : NULL;
+}
+
+struct pivot_value *
+pivot_table_get_rw (struct pivot_table *table, const size_t *dindexes)
+{
+  struct pivot_cell *cell = pivot_table_insert_cell (table, dindexes);
+  if (!cell->value)
+    cell->value = pivot_value_new_user_text ("", -1);
+  return cell->value;
+}
+
+static void
+distribute_extra_depth (struct pivot_category *category, size_t extra_depth)
+{
+  if (pivot_category_is_group (category) && category->n_subs)
+    for (size_t i = 0; i < category->n_subs; i++)
+      distribute_extra_depth (category->subs[i], extra_depth);
+  else
+    category->extra_depth += extra_depth;
+}
+
+static void
+pivot_category_assign_label_depth (struct pivot_category *category,
+                                   bool dimension_labels_in_corner)
+{
+  category->extra_depth = 0;
+
+  if (pivot_category_is_group (category))
+    {
+      size_t depth = 0;
+      for (size_t i = 0; i < category->n_subs; i++)
+        {
+          pivot_category_assign_label_depth (category->subs[i], false);
+          depth = MAX (depth, category->subs[i]->label_depth);
+        }
+
+      for (size_t i = 0; i < category->n_subs; i++)
+        {
+          struct pivot_category *sub = category->subs[i];
+
+          size_t extra_depth = depth - sub->label_depth;
+          if (extra_depth)
+            distribute_extra_depth (sub, extra_depth);
+
+          sub->label_depth = depth;
+        }
+
+      category->show_label_in_corner = (category->show_label
+                                        && dimension_labels_in_corner);
+      category->label_depth
+        = (category->show_label && !category->show_label_in_corner
+           ? depth + 1 : depth);
+    }
+  else
+    category->label_depth = 1;
+}
+
+static bool
+pivot_axis_assign_label_depth (struct pivot_table *table,
+                             enum pivot_axis_type axis_type,
+                             bool dimension_labels_in_corner)
+{
+  struct pivot_axis *axis = &table->axes[axis_type];
+  bool any_label_shown_in_corner = false;
+  axis->label_depth = 0;
+  axis->extent = 1;
+  for (size_t i = 0; i < axis->n_dimensions; i++)
+    {
+      struct pivot_dimension *d = axis->dimensions[i];
+      pivot_category_assign_label_depth (d->root, dimension_labels_in_corner);
+      d->label_depth = d->hide_all_labels ? 0 : d->root->label_depth;
+      axis->label_depth += d->label_depth;
+      axis->extent *= d->n_leaves;
+
+      if (d->root->show_label_in_corner)
+        any_label_shown_in_corner = true;
+    }
+  return any_label_shown_in_corner;
+}
+
+void
+pivot_table_assign_label_depth (struct pivot_table *table)
+{
+  pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
+  if (pivot_axis_assign_label_depth (
+        table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
+                                && !table->corner_text))
+      && table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
+    table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
+  pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
+}
+\f
+/* Footnotes. */
+
+\f
+\f
+static void
+indent (int indentation)
+{
+  for (int i = 0; i < indentation * 2; i++)
+    putchar (' ');
+}
+
+static void
+pivot_value_dump (const struct pivot_value *value)
+{
+  char *s = pivot_value_to_string (value, SETTINGS_VALUE_SHOW_DEFAULT,
+                                   SETTINGS_VALUE_SHOW_DEFAULT);
+  fputs (s, stdout);
+  free (s);
+}
+
+static void
+pivot_table_dump_value (const struct pivot_value *value, const char *name,
+                      int indentation)
+{
+  if (value)
+    {
+      indent (indentation);
+      printf ("%s: ", name);
+      pivot_value_dump (value);
+      putchar ('\n');
+    }
+}
+
+static void
+pivot_table_dump_string (const char *string, const char *name, int indentation)
+{
+  if (string)
+    {
+      indent (indentation);
+      printf ("%s: %s\n", name, string);
+    }
+}
+
+static void
+pivot_category_dump (const struct pivot_category *c, int indentation)
+{
+  indent (indentation);
+  printf ("%s \"", pivot_category_is_leaf (c) ? "leaf" : "group");
+  pivot_value_dump (c->name);
+  printf ("\" ");
+
+  if (pivot_category_is_leaf (c))
+    printf ("data_index=%zu\n", c->data_index);
+  else
+    {
+      printf (" (label %s)", c->show_label ? "shown" : "hidden");
+      printf ("\n");
+
+      for (size_t i = 0; i < c->n_subs; i++)
+        pivot_category_dump (c->subs[i], indentation + 1);
+    }
+}
+
+void
+pivot_dimension_dump (const struct pivot_dimension *d, int indentation)
+{
+  indent (indentation);
+  printf ("%s dimension %zu (where 0=innermost), label_depth=%zu:\n",
+          pivot_axis_type_to_string (d->axis_type), d->level, d->label_depth);
+
+  pivot_category_dump (d->root, indentation + 1);
+}
+
+static void
+area_style_dump (enum pivot_area area, const struct area_style *a,
+                 int indentation)
+{
+  indent (indentation);
+  printf ("%s: ", pivot_area_to_string (area));
+  font_style_dump (&a->font_style);
+  putchar (' ');
+  cell_style_dump (&a->cell_style);
+  putchar ('\n');
+}
+
+static void
+table_border_style_dump (enum pivot_border border,
+                         const struct table_border_style *b, int indentation)
+{
+  indent (indentation);
+  printf ("%s: %s ", pivot_border_to_string (border),
+          table_stroke_to_string (b->stroke));
+  cell_color_dump (&b->color);
+  putchar ('\n');
+}
+
+static char ***
+compose_headings (const struct pivot_axis *axis,
+                  const size_t *column_enumeration,
+                  enum settings_value_show show_values,
+                  enum settings_value_show show_variables)
+{
+  if (!axis->n_dimensions || !axis->extent || !axis->label_depth)
+    return NULL;
+
+  char ***headings = xnmalloc (axis->label_depth, sizeof *headings);
+  for (size_t i = 0; i < axis->label_depth; i++)
+    headings[i] = xcalloc (axis->extent, sizeof **headings);
+
+  const size_t *indexes;
+  size_t column = 0;
+  PIVOT_ENUMERATION_FOR_EACH (indexes, column_enumeration, axis)
+    {
+      int row = axis->label_depth - 1;
+      for (int dim_index = 0; dim_index < axis->n_dimensions; dim_index++)
+        {
+          const struct pivot_dimension *d = axis->dimensions[dim_index];
+          if (d->hide_all_labels)
+            continue;
+          for (const struct pivot_category *c
+                 = d->presentation_leaves[indexes[dim_index]];
+               c;
+               c = c->parent)
+            {
+              if (pivot_category_is_leaf (c) || (c->show_label
+                                                 && !c->show_label_in_corner))
+                {
+                  headings[row][column] = pivot_value_to_string (
+                    c->name, show_values, show_variables);
+                  if (!*headings[row][column])
+                    headings[row][column] = xstrdup ("<blank>");
+                  row--;
+                }
+            }
+        }
+      column++;
+    }
+
+  return headings;
+}
+
+void
+pivot_table_dump (const struct pivot_table *table, int indentation)
+{
+  if (!table)
+    return;
+
+  int old_decimal = settings_get_decimal_char (FMT_COMMA);
+  if (table->decimal == '.' || table->decimal == ',')
+    settings_set_decimal_char (table->decimal);
+
+  pivot_table_dump_value (table->title, "title", indentation);
+  pivot_table_dump_string (table->command_c, "command", indentation);
+  pivot_table_dump_string (table->dataset, "dataset", indentation);
+  pivot_table_dump_string (table->datafile, "datafile", indentation);
+  pivot_table_dump_string (table->notes, "notes", indentation);
+  pivot_table_dump_string (table->table_look, "table-look", indentation);
+  if (table->date)
+    {
+      indent (indentation);
+      printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
+    }
+
+  indent (indentation);
+  printf ("areas:\n");
+  for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
+    area_style_dump (area, &table->areas[area], indentation + 1);
+
+  indent (indentation);
+  printf ("borders:\n");
+  for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
+    table_border_style_dump (border, &table->borders[border], indentation + 1);
+
+  for (size_t i = 0; i < table->n_dimensions; i++)
+    pivot_dimension_dump (table->dimensions[i], indentation);
+
+  /* Presentation and data indexes. */
+  size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
+
+  const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
+  if (layer_axis->n_dimensions)
+    {
+      indent (indentation);
+      printf ("current layer:");
+
+      for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+        {
+          const struct pivot_dimension *d = layer_axis->dimensions[i];
+          char *name = pivot_value_to_string (d->root->name,
+                                              table->show_values,
+                                              table->show_variables);
+          char *value = pivot_value_to_string (
+            d->data_leaves[table->current_layer[i]]->name,
+            table->show_values, table->show_variables);
+          printf (" %s=%s", name, value);
+          free (value);
+          free (name);
+        }
+
+      putchar ('\n');
+    }
+
+  size_t *layer_indexes;
+  size_t layer_iteration = 0;
+  PIVOT_AXIS_FOR_EACH (layer_indexes, &table->axes[PIVOT_AXIS_LAYER])
+    {
+      indent (indentation);
+      printf ("layer %zu:", layer_iteration++);
+
+      const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
+      for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+        {
+          const struct pivot_dimension *d = layer_axis->dimensions[i];
+
+          fputs (i == 0 ? " " : ", ", stdout);
+          pivot_value_dump (d->root->name);
+          fputs (" =", stdout);
+
+          struct pivot_value **names = xnmalloc (layer_axis->label_depth,
+                                               sizeof *names);
+          size_t n_names = 0;
+          for (const struct pivot_category *c
+                 = d->presentation_leaves[layer_indexes[i]];
+               c;
+               c = c->parent)
+            {
+              if (pivot_category_is_leaf (c) || c->show_label)
+                names[n_names++] = c->name;
+            }
+
+          for (size_t i = n_names; i-- > 0; )
+            {
+              putchar (' ');
+              pivot_value_dump (names[i]);
+            }
+          free (names);
+        }
+      putchar ('\n');
+
+      size_t *column_enumeration = pivot_table_enumerate_axis (
+        table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
+      size_t *row_enumeration = pivot_table_enumerate_axis (
+        table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
+
+      char ***column_headings = compose_headings (
+        &table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
+        table->show_values, table->show_variables);
+      for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++)
+        {
+          indent (indentation + 1);
+          for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++)
+            {
+              if (x)
+                fputs ("; ", stdout);
+              if (column_headings[y][x])
+                fputs (column_headings[y][x], stdout);
+            }
+          putchar ('\n');
+        }
+
+      indent (indentation + 1);
+      printf ("-----------------------------------------------\n");
+
+      char ***row_headings = compose_headings (
+        &table->axes[PIVOT_AXIS_ROW], row_enumeration,
+        table->show_values, table->show_variables);
+
+      size_t x = 0;
+      const size_t *pindexes[PIVOT_N_AXES]
+        = { [PIVOT_AXIS_LAYER] = layer_indexes };
+      PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
+                                  &table->axes[PIVOT_AXIS_ROW])
+        {
+          indent (indentation + 1);
+
+          size_t i = 0;
+          for (size_t y = 0; y < table->axes[PIVOT_AXIS_ROW].label_depth; y++)
+            {
+              if (i++)
+                fputs ("; ", stdout);
+              if (row_headings[y][x])
+                fputs (row_headings[y][x], stdout);
+            }
+
+          printf (" | ");
+
+          i = 0;
+          PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
+                                      column_enumeration,
+                                      &table->axes[PIVOT_AXIS_COLUMN])
+            {
+              if (i++)
+                printf ("; ");
+
+              pivot_table_convert_indexes_ptod (table, pindexes, dindexes);
+              const struct pivot_value *value = pivot_table_get (
+                table, dindexes);
+              if (value)
+                pivot_value_dump (value);
+            }
+          printf ("\n");
+
+          x++;
+        }
+
+      free (column_enumeration);
+      free (row_enumeration);
+    }
+
+  pivot_table_dump_value (table->caption, "caption", indentation);
+
+  for (size_t i = 0; i < table->n_footnotes; i++)
+    {
+      const struct pivot_footnote *f = table->footnotes[i];
+      indent (indentation);
+      putchar ('[');
+      if (f->marker)
+        pivot_value_dump (f->marker);
+      else
+        printf ("%d", f->idx);
+      putchar (']');
+      pivot_value_dump (f->content);
+      putchar ('\n');
+    }
+
+  settings_set_decimal_char (old_decimal);
+}
+\f
+static const char *
+consume_int (const char *p, size_t *n)
+{
+  *n = 0;
+  while (c_isdigit (*p))
+    *n = *n * 10 + (*p++ - '0');
+  return p;
+}
+
+static size_t
+pivot_format_inner_template (struct string *out, const char *template,
+                             char escape,
+                             struct pivot_value **values, size_t n_values,
+                             enum settings_value_show show_values,
+                             enum settings_value_show show_variables)
+{
+  size_t args_consumed = 0;
+  while (*template && *template != ':')
+    {
+      if (*template == '\\' && template[1])
+        {
+          ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
+          template += 2;
+        }
+      else if (*template == escape)
+        {
+          size_t index;
+          template = consume_int (template + 1, &index);
+          if (index >= 1 && index <= n_values)
+            {
+              pivot_value_format (values[index - 1], show_values,
+                                  show_variables, out);
+              args_consumed = MAX (args_consumed, index);
+            }
+        }
+      else
+        ds_put_byte (out, *template++);
+    }
+  return args_consumed;
+}
+
+static const char *
+pivot_extract_inner_template (const char *template, const char **p)
+{
+  *p = template;
+
+  for (;;)
+    {
+      if (*template == '\\' && template[1] != '\0')
+        template += 2;
+      else if (*template == ':')
+        return template + 1;
+      else if (*template == '\0')
+        return template;
+      else
+        template++;
+    }
+}
+
+static void
+pivot_format_template (struct string *out, const char *template,
+                       const struct pivot_argument *args, size_t n_args,
+                       enum settings_value_show show_values,
+                       enum settings_value_show show_variables)
+{
+  while (*template)
+    {
+      if (*template == '\\' && template[1] != '\0')
+        {
+          ds_put_byte (out, template[1] == 'n' ? '\n' : template[1]);
+          template += 2;
+        }
+      else if (*template == '^')
+        {
+          size_t index;
+          template = consume_int (template + 1, &index);
+          if (index >= 1 && index <= n_args && args[index - 1].n > 0)
+            pivot_value_format (args[index - 1].values[0],
+                                show_values, show_variables, out);
+        }
+      else if (*template == '[')
+        {
+          const char *tmpl[2];
+          template = pivot_extract_inner_template (template + 1, &tmpl[0]);
+          template = pivot_extract_inner_template (template, &tmpl[1]);
+          template += *template == ']';
+
+          size_t index;
+          template = consume_int (template, &index);
+          if (index < 1 || index > n_args)
+            continue;
+
+          const struct pivot_argument *arg = &args[index - 1];
+          size_t left = arg->n;
+          while (left)
+            {
+              struct pivot_value **values = arg->values + (arg->n - left);
+              int tmpl_idx = left == arg->n && *tmpl[0] != ':' ? 0 : 1;
+              char escape = "%^"[tmpl_idx];
+              size_t used = pivot_format_inner_template (
+                out, tmpl[tmpl_idx], escape, values, left,
+                show_values, show_variables);
+              if (!used || used > left)
+                break;
+              left -= used;
+            }
+        }
+      else
+        ds_put_byte (out, *template++);
+    }
+}
+
+static enum settings_value_show
+interpret_show (enum settings_value_show global_show,
+                enum settings_value_show table_show,
+                enum settings_value_show value_show,
+                bool has_label)
+{
+  return (!has_label ? SETTINGS_VALUE_SHOW_VALUE
+          : value_show != SETTINGS_VALUE_SHOW_DEFAULT ? value_show
+          : table_show != SETTINGS_VALUE_SHOW_DEFAULT ? table_show
+          : global_show);
+}
+
+/* Appends a text representation of the body of VALUE to OUT.  SHOW_VALUES and
+   SHOW_VARIABLES control whether variable and value labels are included.
+
+   The "body" omits subscripts and superscripts and footnotes. */
+bool
+pivot_value_format_body (const struct pivot_value *value,
+                         enum settings_value_show show_values,
+                         enum settings_value_show show_variables,
+                         struct string *out)
+{
+  enum settings_value_show show;
+  bool numeric = false;
+
+  switch (value->type)
+    {
+    case PIVOT_VALUE_NUMERIC:
+      show = interpret_show (settings_get_show_values (),
+                             show_values,
+                             value->numeric.show,
+                             value->numeric.value_label != NULL);
+      if (show & SETTINGS_VALUE_SHOW_VALUE)
+        {
+          char *s = data_out (&(union value) { .f = value->numeric.x },
+                              "UTF-8", &value->numeric.format);
+          ds_put_cstr (out, s + strspn (s, " "));
+          free (s);
+        }
+      if (show & SETTINGS_VALUE_SHOW_LABEL)
+        {
+          if (show & SETTINGS_VALUE_SHOW_VALUE)
+            ds_put_byte (out, ' ');
+          ds_put_cstr (out, value->numeric.value_label);
+        }
+      numeric = !(show & SETTINGS_VALUE_SHOW_LABEL);
+      break;
+
+    case PIVOT_VALUE_STRING:
+      show = interpret_show (settings_get_show_values (),
+                             show_values,
+                             value->string.show,
+                             value->string.value_label != NULL);
+      if (show & SETTINGS_VALUE_SHOW_VALUE)
+        {
+          if (value->string.hex)
+            {
+              for (const uint8_t *p = CHAR_CAST (uint8_t *, value->string.s);
+                   *p; p++)
+                ds_put_format (out, "%02X", *p);
+            }
+          else
+            ds_put_cstr (out, value->string.s);
+        }
+      if (show & SETTINGS_VALUE_SHOW_LABEL)
+        {
+          if (show & SETTINGS_VALUE_SHOW_VALUE)
+            ds_put_byte (out, ' ');
+          ds_put_cstr (out, value->string.value_label);
+        }
+      break;
+
+    case PIVOT_VALUE_VARIABLE:
+      show = interpret_show (settings_get_show_variables (),
+                             show_variables,
+                             value->variable.show,
+                             value->variable.var_label != NULL);
+      if (show & SETTINGS_VALUE_SHOW_VALUE)
+        ds_put_cstr (out, value->variable.var_name);
+      if (show & SETTINGS_VALUE_SHOW_LABEL)
+        {
+          if (show & SETTINGS_VALUE_SHOW_VALUE)
+            ds_put_byte (out, ' ');
+          ds_put_cstr (out, value->variable.var_label);
+        }
+      break;
+
+    case PIVOT_VALUE_TEXT:
+      ds_put_cstr (out, value->text.local);
+      break;
+
+    case PIVOT_VALUE_TEMPLATE:
+      pivot_format_template (out, value->template.s, value->template.args,
+                             value->template.n_args, show_values,
+                             show_variables);
+      break;
+    }
+
+  return numeric;
+}
+
+/* Appends a text representation of VALUE to OUT.  SHOW_VALUES and
+   SHOW_VARIABLES control whether variable and value labels are included.
+
+   Subscripts and superscripts and footnotes are included. */
+void
+pivot_value_format (const struct pivot_value *value,
+                    enum settings_value_show show_values,
+                    enum settings_value_show show_variables,
+                    struct string *out)
+{
+  pivot_value_format_body ( value, show_values, show_variables, out);
+
+  if (value->subscript)
+    ds_put_format (out, "_%s", value->subscript);
+
+  if (value->superscript)
+    ds_put_format (out, "^%s", value->superscript);
+
+  for (size_t i = 0; i < value->n_footnotes; i++)
+    {
+      ds_put_byte (out, '^');
+      pivot_value_format (value->footnotes[i]->marker,
+                          show_values, show_variables, out);
+    }
+}
+
+/* Returns a text representation of VALUE.  The caller must free the string,
+   with free(). */
+char *
+pivot_value_to_string (const struct pivot_value *value,
+                       enum settings_value_show show_values,
+                       enum settings_value_show show_variables)
+{
+  struct string s = DS_EMPTY_INITIALIZER;
+  pivot_value_format (value, show_values, show_variables, &s);
+  return ds_steal_cstr (&s);
+}
+
+/* Frees the data owned by V. */
+void
+pivot_value_destroy (struct pivot_value *value)
+{
+  if (value)
+    {
+      font_style_uninit (value->font_style);
+      free (value->font_style);
+      free (value->cell_style);
+      for (size_t i = 0; i < value->n_footnotes; i++)
+        pivot_footnote_destroy (value->footnotes[i]);
+      free (value->footnotes);
+
+      switch (value->type)
+        {
+        case PIVOT_VALUE_NUMERIC:
+          free (value->numeric.var_name);
+          free (value->numeric.value_label);
+          break;
+
+        case SETTINGS_VALUE_SHOW_VALUE:
+          free (value->string.var_name);
+          free (value->string.value_label);
+          break;
+
+        case PIVOT_VALUE_VARIABLE:
+          free (value->variable.var_name);
+          free (value->variable.var_label);
+          break;
+
+        case PIVOT_VALUE_TEXT:
+          free (value->text.local);
+          if (value->text.c != value->text.local)
+            free (value->text.c);
+          if (value->text.id != value->text.local
+              && value->text.id != value->text.c)
+            free (value->text.id);
+          break;
+
+        case PIVOT_VALUE_TEMPLATE:
+          free (value->template.s);
+          for (size_t i = 0; i < value->template.n_args; i++)
+            pivot_argument_uninit (&value->template.args[i]);
+          free (value->template.args);
+          break;
+        }
+      free (value);
+    }
+}
+
+/* Sets AREA to the style to use for VALUE, with defaults coming from
+   DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
+void
+pivot_value_get_style (struct pivot_value *value,
+                       const struct area_style *default_style,
+                       struct area_style *area)
+{
+  font_style_copy (&area->font_style, (value->font_style
+                                       ? value->font_style
+                                       : &default_style->font_style));
+  area->cell_style = (value->cell_style
+                      ? *value->cell_style
+                      : default_style->cell_style);
+}
+
+/* Copies AREA into VALUE's style. */
+void
+pivot_value_set_style (struct pivot_value *value,
+                       const struct area_style *area)
+{
+  if (value->font_style)
+    font_style_uninit (value->font_style);
+  else
+    value->font_style = xmalloc (sizeof *value->font_style);
+  font_style_copy (value->font_style, &area->font_style);
+
+  if (!value->cell_style)
+    value->cell_style = xmalloc (sizeof *value->cell_style);
+  *value->cell_style = area->cell_style;
+}
+
+/* Frees the data owned by ARG (but not ARG itself). */
+void
+pivot_argument_uninit (struct pivot_argument *arg)
+{
+  if (arg)
+    {
+      for (size_t i = 0; i < arg->n; i++)
+        pivot_value_destroy (arg->values[i]);
+      free (arg->values);
+    }
+}
+
+struct pivot_value *
+pivot_value_new_user_text_nocopy (char *text)
+{
+  struct pivot_value *value = xmalloc (sizeof *value);
+  *value = (struct pivot_value) {
+    .type = PIVOT_VALUE_TEXT,
+    .text = {
+      .local = text,
+      .c = text,
+      .id = text,
+      .user_provided = true,
+    }
+  };
+  return value;
+}
+
+struct pivot_value *
+pivot_value_new_user_text (const char *text, size_t length)
+{
+  return pivot_value_new_user_text_nocopy (
+    xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
+}
+
+/* TEXT should be a translatable string, but not actually translated yet,
+   e.g. enclosed in N_(). */
+struct pivot_value *
+pivot_value_new_text (const char *text)
+{
+  char *c = xstrdup (text);
+  char *local = xstrdup (gettext (c));
+
+  struct pivot_value *value = xmalloc (sizeof *value);
+  *value = (struct pivot_value) {
+    .type = PIVOT_VALUE_TEXT,
+    .text = {
+      .local = local,
+      .c = c,
+      .id = c,
+      .user_provided = false,
+    }
+  };
+  return value;
+}
+
+/* FORMAT should be a translatable string, but not actually translated yet,
+   e.g. enclosed in N_(). */
+struct pivot_value * PRINTF_FORMAT (1, 2)
+pivot_value_new_text_format (const char *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  char *c = xvasprintf (format, args);
+  va_end (args);
+
+  va_start (args, format);
+  char *local = xvasprintf (gettext (format), args);
+  va_end (args);
+
+  struct pivot_value *value = xmalloc (sizeof *value);
+  *value = (struct pivot_value) {
+    .type = PIVOT_VALUE_TEXT,
+    .text = {
+      .local = local,
+      .c = c,
+      .id = xstrdup (c),
+      .user_provided = false,
+    }
+  };
+  return value;
+}
+
+static char *
+xstrdup_if_nonempty (const char *s)
+{
+  return s && s[0] ? xstrdup (s) : NULL;
+}
+
+/* Returns a new pivot_value that represents X.
+
+   The format to use for X is unspecified.  Usually the easiest way to specify
+   a format is through assigning a result class to one of the categories that
+   the pivot_value will end up in.  If that is not suitable, then the caller
+   can use pivot_value_set_rc() or assign directly to value->numeric.format. */
+struct pivot_value *
+pivot_value_new_number (double x)
+{
+  struct pivot_value *value = xmalloc (sizeof *value);
+  *value = (struct pivot_value) {
+    .type = PIVOT_VALUE_NUMERIC,
+    .numeric = { .x = x, },
+  };
+  return value;
+}
+
+/* Returns a new pivot_value that represents X, formatted as an integer. */
+struct pivot_value *
+pivot_value_new_integer (double x)
+{
+  struct pivot_value *value = pivot_value_new_number (x);
+  value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 };
+  return value;
+}
+
+/* Returns a new pivot_value that represents VALUE, formatted as for
+   VARIABLE. */
+struct pivot_value *
+pivot_value_new_var_value (const struct variable *variable,
+                           const union value *value)
+{
+  struct pivot_value *pv = pivot_value_new_value (
+    value, var_get_width (variable), var_get_print_format (variable),
+    var_get_encoding (variable));
+
+  char *var_name = xstrdup (var_get_name (variable));
+  if (var_is_alpha (variable))
+    pv->string.var_name = var_name;
+  else
+    pv->numeric.var_name = var_name;
+
+  const char *label = var_lookup_value_label (variable, value);
+  if (label)
+    {
+      if (var_is_alpha (variable))
+        pv->string.value_label = xstrdup (label);
+      else
+        pv->numeric.value_label = xstrdup (label);
+    }
+
+  return pv;
+}
+
+/* Returns a new pivot_value that represents VALUE, with the given WIDTH,
+   formatted with FORMAT.  For a string value, ENCODING must be its character
+   encoding. */
+struct pivot_value *
+pivot_value_new_value (const union value *value, int width,
+                       const struct fmt_spec *format, const char *encoding)
+{
+  struct pivot_value *pv = xzalloc (sizeof *pv);
+  if (width > 0)
+    {
+      char *s = recode_string (UTF8, encoding,
+                               CHAR_CAST (char *, value_str (value, width)),
+                               width);
+      size_t n = strlen (s);
+      while (n > 0 && s[n - 1] == ' ')
+        s[--n] = '\0';
+
+      pv->type = PIVOT_VALUE_STRING;
+      pv->string.s = s;
+      pv->string.hex = format->type == FMT_AHEX;
+    }
+  else
+    {
+      pv->type = PIVOT_VALUE_NUMERIC;
+      pv->numeric.x = value->f;
+      pv->numeric.format = *format;
+    }
+
+  return pv;
+}
+
+/* Returns a new pivot_value for VARIABLE. */
+struct pivot_value *
+pivot_value_new_variable (const struct variable *variable)
+{
+  struct pivot_value *value = xmalloc (sizeof *value);
+  *value = (struct pivot_value) {
+    .type = PIVOT_VALUE_VARIABLE,
+    .variable = {
+      .var_name = xstrdup (var_get_name (variable)),
+      .var_label = xstrdup_if_nonempty (var_get_label (variable)),
+    },
+  };
+  return value;
+}
+
+/* Attaches a reference to FOOTNOTE to V. */
+void
+pivot_value_add_footnote (struct pivot_value *v,
+                          struct pivot_footnote *footnote)
+{
+  v->footnotes = xrealloc (v->footnotes,
+                           (v->n_footnotes + 1) * sizeof *v->footnotes);
+  v->footnotes[v->n_footnotes++] = footnote;
+}
+
+/* If VALUE is a numeric value, and RC is a result class such as
+   PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
+void
+pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
+                    const char *rc)
+{
+  if (value->type == PIVOT_VALUE_NUMERIC)
+    {
+      const struct fmt_spec *f = pivot_table_get_format (table, rc);
+      if (f)
+        value->numeric.format = *f;
+    }
+}
+
diff --git a/src/output/pivot-table.h b/src/output/pivot-table.h
new file mode 100644 (file)
index 0000000..474b3ac
--- /dev/null
@@ -0,0 +1,703 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2017-2018 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_PIVOT_TABLE_H
+#define OUTPUT_PIVOT_TABLE_H 1
+
+#include <stdint.h>
+#include <time.h>
+#include "data/format.h"
+#include "data/settings.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hmap.h"
+#include "output/table.h"
+
+struct pivot_value;
+struct variable;
+union value;
+
+/* Pivot tables.
+
+   Pivot tables are PSPP's primary form of output.  They are analogous to the
+   pivot tables you might be familiar with from spreadsheets and databases.
+   See https://en.wikipedia.org/wiki/Pivot_table for a brief introduction to
+   the overall concept of a pivot table.
+
+   In PSPP, the most important internal pieces of a pivot table are:
+
+   - Title.  Every pivot table has a title that is displayed above it.  It also
+     has an optional caption (displayed below it) and corner text (displayed in
+     the upper left corner).
+
+   - Dimensions.  A dimension consists of zero or more categories.  A category
+     has a label, such as "df" or "Asymp. Sig." or 123 or a variable name.  The
+     categories are the leaves of a tree whose non-leaf nodes form groups of
+     categories.  The tree always has a root group whose label is the name of
+     the dimension.
+
+   - Axes.  A table has three axes: column, row, and layer.  Each dimension is
+     assigned to an axis, and each axis has zero or more dimensions.  When an
+     axis has more than one dimension, they are ordered from innermost to
+     outermost.
+
+   - Data.  A table's data consists of zero or more cells.  Each cell maps from
+     a category for each dimension to a value, which is commonly a number but
+     could also be a variable name or an arbitrary text string.
+
+   Creating a pivot table usually consists of the following steps:
+
+   1. Create the table with pivot_table_create(), passing in the title.
+
+   2. Create each dimension with pivot_dimension_create() and populate it with
+      categories and, possibly, with groups that contain the categories.  This
+      call also assigns the dimension to an axis.
+
+      In simple cases, only a call to pivot_dimension_create() is needed.
+      Other functions such as pivot__create_group() can be used for
+      hierarchies of categories.
+
+      Sometimes it's easier to create categories in tandem with inserting data,
+      for example by adding a category for a variable just before inserting the
+      first cell for that variable.  In that case, creating categories and
+      inserting data can be interleaved.
+
+   3. Insert data.  For each cell, supply the category indexes, which are
+      assigned starting from 0 in the order in which the categories were
+      created in step 2, and the value to go in the cell.  If the table has a
+      small, fixed number of dimensions, functions like, e.g.
+      pivot_table_put3() for 3 dimensions, can be used.  The general function
+      pivot_table_put() works for other cases.
+
+   4. Output the table for user consumption.  Use pivot_table_submit(). */
+\f
+/* Pivot table display styling. */
+
+/* Areas of a pivot table for styling purposes. */
+enum pivot_area
+  {
+    PIVOT_AREA_TITLE,
+    PIVOT_AREA_CAPTION,
+    PIVOT_AREA_FOOTER,          /* Footnotes. */
+    PIVOT_AREA_CORNER,          /* Top-left corner. */
+    PIVOT_AREA_COLUMN_LABELS,
+    PIVOT_AREA_ROW_LABELS,
+    PIVOT_AREA_DATA,
+    PIVOT_AREA_LAYERS,          /* Layer indication. */
+    PIVOT_N_AREAS
+  };
+
+const char *pivot_area_to_string (enum pivot_area);
+
+/* Table borders for styling purposes. */
+enum pivot_border
+  {
+    PIVOT_BORDER_TITLE,
+
+    /* Outer frame. */
+    PIVOT_BORDER_OUTER_LEFT,
+    PIVOT_BORDER_OUTER_TOP,
+    PIVOT_BORDER_OUTER_RIGHT,
+    PIVOT_BORDER_OUTER_BOTTOM,
+
+    /* Inner frame. */
+    PIVOT_BORDER_INNER_LEFT,
+    PIVOT_BORDER_INNER_TOP,
+    PIVOT_BORDER_INNER_RIGHT,
+    PIVOT_BORDER_INNER_BOTTOM,
+
+    /* Data area. */
+    PIVOT_BORDER_DATA_LEFT,
+    PIVOT_BORDER_DATA_TOP,
+
+    /* Dimensions. */
+    PIVOT_BORDER_DIM_ROW_HORZ,
+    PIVOT_BORDER_DIM_ROW_VERT,
+    PIVOT_BORDER_DIM_COL_HORZ,
+    PIVOT_BORDER_DIM_COL_VERT,
+
+    /* Categories. */
+    PIVOT_BORDER_CAT_ROW_HORZ,
+    PIVOT_BORDER_CAT_ROW_VERT,
+    PIVOT_BORDER_CAT_COL_HORZ,
+    PIVOT_BORDER_CAT_COL_VERT,
+
+    PIVOT_N_BORDERS
+  };
+
+const char *pivot_border_to_string (enum pivot_border);
+
+/* Sizing for rows or columns of a rendered table.  The comments below talk
+   about columns and their widths but they apply equally to rows and their
+   heights. */
+struct pivot_table_sizing
+  {
+    /* Minimum and maximum column width, in 1/96" units. */
+    int range[2];
+
+    /* Specific column widths, in 1/96" units. */
+    int *widths;
+    size_t n_widths;
+
+    /* Specific page breaks: 0-based columns after which a page break must
+       occur, e.g. a value of 1 requests a break after the second column. */
+    size_t *breaks;
+    size_t n_breaks;
+
+    /* Keeps: columns to keep together on a page if possible. */
+    struct pivot_keep *keeps;
+    size_t n_keeps;
+  };
+
+void pivot_table_sizing_uninit (struct pivot_table_sizing *);
+
+/* A set of columns to keep together on a page if possible, e.g. ofs=1, n=10
+   requests keeping together the 2nd through 11th columns. */
+struct pivot_keep
+  {
+    size_t ofs;                 /* 0-based first column. */
+    size_t n;                   /* Number of columns. */
+  };
+\f
+/* Axes. */
+
+enum pivot_axis_type
+  {
+    PIVOT_AXIS_LAYER,
+    PIVOT_AXIS_ROW,
+    PIVOT_AXIS_COLUMN,
+
+    PIVOT_N_AXES
+  };
+
+const char *pivot_axis_type_to_string (enum pivot_axis_type);
+
+/* An axis within a pivot table. */
+struct pivot_axis
+  {
+    /* dimensions[0] is the innermost dimension,
+       dimensions[1] is the next outer dimension,
+       ...
+       dimensions[n_dimensions - 1] is the outermost dimension. */
+    struct pivot_dimension **dimensions;
+    size_t n_dimensions;
+
+    /* The number of rows or columns along the axis,
+       that is, the product of dimension[*]->n_leaves.
+       It is 0 if any dimension has 0 leaves. */
+    size_t extent;
+
+    /* Sum of dimensions[*]->label_depth. */
+    size_t label_depth;
+  };
+
+/* Successively assigns to INDEXES (which should be a "size_t *") each of the
+   combinations of the categories in AXIS's dimensions, in lexicographic order
+   with the innermost dimension iterating most quickly.
+
+   The value assigned to INDEXES is dynamically allocated.  If the client
+   breaks out of the loop prematurely, it needs to free it with free(). */
+#define PIVOT_AXIS_FOR_EACH(INDEXES, AXIS)                              \
+  for ((INDEXES) = NULL;                                                \
+       ((INDEXES) = pivot_axis_iterator_next (INDEXES, AXIS)) != NULL; )
+size_t *pivot_axis_iterator_next (size_t *indexes, const struct pivot_axis *);
+\f
+/* Dimensions.
+
+   A pivot_dimension identifies the categories associated with a single
+   dimension within a multidimensional pivot table.
+
+   A dimension contains a collection of categories, which are the leaves in a
+   tree of groups.
+
+   (A dimension or a group can contain zero categories, but this is unusual.
+   If a dimension contains no categories, then its table cannot contain any
+   data.)
+*/
+struct pivot_dimension
+  {
+    /* table->axes[axis_type]->dimensions[level] == dimension. */
+    struct pivot_table *table;
+    enum pivot_axis_type axis_type;
+    size_t level;               /* 0 for innermost dimension within axis. */
+
+    /* table->dimensions[top_index] == dimension. */
+    size_t top_index;
+
+    /* Hierarchy of categories within the dimension.  The groups and categories
+       are sorted in the order that should be used for display.  This might be
+       different from the original order produced for output if the user
+       adjusted it.
+
+       The root must always be a group, although it is allowed to have no
+       subcategories. */
+    struct pivot_category *root;
+
+    /* All of the leaves reachable via the root.
+
+       The indexing for presentation_leaves is presentation order, thus
+       presentation_leaves[i]->presentation_index == i.  This order is the same
+       as would be produced by an in-order traversal of the groups.  It is the
+       order into which the user reordered or sorted the categories.
+
+       The indexing for data_leaves is that used for idx[] in struct
+       pivot_cell, thus data_leaves[i]->data_index == i.  This might differ
+       from what an in-order traversal of 'root' would yield, if the user
+       reordered categories. */
+    struct pivot_category **data_leaves;
+    struct pivot_category **presentation_leaves;
+    size_t n_leaves, allocated_leaves;
+
+    /* Display. */
+    bool hide_all_labels;
+
+    /* Number of rows or columns needed to express the labels. */
+    int label_depth;
+  };
+
+struct pivot_dimension *pivot_dimension_create (
+  struct pivot_table *, enum pivot_axis_type, const char *name, ...)
+  SENTINEL (0);
+#define pivot_dimension_create(...) \
+  pivot_dimension_create(__VA_ARGS__, NULL_SENTINEL)
+struct pivot_dimension *pivot_dimension_create__ (struct pivot_table *,
+                                                  enum pivot_axis_type,
+                                                  struct pivot_value *name);
+
+void pivot_dimension_destroy (struct pivot_dimension *);
+
+void pivot_dimension_dump (const struct pivot_dimension *, int indentation);
+\f
+/* A pivot_category is a leaf (a category) or a group:
+
+   - For a leaf, neither index is SIZE_MAX.
+
+   - For a group, both indexes are SIZE_MAX.
+
+   Do not use 'subs' or 'n_subs' to determine whether a category is a group,
+   because a group may (pathologically) have no leaves. */
+struct pivot_category
+  {
+    struct pivot_value *name;
+    struct pivot_category *parent;
+    struct pivot_dimension *dimension;
+    size_t label_depth, extra_depth;
+
+    /* Groups only.
+
+       If show_label is true, then the group itself has a row (or a column)
+       giving the group's name.  Otherwise, the group's own name is not
+       displayed. */
+    struct pivot_category **subs; /* Child categories or groups. */
+    size_t n_subs, allocated_subs;
+    bool show_label;            /* Display a label for the group itself? */
+    bool show_label_in_corner;
+
+    /* Leaf only. */
+    struct fmt_spec format;
+    size_t group_index;        /* In ->parent->subs[]. */
+    size_t data_index;         /* In ->dimension->data_leaves[]. */
+    size_t presentation_index; /* In ->dimension->presentation_leaves[]. */
+  };
+
+static inline bool
+pivot_category_is_group (const struct pivot_category *category)
+{
+  return category->data_index == SIZE_MAX;
+}
+
+static inline bool
+pivot_category_is_leaf (const struct pivot_category *category)
+{
+  return !pivot_category_is_group (category);
+}
+
+/* Creating leaf categories. */
+int pivot_category_create_leaves (struct pivot_category *parent, ...)
+  SENTINEL (0);
+#define pivot_category_create_leaves(...) \
+  pivot_category_create_leaves(__VA_ARGS__, NULL_SENTINEL)
+
+int pivot_category_create_leaf (
+  struct pivot_category *parent, struct pivot_value *name);
+int pivot_category_create_leaf_rc (
+  struct pivot_category *parent, struct pivot_value *name, const char *rc);
+
+/* Creating category groups. */
+struct pivot_category *pivot_category_create_group (
+  struct pivot_category *parent, const char *name, ...) SENTINEL (0);
+#define pivot_category_create_group(...) \
+  pivot_category_create_group(__VA_ARGS__, NULL_SENTINEL)
+struct pivot_category *pivot_category_create_group__ (
+  struct pivot_category *parent, struct pivot_value *name);
+
+void pivot_category_destroy (struct pivot_category *);
+
+/* Pivot result classes.
+
+   These are used to mark leaf categories as having particular types of data,
+   to set their numeric formats.  The formats that actually get used for these
+   classes are in the result_classes[] global array in pivot-table.c, except
+   that PIVOT_RC_OTHER comes from settings_get_format() and PIVOT_RC_COUNT
+   should come from the weight variable in the dataset's dictionary. */
+#define PIVOT_RC_OTHER ("RC_OTHER")
+#define PIVOT_RC_INTEGER ("RC_INTEGER")
+#define PIVOT_RC_CORRELATION ("RC_CORRELATIONS")
+#define PIVOT_RC_SIGNIFICANCE ("RC_SIGNIFICANCE")
+#define PIVOT_RC_PERCENT ("RC_PERCENT")
+#define PIVOT_RC_RESIDUAL ("RC_RESIDUAL")
+#define PIVOT_RC_COUNT ("RC_COUNT")
+
+bool pivot_result_class_change (const char *, const struct fmt_spec *);
+\f
+/* A pivot table.  See the top of this file for more information. */
+struct pivot_table
+  {
+    /* Display settings. */
+    bool rotate_inner_column_labels;
+    bool rotate_outer_row_labels;
+    bool row_labels_in_corner;
+    bool show_grid_lines;
+    bool omit_empty;
+    size_t *current_layer; /* axis[PIVOT_AXIS_LAYER]->n_dimensions elements. */
+    char *table_look;
+    enum settings_value_show show_values;
+    enum settings_value_show show_variables;
+    struct fmt_spec weight_format;
+
+    /* Footnote display settings. */
+    bool show_numeric_markers;
+    bool footnote_marker_superscripts;
+
+    /* Column and row sizing and page breaks.
+       sizing[TABLE_HORZ] is for columns, sizing[TABLE_VERT] is for rows. */
+    struct pivot_table_sizing sizing[TABLE_N_AXES];
+
+    /* Print settings. */
+    bool print_all_layers;
+    bool paginate_layers;
+    bool shrink_to_fit[TABLE_N_AXES];
+    bool top_continuation, bottom_continuation;
+    char *continuation;
+    size_t n_orphan_lines;
+
+    /* Format settings. */
+    int epoch;
+    char decimal;               /* Usually ',' or '.'. */
+    char grouping;              /* Usually '.' or ','. */
+    char *ccs[5];               /* Custom currency. */
+    double small;
+
+    /* Command information. */
+    char *command_local;        /* May be NULL. */
+    char *command_c;            /* May be NULL. */
+    char *language;             /* May be NULL. */
+    char *locale;               /* May be NULL. */
+
+    /* Source information. */
+    char *dataset;              /* May be NULL. */
+    char *datafile;             /* May be NULL. */
+    time_t date;                /* May be 0 if unknown. */
+
+    /* Footnotes. */
+    struct pivot_footnote **footnotes;
+    size_t n_footnotes, allocated_footnotes;
+
+    /* Titles. */
+    struct pivot_value *title;
+    struct pivot_value *subtype;  /* Same as pivot_item's subtype. */
+    struct pivot_value *corner_text;
+    struct pivot_value *caption;
+    char *notes;
+
+    /* Styles. */
+    struct area_style areas[PIVOT_N_AREAS];
+    struct table_border_style borders[PIVOT_N_BORDERS];
+
+    /* Dimensions. */
+    struct pivot_dimension **dimensions;
+    size_t n_dimensions;
+
+    /* Allocation of dimensions to rows, columns, and layers. */
+    struct pivot_axis axes[PIVOT_N_AXES];
+
+    struct hmap cells;          /* Contains "struct pivot_cell"s. */
+  };
+
+/* Creating and destroy pivot tables. */
+struct pivot_table *pivot_table_create (const char *title);
+struct pivot_table *pivot_table_create__ (struct pivot_value *title);
+struct pivot_table *pivot_table_create_for_text (struct pivot_value *title,
+                                                 struct pivot_value *content);
+void pivot_table_destroy (struct pivot_table *);
+
+/* Format of PIVOT_RC_COUNT cells. */
+void pivot_table_set_weight_var (struct pivot_table *,
+                                 const struct variable *);
+void pivot_table_set_weight_format (struct pivot_table *,
+                                    const struct fmt_spec *);
+
+/* Query. */
+bool pivot_table_is_empty (const struct pivot_table *);
+
+/* Output. */
+void pivot_table_submit (const struct pivot_table *);
+
+/* Data cells. */
+void pivot_table_put (struct pivot_table *, const size_t *dindexes, size_t n,
+                      struct pivot_value *);
+void pivot_table_put1 (struct pivot_table *, size_t idx1,
+                       struct pivot_value *);
+void pivot_table_put2 (struct pivot_table *, size_t idx1, size_t idx2,
+                       struct pivot_value *);
+void pivot_table_put3 (struct pivot_table *, size_t idx1, size_t idx2,
+                       size_t idx3, struct pivot_value *);
+void pivot_table_put4 (struct pivot_table *, size_t idx1, size_t idx2,
+                       size_t idx3, size_t idx4, struct pivot_value *);
+
+const struct pivot_value *pivot_table_get (const struct pivot_table *,
+                                           const size_t *dindexes);
+
+struct pivot_value *pivot_table_get_rw (struct pivot_table *,
+                                        const size_t *dindexes);
+
+/* Footnotes.
+
+   Use pivot_table_create_footnote() to create a footnote.
+   Use pivot_value_add_footnote() to add a reference to a footnote. */
+struct pivot_footnote
+  {
+    size_t idx;
+    struct pivot_value *content;
+    struct pivot_value *marker;
+  };
+
+struct pivot_footnote *pivot_table_create_footnote (
+  struct pivot_table *, struct pivot_value *content);
+struct pivot_footnote *pivot_table_create_footnote__ (
+  struct pivot_table *, size_t idx,
+  struct pivot_value *marker, struct pivot_value *content);
+
+void pivot_footnote_destroy (struct pivot_footnote *);
+
+/* Internals. */
+void pivot_table_convert_indexes_ptod (const struct pivot_table *,
+                                       const size_t *pindexes[PIVOT_N_AXES],
+                                       size_t *dindexes);
+size_t *pivot_table_enumerate_axis (const struct pivot_table *,
+                                    enum pivot_axis_type,
+                                    const size_t *layer_indexes,
+                                    bool omit_empty, size_t *n);
+#define PIVOT_ENUMERATION_FOR_EACH(INDEXES, ENUMERATION, AXIS)  \
+  for ((INDEXES) = (ENUMERATION); *(INDEXES) != SIZE_MAX;       \
+       (INDEXES) += MAX (1, (AXIS)->n_dimensions))
+
+void pivot_table_assign_label_depth (struct pivot_table *);
+
+void pivot_table_dump (const struct pivot_table *, int indentation);
+\f
+/* pivot_value. */
+
+enum pivot_value_type
+  {
+    PIVOT_VALUE_NUMERIC,          /* A value of a numeric variable. */
+    PIVOT_VALUE_STRING,           /* A value of a string variable. */
+    PIVOT_VALUE_VARIABLE,         /* Name of a variable. */
+    PIVOT_VALUE_TEXT,             /* Text. */
+    PIVOT_VALUE_TEMPLATE,         /* Templated text. */
+  };
+
+/* A pivot_value is the content of a single pivot table cell.  A pivot_value is
+   also a pivot table's title, caption, footnote marker and contents, and so
+   on.
+
+   A given pivot_value is one of:
+
+   1. A number resulting from a calculation (PIVOT_VALUE_NUMERIC).  Use
+      pivot_value_new_number() to create such a pivot_value.
+
+      A numeric pivot_value has an associated display format (usually an F or
+      PCT format).  This format can be set directly on the pivot_value, but
+      that is not usually the easiest way.  Instead, it is usually true that
+      all of the values in a single category should have the same format
+      (e.g. all "Significance" values might use format F40.3), so PSPP makes
+      it easy to set the default format for a category while creating the
+      category.  See pivot_dimension_create() for more details.
+
+      For numbers that should be displayed as integers,
+      pivot_value_new_integer() can occasionally be a useful special case.
+
+   2. A numeric or string value obtained from data (PIVOT_VALUE_NUMERIC or
+      PIVOT_VALUE_STRING).  If such a value corresponds to a variable, then the
+      variable's name can be attached to the pivot_value.  If the value has a
+      value label, then that can also be attached.  When a label is present,
+      the user can control whether to show the value or the label or both.
+
+      Use pivot_value_new_var_value() to create pivot_values of these kinds.
+
+   3. A variable name (PIVOT_VALUE_VARIABLE).  The variable label, if any, can
+      be attached too, and again the user can control whether to show the value
+      or the label or both.
+
+   4. A text string (PIVOT_VALUE_TEXT).  The value stores the string in English
+      and translated into the output language (localized).  Use
+      pivot_value_new_text() or pivot_value_new_text_format() for those cases.
+      In some cases, only an English or a localized version is available for
+      one reason or another, although this is regrettable; in those cases, use
+      pivot_value_new_user_text() or pivot_value_new_user_text_nocopy().
+
+   (There is also a PIVOT_VALUE_TEMPLATE but PSPP does not yet create these
+   itself.)
+
+
+   Footnotes
+   =========
+
+   A pivot_value may reference any number of footnotes.  Use
+   pivot_value_add_footnote() to add a footnote reference.  The footnotes being
+   referenced must first be created with pivot_table_create_footnote().
+
+
+   Styling
+   =======
+
+   A pivot_value can have specific font and cell styles.  Only the user should
+   add these.
+*/
+struct pivot_value
+  {
+    struct font_style *font_style;
+    struct cell_style *cell_style;
+    char *subscript;
+    char *superscript;
+
+    struct pivot_footnote **footnotes;
+    size_t n_footnotes;
+
+    enum pivot_value_type type;
+    union
+      {
+        /* PIVOT_VALUE_NUMERIC. */
+        struct
+          {
+            double x;                 /* The numeric value. */
+            struct fmt_spec format;   /* Format to display 'x'. */
+            char *var_name;           /* May be NULL. */
+            char *value_label;        /* May be NULL. */
+            enum settings_value_show show; /* Show value or label or both? */
+          }
+        numeric;
+
+        /* PIVOT_VALUE_STRING. */
+        struct
+          {
+            char *s;                  /* The string value. */
+            bool hex;                 /* Display in hex? */
+            char *var_name;           /* May be NULL. */
+            char *value_label;        /* May be NULL. */
+            enum settings_value_show show; /* Show value or label or both? */
+          }
+        string;
+
+        /* PIVOT_VALUE_VARIABLE. */
+        struct
+          {
+            char *var_name;
+            char *var_label;          /* May be NULL. */
+            enum settings_value_show show; /* Show name or label or both? */
+          }
+        variable;
+
+        /* PIVOT_VALUE_TEXT. */
+        struct
+          {
+            char *local;              /* Localized. */
+            char *c;                  /* English. */
+            char *id;                 /* Identifier. */
+            bool user_provided;
+          }
+        text;
+
+        /* PIVOT_VALUE_TEMPLATE. */
+        struct
+          {
+            char *s;
+            struct pivot_argument *args;
+            size_t n_args;
+          }
+        template;
+      };
+  };
+
+/* Numbers resulting from calculations. */
+struct pivot_value *pivot_value_new_number (double);
+struct pivot_value *pivot_value_new_integer (double);
+
+/* Values from data. */
+struct pivot_value *pivot_value_new_var_value (
+  const struct variable *, const union value *);
+struct pivot_value *pivot_value_new_value (const union value *, int width,
+                                           const struct fmt_spec *,
+                                           const char *encoding);
+
+/* Values from variable names. */
+struct pivot_value *pivot_value_new_variable (const struct variable *);
+
+/* Values from text strings. */
+struct pivot_value *pivot_value_new_text (const char *);
+struct pivot_value *pivot_value_new_text_format (const char *, ...)
+  PRINTF_FORMAT (1, 2);
+
+struct pivot_value *pivot_value_new_user_text (const char *, size_t length);
+struct pivot_value *pivot_value_new_user_text_nocopy (char *);
+
+/* Footnotes. */
+void pivot_value_add_footnote (struct pivot_value *, struct pivot_footnote *);
+
+/* Numeric formats. */
+void pivot_value_set_rc (struct pivot_table *, struct pivot_value *,
+                         const char *rc);
+
+/* Converting a pivot_value to a string for display. */
+char *pivot_value_to_string (const struct pivot_value *,
+                             enum settings_value_show show_values,
+                             enum settings_value_show show_variables);
+void pivot_value_format (const struct pivot_value *,
+                         enum settings_value_show show_values,
+                         enum settings_value_show show_variables,
+                         struct string *);
+bool pivot_value_format_body (const struct pivot_value *,
+                              enum settings_value_show show_values,
+                              enum settings_value_show show_variables,
+                              struct string *);
+
+void pivot_value_destroy (struct pivot_value *);
+
+/* Styling. */
+void pivot_value_get_style (struct pivot_value *,
+                            const struct area_style *default_style,
+                            struct area_style *);
+void pivot_value_set_style (struct pivot_value *, const struct area_style *);
+
+/* Template arguments. */
+struct pivot_argument
+  {
+    size_t n;
+    struct pivot_value **values;
+  };
+
+void pivot_argument_uninit (struct pivot_argument *);
+
+#endif /* output/pivot-table.h */
index ec00c432226cf4f993c8c5d36367f7b5432160cb..f6f965022e14daaa6fc8d91ab34f8c540cbb906b 100644 (file)
@@ -55,12 +55,7 @@ static const bool debugging = true;
 struct tab_joined_cell
 {
   int d[TABLE_N_AXES][2];       /* Table region, same as struct table_cell. */
-  union
-  {
-    char *text;
-    struct table_item *subtable;
-  }
-    u;
+  char *text;
 
   size_t n_footnotes;
   const struct footnote **footnotes;
@@ -70,14 +65,6 @@ 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 *
@@ -90,8 +77,6 @@ tab_create (int nc, int nr)
   table_set_nc (&t->table, nc);
   table_set_nr (&t->table, nr);
 
-  t->title = NULL;
-  t->caption = NULL;
   t->cf = nc;
   t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
   t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
@@ -102,124 +87,13 @@ tab_create (int nc, int nr)
   t->rv = pool_nmalloc (t->container, nr, nc + 1);
   memset (t->rv, TAL_0, nr * (nc + 1));
 
-  memset (t->fmtmap, 0, sizeof (*t->fmtmap) * n_RC);
-  t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE];
-  t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER];
-  t->fmtmap[RC_OTHER] = *settings_get_format ();
-
   memset (t->styles, 0, sizeof t->styles);
   memset (t->rule_colors, 0, sizeof t->rule_colors);
 
-  t->col_ofs = t->row_ofs = 0;
-
   return t;
 }
 
 
-void
-tab_set_format (struct tab_table *t, enum result_class rc,
-                const struct fmt_spec *fmt)
-{
-  t->fmtmap[rc] = *fmt;
-}
-
-
-/* Sets the width and height of a table, in columns and rows,
-   respectively.  Use only to reduce the size of a table, since it
-   does not change the amount of allocated memory.
-
-   This function is obsolete.  Please do not add new uses of it.  (Instead, use
-   table_select() or one of its helper functions.) */
-void
-tab_resize (struct tab_table *t, int nc, int nr)
-{
-  if (nc != -1)
-    {
-      assert (nc + t->col_ofs <= t->cf);
-      table_set_nc (&t->table, nc + t->col_ofs);
-    }
-  if (nr != -1)
-    {
-      assert (nr + t->row_ofs <= tab_nr (t));
-      table_set_nr (&t->table, nr + t->row_ofs);
-    }
-}
-
-/* Changes either or both dimensions of a table and reallocates memory as
-   necessary.
-
-   This function is obsolete.  Please do not add new uses of it.  (Instead, use
-   table_paste() or one of its helper functions to paste multiple tables
-   together into a larger one.) */
-void
-tab_realloc (struct tab_table *t, int nc, int nr)
-{
-  int ro, co;
-
-  ro = t->row_ofs;
-  co = t->col_ofs;
-  if (ro || co)
-    tab_offset (t, 0, 0);
-
-  if (nc == -1)
-    nc = tab_nc (t);
-  if (nr == -1)
-    nr = tab_nr (t);
-
-  assert (nc == tab_nc (t));
-
-  if (nc > t->cf)
-    {
-      int mr1 = MIN (nr, tab_nr (t));
-      int mc1 = MIN (nc, tab_nc (t));
-
-      void **new_cc;
-      unsigned short *new_ct;
-      int r;
-
-      new_cc = pool_calloc (t->container, nr * nc, sizeof *new_cc);
-      new_ct = pool_malloc (t->container, nr * nc);
-      for (r = 0; r < mr1; r++)
-        {
-          memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)],
-                  mc1 * sizeof *t->cc);
-          memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)],
-                  mc1 * sizeof *t->ct);
-          memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t));
-        }
-      pool_free (t->container, t->cc);
-      pool_free (t->container, t->ct);
-      t->cc = new_cc;
-      t->ct = new_ct;
-      t->cf = nc;
-    }
-  else if (nr != tab_nr (t))
-    {
-      t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
-      t->ct = pool_nrealloc (t->container, t->ct, nr * nc, sizeof *t->ct);
-
-      t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
-      t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
-
-      if (nr > tab_nr (t))
-        {
-          memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0,
-                  (nr - tab_nr (t)) * nc);
-          memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_0,
-                  (nr - tab_nr (t)) * (nc + 1));
-        }
-    }
-
-  memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->ct);
-  memset (&t->cc[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->cc);
-
-  table_set_nr (&t->table, nr);
-  table_set_nc (&t->table, nc);
-
-  if (ro || co)
-    tab_offset (t, co, ro);
-}
-
 /* Sets the number of header rows on each side of TABLE to L on the
    left, R on the right, T on the top, B on the bottom.  Header rows
    are repeated when a table is broken across multiple columns or
@@ -242,23 +116,16 @@ tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
 {
   if (debugging)
     {
-      if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
-          || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
-          || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+      if (x < 0 || x > tab_nc (t)
+          || y1 < 0 || y1 >= tab_nr (t)
+          || y2 < 0 || y2 >= tab_nr (t))
         {
-          printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
-                    "table size (%d,%d)\n"),
-                  x, t->col_ofs, x + t->col_ofs,
-                  y1, t->row_ofs, y1 + t->row_ofs,
-                  y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t));
+          printf (_("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n"),
+                  x, y1, y2, tab_nc (t), tab_nr (t));
           return;
         }
     }
 
-  x += t->col_ofs;
-  y1 += t->row_ofs;
-  y2 += t->row_ofs;
-
   assert (x >= 0);
   assert (x <= tab_nc (t));
   assert (y1 >= 0);
@@ -280,23 +147,16 @@ tab_hline (struct tab_table *t, int style, int x1, int x2, int y)
 {
   if (debugging)
     {
-      if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t)
-          || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
-          || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t))
+      if (y < 0 || y > tab_nr (t)
+          || x1 < 0 || x1 >= tab_nc (t)
+          || x2 < 0 || x2 >= tab_nc (t))
         {
-          printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in "
-                    "table size (%d,%d)\n"),
-                  x1, t->col_ofs, x1 + t->col_ofs,
-                  x2, t->col_ofs, x2 + t->col_ofs,
-                  y, t->row_ofs, y + t->row_ofs, tab_nc (t), tab_nr (t));
+          printf (_("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n"),
+                  x1, x2, y, tab_nc (t), tab_nr (t));
           return;
         }
     }
 
-  x1 += t->col_ofs;
-  x2 += t->col_ofs;
-  y += t->row_ofs;
-
   assert (y >= 0);
   assert (y <= tab_nr (t));
   assert (x2 >= x1);
@@ -323,26 +183,17 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
 {
   if (debugging)
     {
-      if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
-          || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
-          || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
-          || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+      if (x1 < 0 || x1 >= tab_nc (t)
+          || x2 < 0 || x2 >= tab_nc (t)
+          || y1 < 0 || y1 >= tab_nr (t)
+          || y2 < 0 || y2 >= tab_nr (t))
         {
-          printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
-                    "in table size (%d,%d)\n"),
-                  x1, t->col_ofs, x1 + t->col_ofs,
-                  y1, t->row_ofs, y1 + t->row_ofs,
-                  x2, t->col_ofs, x2 + t->col_ofs,
-                  y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t));
+          printf (_("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n"),
+                  x1, y1, x2, y2, tab_nc (t), tab_nr (t));
           NOT_REACHED ();
         }
     }
 
-  x1 += t->col_ofs;
-  x2 += t->col_ofs;
-  y1 += t->row_ofs;
-  y2 += t->row_ofs;
-
   assert (x2 >= x1);
   assert (y2 >= y1);
   assert (x1 >= 0);
@@ -397,81 +248,6 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
 \f
 /* Cells. */
 
-/* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
-   from V, displayed with format spec F. */
-void
-tab_value (struct tab_table *table, int c, int r, unsigned short opt,
-           const union value *v, const struct variable *var,
-           const struct fmt_spec *f)
-{
-  char *contents;
-
-  if (debugging)
-    {
-      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-          || c + table->col_ofs >= tab_nc (table)
-          || r + table->row_ofs >= tab_nr (table))
-        {
-          printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-                  "(%d,%d)\n",
-                  c, table->col_ofs, c + table->col_ofs,
-                  r, table->row_ofs, r + table->row_ofs,
-                  tab_nc (table), tab_nr (table));
-          return;
-        }
-    }
-
-  contents = data_out_stretchy (v, var_get_encoding (var),
-                                f != NULL ? f : var_get_print_format (var),
-                                table->container);
-
-  table->cc[c + r * table->cf] = contents;
-  table->ct[c + r * table->cf] = opt;
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
-   formatted by FMT.
-   If FMT is null, then the default print format will be used.
-*/
-void
-tab_double (struct tab_table *table, int c, int r, unsigned short opt,
-            double val, const struct fmt_spec *fmt, enum result_class rc)
-{
-  union value double_value;
-  char *s;
-
-  assert (c >= 0);
-  assert (c < tab_nc (table));
-  assert (r >= 0);
-  assert (r < tab_nr (table));
-
-  if (fmt == NULL)
-    fmt = &table->fmtmap[rc];
-
-  fmt_check_output (fmt);
-
-  if (debugging)
-    {
-      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-          || c + table->col_ofs >= tab_nc (table)
-          || r + table->row_ofs >= tab_nr (table))
-        {
-          printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-                  "(%d,%d)\n",
-                  c, table->col_ofs, c + table->col_ofs,
-                  r, table->row_ofs, r + table->row_ofs,
-                  tab_nc (table), tab_nr (table));
-          return;
-        }
-    }
-
-  double_value.f = val;
-  s = data_out_stretchy (&double_value, C_ENCODING, fmt, table->container);
-  table->cc[c + r * table->cf] = s + strspn (s, " ");
-  table->ct[c + r * table->cf] = opt;
-}
-
-
 static void
 do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
 {
@@ -482,15 +258,10 @@ do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
 
   if (debugging)
     {
-      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-          || c + table->col_ofs >= tab_nc (table)
-          || r + table->row_ofs >= tab_nr (table))
+      if (c < 0 || r < 0 || c >= tab_nc (table) || r >= tab_nr (table))
         {
-          printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-                  "(%d,%d)\n",
-                  c, table->col_ofs, c + table->col_ofs,
-                  r, table->row_ofs, r + table->row_ofs,
-                  tab_nc (table), tab_nr (table));
+          printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n",
+                  c, r, tab_nc (table), tab_nr (table));
           return;
         }
     }
@@ -528,27 +299,23 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
 {
   struct tab_joined_cell *j;
 
-  assert (x1 + table->col_ofs >= 0);
-  assert (y1 + table->row_ofs >= 0);
+  assert (x1 >= 0);
+  assert (y1 >= 0);
   assert (y2 >= y1);
   assert (x2 >= x1);
-  assert (y2 + table->row_ofs < tab_nr (table));
-  assert (x2 + table->col_ofs < tab_nc (table));
+  assert (y2 < tab_nr (table));
+  assert (x2 < tab_nc (table));
 
   if (debugging)
     {
-      if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
-          || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
-          || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
-          || y2 < y1 || y2 + table->row_ofs >= tab_nr (table))
+      if (x1 < 0 || x1 >= tab_nc (table)
+          || y1 < 0 || y1 >= tab_nr (table)
+          || x2 < x1 || x2 >= tab_nc (table)
+          || y2 < y1 || y2 >= tab_nr (table))
         {
           printf ("tab_joint_text(): bad cell "
-                  "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
-                  x1, table->col_ofs, x1 + table->col_ofs,
-                  y1, table->row_ofs, y1 + table->row_ofs,
-                  x2, table->col_ofs, x2 + table->col_ofs,
-                  y2, table->row_ofs, y2 + table->row_ofs,
-                  tab_nc (table), tab_nr (table));
+                  "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
+                  x1, y1, x2, y2, tab_nc (table), tab_nr (table));
           return NULL;
         }
     }
@@ -556,10 +323,10 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
   tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
 
   j = pool_alloc (table->container, sizeof *j);
-  j->d[TABLE_HORZ][0] = x1 + table->col_ofs;
-  j->d[TABLE_VERT][0] = y1 + table->row_ofs;
-  j->d[TABLE_HORZ][1] = ++x2 + table->col_ofs;
-  j->d[TABLE_VERT][1] = ++y2 + table->row_ofs;
+  j->d[TABLE_HORZ][0] = x1;
+  j->d[TABLE_VERT][0] = y1;
+  j->d[TABLE_HORZ][1] = ++x2;
+  j->d[TABLE_VERT][1] = ++y2;
   j->n_footnotes = 0;
   j->footnotes = NULL;
   j->style = NULL;
@@ -599,24 +366,7 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
   if (x1 == x2 && y1 == y2)
     do_tab_text (table, x1, y1, opt, s);
   else
-    add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
-}
-
-/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them
-   with options OPT to have text value FORMAT, which is formatted
-   as if passed to printf. */
-void
-tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2,
-                       int y2, unsigned opt, const char *format, ...)
-{
-  va_list args;
-  char *s;
-
-  va_start (args, format);
-  s = pool_vasprintf (table->container, format, args);
-  va_end (args);
-
-  add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
+    add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
 }
 
 struct footnote *
@@ -646,7 +396,7 @@ tab_add_footnote (struct tab_table *table, int x, int y,
       char *text = table->cc[index];
 
       j = add_joined_cell (table, x, y, x, y, table->ct[index]);
-      j->u.text = text ? text : xstrdup ("");
+      j->text = text ? text : xstrdup ("");
     }
 
   j->footnotes = pool_realloc (table->container, j->footnotes,
@@ -670,7 +420,7 @@ tab_add_style (struct tab_table *table, int x, int y,
       char *text = table->cc[index];
 
       j = add_joined_cell (table, x, y, x, y, table->ct[index]);
-      j->u.text = text ? text : xstrdup ("");
+      j->text = text ? text : xstrdup ("");
     }
 
   j->style = style;
@@ -682,85 +432,8 @@ tab_cell_is_empty (const struct tab_table *table, int c, int r)
   return table->cc[c + r * table->cf] == NULL;
 }
 \f
-/* Miscellaneous. */
-
-/* Set the title of table T to TITLE, which is formatted as if
-   passed to printf(). */
-void
-tab_title (struct tab_table *t, const char *title, ...)
-{
-  va_list args;
-
-  free (t->title);
-  va_start (args, title);
-  t->title = xvasprintf (title, args);
-  va_end (args);
-}
-
-/* Set the caption of table T to CAPTION, which is formatted as if
-   passed to printf(). */
-void
-tab_caption (struct tab_table *t, const char *caption, ...)
-{
-  va_list args;
-
-  free (t->caption);
-  va_start (args, caption);
-  t->caption = xvasprintf (caption, args);
-  va_end (args);
-}
-
-/* Easy, type-safe way to submit a tab table to som. */
-void
-tab_submit (struct tab_table *t)
-{
-  table_item_submit (table_item_create (&t->table, t->title, t->caption));
-}
-\f
 /* Editing. */
 
-/* Set table row and column offsets for all functions that affect
-   cells or rules. */
-void
-tab_offset (struct tab_table *t, int col, int row)
-{
-  int diff = 0;
-
-  if (debugging)
-    {
-      if (row < -1 || row > tab_nr (t))
-        {
-          printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
-          NOT_REACHED ();
-        }
-      if (col < -1 || col > tab_nc (t))
-        {
-          printf ("tab_offset(): col=%d in %d-column table\n", col,
-                  tab_nc (t));
-          NOT_REACHED ();
-        }
-    }
-
-  if (row != -1)
-    diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
-  if (col != -1)
-    diff += (col - t->col_ofs), t->col_ofs = col;
-
-  t->cc += diff;
-  t->ct += diff;
-}
-
-/* Increment the row offset by one. If the table is too small,
-   increase its size. */
-void
-tab_next_row (struct tab_table *t)
-{
-  t->cc += t->cf;
-  t->ct += t->cf;
-  if (++t->row_ofs >= tab_nr (t))
-    tab_realloc (t, -1, tab_nr (t) * 4 / 3);
-}
-\f
 /* Writes STRING to the output.  OPTIONS may be any valid combination of TAB_*
    bits.
 
@@ -769,8 +442,7 @@ tab_next_row (struct tab_table *t)
 void
 tab_output_text (int options, const char *string)
 {
-  enum text_item_type type = (options & TAB_EMPH ? TEXT_ITEM_TITLE
-                              : options & TAB_FIX ? TEXT_ITEM_LOG
+  enum text_item_type type = (options & TAB_FIX ? TEXT_ITEM_LOG
                               : TEXT_ITEM_PARAGRAPH);
   text_item_submit (text_item_create (type, string));
 }
@@ -798,10 +470,6 @@ static void
 tab_destroy (struct table *table)
 {
   struct tab_table *t = tab_cast (table);
-  free (t->title);
-  t->title = NULL;
-  free (t->caption);
-  t->caption = NULL;
   pool_destroy (t->container);
 }
 
@@ -854,7 +522,7 @@ tab_get_cell (const struct table *table, int x, int y,
   if (opt & TAB_JOIN)
     {
       const struct tab_joined_cell *jc = cc;
-      cell->text = jc->u.text;
+      cell->text = jc->text;
 
       cell->footnotes = jc->footnotes;
       cell->n_footnotes = jc->n_footnotes;
index abd786119c13c5ab39ef8f97cf5cdd3a2056db33..f81a010c65c718a6988d1438f2a7b2c99c3f65ef 100644 (file)
 
    This is a type of table (see output/table.h) whose content is composed
    manually by the code that generates it, by filling in cells one by one.
-
-   Some of the features of this type of table are obsolete but have not yet
-   been removed, because some code still uses them.  These features are:
-
-       - The title and caption.  These are properties of the table_item (see
-         output/table-item.h) in which a table is embedded, not properties of
-         the table itself.
-
-       - Row and columns offsets (via tab_offset(), tab_next_row()).  This
-         feature simply isn't used enough to justify keeping it.
-
-       - Table resizing.  The code that does use this feature is just as well
-         served by creating multiple tables and pasting them together with
-         table_paste().  Eliminating this feature would also slightly simplify
-         the table code here.
 */
 
 #include "libpspp/compiler.h"
 #include "output/table.h"
 #include "data/format.h"
 
-enum result_class
-  {
-    RC_INTEGER,
-    RC_WEIGHT,
-    RC_PVALUE,
-    RC_OTHER,
-    n_RC
-  };
-
 #define TAB_STYLE_MASK (7u << (TAB_FIRST_AVAILABLE + 1))
 #define TAB_STYLE_SHIFT (TAB_FIRST_AVAILABLE + 1)
 
@@ -82,7 +58,6 @@ struct tab_table
     struct pool *container;
 
     /* Table title and caption, or null. */
-    char *title, *caption;
     int cf;                    /* Column factor for indexing purposes. */
 
     /* Table contents.
@@ -99,11 +74,6 @@ struct tab_table
     unsigned char *rh;         /* Horiz rules; unsigned char[nr+1][nc]. */
     unsigned char *rv;         /* Vert rules; unsigned char[nr][nc+1]. */
     struct cell_color *rule_colors[32];
-
-    /* X and Y offsets. */
-    int col_ofs, row_ofs;
-
-    struct fmt_spec fmtmap [n_RC];
   };
 
 struct tab_table *tab_cast (const struct table *);
@@ -126,14 +96,7 @@ static inline int tab_b (const struct tab_table *table)
 
 /* Tables. */
 struct tab_table *tab_create (int nc, int nr);
-void tab_resize (struct tab_table *, int nc, int nr);
-void tab_realloc (struct tab_table *, int nc, int nr);
 void tab_headers (struct tab_table *, int l, int r, int t, int b);
-void tab_title (struct tab_table *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-void tab_caption (struct tab_table *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-void tab_submit (struct tab_table *);
 
 /* Rules. */
 void tab_hline (struct tab_table *, int style, int x1, int x2, int y);
@@ -141,23 +104,7 @@ void tab_vline (struct tab_table *, int style, int x, int y1, int y2);
 void tab_box (struct tab_table *, int f_h, int f_v, int i_h, int i_v,
              int x1, int y1, int x2, int y2);
 
-/* Obsolete cell options. */
-#define TAT_TITLE TAB_EMPH      /* Title attributes. */
-
-void tab_set_format (struct tab_table *, enum result_class, const struct fmt_spec *);
-
-
 /* Cells. */
-struct fmt_spec;
-struct dictionary;
-union value;
-void tab_value (struct tab_table *, int c, int r, unsigned short opt,
-               const union value *, const struct variable *,
-               const struct fmt_spec *);
-
-void tab_double (struct tab_table *, int c, int r, unsigned short opt,
-                double v, const struct fmt_spec *, enum result_class );
-
 void tab_text (struct tab_table *, int c, int r, unsigned opt, const char *);
 void tab_text_format (struct tab_table *, int c, int r, unsigned opt,
                       const char *, ...)
@@ -165,9 +112,6 @@ void tab_text_format (struct tab_table *, int c, int r, unsigned opt,
 
 void tab_joint_text (struct tab_table *, int x1, int y1, int x2, int y2,
                     unsigned opt, const char *);
-void tab_joint_text_format (struct tab_table *, int x1, int y1, int x2, int y2,
-                            unsigned opt, const char *, ...)
-     PRINTF_FORMAT (7, 8);
 
 struct footnote *tab_create_footnote (struct tab_table *, size_t idx,
                                       const char *content, const char *marker,
@@ -180,14 +124,6 @@ void tab_add_style (struct tab_table *, int x, int y,
 
 bool tab_cell_is_empty (const struct tab_table *, int c, int r);
 
-/* Editing. */
-void tab_offset (struct tab_table *, int col, int row);
-void tab_next_row (struct tab_table *);
-
-/* Current row/column offset. */
-#define tab_row(TABLE) ((TABLE)->row_ofs)
-#define tab_col(TABLE) ((TABLE)->col_ofs)
-
 /* Simple output. */
 void tab_output_text (int options, const char *string);
 void tab_output_text_format (int options, const char *, ...)
diff --git a/src/output/table-casereader.c b/src/output/table-casereader.c
deleted file mode 100644 (file)
index e1b75ac..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2011, 2013, 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 <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "output/table-provider.h"
-
-#include "data/casereader.h"
-#include "data/data-out.h"
-#include "data/format.h"
-#include "libpspp/i18n.h"
-
-#include "gl/xalloc.h"
-
-struct table_casereader
-  {
-    struct table table;
-    struct casereader *reader;
-    char *heading;
-    struct fmt_spec format;
-  };
-
-static const struct table_class table_casereader_class;
-
-static struct table_casereader *
-table_casereader_cast (const struct table *table)
-{
-  assert (table->klass == &table_casereader_class);
-  return UP_CAST (table, struct table_casereader, table);
-}
-
-/* Returns a new table that has one column and the same number of rows as
-   READER.  Each row in the table is derived from column COLUMN in the same row
-   of READER by formatting with data_out() using the specified FORMAT (which
-   must be a valid format for the column's width).
-
-   If HEADING is nonnull, adds an additional row above the first row of data
-   that contains HEADING, and sets that row as a header row.
-
-   The returned table has no rules, except that if HEADING is nonnull, a single
-   line (TAL_1) separates HEADING from the first row if data. */
-struct table *
-table_from_casereader (const struct casereader *reader, size_t column,
-                       const char *heading, const struct fmt_spec *format)
-{
-  struct table_casereader *tc;
-  struct table *t;
-
-  assert (fmt_check_width_compat (format,
-                                  caseproto_get_width (
-                                    casereader_get_proto (reader), column)));
-
-  tc = xmalloc (sizeof *tc);
-  t = &tc->table;
-  table_init (t, &table_casereader_class);
-  table_set_nc (t, 1);
-  table_set_nr (t, casereader_count_cases (reader));
-  tc->reader = casereader_project_1 (casereader_clone (reader), column);
-  tc->heading = NULL;
-  tc->format = *format;
-
-  if (heading != NULL)
-    {
-      tc->heading = xstrdup (heading);
-      table_set_nr (t, table_nr (t) + 1);
-      table_set_ht (t, 1);
-    }
-
-  return t;
-}
-
-static void
-table_casereader_destroy (struct table *t)
-{
-  struct table_casereader *tc = table_casereader_cast (t);
-  casereader_destroy (tc->reader);
-  free (tc->heading);
-  free (t);
-}
-
-static void
-free_string (void *s_)
-{
-  char *s = s_;
-  free (s);
-}
-
-static void
-table_casereader_get_cell (const struct table *t, int x, int y,
-                           struct table_cell *cell)
-{
-  struct table_casereader *tc = table_casereader_cast (t);
-  struct ccase *c;
-  char *s;
-
-  static const struct area_style style = {
-    AREA_STYLE_INITIALIZER__,
-    .cell_style.halign = TABLE_HALIGN_RIGHT
-  };
-
-  cell->d[TABLE_HORZ][0] = x;
-  cell->d[TABLE_HORZ][1] = x + 1;
-  cell->d[TABLE_VERT][0] = y;
-  cell->d[TABLE_VERT][1] = y + 1;
-  cell->style = &style;
-  cell->options = 0;
-  cell->n_footnotes = 0;
-  if (tc->heading != NULL)
-    {
-      if (y == 0)
-        {
-          s = xstrdup (tc->heading);
-          cell->text = s;
-          cell->destructor = free_string;
-          cell->destructor_aux = s;
-          return;
-        }
-      y--;
-    }
-
-  c = casereader_peek (tc->reader, y);
-  if (c == NULL)
-    s = xstrdup ("I/O Error");
-  else
-    {
-      s = data_out (case_data_idx (c, 0), UTF8, &tc->format);
-      case_unref (c);
-    }
-  cell->text = s;
-  cell->destructor = free_string;
-  cell->destructor_aux = s;
-}
-
-static int
-table_casereader_get_rule (const struct table *t, enum table_axis axis,
-                           int x UNUSED, int y,
-                           struct cell_color *color UNUSED)
-{
-  struct table_casereader *tc = table_casereader_cast (t);
-  if (axis == TABLE_VERT)
-    return tc->heading != NULL && y == 1 ? TAL_1 : TAL_0;
-  else
-    return TAL_0;
-}
-
-static const struct table_class table_casereader_class =
-  {
-    table_casereader_destroy,
-    table_casereader_get_cell,
-    table_casereader_get_rule,
-    NULL,                       /* paste */
-    NULL,                       /* select (XXX) */
-  };
index d94316eed2bc62ed430d6085431652ec7554e347..aafc2f6db0fbfa30a784ed8ef6812eed38cdee30 100644 (file)
@@ -23,6 +23,7 @@
 #include <inttypes.h>
 #include <stdlib.h>
 
+#include "data/format.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
index b2c194367f6979df381da49f602958d4b19b5fec..d162a28b4aeb399f7230d8fad121b4207c19499a 100644 (file)
@@ -171,7 +171,6 @@ void area_style_free (struct area_style *);
 enum
   {
     TAB_NONE = 0,
-    TAB_EMPH       = 1 << 0,    /* Emphasize cell contents. */
     TAB_FIX        = 1 << 1,    /* Use fixed font. */
     TAB_MARKUP     = 1 << 2,    /* Text contains Pango markup. */
     TAB_NUMERIC    = 1 << 3,    /* Cell contents are numeric. */
@@ -271,12 +270,6 @@ void table_set_hb (struct table *, int hb);
 
 /* Simple kinds of tables. */
 struct table *table_from_string (enum table_halign, const char *);
-struct table *table_from_variables (unsigned int options,
-                                    struct variable **, size_t);
-struct table *table_from_casereader (const struct casereader *,
-                                     size_t column,
-                                     const char *heading,
-                                     const struct fmt_spec *);
 
 /* Combining tables. */
 struct table *table_paste (struct table *, struct table *,
index 9ebc51d19640473648c1750d621939b2a4927f63..f61e8e546e64719a31c0cbac6fb3f4513d61d2cf 100644 (file)
@@ -32,7 +32,6 @@
 #include "output/driver-provider.h"
 #include "output/message-item.h"
 #include "output/output-item.h"
-#include "output/tab.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
 #include "ui/gui/help-menu.h"
index 161bb1b824048128c3a375be52c5ade68d867149..116e32c217406bbbe677ca5106300805ddf7d835 100644 (file)
@@ -250,7 +250,6 @@ tests_output_render_test_LDADD = \
        src/libpspp-core.la \
        $(CAIRO_LIBS)
 
-
 check_PROGRAMS += tests/ui/syntax-gen-test
 tests_ui_syntax_gen_test_SOURCES = tests/ui/syntax-gen-test.c
 tests_ui_syntax_gen_test_LDADD = \
index 44de36a7b00c161e803a2521d35cccfb2cdfc70c..e78dd756a0d34596eaf8dcb62782bfb93bba2ef3 100644 (file)
@@ -105,7 +105,8 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv pc+-file.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-File label: PSPP synthetic test file
+Table: File Label
+Label,PSPP synthetic test file
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -122,7 +123,7 @@ STR6,10,Another string variable's label,Nominal,Input,11,Left,A11,A11,
 
 Table: Data List
 NUM1,NUM2,NUM3,NUM4,STR1,STR2,STR3,STR4,STR5,STR6
-0,1,2,.,abcdefgh,ijkl,mnopq,r,stuvwxyzAB ,CDEFGHIJKLM
+0,1,2,.,abcdefgh,ijkl,mnopq,r,stuvwxyzAB,CDEFGHIJKLM
 ])
 AT_CLEANUP
 
@@ -217,7 +218,8 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv pc+-file.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-File label: PSPP synthetic test file
+Table: File Label
+Label,PSPP synthetic test file
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -236,7 +238,7 @@ STR7,12,,Nominal,Input,7,Left,A7,A7,
 STR8,13,,Nominal,Input,8,Left,A8,A8,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 NUM1,1,one
 NUM2,2,two
 ,3,three
@@ -330,7 +332,8 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv pc+-file.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-File label: PSPP synthetic test file
+Table: File Label
+Label,PSPP synthetic test file
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -342,7 +345,7 @@ STR15,5,,Nominal,Input,15,Left,A15,A15,
 
 Table: Data List
 NUM1,NUM2,STR4,STR8,STR15
--5,150,abcd,efghj   ,efghijklABCDEFG
+-5,150,abcd,efghj,efghijklABCDEFG
 1000,.,PQRS,TUVWXYZa,bcdefghijklmnop
 ])
 AT_CLEANUP
@@ -395,17 +398,18 @@ AT_DATA([pc+-file.sps], [dnl
 SYSFILE INFO FILE='pc+-file.sav' ENCODING='us-ascii'.
 ])
 AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [dnl
-File:,pc+-file.sav
-Label:,PSPP synthetic test file
-Created:,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product
-Integer Format:,Little Endian
-Real Format:,IEEE 754 LE.
-Variables:,4
-Cases:,1
-Type:,SPSS/PC+ System File
-Weight:,NUM3
-Compression:,None
-Encoding:,us-ascii
+Table: File Information
+File,pc+-file.sav
+Label,PSPP synthetic test file
+Created,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product
+Integer Format,Little Endian
+Real Format,IEEE 754 LE.
+Variables,4
+Cases,1
+Type,SPSS/PC+ System File
+Weight,NUM3
+Compression,None
+Encoding,us-ascii
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -474,7 +478,8 @@ AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [stdout], [])
 AT_CHECK([sed 's/default encoding.*For/default encoding.  For/' stdout], [0], [dnl
 "warning: `pc+-file.sav': Using default encoding.  For best results, specify an encoding explicitly.  Use SYSFILE INFO with ENCODING=""DETECT"" to analyze the possible encodings."
 
-File label: PSPP synthetic test file
+Table: File Label
+Label,PSPP synthetic test file
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -487,17 +492,18 @@ Table: Data List
 NUM1,NUM2,NUM3,NUM4
 2,3,4,5
 
-File:,pc+-file.sav
-Label:,PSPP synthetic test file
-Created:,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product
-Integer Format:,Little Endian
-Real Format:,IEEE 754 LE.
-Variables:,4
-Cases:,1
-Type:,SPSS/PC+ System File
-Weight:,Not weighted.
-Compression:,None
-Encoding:,us-ascii
+Table: File Information
+File,pc+-file.sav
+Label,PSPP synthetic test file
+Created,11/28/14 15:11:00 by PCSPSS PSPP synthetic test product
+Integer Format,Little Endian
+Real Format,IEEE 754 LE.
+Variables,4
+Cases,1
+Type,SPSS/PC+ System File
+Weight,Not weighted
+Compression,None
+Encoding,us-ascii
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -1240,7 +1246,8 @@ DISPLAY DICTIONARY.
 LIST.
 ])
 AT_CHECK([pspp -O format=csv pc+-file.sps], [0], [dnl
-File label: PSPP synthetic test file
+Table: File Label
+Label,PSPP synthetic test file
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -1254,7 +1261,7 @@ warning: `pc+-file.sav' near offset 0x308: Possible compressed data corruption:
 
 Table: Data List
 NUM1,NUM2,STR4,STR8,STR15
--5,150,abcd,efghj   ,efghijklABCDEFG
+-5,150,abcd,efghj,efghijklABCDEFG
 1000,.,PQRS,TUVWXYZa,bcdefghijklmnop
 ])
 AT_CLEANUP
index 3139bbf490e305b9ee5151c60a96d34b2aa34228..1b5fc2117422ee7c6f52c5b9b08ce426516e320b 100644 (file)
@@ -113,7 +113,7 @@ VAR4,4,,Scale,Input,8,Right,F1.0,F1.0,
 VAR5,5,,Scale,Input,8,Right,F1.0,F1.0,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 VAR1,1,one
 VAR2,2,two
 VAR3,3,three
@@ -132,13 +132,14 @@ AT_CHECK([pspp -O format=csv sys-file-info.sps | sed '/Encoding/d
 /Created/d
 /Product/d
 '], [0], [dnl
-File:,data.por
-Label:,No label.
-Variables:,5
-Cases:,Unknown
-Type:,SPSS Portable File
-Weight:,Not weighted.
-Compression:,None
+Table: File Information
+File,data.por
+Label,
+Variables,5
+Cases,Unknown
+Type,SPSS Portable File
+Weight,Not weighted
+Compression,None
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -149,7 +150,7 @@ VAR4,4,,Scale,Input,8,Right,F1.0,F1.0,
 VAR5,5,,Scale,Input,8,Right,F1.0,F1.0,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 VAR1,1,one
 VAR2,2,two
 VAR3,3,three
index afe3bff3b5d87195ebad697c8d048706bcb0445c..a22ecfa56b28b7bf4c67a76bed56f4e75ad2458a 100644 (file)
@@ -147,7 +147,8 @@ LIST.
 ])
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
   AT_CHECK([cat pspp.csv], [0], [dnl
-File label: PSPP synthetic test file: ôõöø
+Table: File Label
+Label,PSPP synthetic test file: ôõöø
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -427,7 +428,7 @@ str16,16,,Nominal,Input,16,Left,A16,A16,
 str17,17,,Nominal,Input,17,Left,A17,A17,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 num1,1,один (in Russian)
 num2,1,one
 ,2,two
@@ -515,17 +516,12 @@ LIST.
 ])
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
   AT_CHECK([cat pspp.csv], [0], [dnl
-Documents in the active dataset:
-
-First line of documents
-
+Table: Documents
+"First line of documents
 Second line of documents
-
 abbé appliqué attaché blasé café canapé cliché consommé
 
-
-
-Last line of documents
+Last line of documents"
 
 Table: Data List
 num1
@@ -651,47 +647,23 @@ MRSETS /DISPLAY NAME=ALL.
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
   AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Multiple Response Sets
-Name,Variables,Details
-$a,"あ
+Name,Label,Encoding,Counted Value,Member Variables
+$a,my mcgroup,Categories,,"あ
 b
-c
-","Multiple category set
-Label: my mcgroup
-"
-$b,"g
+c"
+$b,,Dichotomies,55,"g
 e
 f
-d
-","Multiple dichotomy set
-Counted value: 55
-Category label source: Variable labels
-"
-$c,"h
+d"
+$c,mdgroup #2,Dichotomies,はい,"h
 i
-j
-","Multiple dichotomy set
-Label: mdgroup #2
-Label source: Provided by user
-Counted value: `はい'
-Category label source: Variable labels
-"
-$d,"k
+j"
+$d,third mdgroup,Dichotomies,34,"k
 l
-m
-","Multiple dichotomy set
-Label: third mdgroup
-Label source: Provided by user
-Counted value: 34
-Category label source: Value labels of counted value
-"
-$e,"n
+m"
+$e,,Dichotomies,choice,"n
 o
-p
-","Multiple dichotomy set
-Label source: First variable label among variables
-Counted value: `choice'
-Category label source: Value labels of counted value
-"
+p"
 ])
 done
 AT_CLEANUP
@@ -733,12 +705,13 @@ for variant in be le; do
 SYSFILE INFO FILE='sys-file.sav'.
 ])
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
-  AT_CHECK([sed 7q pspp.csv], [0], [dnl
-File:,sys-file.sav
-Label:,"PSPP synthetic
+  AT_CHECK([sed 8q pspp.csv], [0], [dnl
+Table: File Information
+File,sys-file.sav
+Label,"PSPP synthetic
 test file"
-Created:,01 Jan 11 20:53:52 by $(@%:@) SPSS DATA FILE PSPP synthetic test file
-Product:,"Extra product info
+Created,01 Jan 11 20:53:52 by $(@%:@) SPSS DATA FILE PSPP synthetic test file
+Product,"Extra product info
 another line
 blah"
 ])
@@ -1112,7 +1085,7 @@ DISPLAY @ATTRIBUTES.
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
   AT_CHECK([cat pspp.csv], [0],
 [[Table: Variable and Dataset Attributes
-Variable,Name,Value
+Variable and Name,,Value
 (dataset),Attr1[1],Value1
 ,Attr1[2],'déclaration'
 ,SécondAttr[1],123
@@ -1263,8 +1236,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15,
 
 Table: Data List
 num1,num2,str4,str8,str15
--99,0,,abcdefgh,0123   @&t@
-.,151,jklm,nopqrstu,vwxyzABC       @&t@
+-99,0,,abcdefgh,0123
+.,151,jklm,nopqrstu,vwxyzABC
 1,2,DEFG,HIJKLMNO,PQRSTUV
 ])
 done
@@ -1326,8 +1299,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15,
 
 Table: Data List
 num1,num2,str4,str8,str15
-1,100,,abcdefgh,0123   @&t@
-.,251,jklm,nopqrstu,vwxyzABC       @&t@
+1,100,,abcdefgh,0123
+.,251,jklm,nopqrstu,vwxyzABC
 101,102,DEFG,HIJKLMNO,PQRSTUV
 ])
 done
@@ -1393,8 +1366,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15,
 
 Table: Data List
 num1,num2,str4,str8,str15
--49,50,,abcdefgh,0123   @&t@
-.,201,jklm,nopqrstu,vwxyzABC       @&t@
+-49,50,,abcdefgh,0123
+.,201,jklm,nopqrstu,vwxyzABC
 51,52,DEFG,HIJKLMNO,PQRSTUV
 ])
 done
@@ -1491,8 +1464,8 @@ str15,5,,Nominal,Input,15,Left,A15,A15,
 
 Table: Data List
 num1,num2,str4,str8,str15
--99,0,,abcdefgh,0123   @&t@
-.,151,jklm,nopqrstu,vwxyzABC       @&t@
+-99,0,,abcdefgh,0123
+.,151,jklm,nopqrstu,vwxyzABC
 1,2,DEFG,HIJKLMNO,PQRSTUV
 ])
 done
@@ -2414,31 +2387,16 @@ warning: `sys-file.sav': Invalid multiple response set name `b'.
 warning: `sys-file.sav': Invalid multiple response set name `e'.
 
 Table: Multiple Response Sets
-Name,Variables,Details
-$a,"あ
+Name,Label,Encoding,Counted Value,Member Variables
+$a,my mcgroup,Categories,,"あ
 b
-c
-","Multiple category set
-Label: my mcgroup
-"
-$c,"h
+c"
+$c,mdgroup #2,Dichotomies,はい,"h
 i
-j
-","Multiple dichotomy set
-Label: mdgroup #2
-Label source: Provided by user
-Counted value: `はい'
-Category label source: Variable labels
-"
-$d,"k
+j"
+$d,third mdgroup,Dichotomies,34,"k
 l
-m
-","Multiple dichotomy set
-Label: third mdgroup
-Label source: Provided by user
-Counted value: 34
-Category label source: Value labels of counted value
-"
+m"
 ])
 done
 AT_CLEANUP
@@ -3569,7 +3527,7 @@ LIST.
 
 Table: Data List
 str14
-one data item @&t@
+one data item
 ])
 done
 AT_CLEANUP
@@ -3617,7 +3575,7 @@ LIST.
 
 Table: Data List
 num1,num2,str4,str8,str15
--99,0,,abcdefgh,0123   @&t@
+-99,0,,abcdefgh,0123
 ])
 done
 AT_CLEANUP
index b6c17b35fa9369fa75265b32bfb0cb4057ff4c36..e260f0eada3aa912ae8ff92497ba0b885af3c1a0 100644 (file)
@@ -96,12 +96,12 @@ s2,2,,Nominal,Input,9,Left,A9,A9,"""12      ""; ""123     """
 s3,3,,Nominal,Input,9,Left,A9,A9,"""1234    ""; ""12345   ""; ""12345678"""
 
 Table: Value Labels
-Variable,Value,Label
-s1,abc      ,First value label
-,abcdefgh ,Second value label
+Variable Value,,Label
+s1,abc,First value label
+,abcdefgh,Second value label
 ,abcdefghi,Third value label
-s2,0        ,Fourth value label
-,01234567 ,Fifth value label
+s2,0,Fourth value label
+,01234567,Fifth value label
 ,012345678,Sixth value label
 ])
     AT_CHECK_UNQUOTED([dd if=foo.sav bs=1 count=4; echo], [0], [$magic
@@ -276,13 +276,13 @@ count,4,number of countries
 
 Table: Data List
 cont,size,pop,count
-Asia                            ,44579000,3.7E+009,44.00
-Africa                          ,30065000,7.8E+008,53.00
-North America                   ,24256000,4.8E+008,23.00
-South America                   ,17819000,3.4E+008,12.00
-Antarctica                      ,13209000,.00,.00
-Europe                          ,9938000,7.3E+008,46.00
-Australia/Oceania               ,7687000,31000000,14.00
+Asia,44579000,3.7E+009,44.00
+Africa,30065000,7.8E+008,53.00
+North America,24256000,4.8E+008,23.00
+South America,17819000,3.4E+008,12.00
+Antarctica,13209000,.00,.00
+Europe,9938000,7.3E+008,46.00
+Australia/Oceania,7687000,31000000,14.00
 ])
 AT_CLEANUP
 
@@ -459,17 +459,14 @@ DISPLAY ATTRIBUTES.
 ])
 AT_CHECK([pspp -o pspp.csv get.sps])
 AT_CHECK([[sed 's/(Entered [^)]*)/(Entered <date>)/' pspp.csv]], [0], [dnl
-File label: clientèle confrère cortège crèche
-
-Documents in the active dataset:
-
-DOCUMENT coördinate smörgåsbord
+Table: File Label
+Label,clientèle confrère cortège crèche
 
+Table: Documents
+"DOCUMENT coördinate smörgåsbord
 épée séance soufflé soirée
-
 jalapeño vicuña.
-
-(Entered <date>)
+   (Entered <date>)"
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -478,12 +475,12 @@ roué,2,Provençal soupçon,Nominal,Input,9,Left,A9,A9,
 croûton,3,,Nominal,Input,32,Left,A1000,A1000,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 àéîöçxyzabc,1.00,éclair élan
-roué,abcdefghi,sauté précis
+Provençal soupçon,abcdefghi,sauté précis
 
 Table: Variable and Dataset Attributes
-Variable,Name,Value
+Variable and Name,,Value
 (dataset),Furtwängler,kindergärtner
 àéîöçxyzabc,Atatürk,Düsseldorf Gewürztraminer
 ])
index 5bfdb497b1f60b4fc4fa708ccfa28b2e1698f066..a1f599cba961b61afce6c29b7ffb4e3768932c23 100644 (file)
@@ -349,8 +349,8 @@ data-list.sps:4: warning: Missing delimiter following quoted string.
 
 Table: Data List
 s
-y         @&t@
-z         @&t@
+y
+z
 ])
 AT_CLEANUP
 
index 64139f9360732dc50059b379621725242bde0212..32ff5e140ad8cd1616809ee09f8a0477fdb79f3c 100644 (file)
@@ -66,13 +66,11 @@ y
 7
 8
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 clone
 initial (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 clone (active dataset)
 initial
 
@@ -84,8 +82,7 @@ x
 5
 6
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 clone
 initial (active dataset)
 
@@ -101,13 +98,11 @@ y,z
 7,7.00
 8,8.00
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 initial
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 ])
 AT_CLEANUP
@@ -126,8 +121,7 @@ DATASET DISPLAY.
 LIST.
 ])
 AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 second
 
@@ -135,8 +129,7 @@ Table: Data List
 x
 1
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 second (active dataset)
 
 dataset.pspp:10: error: LIST: LIST is allowed only after the active dataset has been defined.
@@ -155,14 +148,12 @@ DATASET NAME c.
 DATASET DISPLAY.
 ])
 AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
-Table: Open datasets.
-Dataset
+Table: Datasets
 a (active dataset)
 b
 c
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 c (active dataset)
 ])
 AT_CLEANUP
@@ -176,13 +167,11 @@ DATASET ACTIVATE x.
 DATASET DISPLAY.
 ])
 AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 x
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 x (active dataset)
 ])
 AT_CLEANUP
@@ -210,8 +199,7 @@ DATASET ACTIVATE one.
 LIST.
 ])
 AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl
-Table: Open datasets.
-Dataset
+Table: Datasets
 another
 one (active dataset)
 
@@ -269,50 +257,40 @@ DATASET CLOSE ALL.
 DATASET DISPLAY.
 ])
 AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 this (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 this (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 that
 theother
 yetanother
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 that
 theother
 this (active dataset)
 yetanother
 
-Table: Open datasets.
-Dataset
+Table: Datasets
 unnamed dataset (active dataset)
 ])
 AT_CLEANUP
index b6bfc8f2cdb2f69fed59fcada04967bdb24f02b6..923c9bd3c7637ec512e81b9c038cbfebd7607e9f 100644 (file)
@@ -189,9 +189,9 @@ timetz_zone,22,,Scale,Input,8,Right,F8.2,F8.2,
 
 Table: Data List
 bool,bytea,char,int8,int2,int4,numeric,text,oid,float4,float8,money,pbchar,varchar,date,time,timestamp,timestamptz,interval,interval_months,timetz,timetz_zone
-.00,30,a       ,.00,.00,.00,-2.560980E+002,this-long-text  ,.00,.00,.00,$.01,a       ,A       ,01-JAN-2000,0:00:00,08-JAN-1999 04:05:06,08-JAN-1999 12:05:06,0 00:01:00,0,10:09:00,4.00
-.  ,20,,.  ,.  ,.  ,.          ,,.  ,.  ,.  ,.  ,,,.,.,.,.,.,.,.,.  @&t@
-1.00,31,b       ,1.00,1.00,1.00,6.553500E+004,that-long-text  ,.00,1.00,1.00,$1.23,b       ,B       ,10-JAN-1963,1:05:02,10-JAN-1963 23:58:00,10-JAN-1963 22:58:00,12 01:03:04,25,1:05:02,-7.00
+.00,30,a,.00,.00,.00,-2.560980E+002,this-long-text,.00,.00,.00,$.01,a,A,01-JAN-2000,0:00:00,08-JAN-1999 04:05:06,08-JAN-1999 12:05:06,0 00:01:00,0,10:09:00,4.00
+.  ,,,.  ,.  ,.  ,.          ,,.  ,.  ,.  ,.  ,,,.,.,.,.,.,.,.,.  @&t@
+1.00,31,b,1.00,1.00,1.00,6.553500E+004,that-long-text,.00,1.00,1.00,$1.23,b,B,10-JAN-1963,1:05:02,10-JAN-1963 23:58:00,10-JAN-1963 22:58:00,12 01:03:04,25,1:05:02,-7.00
 ])
 
 dnl Test query with empty result set.
index 86ca4554628fb419a69ede90fb0ac4d06d6cc528..2bac423367fe30c8cfc3f2f38d02ba15345e4975 100644 (file)
@@ -44,11 +44,11 @@ VAR003,3,F8.2,F8.2,
 
 Table: Data List
 VAR001,VAR002,VAR003
-.00,fred    ,20.00
-1.00,11      ,21.00
-2.00,twelve  ,22.00
-3.00,13      ,23.00
-4.00,14      ,24.00
+.00,fred,20.00
+1.00,11,21.00
+2.00,twelve,22.00
+3.00,13,23.00
+4.00,14,24.00
 ])
 AT_CLEANUP
 
@@ -69,11 +69,11 @@ VAR001,3,F8.2,F8.2,
 
 Table: Data List
 V1,V2,VAR001
-.00,fred    ,20.00
-1.00,11      ,21.00
-2.00,twelve  ,22.00
-3.00,13      ,23.00
-4.00,14      ,24.00
+.00,fred,20.00
+1.00,11,21.00
+2.00,twelve,22.00
+3.00,13,23.00
+4.00,14,24.00
 ])
 AT_CLEANUP
 
@@ -95,10 +95,10 @@ warning: Cannot convert the value in the spreadsheet cell C4 to format (F8.2): F
 
 Table: Data List
 name,id,height
-fred    ,.00,23.40
-bert    ,1.00,.56
-charlie ,2.00,.  @&t@
-dick    ,3.00,-34.09
+fred,.00,23.40
+bert,1.00,.56
+charlie,2.00,.  @&t@
+dick,3.00,-34.09
 ])
 AT_CLEANUP
 
@@ -309,9 +309,9 @@ LIST.
 AT_CHECK([pspp -O format=csv gnum.sps], [0], [dnl
 Table: Data List
 VAR001,VAR002,VAR003
-3       ,4.00,5.00
-6       ,7.00,8.00
-9       ,10.00,11.00
+3,4.00,5.00
+6,7.00,8.00
+9,10.00,11.00
 ])
 
 
index 25d7d6b93dce48ad336fc9a22d1878568ef0a3e1..f1cd7615ec781bbce8d35fe83682043f0e8d269b 100644 (file)
@@ -213,10 +213,10 @@ AT_CHECK([pspp -o pspp.csv passwd.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Data List
 username,password,uid,gid,gecos,home,shell
-root                ,$1$nyeSP5gD$pDq/                        ,0,0,",,,                                     ",/root                                   ,/bin/bash                               @&t@
-blp                 ,$1$BrP/pFg4$g7OG                        ,1000,1000,"Ben Pfaff,,,                            ",/home/blp                               ,/bin/bash                               @&t@
-john                ,$1$JBuq/Fioq$g4A                        ,1001,1001,"John Darrington,,,                      ",/home/john                              ,/bin/bash                               @&t@
-jhs                 ,$1$D3li4hPL$88X1                        ,1002,1002,"Jason Stover,,,                         ",/home/jhs                               ,/bin/csh                                @&t@
+root,$1$nyeSP5gD$pDq/,0,0,",,,",/root,/bin/bash
+blp,$1$BrP/pFg4$g7OG,1000,1000,"Ben Pfaff,,,",/home/blp,/bin/bash
+john,$1$JBuq/Fioq$g4A,1001,1001,"John Darrington,,,",/home/john,/bin/bash
+jhs,$1$D3li4hPL$88X1,1002,1002,"Jason Stover,,,",/home/jhs,/bin/csh
 ])
 AT_CLEANUP
 
@@ -253,17 +253,17 @@ AT_CHECK([pspp -o pspp.csv cars.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Data List
 model,year,mileage,price,type,age
-Civic   ,2002,29883,15900,Si  ,2
-Civic   ,2003,13415,15900,EX  ,1
-Civic   ,1992,107000,3800,n/a ,12
-Accord  ,2002,26613,17900,EX  ,1
+Civic,2002,29883,15900,Si,2
+Civic,2003,13415,15900,EX,1
+Civic,1992,107000,3800,n/a,12
+Accord,2002,26613,17900,EX,1
 
 Table: Data List
 model,year,mileage,price,type,age
-Civic   ,2002,29883,15900,Si      ,2
-Civic   ,2003,13415,15900,EX      ,1
-Civic   ,1992,107000,3800,n/a     ,12
-Accord  ,2002,26613,17900,EX      ,1
+Civic,2002,29883,15900,Si,2
+Civic,2003,13415,15900,EX,1
+Civic,1992,107000,3800,n/a,12
+Accord,2002,26613,17900,EX,1
 ])
 AT_CLEANUP
 
@@ -294,10 +294,10 @@ AT_CHECK([pspp -o pspp.csv pets.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Data List
 name,age,color,received,price,height,type
-Rover     ,4.5,Brown,12.02.2004,80.00,"1'4"" ",Dog       @&t@
-Charlie   ,. ,Gold ,05.04.2007,12.30,"3""   ",Fish      @&t@
-Molly     ,2.0,Black,12.12.2006,25.00,"5""   ",Cat       @&t@
-Gilly     ,. ,White,10.04.2007,10.00,"3""   ",Guinea Pig
+Rover,4.5,Brown,12.02.2004,80.00,"1'4""",Dog
+Charlie,. ,Gold,05.04.2007,12.30,"3""",Fish
+Molly,2.0,Black,12.12.2006,25.00,"5""",Cat
+Gilly,. ,White,10.04.2007,10.00,"3""",Guinea Pig
 ])
 AT_CLEANUP
 dnl " (fixes Emacs highlighting)
@@ -342,7 +342,7 @@ AT_CHECK([pspp -o pspp.csv get-data.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Data List
 s
      @&t@
 ])
 AT_CLEANUP
 
@@ -388,9 +388,9 @@ list.
 AT_CHECK([pspp -O format=csv x.sps], [0], [dnl
 Table: Data List
 foo,title,last
-1,this   ,1
-2,that   ,2
-3,other  ,3
+1,this,1
+2,that,2
+3,other,3
 ])
 
 AT_CLEANUP
index d495ddc51568a22cf2fe394aab547deed8eab79e..c93437ae9b1b658692efa44af437c1dccaf03748 100644 (file)
@@ -118,8 +118,9 @@ LIST n.
 ])
 AT_CHECK([pspp -o pspp.csv list.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variable,Value,Label
-s,a,
+Table: Split Values
+Variable,Value
+s,a
 
 Table: Data List
 n
@@ -127,15 +128,17 @@ n
 2.00
 3.00
 
-Variable,Value,Label
-s,b,
+Table: Split Values
+Variable,Value
+s,b
 
 Table: Data List
 n
 1.00
 
-Variable,Value,Label
-s,c,
+Table: Split Values
+Variable,Value
+s,c
 
 Table: Data List
 n
@@ -283,3 +286,34 @@ LIST.
 AT_CHECK([pspp -o pspp.csv list.sps], [1], [ignore])
 
 AT_CLEANUP
+
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([LIST tutorial example])
+AT_DATA([list.sps], [dnl
+data list list /forename (A12) height.
+begin data.
+Ahmed 188
+Bertram 167
+Catherine 134.231
+David 109.1
+end data
+
+list /format=numbered.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt list.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+forename,A12
+height,F8.0
+
+Table: Data List
+Case Number,forename,height
+1,Ahmed,188.00
+2,Bertram,167.00
+3,Catherine,134.23
+4,David,109.10
+])
+AT_CLEANUP
index 7d4c0f39fae4745fcb3f45c6ed1ff7aa7d159622..b590061efbd2fcfa39efee4aedd31c0155c4cc34 100644 (file)
@@ -47,17 +47,17 @@ corr .17  .29  -.05  .20  .27  .20  .04  1.00
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04,var05,var06,var07,var08
-mean    ,,24.3000,5.4000,69.7000,20.1000,13.4000,2.7000,27.9000,3.7000
-STDDEV  ,,5.7000,1.5000,23.5000,5.8000,2.8000,4.5000,5.4000,1.5000
-n       ,,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000
-corr    ,var01,1.0000,.1800,-.2200,.3600,.2700,.3300,.5000,.1700
-corr    ,var02,.1800,1.0000,-.1700,.3100,.1600,.1500,.2900,.2900
-corr    ,var03,-.2200,-.1700,1.0000,-.1400,-.1200,-.1700,-.2000,-.0500
-corr    ,var04,.3600,.3100,-.1400,1.0000,.2200,.2400,.3200,.2000
-corr    ,var05,.2700,.1600,-.1200,.2200,1.0000,.2100,.1200,.2700
-corr    ,var06,.3300,.1500,-.1700,.2400,.2100,1.0000,.3800,.2000
-corr    ,var07,.5000,.2900,-.2000,.3200,.1200,.3800,1.0000,.0400
-corr    ,var08,.1700,.2900,-.0500,.2000,.2700,.2000,.0400,1.0000
+mean,,24.3000,5.4000,69.7000,20.1000,13.4000,2.7000,27.9000,3.7000
+STDDEV,,5.7000,1.5000,23.5000,5.8000,2.8000,4.5000,5.4000,1.5000
+n,,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000,92.0000
+corr,var01,1.0000,.1800,-.2200,.3600,.2700,.3300,.5000,.1700
+corr,var02,.1800,1.0000,-.1700,.3100,.1600,.1500,.2900,.2900
+corr,var03,-.2200,-.1700,1.0000,-.1400,-.1200,-.1700,-.2000,-.0500
+corr,var04,.3600,.3100,-.1400,1.0000,.2200,.2400,.3200,.2000
+corr,var05,.2700,.1600,-.1200,.2200,1.0000,.2100,.1200,.2700
+corr,var06,.3300,.1500,-.1700,.2400,.2100,1.0000,.3800,.2000
+corr,var07,.5000,.2900,-.2000,.3200,.1200,.3800,1.0000,.0400
+corr,var08,.1700,.2900,-.0500,.2000,.2700,.2000,.0400,1.0000
 ])
 AT_CLEANUP
 
@@ -86,13 +86,13 @@ list.
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04
-mean    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-N       ,,100.0000,101.0000,102.0000,103.0000
-corr    ,var01,1.0000,9.0000,8.0000,7.0000
-corr    ,var02,9.0000,1.0000,6.0000,5.0000
-corr    ,var03,8.0000,6.0000,1.0000,4.0000
-corr    ,var04,7.0000,5.0000,4.0000,1.0000
+mean,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+N,,100.0000,101.0000,102.0000,103.0000
+corr,var01,1.0000,9.0000,8.0000,7.0000
+corr,var02,9.0000,1.0000,6.0000,5.0000
+corr,var03,8.0000,6.0000,1.0000,4.0000
+corr,var04,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
@@ -122,13 +122,13 @@ list.
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04
-MEAN    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-N       ,,100.0000,101.0000,102.0000,103.0000
-CORR    ,var01,1.0000,9.0000,8.0000,7.0000
-CORR    ,var02,9.0000,1.0000,6.0000,5.0000
-CORR    ,var03,8.0000,6.0000,1.0000,4.0000
-CORR    ,var04,7.0000,5.0000,4.0000,1.0000
+MEAN,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+N,,100.0000,101.0000,102.0000,103.0000
+CORR,var01,1.0000,9.0000,8.0000,7.0000
+CORR,var02,9.0000,1.0000,6.0000,5.0000
+CORR,var03,8.0000,6.0000,1.0000,4.0000
+CORR,var04,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
@@ -156,13 +156,13 @@ list.
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04
-mean    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-n       ,,100.0000,101.0000,102.0000,103.0000
-corr    ,var01,1.0000,9.0000,8.0000,7.0000
-corr    ,var02,9.0000,1.0000,6.0000,5.0000
-corr    ,var03,8.0000,6.0000,1.0000,4.0000
-corr    ,var04,7.0000,5.0000,4.0000,1.0000
+mean,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+n,,100.0000,101.0000,102.0000,103.0000
+corr,var01,1.0000,9.0000,8.0000,7.0000
+corr,var02,9.0000,1.0000,6.0000,5.0000
+corr,var03,8.0000,6.0000,1.0000,4.0000
+corr,var04,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
@@ -190,13 +190,13 @@ list.
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04
-mean    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-n       ,,100.0000,101.0000,102.0000,103.0000
-corr    ,var01,1.0000,9.0000,8.0000,7.0000
-corr    ,var02,9.0000,1.0000,6.0000,5.0000
-corr    ,var03,8.0000,6.0000,1.0000,4.0000
-corr    ,var04,7.0000,5.0000,4.0000,1.0000
+mean,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+n,,100.0000,101.0000,102.0000,103.0000
+corr,var01,1.0000,9.0000,8.0000,7.0000
+corr,var02,9.0000,1.0000,6.0000,5.0000
+corr,var03,8.0000,6.0000,1.0000,4.0000
+corr,var04,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
@@ -244,18 +244,18 @@ var03,7,,Scale,Input,8,Right,F10.4,F10.4,
 
 Table: Data List
 s1,s2,ROWTYPE_,VARNAME_,var01,var02,var03
-8,0,mean    ,,21.4000,5.0000,72.9000
-8,0,STDDEV  ,,6.5000,1.6000,22.8000
-8,0,n       ,,106.0000,106.0000,106.0000
-8,0,corr    ,var01,1.0000,.4100,-.1600
-8,0,corr    ,var02,.4100,1.0000,-.2200
-8,0,corr    ,var03,-.1600,-.2200,1.0000
-8,1,mean    ,,11.4000,1.0000,52.9000
-8,1,STDDEV  ,,9.5000,8.6000,12.8000
-8,1,n       ,,10.0000,11.0000,12.0000
-8,1,corr    ,var01,1.0000,.5100,.3600
-8,1,corr    ,var02,.5100,1.0000,-.4100
-8,1,corr    ,var03,.3600,-.4100,1.0000
+8,0,mean,,21.4000,5.0000,72.9000
+8,0,STDDEV,,6.5000,1.6000,22.8000
+8,0,n,,106.0000,106.0000,106.0000
+8,0,corr,var01,1.0000,.4100,-.1600
+8,0,corr,var02,.4100,1.0000,-.2200
+8,0,corr,var03,-.1600,-.2200,1.0000
+8,1,mean,,11.4000,1.0000,52.9000
+8,1,STDDEV,,9.5000,8.6000,12.8000
+8,1,n,,10.0000,11.0000,12.0000
+8,1,corr,var01,1.0000,.5100,.3600
+8,1,corr,var02,.5100,1.0000,-.4100
+8,1,corr,var03,.3600,-.4100,1.0000
 ])
 
 AT_CLEANUP
@@ -318,13 +318,13 @@ list.
 AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var_two,variable_number_three,variableFour
-mean    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-N       ,,100.0000,101.0000,102.0000,103.0000
-corr    ,var01,1.0000,9.0000,8.0000,7.0000
-corr    ,var_two,9.0000,1.0000,6.0000,5.0000
-corr    ,variable_number_three,8.0000,6.0000,1.0000,4.0000
-corr    ,variableFour,7.0000,5.0000,4.0000,1.0000
+mean,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+N,,100.0000,101.0000,102.0000,103.0000
+corr,var01,1.0000,9.0000,8.0000,7.0000
+corr,var_two,9.0000,1.0000,6.0000,5.0000
+corr,variable_number_three,8.0000,6.0000,1.0000,4.0000
+corr,variableFour,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
@@ -366,9 +366,9 @@ factor  /matrix = in (corr = *)
 AT_CHECK([pspp -O format=csv matrix-reader.pspp], [0], [dnl
 Table: Correlation Matrix
 ,,var02,var04,var06
-Correlations,var02,22.00,24.00,26.00
-,var04,42.00,44.00,46.00
-,var06,62.00,64.00,66.00
+Correlation,var02,22.000,24.000,26.000
+,var04,42.000,44.000,46.000
+,var06,62.000,64.000,66.000
 
 Table: Component Matrix
 ,Component,
@@ -472,13 +472,13 @@ AT_CHECK([pspp -O format=csv matrix-data.pspp], [0], [dnl
 
 Table: Data List
 ROWTYPE_,VARNAME_,var01,var02,var03,var04
-N       ,,99.0000,99.0000,99.0000,99.0000
-mean    ,,34.0000,35.0000,36.0000,37.0000
-STDDEV  ,,22.0000,11.0000,55.0000,66.0000
-corr    ,var01,1.0000,9.0000,8.0000,7.0000
-corr    ,var02,9.0000,1.0000,6.0000,5.0000
-corr    ,var03,8.0000,6.0000,1.0000,4.0000
-corr    ,var04,7.0000,5.0000,4.0000,1.0000
+N,,99.0000,99.0000,99.0000,99.0000
+mean,,34.0000,35.0000,36.0000,37.0000
+STDDEV,,22.0000,11.0000,55.0000,66.0000
+corr,var01,1.0000,9.0000,8.0000,7.0000
+corr,var02,9.0000,1.0000,6.0000,5.0000
+corr,var03,8.0000,6.0000,1.0000,4.0000
+corr,var04,7.0000,5.0000,4.0000,1.0000
 ])
 
 AT_CLEANUP
index a2c005a93d57cb771adc240bd1501cc6991ac44b..fd907d7a84da0e1be004bad568f631c54af55c2a 100644 (file)
@@ -67,7 +67,7 @@ AT_CHECK([pspp -O format=csv save.pspp])
 AT_CHECK([pspp -O format=csv get.pspp], [0], [dnl
 Table: Data List
 number,time,date,datetime,string,filter
-.   ,-0 05:17,10/31/2010,09-APR-2008 09:29:00,xxx    ,1
-1.625,0 12:00:00,.,.,xyzzy   ,1
+.   ,-0 05:17,10/31/2010,09-APR-2008 09:29:00,xxx,1
+1.625,0 12:00:00,.,.,xyzzy,1
 ])
 AT_CLEANUP
index e3d63657d685a257f7c2b4ce53d14ec249bb3fc0..f0407b6369a4a55323611f8dae7bf3dd08578b0a 100644 (file)
@@ -52,7 +52,7 @@ DISPLAY ATTRIBUTES.
 ]])
 AT_CHECK([pspp -O format=csv save-attrs.pspp], [0],
   [[Table: Variable and Dataset Attributes
-Variable,Name,Value
+Variable and Name,,Value
 (dataset),array[1],array element 1
 ,array[2],array element 2
 ,key,value
@@ -64,7 +64,7 @@ c,QuestionWording,X or Y?
 ]])
 AT_CHECK([pspp -O format=csv get-attrs.pspp], [0], [dnl
 Table: Variable and Dataset Attributes
-Variable,Name,Value
+Variable and Name,,Value
 (dataset),array,array element 2
 ,key,value
 b,ValidationRule,a * b > 3
index 49d9c7b215a56f68fc014df6ae0d14b38d39f529..a520a41370a43aa4b8937c0736623f9da1c0d12d 100644 (file)
@@ -82,56 +82,31 @@ mrsets.sps:38: warning: MRSETS: MDGROUP subcommand for group $d specifies LABELS
 "mrsets.sps:42: warning: MRSETS: Variables specified on MCGROUP should have the same categories, but a and c (and possibly others) in multiple category group $f have different value labels for value b."
 ])
 
-m4_define([MRSETS_DISPLAY_OUTPUT],
-  [Table: Multiple Response Sets
-Name,Variables,Details
-$a,"w
+m4_define([MRSETS_DISPLAY_OUTPUT], [dnl
+Table: Multiple Response Sets
+Name,Label,Encoding,Counted Value,Member Variables
+$a,First multiple dichotomy group,Dichotomies,5,"w
 x
 y
-z
-","Multiple dichotomy set
-Label: First multiple dichotomy group
-Label source: Provided by user
-Counted value: 5
-Category label source: Variable labels
-"
-$b,"z
-y
-","Multiple dichotomy set
-Counted value: 123
-Category label source: Value labels of counted value
-"
-$c,"w
+z"
+$b,,Dichotomies,123,"z
+y"
+$c,duplicate variable label,Dichotomies,1,"w
 x
 y
-z
-","Multiple dichotomy set
-Label: duplicate variable label
-Label source: First variable label among variables
-Counted value: 1
-Category label source: Value labels of counted value
-"
-$d,"a
+z"
+$d,,Dichotomies,c,"a
 b
 c
-d
-","Multiple dichotomy set
-Counted value: `c'
-Category label source: Variable labels
-"
-$e,"w
+d"
+$e,First multiple category group,Categories,,"w
 x
 y
-z
-","Multiple category set
-Label: First multiple category group
-"
-$f,"a
+z"
+$f,,Categories,,"a
 b
 c
-d
-","Multiple category set
-"
+d"
 ])
 
 AT_SETUP([MRSETS add, display, delete])
@@ -145,61 +120,60 @@ AT_DATA([mrsets.sps],
     /DELETE NAME=ALL
     /DISPLAY NAME=ALL.
 ]])
-AT_CHECK([pspp -O format=csv mrsets.sps], [0],
+AT_CHECK([pspp -o - -O format=csv -o mrsets.csv -o mrsets.txt -o mrsets.pdf mrsets.sps], [0],
   [DEFINE_MRSETS_OUTPUT
 Table: Multiple Response Sets
-Name,Variables,Details
-$a,"w
+Name,Label,Encoding,Counted Value,Member Variables
+$a,First multiple dichotomy group,Dichotomies,5,"w
 x
 y
-z
-","Multiple dichotomy set
-Label: First multiple dichotomy group
-Label source: Provided by user
-Counted value: 5
-Category label source: Variable labels
-"
+z"
 
-MRSETS_DISPLAY_OUTPUT
 Table: Multiple Response Sets
-Name,Variables,Details
-$a,"w
+Name,Label,Encoding,Counted Value,Member Variables
+$a,First multiple dichotomy group,Dichotomies,5,"w
+x
+y
+z"
+$b,,Dichotomies,123,"z
+y"
+$c,duplicate variable label,Dichotomies,1,"w
+x
+y
+z"
+$d,,Dichotomies,c,"a
+b
+c
+d"
+$e,First multiple category group,Categories,,"w
 x
 y
-z
-","Multiple dichotomy set
-Label: First multiple dichotomy group
-Label source: Provided by user
-Counted value: 5
-Category label source: Variable labels
-"
-$b,"z
+z"
+$f,,Categories,,"a
+b
+c
+d"
+
+Table: Multiple Response Sets
+Name,Label,Encoding,Counted Value,Member Variables
+$a,First multiple dichotomy group,Dichotomies,5,"w
+x
 y
-","Multiple dichotomy set
-Counted value: 123
-Category label source: Value labels of counted value
-"
-$d,"a
+z"
+$b,,Dichotomies,123,"z
+y"
+$d,,Dichotomies,c,"a
 b
 c
-d
-","Multiple dichotomy set
-Counted value: `c'
-Category label source: Variable labels
-"
-$e,"w
+d"
+$e,First multiple category group,Categories,,"w
 x
 y
-z
-","Multiple category set
-Label: First multiple category group
-"
-$f,"a
+z"
+$f,,Categories,,"a
 b
 c
-d
-","Multiple category set
-"
+d"
 
 mrsets.sps:50: note: MRSETS: The active dataset dictionary does not contain any multiple response sets.
 ])
index 2dc9a2e5063f3d42b205cf6bbc8464cbe52ac772..427bf2d9934fac8ddb62a2413fd9c58d559963d1 100644 (file)
@@ -41,8 +41,9 @@ list.
 ])
 AT_CHECK([pspp -o pspp.csv split-file.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variable,Value,Label
-X,1,
+Table: Split Values
+Variable,Value
+X,1
 
 Table: Data List
 X,Y
@@ -53,8 +54,9 @@ X,Y
 1,5
 1,4
 
-Variable,Value,Label
-X,2,
+Table: Split Values
+Variable,Value
+X,2
 
 Table: Data List
 X,Y
index d71e813743b0119fb60f6424c9d589630405c25c..11f5d4e9f82c8ca0b6ea562a7512adfeab81a2ee 100644 (file)
@@ -30,24 +30,25 @@ sysfile info file='pro.sav'.
 ])
 AT_CHECK([pspp -o pspp.csv sysfile-info.sps])
 AT_CHECK(
-  [sed -e '/^Created:,/d' \
-       -e '/^Endian:,/d' \
-       -e '/^Integer Format:,/d' \
-       -e '/^Real Format:,/d' \
-       -e '/^Encoding:,/d' pspp.csv],
+  [sed -e '/^Created,/d' \
+       -e '/^Endian,/d' \
+       -e '/^Integer Format,/d' \
+       -e '/^Real Format,/d' \
+       -e '/^Encoding,/d' pspp.csv],
   [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 x,F8.0
 name,A10
 
-File:,pro.sav
-Label:,No label.
-Variables:,2
-Cases:,3
-Type:,SPSS System File
-Weight:,Not weighted.
-Compression:,SAV
+Table: File Information
+File,pro.sav
+Label,
+Variables,2
+Cases,3
+Type,SPSS System File
+Weight,Not weighted
+Compression,SAV
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -70,9 +71,11 @@ FILE LABEL 'foo bar baz quux'.
 DISPLAY FILE LABEL.
 ])
 AT_CHECK([pspp -O format=csv display.sps], [0], [dnl
-The active dataset does not have a file label.
+Table: File Label
+Label,(none)
 
-File label: foo bar baz quux
+Table: File Label
+Label,foo bar baz quux
 ])
 AT_CLEANUP
 
index b7e6eaf8d7499e2abc1829d598fec8ace060eb7c..1ddabf972ab671d92b8adb534c2b43ddb25801a3 100644 (file)
@@ -32,7 +32,7 @@ ad,1,,Scale,Input,8,Right,ADATE10,ADATE10,
 dt,2,,Scale,Input,8,Right,DATETIME20.0,DATETIME20.0,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 ad,07/10/1982,label 1
 ,01/02/1993,label 2
 ,05/04/2003,label 3
@@ -52,24 +52,25 @@ END DATA.
 DISPLAY DICTIONARY.
 FREQUENCIES x/STAT=NONE.
 ])
-AT_CHECK([pspp -O format=csv value-labels.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt value-labels.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
 x,1,,Scale,Input,8,Right,F8.2,F8.2,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 x,1.00,one
 ,2.00,first line\nsecond line
 ,3.00,three
 
 Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-one,1.00,1,33.33,33.33,33.33
-"first line
-second line",2.00,1,33.33,33.33,66.67
-three,3.00,1,33.33,33.33,100.00
-Total,,3,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,one,1,33.3%,33.3%,33.3%
+,"first line
+second line",1,33.3%,33.3%,66.7%
+,three,1,33.3%,33.3%,100.0%
+Total,,3,100.0%,,
 ])
 AT_CLEANUP
 
@@ -90,24 +91,25 @@ GET FILE='value-labels.sav'.
 DISPLAY DICTIONARY.
 FREQUENCIES x/STAT=NONE.
 ])
-AT_CHECK([pspp -O format=csv get.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt get.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
 x,1,,Scale,Input,8,Right,F8.2,F8.2,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 x,1.00,one
 ,2.00,first line\nsecond line
 ,3.00,three
 
 Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-one,1.00,1,33.33,33.33,33.33
-"first line
-second line",2.00,1,33.33,33.33,66.67
-three,3.00,1,33.33,33.33,100.00
-Total,,3,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,one,1,33.3%,33.3%,33.3%
+,"first line
+second line",1,33.3%,33.3%,66.7%
+,three,1,33.3%,33.3%,100.0%
+Total,,3,100.0%,,
 ])
 AT_CLEANUP
 
index 5daa3c1bbf645e54160dbae0f50d17bb16b6a252..b586f64d565cc43f2507df1099ee353a3e8e4113 100644 (file)
@@ -75,36 +75,49 @@ SET TVARS=BOTH.
 DESCRIPTIVES ALL.
 ])
 
-AT_CHECK([pspp -O format=csv var-labels.sps], [0],[dnl
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+AT_CHECK([pspp -o pspp.csv -o pspp.txt var-labels.sps])
+AT_CHECK([cat pspp.csv], [0],[dnl
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 x,4,2.50,1.29,1.00,4.00
 y,4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 x,4,2.50,1.29,1.00,4.00
 y,4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 x,4,2.50,1.29,1.00,4.00
 y,4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 x,4,2.50,1.29,1.00,4.00
 y,4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 foo,4,2.50,1.29,1.00,4.00
 bar,4,250.00,129.10,100.00,400.00
-
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
-foo (x),4,2.50,1.29,1.00,4.00
-bar (y),4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
+
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
+x foo,4,2.50,1.29,1.00,4.00
+y bar,4,250.00,129.10,100.00,400.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 ])
 
 AT_CLEANUP
index 67fdee495f80d54ebd5afd7696d544c737d5a65b..1c274402cdaee836759f3b9a7ccf5f886e4e5ed3 100644 (file)
@@ -24,7 +24,8 @@ display vector.
 ])
 AT_CHECK([pspp -o pspp.csv vector.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Vector,Position,Variable,Print Format
+Table: Vectors
+Vector and Position,,Variable,Print Format
 v,1,v1,F8.2
 ,2,v2,F8.2
 ,3,v3,F8.2
@@ -41,7 +42,8 @@ display vector.
 ])
 AT_CHECK([pspp -o pspp.csv vector.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Vector,Position,Variable,Print Format
+Table: Vectors
+Vector and Position,,Variable,Print Format
 #vec,1,#vec1,COMMA10.2
 ,2,#vec2,COMMA10.2
 ,3,#vec3,COMMA10.2
@@ -62,7 +64,8 @@ display vector.
 ])
 AT_CHECK([pspp -o pspp.csv vector.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Vector,Position,Variable,Print Format
+Table: Vectors
+Vector and Position,,Variable,Print Format
 x,1,x1,F8.2
 ,2,x2,F8.2
 ,3,x3,F8.2
@@ -81,7 +84,8 @@ display vector.
 ])
 AT_CHECK([pspp -o pspp.csv vector.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Vector,Position,Variable,Print Format
+Table: Vectors
+Vector and Position,,Variable,Print Format
 a,1,u,F1.0
 ,2,w,F1.0
 ,3,x,F1.0
index a0f3c53cd629312edcf7bf0e43e67e3f2c77820d..92de2177b2c154d47b7c7f53799aaf72b94093da 100644 (file)
@@ -79,79 +79,27 @@ weight by BVAR.
 descriptives AVAR /statistics all /format serial.
 frequencies AVAR /statistics all.
 ])
-AT_CHECK([pspp -o pspp.csv weight.sps])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt weight.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading 1 record from `weight.txt'.
 Variable,Record,Columns,Format
 AVAR,1,1-  5,F5.0
 BVAR,1,6- 10,F5.0
 
-Table: Valid cases = 730; cases with missing value(s) = 0.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-AVAR,730,0,31.515,.405,10.937,119.608,2.411,.181,1.345,.090,76.000,18.000,94.000,23006.000
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+AVAR,730,31.515,.405,10.937,119.608,2.411,.181,1.345,.090,76.000,18,94,23006.00
+Valid N (listwise),730,,,,,,,,,,,,
+Missing N (listwise),0,,,,,,,,,,,,
 
-Table: AVAR
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,18,1,.137,.137,.137
-,19,7,.959,.959,1.096
-,20,26,3.562,3.562,4.658
-,21,76,10.411,10.411,15.068
-,22,57,7.808,7.808,22.877
-,23,58,7.945,7.945,30.822
-,24,38,5.205,5.205,36.027
-,25,38,5.205,5.205,41.233
-,26,30,4.110,4.110,45.342
-,27,21,2.877,2.877,48.219
-,28,23,3.151,3.151,51.370
-,29,24,3.288,3.288,54.658
-,30,23,3.151,3.151,57.808
-,31,14,1.918,1.918,59.726
-,32,21,2.877,2.877,62.603
-,33,21,2.877,2.877,65.479
-,34,14,1.918,1.918,67.397
-,35,14,1.918,1.918,69.315
-,36,17,2.329,2.329,71.644
-,37,11,1.507,1.507,73.151
-,38,16,2.192,2.192,75.342
-,39,14,1.918,1.918,77.260
-,40,15,2.055,2.055,79.315
-,41,14,1.918,1.918,81.233
-,42,14,1.918,1.918,83.151
-,43,8,1.096,1.096,84.247
-,44,15,2.055,2.055,86.301
-,45,10,1.370,1.370,87.671
-,46,12,1.644,1.644,89.315
-,47,13,1.781,1.781,91.096
-,48,13,1.781,1.781,92.877
-,49,5,.685,.685,93.562
-,50,5,.685,.685,94.247
-,51,3,.411,.411,94.658
-,52,7,.959,.959,95.616
-,53,6,.822,.822,96.438
-,54,2,.274,.274,96.712
-,55,2,.274,.274,96.986
-,56,2,.274,.274,97.260
-,57,3,.411,.411,97.671
-,58,1,.137,.137,97.808
-,59,3,.411,.411,98.219
-,61,1,.137,.137,98.356
-,62,3,.411,.411,98.767
-,63,1,.137,.137,98.904
-,64,1,.137,.137,99.041
-,65,2,.274,.274,99.315
-,70,1,.137,.137,99.452
-,78,1,.137,.137,99.589
-,79,1,.137,.137,99.726
-,80,1,.137,.137,99.863
-,94,1,.137,.137,100.000
-Total,,730,100.0,100.0,
-
-Table: AVAR
+Table: Statistics
+,,AVAR
 N,Valid,730
 ,Missing,0
 Mean,,31.515
 S.E. Mean,,.405
-Mode,,21.000
+Median,,28.000
+Mode,,21
 Std Dev,,10.937
 Variance,,119.608
 Kurtosis,,2.411
@@ -159,9 +107,64 @@ S.E. Kurt,,.181
 Skewness,,1.345
 S.E. Skew,,.090
 Range,,76.000
-Minimum,,18.000
-Maximum,,94.000
-Sum,,23006.000
-Percentiles,50 (Median),28
+Minimum,,18
+Maximum,,94
+Sum,,23006.00
+
+Table: AVAR
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,18,1,.1%,.1%,.1%
+,19,7,1.0%,1.0%,1.1%
+,20,26,3.6%,3.6%,4.7%
+,21,76,10.4%,10.4%,15.1%
+,22,57,7.8%,7.8%,22.9%
+,23,58,7.9%,7.9%,30.8%
+,24,38,5.2%,5.2%,36.0%
+,25,38,5.2%,5.2%,41.2%
+,26,30,4.1%,4.1%,45.3%
+,27,21,2.9%,2.9%,48.2%
+,28,23,3.2%,3.2%,51.4%
+,29,24,3.3%,3.3%,54.7%
+,30,23,3.2%,3.2%,57.8%
+,31,14,1.9%,1.9%,59.7%
+,32,21,2.9%,2.9%,62.6%
+,33,21,2.9%,2.9%,65.5%
+,34,14,1.9%,1.9%,67.4%
+,35,14,1.9%,1.9%,69.3%
+,36,17,2.3%,2.3%,71.6%
+,37,11,1.5%,1.5%,73.2%
+,38,16,2.2%,2.2%,75.3%
+,39,14,1.9%,1.9%,77.3%
+,40,15,2.1%,2.1%,79.3%
+,41,14,1.9%,1.9%,81.2%
+,42,14,1.9%,1.9%,83.2%
+,43,8,1.1%,1.1%,84.2%
+,44,15,2.1%,2.1%,86.3%
+,45,10,1.4%,1.4%,87.7%
+,46,12,1.6%,1.6%,89.3%
+,47,13,1.8%,1.8%,91.1%
+,48,13,1.8%,1.8%,92.9%
+,49,5,.7%,.7%,93.6%
+,50,5,.7%,.7%,94.2%
+,51,3,.4%,.4%,94.7%
+,52,7,1.0%,1.0%,95.6%
+,53,6,.8%,.8%,96.4%
+,54,2,.3%,.3%,96.7%
+,55,2,.3%,.3%,97.0%
+,56,2,.3%,.3%,97.3%
+,57,3,.4%,.4%,97.7%
+,58,1,.1%,.1%,97.8%
+,59,3,.4%,.4%,98.2%
+,61,1,.1%,.1%,98.4%
+,62,3,.4%,.4%,98.8%
+,63,1,.1%,.1%,98.9%
+,64,1,.1%,.1%,99.0%
+,65,2,.3%,.3%,99.3%
+,70,1,.1%,.1%,99.5%
+,78,1,.1%,.1%,99.6%
+,79,1,.1%,.1%,99.7%
+,80,1,.1%,.1%,99.9%
+,94,1,.1%,.1%,100.0%
+Total,,730,100.0%,,
 ])
 AT_CLEANUP
index e2f70e09d3fd67ca7556f977ea70bda6da279261..76e11d885eb256b35ebd450f2c5b1d7059fbf8f5 100644 (file)
@@ -2120,10 +2120,10 @@ Table: Data List
 n,s,nlabel,slabel
 .,,,
 0,a,Very dissa,Wouldn't b
-1,b,Dissatisfi,Unhappy   @&t@
-2,c,Neutral   ,Bored     @&t@
-3,d,Satisfied ,Satiated  @&t@
-4,e,Very satis,Elated    @&t@
+1,b,Dissatisfi,Unhappy
+2,c,Neutral,Bored
+3,d,Satisfied,Satiated
+4,e,Very satis,Elated
 5,f,,
 6,g,,
 ])
index a7f792fb2ed598e7857d9eef5e05437a24ab6294..a1682a9083dc3f27151d8a1cebc441dd000a1986 100644 (file)
@@ -45,22 +45,22 @@ Table: Data List
 AlphaBetaGamma,B,X,Yabbadabbadoo
 2.00,3.00,4.00,5.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X * Yabbadabbadoo,1,100.0%,0,0.0%,1,100.0%
+X × Yabbadabbadoo,1,100.0%,0,.0%,1,100.0%
 
-Table: X * Yabbadabbadoo [[count]].
-,Yabbadabbadoo,,,,,,,
-X,1.00,2.00,3.00,4.00,5.00,6.00,7.00,Total
-1.00,.00,.00,.00,.00,.00,.00,.00,.00
-2.00,.00,.00,.00,.00,.00,.00,.00,.00
-3.00,.00,.00,.00,.00,.00,.00,.00,.00
-4.00,.00,.00,.00,.00,1.00,.00,.00,1.00
-5.00,.00,.00,.00,.00,.00,.00,.00,.00
-6.00,.00,.00,.00,.00,.00,.00,.00,.00
-7.00,.00,.00,.00,.00,.00,.00,.00,.00
-Total,.00,.00,.00,.00,1.00,.00,.00,1.00
+Table: X × Yabbadabbadoo
+,,,Yabbadabbadoo,,,,,,,Total
+,,,1.00,2.00,3.00,4.00,5.00,6.00,7.00,
+X,1.00,Count,0,0,0,0,0,0,0,0
+,2.00,,0,0,0,0,0,0,0,0
+,3.00,,0,0,0,0,0,0,0,0
+,4.00,,0,0,0,0,1,0,0,1
+,5.00,,0,0,0,0,0,0,0,0
+,6.00,,0,0,0,0,0,0,0,0
+,7.00,,0,0,0,0,0,0,0,0
+Total,,,0,0,0,0,1,0,0,1
 ])
 AT_CLEANUP
index 976899b23386602b1d055e058dc4b856228fc7e6..590a63f20005d8e4effb0aeae259cb3985ff3180 100644 (file)
@@ -208,8 +208,8 @@ Y,A25
 
 Table: Data List
 X,Y
-87.34,bar                      @&t@
-87.50,foo                      @&t@
+87.34,bar
+87.50,foo
 ])
 AT_CLEANUP
 
index fdd7c33e6bfe6c8de63d87bff76237a2455ebc88..33a1fd26def954312b6c561e368851819d2b9683 100644 (file)
@@ -95,13 +95,13 @@ display dictionary.
 AT_CHECK([pspp -O format=csv ar.sps], [0],
   [Table: Data List
 s,x,new
-widgets         ,1.00,4.00
-thingummies     ,2.00,3.00
-oojars          ,3.00,1.00
-widgets         ,4.00,4.00
-oojars          ,5.00,1.00
-thingummies     ,6.00,3.00
-oojimiflips     ,7.00,2.00
+widgets,1.00,4.00
+thingummies,2.00,3.00
+oojars,3.00,1.00
+widgets,4.00,4.00
+oojars,5.00,1.00
+thingummies,6.00,3.00
+oojimiflips,7.00,2.00
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -110,7 +110,7 @@ x,2,,Scale,Input,8,Right,F8.2,F8.2,
 new,3,,Scale,Input,8,Right,F8.2,F8.2,
 
 Table: Value Labels
-Variable,Value,Label
+Variable Value,,Label
 new,1.00,oojars
 ,2.00,oojimiflips
 ,3.00,thingummies
@@ -210,10 +210,10 @@ AT_CHECK([pspp -O format=csv ar-strings.sps], [0],
 [dnl
 Table: Data List
 a,b,x,y
-one         ,nine  ,5.00,3.00
-two         ,ten   ,8.00,6.00
-three       ,eleven,7.00,1.00
-four        ,nought,2.00,4.00
+one,nine,5.00,3.00
+two,ten,8.00,6.00
+three,eleven,7.00,1.00
+four,nought,2.00,4.00
 ])
 
 AT_CLEANUP
index 12819835d33dc72e7e207e7f4518f381f284b7b5..df00e67723f75278c3b83b5d39e5c1af238a3ac5 100644 (file)
@@ -49,19 +49,22 @@ correlations
        /missing = pairwise
        .
 ])
-AT_CHECK([pspp -o pspp.csv correlations.sps])
-AT_CHECK([cat pspp.csv], [0], [dnl
-Table: Correlations
+AT_CHECK([pspp -o pspp.csv -o pspp.txt correlations.sps])
+AT_CHECK([cat pspp.csv], [0],
+[[Table: Correlations
 ,,foo,bar,wiz,bang
-foo,Pearson Correlation,1.000,.802,.890,-.308
+foo,Pearson Correlation,1.000,.802,.890[a],-.308
 ,Sig. (2-tailed),,.055,.017,.553
 bar,Pearson Correlation,.802,1.000,.519,.118
 ,Sig. (2-tailed),.055,,.291,.824
-wiz,Pearson Correlation,.890,.519,1.000,-.344
+wiz,Pearson Correlation,.890[a],.519,1.000,-.344
 ,Sig. (2-tailed),.017,.291,,.505
 bang,Pearson Correlation,-.308,.118,-.344,1.000
 ,Sig. (2-tailed),.553,.824,.505,
 
+Footnotes:
+a,Significant at .05 level
+
 Table: Correlations
 ,,bar,wiz
 bar,Pearson Correlation,1.000,.497
@@ -71,19 +74,22 @@ wiz,Pearson Correlation,.497,1.000
 
 Table: Correlations
 ,,foo,bar,wiz,bang
-foo,Pearson Correlation,1.000,.805,.883,-.308
+foo,Pearson Correlation,1.000,.805[a],.883[a],-.308
 ,Sig. (2-tailed),,.029,.008,.553
 ,N,7,7,7,6
-bar,Pearson Correlation,.805,1.000,.497,.164
+bar,Pearson Correlation,.805[a],1.000,.497,.164
 ,Sig. (2-tailed),.029,,.210,.725
 ,N,7,8,8,7
-wiz,Pearson Correlation,.883,.497,1.000,-.337
+wiz,Pearson Correlation,.883[a],.497,1.000,-.337
 ,Sig. (2-tailed),.008,.210,,.460
 ,N,7,8,8,7
 bang,Pearson Correlation,-.308,.164,-.337,1.000
 ,Sig. (2-tailed),.553,.725,.460,
 ,N,6,7,7,7
-])
+
+Footnotes:
+a,Significant at .05 level
+]])
 AT_CLEANUP
 
 AT_SETUP([CORRELATIONS -- weighted])
@@ -192,15 +198,15 @@ AT_CHECK([pspp -o pspp.csv correlations.sps])
 AT_CHECK([sed '/a,Pearson/,$s/,\([[^,]]*\),.*/,\1,.../' pspp.csv], [0], [dnl
 Table: Descriptive Statistics
 ,Mean,Std. Deviation,N
-a,24.00,8.93,14.00
-f,4.73,.85,12.00
-b,14.50,6.41,14.00
-c,21.71,4.98,14.00
-g,24.86,6.09,14.00
-h,23.57,6.30,14.00
-i,27.79,6.73,14.00
-e,27.21,4.95,14.00
-d,27.93,5.23,14.00
+a,24.00,8.93,14
+f,4.73,.85,12
+b,14.50,6.41,14
+c,21.71,4.98,14
+g,24.86,6.09,14
+h,23.57,6.30,14
+i,27.79,6.73,14
+e,27.21,4.95,14
+d,27.93,5.23,14
 
 Table: Correlations
 ,,c,g,h,i,e,d
@@ -222,6 +228,7 @@ dnl Checks for bug #40661
 AT_SETUP([CORRELATIONS -- incorrect subtable selection])
 AT_DATA([correlations.sps], [dnl
 set format = F12.4.
+OUTPUT MODIFY /SELECT TABLES /TABLECELLS SELECT = [[CORRELATIONS]] FORMAT=F12.4.
 set decimal = dot.
 data list notable list /var1 var2 var3 var4 var5 *.
 begin data.
@@ -337,31 +344,38 @@ CORRELATION
 
 ])
 
-AT_CHECK([pspp -O format=csv  correlations.sps], [0],
-[Table: Correlations
+AT_CHECK([pspp -o pspp.csv -o pspp.txt correlations.sps])
+AT_CHECK([cat pspp.csv], [0],
+[[Table: Correlations
 ,,var4,var5
-var1,Pearson Correlation,.5693,-.0519
+var1,Pearson Correlation,.5693[a],-.0519
 ,Sig. (2-tailed),.000,.623
 ,N,93,92
-var2,Pearson Correlation,.3792,-.0407
+var2,Pearson Correlation,.3792[a],-.0407
 ,Sig. (2-tailed),.000,.698
 ,N,95,93
-var3,Pearson Correlation,.3699,-.0543
+var3,Pearson Correlation,.3699[a],-.0543
 ,Sig. (2-tailed),.000,.603
 ,N,95,94
 
+Footnotes:
+a,Significant at .05 level
+
 Table: Correlations
 ,,var1,var2
-var3,Pearson Correlation,.6964,.5615
+var3,Pearson Correlation,.6964[a],.5615[a]
 ,Sig. (2-tailed),.000,.000
 ,N,96,97
-var4,Pearson Correlation,.5693,.3792
+var4,Pearson Correlation,.5693[a],.3792[a]
 ,Sig. (2-tailed),.000,.000
 ,N,93,95
 var5,Pearson Correlation,-.0519,-.0407
 ,Sig. (2-tailed),.623,.698
 ,N,92,93
-])
+
+Footnotes:
+a,Significant at .05 level
+]])
 
 AT_CLEANUP
 
index 6c34c68a436ad7fd6367da29354be1b0ba5ed024..3208e0e2b262611e792caca244b11c4e94a00b67 100644 (file)
@@ -25,7 +25,8 @@ END DATA.
 
 CROSSTABS VARIABLES X (1,7) Y (1,7) /TABLES X BY Y.
 ])
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0], 
+AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps])
+AT_CHECK([cat pspp.csv], [0],
   [[Table: Reading free-form data from INLINE.
 Variable,Format
 A,F8.0
@@ -33,23 +34,23 @@ B,F8.0
 X,F8.0
 Y,F8.0
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X * Y,1,100.0%,0,0.0%,1,100.0%
-
-Table: X * Y [count].
-,Y,,,,,,,
-X,1.00,2.00,3.00,4.00,5.00,6.00,7.00,Total
-1.00,.00,.00,.00,.00,.00,.00,.00,.00
-2.00,.00,.00,.00,.00,.00,.00,.00,.00
-3.00,.00,.00,.00,.00,.00,.00,.00,.00
-4.00,.00,.00,.00,.00,1.00,.00,.00,1.00
-5.00,.00,.00,.00,.00,.00,.00,.00,.00
-6.00,.00,.00,.00,.00,.00,.00,.00,.00
-7.00,.00,.00,.00,.00,.00,.00,.00,.00
-Total,.00,.00,.00,.00,1.00,.00,.00,1.00
+X × Y,1,100.0%,0,.0%,1,100.0%
+
+Table: X × Y
+,,,Y,,,,,,,Total
+,,,1.00,2.00,3.00,4.00,5.00,6.00,7.00,
+X,1.00,Count,0,0,0,0,0,0,0,0
+,2.00,,0,0,0,0,0,0,0,0
+,3.00,,0,0,0,0,0,0,0,0
+,4.00,,0,0,0,0,1,0,0,1
+,5.00,,0,0,0,0,0,0,0,0
+,6.00,,0,0,0,0,0,0,0,0
+,7.00,,0,0,0,0,0,0,0,0
+Total,,,0,0,0,0,1,0,0,1
 ]])
 AT_CLEANUP
 
@@ -71,11 +72,15 @@ Variable,Format
 x,F8.0
 y,F8.0
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,0,0.0%,1,100.0%,1,100.0%
+x × y,0,.0%,1,100.0%,1,100.0%
+
+Table: x × y
+,,
+,,
 ]])
 AT_CLEANUP
 
@@ -95,7 +100,7 @@ end data.
 
 CROSSTABS /TABLES = x BY y.
 ])
-AT_CHECK([pspp -o - -O format=csv crosstabs.sps], [0],
+AT_CHECK([pspp -o - -O format=csv -o pspp.txt crosstabs.sps], [0],
   [[Table: Reading free-form data from INLINE.
 Variable,Format
 x,F8.0
@@ -105,19 +110,19 @@ y,A18
 
 "crosstabs.sps:6: warning: Missing value(s) for all variables from x onward.  These will be filled with the system-missing value or blanks, as appropriate."
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,4,66.7%,2,33.3%,6,100.0%
-
-Table: x * y [count].
-,y,,,,
-x,one unity         ,three lots        ,two duality       ,zero none         ,Total
-1.00,1.00,.00,.00,1.00,2.00
-2.00,.00,.00,1.00,.00,1.00
-3.00,.00,1.00,.00,.00,1.00
-Total,1.00,1.00,1.00,1.00,4.00
+x × y,4,66.7%,2,33.3%,6,100.0%
+
+Table: x × y
+,,,y,,,,Total
+,,,one unity,three lots,two duality,zero none,
+x,1.00,Count,1,0,0,1,2
+,2.00,,0,0,1,0,1
+,3.00,,0,1,0,0,1
+Total,,,1,1,1,1,4
 ]])
 AT_CLEANUP
 
@@ -145,8 +150,8 @@ LIST.
 
 CROSSTABS TABLES  y by z.
 ]])
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
-  [[Table: Reading 1 record from INLINE.
+AT_CHECK([pspp -o - -O format=csv -o pspp.txt crosstabs.sps], [0],
+  [Table: Reading 1 record from INLINE.
 Variable,Record,Columns,Format
 x,1,1-  2,F2.0
 y,1,3-  3,F1.0
@@ -164,19 +169,19 @@ x,y,z
 8,1,1
 9,1,2
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-y * z,9,100.0%,0,0.0%,9,100.0%
-
-Table: y * z [count].
-,z,,
-y,1,2,Total
-1,4.00,3.00,7.00
-2,1.00,1.00,2.00
-Total,5.00,4.00,9.00
-]])
+y × z,9,100.0%,0,.0%,9,100.0%
+
+Table: y × z
+,,,z,,Total
+,,,1,2,
+y,1,Count,4,3,7
+,2,,1,1,2
+Total,,,5,4,9
+])
 AT_CLEANUP
 
 # Bug #26739, which caused CROSSTABS to crash or to fail to output
@@ -201,22 +206,22 @@ Variable,Format
 x,F8.0
 y,F8.0
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,4,100.0%,0,0.0%,4,100.0%
-
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-2.00,.00,1.00,1.00
-3.00,1.00,.00,1.00
-4.00,1.00,1.00,2.00
-Total,2.00,2.00,4.00
-
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed)
+x × y,4,100.0%,0,.0%,4,100.0%
+
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,2.00,Count,0,1,1
+,3.00,,1,0,1
+,4.00,,1,1,2
+Total,,,2,2,4
+
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed)
 Pearson Chi-Square,2.00,2,.368
 Likelihood Ratio,2.77,2,.250
 Linear-by-Linear Association,.27,1,.602
@@ -250,73 +255,76 @@ CROSSTABS
     /CELLS=COUNT ROW COLUMN TOTAL.
 ])
 
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
-  [[Variable,Value,Label
-v0,a ,
+AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Split Values
+Variable,Value
+v0,a
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-v1 * v2,6,100.0%,0,0.0%,6,100.0%
-
-"Table: v1 * v2 [count, row %, column %, total %]."
-,v2,,
-v1,e ,f ,Total
-c ,3.00,1.00,4.00
-,75.00%,25.00%,100.00%
-,75.00%,50.00%,66.67%
-,50.00%,16.67%,66.67%
-d ,1.00,1.00,2.00
-,50.00%,50.00%,100.00%
-,25.00%,50.00%,33.33%
-,16.67%,16.67%,33.33%
-Total,4.00,2.00,6.00
-,66.67%,33.33%,100.00%
-,100.00%,100.00%,100.00%
-,66.67%,33.33%,100.00%
-
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
+v1 × v2,6,100.0%,0,.0%,6,100.0%
+
+Table: v1 × v2
+,,,v2,,Total
+,,,e,f,
+v1,c,Count,3,1,4
+,,Row %,75.0%,25.0%,100.0%
+,,Column %,75.0%,50.0%,66.7%
+,,Total %,50.0%,16.7%,66.7%
+,d,Count,1,1,2
+,,Row %,50.0%,50.0%,100.0%
+,,Column %,25.0%,50.0%,33.3%
+,,Total %,16.7%,16.7%,33.3%
+Total,,Count,4,2,6
+,,Row %,66.7%,33.3%,100.0%
+,,Column %,100.0%,100.0%,100.0%
+,,Total %,66.7%,33.3%,100.0%
+
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
 Pearson Chi-Square,.38,1,.540,,
 Likelihood Ratio,.37,1,.545,,
 Fisher's Exact Test,,,,1.000,.600
 Continuity Correction,.00,1,1.000,,
 N of Valid Cases,6,,,,
 
-Variable,Value,Label
-v0,b ,
+Table: Split Values
+Variable,Value
+v0,b
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-v1 * v2,4,100.0%,0,0.0%,4,100.0%
-
-"Table: v1 * v2 [count, row %, column %, total %]."
-,v2,,
-v1,e ,f ,Total
-c ,.00,1.00,1.00
-,.00%,100.00%,100.00%
-,.00%,33.33%,25.00%
-,.00%,25.00%,25.00%
-d ,1.00,2.00,3.00
-,33.33%,66.67%,100.00%
-,100.00%,66.67%,75.00%
-,25.00%,50.00%,75.00%
-Total,1.00,3.00,4.00
-,25.00%,75.00%,100.00%
-,100.00%,100.00%,100.00%
-,25.00%,75.00%,100.00%
-
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
+v1 × v2,4,100.0%,0,.0%,4,100.0%
+
+Table: v1 × v2
+,,,v2,,Total
+,,,e,f,
+v1,c,Count,0,1,1
+,,Row %,.0%,100.0%,100.0%
+,,Column %,.0%,33.3%,25.0%
+,,Total %,.0%,25.0%,25.0%
+,d,Count,1,2,3
+,,Row %,33.3%,66.7%,100.0%
+,,Column %,100.0%,66.7%,75.0%
+,,Total %,25.0%,50.0%,75.0%
+Total,,Count,1,3,4
+,,Row %,25.0%,75.0%,100.0%
+,,Column %,100.0%,100.0%,100.0%
+,,Total %,25.0%,75.0%,100.0%
+
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
 Pearson Chi-Square,.44,1,.505,,
 Likelihood Ratio,.68,1,.410,,
 Fisher's Exact Test,,,,1.000,.750
 Continuity Correction,.00,1,1.000,,
 N of Valid Cases,4,,,,
-]])
+])
 AT_CLEANUP
 
 # Bug #24752.
@@ -344,8 +352,8 @@ LIST.
 
 CROSSTABS TABLES  x BY y BY z/STATISTICS=ALL.
 ]])
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
-  [[Table: Reading 1 record from INLINE.
+AT_CHECK([pspp -o - -O format=csv -o pspp.csv -o pspp.txt crosstabs.sps], [0],
+  [Table: Reading 1 record from INLINE.
 Variable,Record,Columns,Format
 x,1,1-  2,F2.0
 y,1,3-  3,F1.0
@@ -363,88 +371,88 @@ x,y,z
 8,1,1
 9,1,2
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y * z,9,100.0%,0,0.0%,9,100.0%
-
-Table: x * y * z [count].
-z,,y,,
-,x,1,2,Total
-1,1,1.00,.00,1.00
-,3,1.00,.00,1.00
-,5,.00,1.00,1.00
-,7,1.00,.00,1.00
-,8,1.00,.00,1.00
-Total,,4.00,1.00,5.00
-2,2,.00,1.00,1.00
-,4,1.00,.00,1.00
-,6,1.00,.00,1.00
-,9,1.00,.00,1.00
-Total,,3.00,1.00,4.00
-
-Table: Chi-square tests.
-z,Statistic,Value,df,Asymp. Sig. (2-tailed)
-1,Pearson Chi-Square,5.00,4,.287
-,Likelihood Ratio,5.00,4,.287
-,Linear-by-Linear Association,.01,1,.938
-,N of Valid Cases,5,,
-2,Pearson Chi-Square,4.00,3,.261
-,Likelihood Ratio,4.50,3,.212
-,Linear-by-Linear Association,1.58,1,.209
-,N of Valid Cases,4,,
-
-Table: Symmetric measures.
-z,Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-1,Nominal by Nominal,Phi,1.00,,,
-,,Cramer's V,1.00,,,
-,,Contingency Coefficient,.71,,,
-,Ordinal by Ordinal,Kendall's tau-b,.00,.32,.00,
-,,Kendall's tau-c,.00,.32,.00,
-,,Gamma,.00,.50,.00,
-,,Spearman Correlation,.00,.22,.00,
-,Interval by Interval,Pearson's R,.04,.22,.07,
-,N of Valid Cases,,5,,,
-2,Nominal by Nominal,Phi,1.00,,,
-,,Cramer's V,1.00,,,
-,,Contingency Coefficient,.71,,,
-,Ordinal by Ordinal,Kendall's tau-b,-.71,.20,-1.73,
-,,Kendall's tau-c,-.75,.43,-1.73,
-,,Gamma,-1.00,.00,-1.73,
-,,Spearman Correlation,-.77,.17,-1.73,
-,Interval by Interval,Pearson's R,-.73,.18,-1.49,
-,N of Valid Cases,,4,,,
-
-Table: Directional measures.
-z,Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-1,Nominal by Nominal,Lambda,Symmetric,.40,.28,1.12,.264
-,,,x Dependent,.25,.22,1.12,.264
-,,,y Dependent,1.00,.00,1.12,.264
-,,Goodman and Kruskal tau,x Dependent,.25,,,.   @&t@
-,,,y Dependent,1.00,,,.   @&t@
-,,Uncertainty Coefficient,Symmetric,.47,.18,,.   @&t@
-,,,x Dependent,.31,.15,2.02,.   @&t@
-,,,y Dependent,1.00,.00,2.02,.   @&t@
-,Ordinal by Ordinal,Somers' d,Symmetric,.00,,.00,1.000
-,,,x Dependent,.00,.50,.00,1.000
-,,,y Dependent,.00,.20,.00,1.000
-,Nominal by Interval,Eta,x Dependent,.04,,,.   @&t@
-,,,y Dependent,1.00,,,.   @&t@
-2,Nominal by Nominal,Lambda,Symmetric,.50,.25,2.00,.046
-,,,x Dependent,.33,.27,1.15,.248
-,,,y Dependent,1.00,.00,1.15,.248
-,,Goodman and Kruskal tau,x Dependent,.33,,,.   @&t@
-,,,y Dependent,1.00,,,.   @&t@
-,,Uncertainty Coefficient,Symmetric,.58,.17,,.   @&t@
-,,,x Dependent,.41,.17,2.36,.   @&t@
-,,,y Dependent,1.00,.00,2.36,.   @&t@
-,Ordinal by Ordinal,Somers' d,Symmetric,-.67,,-1.73,.083
-,,,x Dependent,-1.00,.00,-1.73,.083
-,,,y Dependent,-.50,.29,-1.73,.083
-,Nominal by Interval,Eta,x Dependent,.73,,,.   @&t@
-,,,y Dependent,1.00,,,.   @&t@
-]])
+x × y × z,9,100.0%,0,.0%,9,100.0%
+
+Table: x × y × z
+,,,,,y,,Total
+,,,,,1,2,
+z,1,x,1,Count,1,0,1
+,,,3,,0,0,1
+,,,5,,1,0,1
+,,,7,,0,0,1
+,,,8,,0,1,1
+,,Total,,,4,1,5
+,2,x,2,,0,0,1
+,,,4,,0,1,1
+,,,6,,0,0,1
+,,,9,,1,0,1
+,,Total,,,3,1,4
+
+Table: Chi-Square Tests
+,,,Value,df,Asymptotic Sig. (2-tailed)
+z,1,Pearson Chi-Square,5.00,4,.287
+,,Likelihood Ratio,5.00,4,.287
+,,Linear-by-Linear Association,.01,1,.938
+,,N of Valid Cases,5,,
+,2,Pearson Chi-Square,4.00,3,.261
+,,Likelihood Ratio,4.50,3,.212
+,,Linear-by-Linear Association,1.58,1,.209
+,,N of Valid Cases,4,,
+
+Table: Symmetric Measures
+,,,,Value,Asymp. Std. Error,Approx. T
+z,1,Nominal by Nominal,Phi,1.00,,
+,,,Cramer's V,1.00,,
+,,,Contingency Coefficient,.71,,
+,,Ordinal by Ordinal,Kendall's tau-b,.00,.32,.00
+,,,Kendall's tau-c,.00,.32,.00
+,,,Gamma,.00,.50,.00
+,,,Spearman Correlation,.00,.22,.00
+,,Interval by Interval,Pearson's R,.04,.22,.07
+,,N of Valid Cases,,5,,
+,2,Nominal by Nominal,Phi,1.00,,
+,,,Cramer's V,1.00,,
+,,,Contingency Coefficient,.71,,
+,,Ordinal by Ordinal,Kendall's tau-b,-.71,.20,-1.73
+,,,Kendall's tau-c,-.75,.43,-1.73
+,,,Gamma,-1.00,.00,-1.73
+,,,Spearman Correlation,-.77,.17,-1.73
+,,Interval by Interval,Pearson's R,-.73,.18,-1.49
+,,N of Valid Cases,,4,,
+
+Table: Directional Measures
+,,,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
+z,1,Nominal by Nominal,Lambda,Symmetric,.40,.28,1.12,.264
+,,,,x Dependent,.25,.22,1.12,.264
+,,,,y Dependent,1.00,.00,1.12,.264
+,,,Goodman and Kruskal tau,x Dependent,.25,,,
+,,,,y Dependent,1.00,,,
+,,,Uncertainty Coefficient,Symmetric,.47,.18,,
+,,,,x Dependent,.31,.15,2.02,
+,,,,y Dependent,1.00,.00,2.02,
+,,Ordinal by Ordinal,Somers' d,Symmetric,.00,,.00,1.000
+,,,,x Dependent,.00,.50,.00,1.000
+,,,,y Dependent,.00,.20,.00,1.000
+,,Nominal by Interval,Eta,x Dependent,.04,,,
+,,,,y Dependent,1.00,,,
+,2,Nominal by Nominal,Lambda,Symmetric,.50,.25,2.00,.046
+,,,,x Dependent,.33,.27,1.15,.248
+,,,,y Dependent,1.00,.00,1.15,.248
+,,,Goodman and Kruskal tau,x Dependent,.33,,,
+,,,,y Dependent,1.00,,,
+,,,Uncertainty Coefficient,Symmetric,.58,.17,,
+,,,,x Dependent,.41,.17,2.36,
+,,,,y Dependent,1.00,.00,2.36,
+,,Ordinal by Ordinal,Somers' d,Symmetric,-.67,,-1.73,.083
+,,,,x Dependent,-1.00,.00,-1.73,.083
+,,,,y Dependent,-.50,.29,-1.73,.083
+,,Nominal by Interval,Eta,x Dependent,.73,,,
+,,,,y Dependent,1.00,,,
+])
 AT_CLEANUP
 
 AT_SETUP([CROSSTABS rounding weights with COUNT])
@@ -473,85 +481,86 @@ CROSSTABS /TABLES x BY y /COUNT.
 CROSSTABS /TABLES x BY y /COUNT TRUNCATE.
 ]])
 
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
-  [[Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps])
+AT_CHECK([cat pspp.csv], [0],
+  [Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+x × y,9.00,100.0%,.00,.0%,9.00,100.0%
 
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,2.80,3.20,6.00
-2.00,1.00,2.00,3.00
-Total,3.80,5.20,9.00
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,2.80,3.20,6.00
+,2.00,,1.00,2.00,3.00
+Total,,,3.80,5.20,9.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+x × y,9.00,100.0%,.00,.0%,9.00,100.0%
 
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,2.80,3.20,6.00
-2.00,1.00,2.00,3.00
-Total,3.80,5.20,9.00
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,2.80,3.20,6.00
+,2.00,,1.00,2.00,3.00
+Total,,,3.80,5.20,9.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+x × y,9.00,100.0%,.00,.0%,9.00,100.0%
 
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,2.00,4.00,6.00
-2.00,1.00,2.00,3.00
-Total,3.00,6.00,9.00
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,2.00,4.00,6.00
+,2.00,,1.00,2.00,3.00
+Total,,,3.00,6.00,9.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,7.00,100.0%,.00,0.0%,7.00,100.0%
+x × y,7.00,100.0%,.00,.0%,7.00,100.0%
 
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,2.00,2.00,4.00
-2.00,1.00,2.00,3.00
-Total,3.00,4.00,7.00
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,2.00,2.00,4.00
+,2.00,,1.00,2.00,3.00
+Total,,,3.00,4.00,7.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+x × y,9.00,100.0%,.00,.0%,9.00,100.0%
 
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,3.00,3.00,6.00
-2.00,1.00,2.00,3.00
-Total,4.00,5.00,9.00
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,3.00,3.00,6.00
+,2.00,,1.00,2.00,3.00
+Total,,,4.00,5.00,9.00
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,8.00,100.0%,.00,0.0%,8.00,100.0%
-
-Table: x * y [count].
-,y,,
-x,1.00,2.00,Total
-1.00,2.00,3.00,5.00
-2.00,1.00,2.00,3.00
-Total,3.00,5.00,8.00
-]])
+x × y,8.00,100.0%,.00,.0%,8.00,100.0%
+
+Table: x × y
+,,,y,,Total
+,,,1.00,2.00,
+x,1.00,Count,2.00,3.00,5.00
+,2.00,,1.00,2.00,3.00
+Total,,,3.00,5.00,8.00
+])
 AT_CLEANUP
 
 AT_SETUP([CROSSTABS descending sort order])
@@ -571,21 +580,22 @@ CROSSTABS
        /FORMAT = DVALUE.
 ]])
 
-AT_CHECK([pspp -O format=csv crosstabs-descending.sps], [0],
-  [[Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs-descending.sps])
+AT_CHECK([cat pspp.csv], [0],
+  [Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,6,100.0%,0,0.0%,6,100.0%
-
-Table: x * y [count].
-,y,,
-x,2.00,1.00,Total
-4.00,.00,1.00,1.00
-3.00,2.00,1.00,3.00
-2.00,2.00,.00,2.00
-Total,4.00,2.00,6.00
-]])
+x × y,6,100.0%,0,.0%,6,100.0%
+
+Table: x × y
+,,,y,,Total
+,,,2.00,1.00,
+x,4.00,Count,0,1,1
+,3.00,,2,1,3
+,2.00,,2,0,2
+Total,,,4,2,6
+])
 AT_CLEANUP
 
 # Bug #31260.
@@ -601,13 +611,13 @@ MISSING VALUES x2 (1).
 CROSSTABS /TABLES= X1 by X2.
 ])
 AT_CHECK([pspp -O format=csv crosstabs.sps], [0], [dnl
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X1 * X2,0,0.0%,1,100.0%,1,100.0%
+X1 × X2,0,.0%,1,100.0%,1,100.0%
 
-crosstabs.sps:8: warning: CROSSTABS: Crosstabulation X1 * X2 contained no non-missing cases.
+crosstabs.sps:8: warning: CROSSTABS: Crosstabulation X1 × X2 contained no non-missing cases.
 ])
 AT_CLEANUP
 
@@ -833,22 +843,22 @@ crosstabs /tables = schtyp by female /statistic = chisq.
 crosstabs /tables = female by ses  /statistic = chisq.
 ])
 
-AT_CHECK([pspp -O format=csv fisher-exact.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt fisher-exact.sps])
+AT_CHECK([cat pspp.csv], [0], [Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-type of school * female,200,100.0%,0,0.0%,200,100.0%
+type of school × female,200,100.0%,0,.0%,200,100.0%
 
-Table: type of school * female [[count]].
-,female,,
-type of school,male,female,Total
-public,77.000,91.000,168.000
-private,14.000,18.000,32.000
-Total,91.000,109.000,200.000
+Table: type of school × female
+,,,female,,Total
+,,,male,female,
+type of school,public,Count,77,91,168
+,private,,14,18,32
+Total,,,91,109,200
 
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
 Pearson Chi-Square,.047,1,.828,,
 Likelihood Ratio,.047,1,.828,,
 Fisher's Exact Test,,,,.849,.492
@@ -856,21 +866,21 @@ Continuity Correction,.001,1,.981,,
 Linear-by-Linear Association,.047,1,.829,,
 N of Valid Cases,200,,,,
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-female * ses,200,100.0%,0,0.0%,200,100.0%
+female × ses,200,100.0%,0,.0%,200,100.0%
 
-Table: female * ses [[count]].
-,ses,,,
-female,low,middle,high,Total
-male,15.000,47.000,29.000,91.000
-female,32.000,48.000,29.000,109.000
-Total,47.000,95.000,58.000,200.000
+Table: female × ses
+,,,ses,,,Total
+,,,low,middle,high,
+female,male,Count,15,47,29,91
+,female,,32,48,29,109
+Total,,,47,95,58,200
 
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed)
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed)
 Pearson Chi-Square,4.577,2,.101
 Likelihood Ratio,4.679,2,.096
 Linear-by-Linear Association,3.110,1,.078
@@ -879,8 +889,7 @@ N of Valid Cases,200,,
 
 AT_CLEANUP
 
-AT_SETUP([CROSSTABS Pearson's R])
-# Test 1.
+AT_SETUP([CROSSTABS Pearson's R - 1])
 AT_DATA([pearson.sps], [dnl
 SET FORMAT F8.3.
 
@@ -895,30 +904,32 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CORR.
 ])
-AT_CHECK([pspp -O format=csv pearson.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,5,100.0%,0,0.0%,5,100.0%
-
-Table: x * y [[count]].
-,y,,,,,
-x,4.000,6.000,10.000,12.000,13.000,Total
-1.000,1.000,.000,.000,.000,.000,1.000
-3.000,.000,1.000,.000,.000,.000,1.000
-5.000,.000,.000,1.000,1.000,.000,2.000
-6.000,.000,.000,.000,.000,1.000,1.000
-Total,1.000,1.000,1.000,1.000,1.000,5.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Spearman Correlation,.975,.022,7.550,
-Interval by Interval,Pearson's R,.968,.017,6.708,
-N of Valid Cases,,5,,,
+x × y,5,100.0%,0,.0%,5,100.0%
+
+Table: x × y
+,,,y,,,,,Total
+,,,4.000,6.000,10.000,12.000,13.000,
+x,1.000,Count,1,0,0,0,0,1
+,3.000,,0,1,0,0,0,1
+,5.000,,0,0,1,1,0,2
+,6.000,,0,0,0,0,1,1
+Total,,,1,1,1,1,1,5
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Spearman Correlation,.975,.022,7.550
+Interval by Interval,Pearson's R,.968,.017,6.708
+N of Valid Cases,,5,,
 ])
+AT_CLEANUP
 
-# Test 2.
+AT_SETUP([CROSSTABS Pearson's R - 2])
 AT_DATA([pearson2.sps], [dnl
 SET FORMAT F8.3.
 
@@ -938,36 +949,38 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CORR.
 ])
-AT_CHECK([pspp -O format=csv pearson2.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson2.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,10,100.0%,0,0.0%,10,100.0%
-
-Table: x * y [[count]].
-,y,,,,,,,,,
-x,1.500,4.000,5.000,6.000,6.500,7.000,9.000,10.500,11.000,Total
-1.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-2.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-3.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000
-4.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000
-5.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000
-6.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000
-7.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000
-8.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000
-9.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,1.000
-10.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000
-Total,2.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,10.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Spearman Correlation,.973,.015,11.844,
-Interval by Interval,Pearson's R,.971,.017,11.580,
-N of Valid Cases,,10,,,
+x × y,10,100.0%,0,.0%,10,100.0%
+
+Table: x × y
+,,,y,,,,,,,,,Total
+,,,1.500,4.000,5.000,6.000,6.500,7.000,9.000,10.500,11.000,
+x,1.000,Count,1,0,0,0,0,0,0,0,0,1
+,2.000,,1,0,0,0,0,0,0,0,0,1
+,3.000,,0,1,0,0,0,0,0,0,0,1
+,4.000,,0,0,0,1,0,0,0,0,0,1
+,5.000,,0,0,1,0,0,0,0,0,0,1
+,6.000,,0,0,0,0,0,1,0,0,0,1
+,7.000,,0,0,0,0,1,0,0,0,0,1
+,8.000,,0,0,0,0,0,0,1,0,0,1
+,9.000,,0,0,0,0,0,0,0,1,0,1
+,10.000,,0,0,0,0,0,0,0,0,1,1
+Total,,,2,1,1,1,1,1,1,1,1,10
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Spearman Correlation,.973,.015,11.844
+Interval by Interval,Pearson's R,.971,.017,11.580
+N of Valid Cases,,10,,
 ])
+AT_CLEANUP
 
-# Test 3.
+AT_SETUP([CROSSTABS Pearson's R - 3])
 AT_DATA([pearson3.sps], [dnl
 SET FORMAT F8.3.
 
@@ -986,33 +999,35 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CORR.
 ])
-AT_CHECK([pspp -O format=csv pearson3.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson3.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,9,100.0%,0,0.0%,9,100.0%
-
-Table: x * y [[count]].
-,y,,,,,,,,
-x,28.000,58.000,66.000,75.000,85.000,87.000,91.000,122.000,Total
-25.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000
-35.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000
-44.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000
-50.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000
-56.000,.000,.000,.000,.000,.000,1.000,1.000,.000,2.000
-65.000,.000,.000,.000,.000,1.000,.000,1.000,.000,2.000
-87.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000
-Total,1.000,1.000,1.000,1.000,1.000,1.000,2.000,1.000,9.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Spearman Correlation,.911,.068,5.860,
-Interval by Interval,Pearson's R,.966,.017,9.915,
-N of Valid Cases,,9,,,
+x × y,9,100.0%,0,.0%,9,100.0%
+
+Table: x × y
+,,,y,,,,,,,,Total
+,,,28.000,58.000,66.000,75.000,85.000,87.000,91.000,122.000,
+x,25.000,Count,1,0,0,0,0,0,0,0,1
+,35.000,,0,1,0,0,0,0,0,0,1
+,44.000,,0,0,1,0,0,0,0,0,1
+,50.000,,0,0,0,1,0,0,0,0,1
+,56.000,,0,0,0,0,0,1,1,0,2
+,65.000,,0,0,0,0,1,0,1,0,2
+,87.000,,0,0,0,0,0,0,0,1,1
+Total,,,1,1,1,1,1,1,2,1,9
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Spearman Correlation,.911,.068,5.860
+Interval by Interval,Pearson's R,.966,.017,9.915
+N of Valid Cases,,9,,
 ])
+AT_CLEANUP
 
-# Test 4.
+AT_SETUP([CROSSTABS Pearson's R - 4])
 AT_DATA([pearson4.sps], [dnl
 SET FORMAT F8.3.
 
@@ -1034,35 +1049,37 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CORR.
 ])
-AT_CHECK([pspp -O format=csv pearson4.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson4.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,12,100.0%,0,0.0%,12,100.0%
-
-Table: x * y [[count]].
-,y,,,,,,,,,,,,
-x,2.000,4.000,5.000,7.000,9.000,11.000,12.000,14.000,15.000,17.000,18.000,20.000,Total
-2.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-3.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000
-4.000,.000,.000,.000,.000,1.000,1.000,.000,.000,.000,.000,.000,.000,2.000
-5.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-6.000,1.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,2.000
-7.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000
-8.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000
-9.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000
-10.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000,2.000
-Total,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,12.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Spearman Correlation,.657,.140,2.758,
-Interval by Interval,Pearson's R,.667,.132,2.830,
-N of Valid Cases,,12,,,
+x × y,12,100.0%,0,.0%,12,100.0%
+
+Table: x × y
+,,,y,,,,,,,,,,,,Total
+,,,2.000,4.000,5.000,7.000,9.000,11.000,12.000,14.000,15.000,17.000,18.000,20.000,
+x,2.000,Count,0,0,0,1,0,0,0,0,0,0,0,0,1
+,3.000,,0,0,0,0,0,0,1,0,0,0,0,0,1
+,4.000,,0,0,0,0,1,1,0,0,0,0,0,0,2
+,5.000,,0,0,1,0,0,0,0,0,0,0,0,0,1
+,6.000,,1,1,0,0,0,0,0,0,0,0,0,0,2
+,7.000,,0,0,0,0,0,0,0,1,0,0,0,0,1
+,8.000,,0,0,0,0,0,0,0,0,1,0,0,0,1
+,9.000,,0,0,0,0,0,0,0,0,0,1,0,0,1
+,10.000,,0,0,0,0,0,0,0,0,0,0,1,1,2
+Total,,,1,1,1,1,1,1,1,1,1,1,1,1,12
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Spearman Correlation,.657,.140,2.758
+Interval by Interval,Pearson's R,.667,.132,2.830
+N of Valid Cases,,12,,
 ])
+AT_CLEANUP
 
-# Test 5.
+AT_SETUP([CROSSTABS Pearson's R - 5])
 AT_DATA([pearson5.sps], [dnl
 SET FORMAT F8.3.
 
@@ -1082,37 +1099,38 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CORR.
 ])
-AT_CHECK([pspp -O format=csv pearson5.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt pearson5.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,10,100.0%,0,0.0%,10,100.0%
-
-Table: x * y [[count]].
-,y,,,,,,,,,,
-x,15000.000,26000.000,29000.000,32000.000,33000.000,41000.000,45000.000,52000.000,68000.000,80000.000,Total
-18.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-24.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000
-25.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,.000,1.000
-26.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,.000,1.000
-33.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,.000,1.000
-37.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,.000,1.000
-40.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,.000,1.000
-45.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,.000,1.000
-57.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,.000,1.000
-64.000,.000,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000
-Total,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,10.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Spearman Correlation,1.000,.000,+Infinity,
-Interval by Interval,Pearson's R,.992,.004,22.638,
-N of Valid Cases,,10,,,
+x × y,10,100.0%,0,.0%,10,100.0%
+
+Table: x × y
+,,,y,,,,,,,,,,Total
+,,,15000.00,26000.00,29000.00,32000.00,33000.00,41000.00,45000.00,52000.00,68000.00,80000.00,
+x,18.000,Count,1,0,0,0,0,0,0,0,0,0,1
+,24.000,,0,1,0,0,0,0,0,0,0,0,1
+,25.000,,0,0,1,0,0,0,0,0,0,0,1
+,26.000,,0,0,0,1,0,0,0,0,0,0,1
+,33.000,,0,0,0,0,1,0,0,0,0,0,1
+,37.000,,0,0,0,0,0,1,0,0,0,0,1
+,40.000,,0,0,0,0,0,0,1,0,0,0,1
+,45.000,,0,0,0,0,0,0,0,1,0,0,1
+,57.000,,0,0,0,0,0,0,0,0,1,0,1
+,64.000,,0,0,0,0,0,0,0,0,0,1,1
+Total,,,1,1,1,1,1,1,1,1,1,1,10
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Spearman Correlation,1.000,.000,+Infinit
+Interval by Interval,Pearson's R,.992,.004,22.638
+N of Valid Cases,,10,,
 ])
 AT_CLEANUP
 
-AT_SETUP([CROSSTABS Goodman and Kruskal's lambda])
+AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 1])
 AT_DATA([lambda.sps], [dnl
 SET FORMAT F8.3.
 
@@ -1129,6 +1147,28 @@ BEGIN DATA.
 END DATA.
 
 CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x × y,1296.000,100.0%,.000,.0%,1296.000,100.0%
+
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
+Nominal by Nominal,Lambda,Symmetric,.423,.021,16.875,.000
+,,x Dependent,.497,.024,15.986,.000
+,,y Dependent,.370,.020,16.339,.000
+,Goodman and Kruskal tau,x Dependent,.382,,,
+,,y Dependent,.198,,,
+])
+AT_CLEANUP
+
+AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 2])
+AT_DATA([lambda.sps], [dnl
+SET FORMAT F8.3.
 
 * From http://vassarstats.net.
 DATA LIST LIST NOTABLE/x y w.
@@ -1146,6 +1186,28 @@ BEGIN DATA.
 END DATA.
 
 CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x × y,137.000,100.0%,.000,.0%,137.000,100.0%
+
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
+Nominal by Nominal,Lambda,Symmetric,.259,.081,2.902,.004
+,,x Dependent,.250,.089,2.479,.013
+,,y Dependent,.267,.085,2.766,.006
+,Goodman and Kruskal tau,x Dependent,.129,,,
+,,y Dependent,.123,,,
+])
+AT_CLEANUP
+
+AT_SETUP([CROSSTABS Goodman and Kruskal's lambda - 3])
+AT_DATA([lambda.sps], [dnl
+SET FORMAT F8.3.
 
 * From Goodman, L.A., Kruskal, W.H. (1954) "Measures of association for
   cross classifications". Part I. Journal of the American Statistical
@@ -1168,48 +1230,21 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA.
 ])
-AT_CHECK([pspp -O format=csv lambda.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,1296.000,100.0%,.000,0.0%,1296.000,100.0%
+x × y,6800.000,100.0%,.000,.0%,6800.000,100.0%
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Nominal by Nominal,Lambda,Symmetric,.423,.021,16.875,.000
-,,x Dependent,.497,.024,15.986,.000
-,,y Dependent,.370,.020,16.339,.000
-,Goodman and Kruskal tau,x Dependent,.382,,,.   @&t@
-,,y Dependent,.198,,,.   @&t@
-
-Table: Summary.
-,Cases,,,,,
-,Valid,,Missing,,Total,
-,N,Percent,N,Percent,N,Percent
-x * y,137.000,100.0%,.000,0.0%,137.000,100.0%
-
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Nominal by Nominal,Lambda,Symmetric,.259,.081,2.902,.004
-,,x Dependent,.250,.089,2.479,.013
-,,y Dependent,.267,.085,2.766,.006
-,Goodman and Kruskal tau,x Dependent,.129,,,.   @&t@
-,,y Dependent,.123,,,.   @&t@
-
-Table: Summary.
-,Cases,,,,,
-,Valid,,Missing,,Total,
-,N,Percent,N,Percent,N,Percent
-x * y,6800.000,100.0%,.000,0.0%,6800.000,100.0%
-
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.208,.010,18.793,.000
 ,,x Dependent,.224,.013,16.076,.000
 ,,y Dependent,.192,.012,14.438,.000
-,Goodman and Kruskal tau,x Dependent,.089,,,.   @&t@
-,,y Dependent,.081,,,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.089,,,
+,,y Dependent,.081,,,
 ])
 AT_CLEANUP
 
@@ -1231,24 +1266,25 @@ END DATA.
 
 CROSSTABS x BY y/CELLS=NONE/STATISTICS=LAMBDA.
 ])
-AT_CHECK([pspp -O format=csv lambda.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt lambda.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,500.000,100.0%,.000,0.0%,500.000,100.0%
+x × y,500.000,100.0%,.000,.0%,500.000,100.0%
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.031,.013,2.336,.019
 ,,x Dependent,.000,.000,NaN,NaN
 ,,y Dependent,.033,.014,2.336,.019
-,Goodman and Kruskal tau,x Dependent,.012,,,.   @&t@
-,,y Dependent,.009,,,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.012,,,
+,,y Dependent,.009,,,
 ])
 AT_CLEANUP
 
-AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma])
+AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 1])
 AT_DATA([somersd.sps], [dnl
 SET FORMAT F8.3.
 
@@ -1272,6 +1308,26 @@ BEGIN DATA.
 2 7 0.0375
 END DATA.
 CROSSTABS x BY y/STATISTICS=D/CELLS=NONE.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt somersd.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x × y,1.000000,100.0%,.000000,.0%,1.000000,100.0%
+
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
+Ordinal by Ordinal,Somers' d,Symmetric,-.084,,-.149,.882
+,,x Dependent,-.045,.300,-.149,.882
+,,y Dependent,-.684,2.378,-.149,.882
+])
+AT_CLEANUP
+
+AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 2])
+AT_DATA([somersd.sps], [dnl
+SET FORMAT F8.3.
 
 * From http://uregina.ca/~gingrich/gamma.pdf.
 DATA LIST LIST NOTABLE/x y w.
@@ -1289,39 +1345,30 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=BTAU CTAU GAMMA D/CELLS=NONE.
 ])
-AT_CHECK([pspp -O format=csv somersd.sps], [0], [dnl
-Table: Summary.
-,Cases,,,,,
-,Valid,,Missing,,Total,
-,N,Percent,N,Percent,N,Percent
-x * y,1.000000,100.0%,.000000,0.0%,1.000000,100.0%
-
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Somers' d,Symmetric,-.084,,-.149,.882
-,,x Dependent,-.045,.300,-.149,.882
-,,y Dependent,-.684,2.378,-.149,.882
-
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt somersd.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,687.000,100.0%,.000,0.0%,687.000,100.0%
+x × y,687.000,100.0%,.000,.0%,687.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,.372,.033,10.669,
-,Kendall's tau-c,.310,.029,10.669,
-,Gamma,.591,.043,10.669,
-N of Valid Cases,,687.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,.372,.033,10.669
+,Kendall's tau-c,.310,.029,10.669
+,Gamma,.591,.043,10.669
+N of Valid Cases,,687.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,.371,,10.669,.000
 ,,x Dependent,.351,.032,10.669,.000
 ,,y Dependent,.394,.035,10.669,.000
 ])
+AT_CLEANUP
 
+AT_SETUP([CROSSTABS Somers' D, Tau-B, Tau-C, Gamma - 3])
 AT_DATA([ordinal.sps], [dnl
 SET FORMAT F8.3.
 
@@ -1430,159 +1477,160 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=LAMBDA D PHI BTAU/CELLS=NONE.
 ])
-AT_CHECK([pspp -O format=csv ordinal.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt ordinal.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,150.000,100.0%,.000,0.0%,150.000,100.0%
+x × y,150.000,100.0%,.000,.0%,150.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841,
-,Gamma,1.000,.000,24.841,
-N of Valid Cases,,150.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841
+,Gamma,1.000,.000,24.841
+N of Valid Cases,,150.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,1.000,,24.841,.000
 ,,x Dependent,1.000,.000,24.841,.000
 ,,y Dependent,1.000,.000,24.841,.000
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,150.000,100.0%,.000,0.0%,150.000,100.0%
+x × y,150.000,100.0%,.000,.0%,150.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841,
-,Gamma,1.000,.000,24.841,
-N of Valid Cases,,150.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,1.000,.000,24.841
+,Gamma,1.000,.000,24.841
+N of Valid Cases,,150.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,1.000,,24.841,.000
 ,,x Dependent,1.000,.000,24.841,.000
 ,,y Dependent,1.000,.000,24.841,.000
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,150.000,100.0%,.000,0.0%,150.000,100.0%
+x × y,150.000,100.0%,.000,.0%,150.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,-1.000,.000,-24.841,
-,Gamma,-1.000,.000,-24.841,
-N of Valid Cases,,150.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,-1.000,.000,-24.841
+,Gamma,-1.000,.000,-24.841
+N of Valid Cases,,150.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,-1.000,,-24.841,.000
 ,,x Dependent,-1.000,.000,-24.841,.000
 ,,y Dependent,-1.000,.000,-24.841,.000
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,150.000,100.0%,.000,0.0%,150.000,100.0%
+x × y,150.000,100.0%,.000,.0%,150.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,.972,.007,24.841,
-,Gamma,1.000,.000,24.841,
-N of Valid Cases,,150.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,.972,.007,24.841
+,Gamma,1.000,.000,24.841
+N of Valid Cases,,150.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,.971,,24.841,.000
 ,,x Dependent,.944,.013,24.841,.000
 ,,y Dependent,1.000,.000,24.841,.000
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,150.000,100.0%,.000,0.0%,150.000,100.0%
+x × y,150.000,100.0%,.000,.0%,150.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,.119,.059,1.009,
-,Gamma,1.000,.000,1.009,
-N of Valid Cases,,150.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,.119,.059,1.009
+,Gamma,1.000,.000,1.009
+N of Valid Cases,,150.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,.035,,1.009,.313
 ,,x Dependent,.805,.032,1.009,.313
 ,,y Dependent,.018,.017,1.009,.313
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,148.000,100.0%,.000,0.0%,148.000,100.0%
+x × y,148.000,100.0%,.000,.0%,148.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Ordinal by Ordinal,Kendall's tau-b,-.208,.078,-2.641,
-,Gamma,-.381,.130,-2.641,
-N of Valid Cases,,148.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Ordinal by Ordinal,Kendall's tau-b,-.208,.078,-2.641
+,Gamma,-.381,.130,-2.641
+N of Valid Cases,,148.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Ordinal by Ordinal,Somers' d,Symmetric,-.206,,-2.641,.008
 ,,x Dependent,-.182,.069,-2.641,.008
 ,,y Dependent,-.237,.089,-2.641,.008
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,148.000,100.0%,.000,0.0%,148.000,100.0%
+x × y,148.000,100.0%,.000,.0%,148.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Nominal by Nominal,Phi,.731,,,
-,Cramer's V,.731,,,
-Ordinal by Ordinal,Gamma,-.110,.107,-1.022,
-N of Valid Cases,,148.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Nominal by Nominal,Phi,.731,,
+,Cramer's V,.731,,
+Ordinal by Ordinal,Gamma,-.110,.107,-1.022
+N of Valid Cases,,148.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.338,.059,4.743,.000
 ,,x Dependent,.640,.085,4.875,.000
 ,,y Dependent,.174,.050,3.248,.001
-,Goodman and Kruskal tau,x Dependent,.534,,,.   @&t@
-,,y Dependent,.167,,,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.534,,,
+,,y Dependent,.167,,,
 Ordinal by Ordinal,Somers' d,Symmetric,-.074,,-1.022,.307
 ,,x Dependent,-.060,.059,-1.022,.307
 ,,y Dependent,-.096,.094,-1.022,.307
 
-Table: Summary.
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,212.000,100.0%,.000,0.0%,212.000,100.0%
+x × y,212.000,100.0%,.000,.0%,212.000,100.0%
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Nominal by Nominal,Phi,.432,,,
-,Cramer's V,.249,,,
-Ordinal by Ordinal,Kendall's tau-b,.209,.062,3.338,
-N of Valid Cases,,212.000,,,
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Nominal by Nominal,Phi,.432,,
+,Cramer's V,.249,,
+Ordinal by Ordinal,Kendall's tau-b,.209,.062,3.338
+N of Valid Cases,,212.000,,
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.102,.067,1.473,.141
 ,,x Dependent,.027,.087,.302,.763
 ,,y Dependent,.165,.065,2.349,.019
-,Goodman and Kruskal tau,x Dependent,.051,,,.   @&t@
-,,y Dependent,.068,,,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.051,,,
+,,y Dependent,.068,,,
 Ordinal by Ordinal,Somers' d,Symmetric,.209,,3.338,.001
 ,,x Dependent,.202,.060,3.338,.001
 ,,y Dependent,.217,.064,3.338,.001
@@ -1611,24 +1659,25 @@ crosstabs /table = p1 by p2
        .
 ])
 
-AT_CHECK([pspp -O format=csv kappa.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt kappa.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-p1 * p2,20.000,100.0%,.000,0.0%,20.000,100.0%
-
-Table: p1 * p2 [[count]].
-,p2,,
-p1,.000,1.000,Total
-.000,18.000,1.000,19.000
-1.000,1.000,.000,1.000
-Total,19.000,1.000,20.000
-
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Measure of Agreement,Kappa,-.053,.037,-.235,
-N of Valid Cases,,20.000,,,
+p1 × p2,20.000,100.0%,.000,.0%,20.000,100.0%
+
+Table: p1 × p2
+,,,p2,,Total
+,,,.000,1.000,
+p1,.000,Count,18.000,1.000,19.000
+,1.000,,1.000,.000,1.000
+Total,,,19.000,1.000,20.000
+
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Measure of Agreement,Kappa,-.053,.037,-.235
+N of Valid Cases,,20.000,,
 ])
 
 AT_CLEANUP
@@ -1650,42 +1699,43 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=CHISQ PHI CC LAMBDA UC BTAU CTAU GAMMA D CORR/CELLS=NONE.
 ])
-AT_CHECK([pspp -O format=csv crosstabs.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt crosstabs.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,66.0000,100.0%,.0000,0.0%,66.0000,100.0%
+x × y,66.0000,100.0%,.0000,.0%,66.0000,100.0%
 
-Table: Chi-square tests.
-Statistic,Value,df,Asymp. Sig. (2-tailed)
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed)
 Pearson Chi-Square,6.9562,2.0000,.031
 Likelihood Ratio,6.6901,2.0000,.035
 Linear-by-Linear Association,5.8450,1.0000,.016
 N of Valid Cases,66.0000,,
 
-Table: Symmetric measures.
-Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
-Nominal by Nominal,Phi,.3246,,,
-,Cramer's V,.3246,,,
-,Contingency Coefficient,.3088,,,
-Ordinal by Ordinal,Kendall's tau-b,.2752,.0856,1.9920,
-,Kendall's tau-c,.1497,.0751,1.9920,
-,Gamma,.8717,.1250,1.9920,
-,Spearman Correlation,.2908,.0906,2.4311,
-Interval by Interval,Pearson's R,.2999,.0973,2.5147,
-N of Valid Cases,,66.0000,,,
-
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Symmetric Measures
+,,Value,Asymp. Std. Error,Approx. T
+Nominal by Nominal,Phi,.3246,,
+,Cramer's V,.3246,,
+,Contingency Coefficient,.3088,,
+Ordinal by Ordinal,Kendall's tau-b,.2752,.0856,1.9920
+,Kendall's tau-c,.1497,.0751,1.9920
+,Gamma,.8717,.1250,1.9920
+,Spearman Correlation,.2908,.0906,2.4311
+Interval by Interval,Pearson's R,.2999,.0973,2.5147
+N of Valid Cases,,66.0000,,
+
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.0455,.1629,.2723,.785
 ,,x Dependent,.0000,.0000,NaN,NaN
 ,,y Dependent,.0500,.1791,.2723,.785
-,Goodman and Kruskal tau,x Dependent,.1054,,,.   @&t@
-,,y Dependent,.0434,,,.   @&t@
-,Uncertainty Coefficient,Symmetric,.0780,.0474,,.   @&t@
-,,x Dependent,.2217,.1062,1.5373,.   @&t@
-,,y Dependent,.0473,.0306,1.5373,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.1054,,,
+,,y Dependent,.0434,,,
+,Uncertainty Coefficient,Symmetric,.0780,.0474,,
+,,x Dependent,.2217,.1062,1.5373,
+,,y Dependent,.0473,.0306,1.5373,
 Ordinal by Ordinal,Somers' d,Symmetric,.1960,,1.9920,.046
 ,,x Dependent,.1152,.0572,1.9920,.046
 ,,y Dependent,.6573,.1417,1.9920,.046
@@ -1709,27 +1759,82 @@ BEGIN DATA.
 END DATA.
 CROSSTABS x BY y/STATISTICS=LAMBDA UC/CELLS=NONE.
 ])
-AT_CHECK([pspp -O format=csv uc.sps], [0], [dnl
-Table: Summary.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt uc.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x * y,987.000,100.0%,.000,0.0%,987.000,100.0%
+x × y,987.000,100.0%,.000,.0%,987.000,100.0%
 
-Table: Directional measures.
-Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+Table: Directional Measures
+,,,Value,Asymp. Std. Error,Approx. T,Approx Sig.
 Nominal by Nominal,Lambda,Symmetric,.000,.000,NaN,NaN
 ,,x Dependent,.000,.000,NaN,NaN
 ,,y Dependent,.000,.000,NaN,NaN
-,Goodman and Kruskal tau,x Dependent,.076,,,.   @&t@
-,,y Dependent,.108,,,.   @&t@
-,Uncertainty Coefficient,Symmetric,.105,.012,,.   @&t@
-,,x Dependent,.073,.009,7.890,.   @&t@
-,,y Dependent,.184,.019,7.890,.   @&t@
+,Goodman and Kruskal tau,x Dependent,.076,,,
+,,y Dependent,.108,,,
+,Uncertainty Coefficient,Symmetric,.105,.012,,
+,,x Dependent,.073,.009,7.890,
+,,y Dependent,.184,.019,7.890,
 ])
 AT_CLEANUP
 
+AT_SETUP([CROSSTABS estimated risk])
+dnl Example data and expected output from
+dnl http://www.psychology.nottingham.ac.uk/staff/ddc/c8cxpa/further/Project_resources/SPSSCrosstabW.pdf
+AT_DATA([risk.sps], [dnl
+DATA LIST LIST /factor disease count (F8.0).
+WEIGHT BY count.
+VALUE LABELS /factor 0 'Placebo' 1 'Aspirin'
+             /disease 1 'No' 0 'Yes'.
+BEGIN DATA.
+0 1 80
+0 0 20
+1 1 135
+1 0 15
+END DATA.
+CROSSTABS factor BY disease/STATISTICS=RISK CHISQ.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt risk.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+factor,F8.0
+disease,F8.0
+count,F8.0
 
+Table: Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+factor × disease,250,100.0%,0,.0%,250,100.0%
+
+Table: factor × disease
+,,,disease,,Total
+,,,Yes,No,
+factor,Placebo,Count,20,80,100
+,Aspirin,,15,135,150
+Total,,,35,215,250
+
+Table: Chi-Square Tests
+,Value,df,Asymptotic Sig. (2-tailed),Exact Sig. (2-tailed),Exact Sig. (1-tailed)
+Pearson Chi-Square,4.98,1,.026,,
+Likelihood Ratio,4.88,1,.027,,
+Fisher's Exact Test,,,,.039,.021
+Continuity Correction,4.19,1,.041,,
+Linear-by-Linear Association,4.96,1,.026,,
+N of Valid Cases,250,,,,
+
+Table: Risk Estimate
+,Value,95% Confidence Interval,
+,,Lower,Upper
+Odds Ratio for factor (Placebo / Aspirin),2.25,2.25,2.25
+For cohort disease = Yes,1.08,1.08,1.08
+For cohort disease = No,.99,.99,.99
+N of Valid Cases,250.00,,
+])
+AT_CLEANUP
 
 AT_SETUP([CROSSTABS barchart])
 AT_DATA([bc.sps], [dnl
index 508f954e12cc69cda8a40f17f356d392c1a2db82..60ec213097d8a2bf41c901c2c5d8596e4e251174 100644 (file)
@@ -57,25 +57,27 @@ V14,1,15- 15,F1.0
 V15,1,16- 16,F1.0
 V16,1,17- 17,F1.0
 
-Table: Valid cases = 10; cases with missing value(s) = 0.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-V0,10,0,3.80,.84,2.66,7.07,-.03,1.33,.89,.69,8.00,1.00,9.00,38.00
-V1,10,0,4.60,.96,3.03,9.16,-1.39,1.33,-.03,.69,9.00,.00,9.00,46.00
-V2,10,0,4.10,1.16,3.67,13.43,-2.02,1.33,.48,.69,8.00,1.00,9.00,41.00
-V3,10,0,4.10,.87,2.77,7.66,-2.05,1.33,.42,.69,7.00,1.00,8.00,41.00
-V4,10,0,7.00,.47,1.49,2.22,7.15,1.33,-2.52,.69,5.00,3.00,8.00,70.00
-V5,10,0,4.90,1.03,3.25,10.54,-1.40,1.33,-.20,.69,9.00,.00,9.00,49.00
-V6,10,0,5.90,.80,2.51,6.32,-.29,1.33,-.96,.69,7.00,1.00,8.00,59.00
-V7,10,0,4.70,1.10,3.47,12.01,-1.99,1.33,-.16,.69,9.00,.00,9.00,47.00
-V8,10,0,4.10,1.10,3.48,12.10,-1.93,1.33,.37,.69,9.00,.00,9.00,41.00
-V9,10,0,4.30,.87,2.75,7.57,-.87,1.33,.73,.69,8.00,1.00,9.00,43.00
-V10,10,0,5.50,.85,2.68,7.17,-1.84,1.33,-.33,.69,7.00,2.00,9.00,55.00
-V11,10,0,6.50,.78,2.46,6.06,-1.28,1.33,-.89,.69,6.00,3.00,9.00,65.00
-V12,10,0,7.90,.60,1.91,3.66,5.24,1.33,-2.21,.69,6.00,3.00,9.00,79.00
-V13,10,0,4.30,.99,3.13,9.79,-1.25,1.33,.33,.69,9.00,.00,9.00,43.00
-V14,10,0,3.60,1.01,3.20,10.27,-.96,1.33,.81,.69,9.00,.00,9.00,36.00
-V15,10,0,3.70,.92,2.91,8.46,-1.35,1.33,.71,.69,7.00,1.00,8.00,37.00
-V16,10,0,6.40,.91,2.88,8.27,-1.14,1.33,-.92,.69,7.00,2.00,9.00,64.00
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+V0,10,3.80,.84,2.66,7.07,-.03,1.33,.89,.69,8.00,1,9,38.00
+V1,10,4.60,.96,3.03,9.16,-1.39,1.33,-.03,.69,9.00,0,9,46.00
+V2,10,4.10,1.16,3.67,13.43,-2.02,1.33,.48,.69,8.00,1,9,41.00
+V3,10,4.10,.87,2.77,7.66,-2.05,1.33,.42,.69,7.00,1,8,41.00
+V4,10,7.00,.47,1.49,2.22,7.15,1.33,-2.52,.69,5.00,3,8,70.00
+V5,10,4.90,1.03,3.25,10.54,-1.40,1.33,-.20,.69,9.00,0,9,49.00
+V6,10,5.90,.80,2.51,6.32,-.29,1.33,-.96,.69,7.00,1,8,59.00
+V7,10,4.70,1.10,3.47,12.01,-1.99,1.33,-.16,.69,9.00,0,9,47.00
+V8,10,4.10,1.10,3.48,12.10,-1.93,1.33,.37,.69,9.00,0,9,41.00
+V9,10,4.30,.87,2.75,7.57,-.87,1.33,.73,.69,8.00,1,9,43.00
+V10,10,5.50,.85,2.68,7.17,-1.84,1.33,-.33,.69,7.00,2,9,55.00
+V11,10,6.50,.78,2.46,6.06,-1.28,1.33,-.89,.69,6.00,3,9,65.00
+V12,10,7.90,.60,1.91,3.66,5.24,1.33,-2.21,.69,6.00,3,9,79.00
+V13,10,4.30,.99,3.13,9.79,-1.25,1.33,.33,.69,9.00,0,9,43.00
+V14,10,3.60,1.01,3.20,10.27,-.96,1.33,.81,.69,9.00,0,9,36.00
+V15,10,3.70,.92,2.91,8.46,-1.35,1.33,.71,.69,7.00,1,8,37.00
+V16,10,6.40,.91,2.88,8.27,-1.14,1.33,-.92,.69,7.00,2,9,64.00
+Valid N (listwise),10,,,,,,,,,,,,
+Missing N (listwise),0,,,,,,,,,,,,
 ])
 AT_CLEANUP
 
@@ -98,12 +100,14 @@ AT_DATA([descriptives.sps],
   [DESCRIPTIVES_MISSING_DATA
 descript all/stat=all/format=serial.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0],
-  [Table: Valid cases = 7; cases with missing value(s) = 6.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-V1,1,6,2.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,2.00,2.00,2.00
-V2,2,5,2.50,.50,.71,.50,.  ,.  ,.  ,.  ,1.00,2.00,3.00,5.00
-V3,3,4,3.00,.58,1.00,1.00,.  ,.  ,.00,1.22,2.00,2.00,4.00,9.00
+AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+V1,1,2.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,2,2,2.00
+V2,2,2.50,.50,.71,.50,.  ,.  ,.  ,.  ,1.00,2,3,5.00
+V3,3,3.00,.58,1.00,1.00,.  ,.  ,.00,1.22,2.00,2,4,9.00
+Valid N (listwise),7,,,,,,,,,,,,
+Missing N (listwise),6,,,,,,,,,,,,
 ])
 AT_CLEANUP
 
@@ -112,12 +116,14 @@ AT_DATA([descriptives.sps],
   [DESCRIPTIVES_MISSING_DATA
 descript all/stat=all/format=serial/missing=include.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0],
-  [Table: Valid cases = 7; cases with missing value(s) = 3.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-V1,5,2,1.20,.20,.45,.20,5.00,2.00,2.24,.91,1.00,1.00,2.00,6.00
-V2,5,2,1.60,.40,.89,.80,.31,2.00,1.26,.91,2.00,1.00,3.00,8.00
-V3,5,2,2.20,.58,1.30,1.70,-1.49,2.00,.54,.91,3.00,1.00,4.00,11.00
+AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+V1,5,1.20,.20,.45,.20,5.00,2.00,2.24,.91,1.00,1,2,6.00
+V2,5,1.60,.40,.89,.80,.31,2.00,1.26,.91,2.00,1,3,8.00
+V3,5,2.20,.58,1.30,1.70,-1.49,2.00,.54,.91,3.00,1,4,11.00
+Valid N (listwise),7,,,,,,,,,,,,
+Missing N (listwise),3,,,,,,,,,,,,
 ])
 AT_CLEANUP
 
@@ -126,12 +132,14 @@ AT_DATA([descriptives.sps],
   [DESCRIPTIVES_MISSING_DATA
 descript all/stat=all/format=serial/missing=listwise.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0],
-  [Table: Valid cases = 1; cases with missing value(s) = 6.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-V1,1,0,2.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,2.00,2.00,2.00
-V2,1,0,3.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,3.00,3.00,3.00
-V3,1,0,4.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,4.00,4.00,4.00
+AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+V1,1,2.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,2,2,2.00
+V2,1,3.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,3,3,3.00
+V3,1,4.00,.  ,.  ,.  ,.  ,.  ,.  ,.  ,.00,4,4,4.00
+Valid N (listwise),1,,,,,,,,,,,,
+Missing N (listwise),6,,,,,,,,,,,,
 ])
 AT_CLEANUP
 
@@ -140,12 +148,14 @@ AT_DATA([descriptives.sps],
   [DESCRIPTIVES_MISSING_DATA
 descript all/stat=all/format=serial/missing=listwise include.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0],
-  [Table: Valid cases = 4; cases with missing value(s) = 3.
-Variable,Valid N,Missing N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
-V1,4,0,1.25,.25,.50,.25,4.00,2.62,2.00,1.01,1.00,1.00,2.00,5.00
-V2,4,0,1.75,.48,.96,.92,-1.29,2.62,.85,1.01,2.00,1.00,3.00,7.00
-V3,4,0,2.50,.65,1.29,1.67,-1.20,2.62,.00,1.01,3.00,1.00,4.00,10.00
+AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean,S.E. Mean,Std Dev,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,Range,Minimum,Maximum,Sum
+V1,4,1.25,.25,.50,.25,4.00,2.62,2.00,1.01,1.00,1,2,5.00
+V2,4,1.75,.48,.96,.92,-1.29,2.62,.85,1.01,2.00,1,3,7.00
+V3,4,2.50,.65,1.29,1.67,-1.20,2.62,.00,1.01,3.00,1,4,10.00
+Valid N (listwise),4,,,,,,,,,,,,
+Missing N (listwise),3,,,,,,,,,,,,
 ])
 AT_CLEANUP
 
@@ -165,10 +175,12 @@ end data.
 
 descript all/stat=mean.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0],
-  [Table: Valid cases = 6; cases with missing value(s) = 0.
-Variable,N,Mean
+AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean
 X,6,2.500
+Valid N (listwise),6,
+Missing N (listwise),0,
 ])
 AT_CLEANUP
 
@@ -194,9 +206,11 @@ SELECT IF id < 7 .
 DESCRIPTIVES /VAR=abc.
 ])
 AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
-Table: Valid cases = 6; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 abc,6,3.00,.84,2.00,4.00
+Valid N (listwise),6,,,,
+Missing N (listwise),0,,,,
 ])
 AT_CLEANUP
 
@@ -213,15 +227,17 @@ DESCRIPTIVES /VAR=a b /SAVE.
 LIST.
 ])
 AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
-Table: Mapping of variables to corresponding Z-scores.
+Table: Mapping of Variables to Z-scores
 Source,Target
 a,Za
 b,Zb
 
-Table: Valid cases = 3; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 a,3,2.00,1.00,1.00,3.00
 b,3,60.00,10.00,50.00,70.00
+Valid N (listwise),3,,,,
+Missing N (listwise),0,,,,
 
 Table: Data List
 a,b,Za,Zb
@@ -248,30 +264,38 @@ SPLIT FILE BY group.
 DESCRIPTIVES /VAR=a b /SAVE.
 LIST.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
-Table: Mapping of variables to corresponding Z-scores.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Mapping of Variables to Z-scores
 Source,Target
 a,Za
 b,Zb
 
-Variable,Value,Label
-group,1.00,
+Table: Split Values
+Variable,Value
+group,1.00
 
-Table: Valid cases = 3; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 a,3,2.00,1.00,1.00,3.00
 b,3,60.00,10.00,50.00,70.00
+Valid N (listwise),3,,,,
+Missing N (listwise),0,,,,
 
-Variable,Value,Label
-group,2.00,
+Table: Split Values
+Variable,Value
+group,2.00
 
-Table: Valid cases = 4; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 a,4,300.00,182.57,100.00,500.00
 b,4,8000.00,1825.74,6000.00,10000.00
+Valid N (listwise),4,,,,
+Missing N (listwise),0,,,,
 
-Variable,Value,Label
-group,1.00,
+Table: Split Values
+Variable,Value
+group,1.00
 
 Table: Data List
 group,a,b,Za,Zb
@@ -279,8 +303,9 @@ group,a,b,Za,Zb
 1.00,2.00,60.00,.00,.00
 1.00,3.00,70.00,1.00,1.00
 
-Variable,Value,Label
-group,2.00,
+Table: Split Values
+Variable,Value
+group,2.00
 
 Table: Data List
 group,a,b,Za,Zb
@@ -314,16 +339,21 @@ SELECT IF id < 7 .
 DESCRIPTIVES /VAR=abc/SAVE.
 LIST.
 ])
-AT_CHECK([pspp -O format=csv descriptives.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps], [0], [dnl
+descriptives.sps:15: warning: DESCRIPTIVES: DESCRIPTIVES with Z scores ignores TEMPORARY.  Temporary transformations will be made permanent.
+])
+AT_CHECK([cat pspp.csv], [0], [dnl
 descriptives.sps:15: warning: DESCRIPTIVES: DESCRIPTIVES with Z scores ignores TEMPORARY.  Temporary transformations will be made permanent.
 
-Table: Mapping of variables to corresponding Z-scores.
+Table: Mapping of Variables to Z-scores
 Source,Target
 abc,Zabc
 
-Table: Valid cases = 6; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 abc,6,3.00,.84,2.00,4.00
+Valid N (listwise),6,,,,
+Missing N (listwise),0,,,,
 
 Table: Data List
 id,abc,Zabc
@@ -391,3 +421,24 @@ filter1,filter2,x,Zx,ZSC001,ZSC002,ZSC003,ZSC004
 1.00,1.00,1.00,-.66,-1.26,-1.26,-1.00,-1.00
 ])
 AT_CLEANUP
+
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([DESCRIPTIVES tutorial example])
+cp $top_srcdir/examples/physiology.sav .
+AT_DATA([descriptives.sps], [dnl
+GET FILE='physiology.sav'.
+DESCRIPTIVES sex, weight, height.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt descriptives.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
+Sex of subject  ,40,.45,.50,Male,Female
+Weight in kilograms ,40,72.12,26.70,-55.6,92.1
+Height in millimeters   ,40,1677.12,262.87,179,1903
+Valid N (listwise),40,,,,
+Missing N (listwise),0,,,,
+])
+AT_CLEANUP
index 9d4374d376e0e96c731382a8f4bceb0121436189..b2afe616b86f5750e670d03b23adb561b885a0aa 100644 (file)
@@ -87,7 +87,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-Breaking Strain,24.00,100%,.00,0%,24.00,100%
+Breaking Strain,24.00,100.0%,.00,.0%,24.00,100.0%
 
 Table: Extreme Values
 ,,,Case Number,Value
@@ -118,9 +118,9 @@ Table: Case Processing Summary
 ,,Cases,,,,,
 ,,Valid,,Missing,,Total,
 ,Manufacturer,N,Percent,N,Percent,N,Percent
-Breaking Strain,Aspeger,8.00,100%,.00,0%,8.00,100%
-,Bloggs,8.00,100%,.00,0%,8.00,100%
-,Charlies,8.00,100%,.00,0%,8.00,100%
+Breaking Strain,Aspeger,8.00,100.0%,.00,.0%,8.00,100.0%
+,Bloggs,8.00,100.0%,.00,.0%,8.00,100.0%
+,Charlies,8.00,100.0%,.00,.0%,8.00,100.0%
 
 Table: Extreme Values
 ,Manufacturer,,,Case Number,Value
@@ -228,7 +228,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-V1,23.00,100%,.00,0%,23.00,100%
+V1,23.00,100.0%,.00,.0%,23.00,100.0%
 
 Table: Extreme Values
 ,,,Case Number,Value
@@ -290,7 +290,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x,19.430,100%,.000,0%,19.430,100%
+x,19.430,100.0%,.000,.0%,19.430,100.0%
 
 Table: Extreme Values
 ,,,Case Number,Value
@@ -352,7 +352,7 @@ EXAMINE /x
 EXAMINE /x
        /PERCENTILES=AEMPIRICAL.
 ])
-AT_CHECK([pspp -o pspp.csv examine.sps])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt examine.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
@@ -362,19 +362,19 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,3,100%,0,0%,3,100%
+X,3,100.0%,0,.0%,3,100.0%
 
 Table: Percentiles
 ,,Percentiles,,,,,,
 ,,5,10,25,50,75,90,95
-X,HAverage,.40,.80,2.00,5.00,8.00,8.00,8.00
+X,Weighted Average,.40,.80,2.00,5.00,8.00,8.00,8.00
 ,Tukey's Hinges,,,3.50,5.00,6.50,,
 
 Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,3,100%,0,0%,3,100%
+X,3,100.0%,0,.0%,3,100.0%
 
 Table: Percentiles
 ,,Percentiles,,,,,,
@@ -386,36 +386,36 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,3,100%,0,0%,3,100%
+X,3,100.0%,0,.0%,3,100.0%
 
 Table: Percentiles
 ,,Percentiles,,,,,,
 ,,5,10,25,50,75,90,95
-X,Rounded,.00,.00,2.00,5.00,5.00,8.00,8.00
+X,Weighted Average,.00,.00,2.00,5.00,5.00,8.00,8.00
 ,Tukey's Hinges,,,3.50,5.00,6.50,,
 
 Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,3,100%,0,0%,3,100%
+X,3,100.0%,0,.0%,3,100.0%
 
 Table: Percentiles
 ,,Percentiles,,,,,,
 ,,5,10,25,50,75,90,95
-X,Empirical,2.00,2.00,2.00,5.00,8.00,8.00,8.00
+X,Weighted Average,2.00,2.00,2.00,5.00,8.00,8.00,8.00
 ,Tukey's Hinges,,,3.50,5.00,6.50,,
 
 Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,3,100%,0,0%,3,100%
+X,3,100.0%,0,.0%,3,100.0%
 
 Table: Percentiles
 ,,Percentiles,,,,,,
 ,,5,10,25,50,75,90,95
-X,Empirical with averaging,2.00,2.00,2.00,5.00,8.00,8.00,8.00
+X,Weighted Average,2.00,2.00,2.00,5.00,8.00,8.00,8.00
 ,Tukey's Hinges,,,3.50,5.00,6.50,,
 ])
 AT_CLEANUP
@@ -449,14 +449,14 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x,6,85.7143%,1,14.2857%,7,100%
+x,6,85.7%,1,14.3%,7,100.0%
 
 Table: Case Processing Summary
 ,,Cases,,,,,
 ,,Valid,,Missing,,Total,
 ,y,N,Percent,N,Percent,N,Percent
-x,1.00,4,100%,0,0%,4,100%
-,2.00,2,66.6667%,1,33.3333%,3,100%
+x,1.00,4,100.0%,0,.0%,4,100.0%
+,2.00,2,66.7%,1,33.3%,3,100.0%
 ])
 AT_CLEANUP
 
@@ -483,8 +483,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x,1,33.3333%,2,66.6667%,3,100%
-y,2,66.6667%,1,33.3333%,3,100%
+x,1,33.3%,2,66.7%,3,100.0%
+y,2,66.7%,1,33.3%,3,100.0%
 ])
 AT_CLEANUP
 
@@ -537,7 +537,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,52.00,100%,.00,0%,52.00,100%
+X,52.00,100.0%,.00,.0%,52.00,100.0%
 
 Table: Descriptives
 ,,,Statistic,Std. Error
@@ -657,7 +657,7 @@ AT_CLEANUP
 
 dnl Test that big input doesn't crash (bug 11307).
 AT_SETUP([EXAMINE -- big input doesn't crash])
-AT_KEYWORDS([categorical categoricals])
+AT_KEYWORDS([categorical categoricals slow])
 AT_DATA([examine.sps], [dnl
 INPUT PROGRAM.
        LOOP #I=1 TO 50000.
@@ -678,7 +678,7 @@ AT_CLEANUP
 dnl Another test that big input doesn't crash.
 dnl The actual bug that this checks for has been lost.
 AT_SETUP([EXAMINE -- big input doesn't crash 2])
-AT_KEYWORDS([categorical categoricals])
+AT_KEYWORDS([categorical categoricals slow])
 AT_DATA([make-big-input.pl], 
   [for ($i=0; $i<100000; $i++) { print "AB12\n" };
    for ($i=0; $i<100000; $i++) { print "AB04\n" };
@@ -739,20 +739,20 @@ AT_CHECK([pspp -O format=csv examine-id.sps], [0],
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-x,14,100%,0,0%,14,100%
+x,14,100.0%,0,.0%,14,100.0%
 
 Table: Extreme Values
 ,,,y,Value
 x,Highest,1,threehundred,300.00
-,,2,thirty      ,30.00
-,,3,twelve      ,12.00
-,,4,eleven      ,11.00
-,,5,ten         ,10.00
-,Lowest,1,one         ,1.00
-,,2,two         ,2.00
-,,3,three       ,3.00
-,,4,four        ,4.00
-,,5,five        ,5.00
+,,2,thirty,30.00
+,,3,twelve,12.00
+,,4,eleven,11.00
+,,5,ten,10.00
+,Lowest,1,one,1.00
+,,2,two,2.00
+,,3,three,3.00
+,,4,four,4.00
+,,5,five,5.00
 ])
 
 AT_CLEANUP 
@@ -840,8 +840,9 @@ EXAMINE
 ])
 
 
-AT_CHECK([pspp -O format=csv examine-report.sps], [0], [dnl
-Table: Reading free-form data from INLINE.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt examine-report.sps])
+AT_CHECK([cat pspp.csv], [0],
+  [[Table: Reading free-form data from INLINE.
 Variable,Format
 x,F8.0
 g,F8.0
@@ -850,15 +851,18 @@ Table: Case Processing Summary
 ,,Cases,,,,,
 ,,Valid,,Missing,,Total,
 ,g,N,Percent,N,Percent,N,Percent
-x,. (missing),4,100%,0,0%,4,100%
-,1,9,100%,0,0%,9,100%
-,2,9,100%,0,0%,9,100%
-,9 (missing),4,100%,0,0%,4,100%
-,99 (missing),5,100%,0,0%,5,100%
+x,.,4,100.0%,0,.0%,4,100.0%
+,1,9,100.0%,0,.0%,9,100.0%
+,2,9,100.0%,0,.0%,9,100.0%
+,9[a],4,100.0%,0,.0%,4,100.0%
+,99[a],5,100.0%,0,.0%,5,100.0%
+
+Footnotes:
+a,User-missing value.
 
 Table: Extreme Values
 ,g,,,Case Number,Value
-x,. (missing),Highest,1,31,4004
+x,.,Highest,1,31,4004
 ,,,2,30,3003
 ,,,3,29,2002
 ,,,4,28,1001
@@ -888,7 +892,7 @@ x,. (missing),Highest,1,31,4004
 ,,,3,12,30
 ,,,4,13,40
 ,,,5,14,50
-,9 (missing),Highest,1,22,401
+,9[a],Highest,1,22,401
 ,,,2,21,301
 ,,,3,20,201
 ,,,4,19,101
@@ -898,7 +902,7 @@ x,. (missing),Highest,1,31,4004
 ,,,3,21,301
 ,,,4,22,401
 ,,,5,22,401
-,99 (missing),Highest,1,27,901
+,99[a],Highest,1,27,901
 ,,,2,26,801
 ,,,3,25,701
 ,,,4,24,601
@@ -908,8 +912,10 @@ x,. (missing),Highest,1,31,4004
 ,,,3,25,701
 ,,,4,26,801
 ,,,5,27,901
-])
 
+Footnotes:
+a,User-missing value.
+]])
 
 AT_CLEANUP 
 
@@ -1037,7 +1043,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-X,100,100%,0,0%,100,100%
+X,100,100.0%,0,.0%,100,100.0%
 
 Table: Descriptives
 ,,,Statistic,Std. Error
@@ -1136,7 +1142,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Valid,,Missing,,Total,
 ,N,Percent,N,Percent,N,Percent
-h,3.00,100%,.00,0%,3.00,100%
+h,3.00,100.0%,.00,.0%,3.00,100.0%
 
 Table: Extreme Values
 ,,,Case Number,Value
@@ -1150,5 +1156,97 @@ h,Highest,1,3,5.00
 
 AT_CLEANUP 
 
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([EXAMINE tutorial example 1])
+cp $top_srcdir/examples/repairs.sav .
+AT_DATA([repairs.sps], [dnl
+GET FILE='repairs.sav'.
+EXAMINE mtbf /STATISTICS=DESCRIPTIVES.
+COMPUTE mtbf_ln = LN (mtbf).
+EXAMINE mtbf_ln /STATISTICS=DESCRIPTIVES.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt repairs.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+Mean time between failures (months) ,15,100.0%,0,.0%,15,100.0%
+
+Table: Descriptives
+,,,Statistic,Std. Error
+Mean time between failures (months) ,Mean,,8.32,1.62
+,95% Confidence Interval for Mean,Lower Bound,4.85,
+,,Upper Bound,11.79,
+,5% Trimmed Mean,,7.69,
+,Median,,8.12,
+,Variance,,39.21,
+,Std. Deviation,,6.26,
+,Minimum,,1.63,
+,Maximum,,26.47,
+,Range,,24.84,
+,Interquartile Range,,5.83,
+,Skewness,,1.85,.58
+,Kurtosis,,4.49,1.12
 
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+mtbf_ln,15,100.0%,0,.0%,15,100.0%
+
+Table: Descriptives
+,,,Statistic,Std. Error
+mtbf_ln,Mean,,1.88,.19
+,95% Confidence Interval for Mean,Lower Bound,1.47,
+,,Upper Bound,2.29,
+,5% Trimmed Mean,,1.88,
+,Median,,2.09,
+,Variance,,.54,
+,Std. Deviation,,.74,
+,Minimum,,.49,
+,Maximum,,3.28,
+,Range,,2.79,
+,Interquartile Range,,.92,
+,Skewness,,-.16,.58
+,Kurtosis,,-.09,1.12
+])
+AT_CLEANUP
+
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([EXAMINE tutorial example 2])
+cp $top_srcdir/examples/physiology.sav .
+AT_DATA([examine.sps], [dnl
+GET FILE='physiology.sav'.
+EXAMINE height, weight /STATISTICS=EXTREME(3).
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt examine.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+Height in millimeters   ,40,100.0%,0,.0%,40,100.0%
+Weight in kilograms ,40,100.0%,0,.0%,40,100.0%
+
+Table: Extreme Values
+,,,Case Number,Value
+Height in millimeters   ,Highest,1,14,1903
+,,2,15,1884
+,,3,12,1802
+,Lowest,1,30,179
+,,2,31,1598
+,,3,28,1601
+Weight in kilograms ,Highest,1,13,92.1
+,,2,5,92.1
+,,3,17,91.7
+,Lowest,1,38,-55.6
+,,2,39,54.5
+,,3,33,55.4
+])
+AT_CLEANUP
 
index ac29f50cfc4e024d3840dd1c43b3f2eec580bc0f..ab0b066c2b88c16eec804755c0d198bbf737f777 100644 (file)
@@ -1487,7 +1487,7 @@ question24,3.666,.926,1365
 
 Table: Correlation Matrix
 ,,question13,question14,question15,question16,question17,question18,question19,question20,question21,question22,question23,question24
-Correlations,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564,.454
+Correlation,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564,.454
 ,question14,.661,1.000,.635,.500,.552,.433,.320,.315,.449,.333,.565,.443
 ,question15,.600,.635,1.000,.505,.587,.457,.359,.356,.509,.369,.582,.435
 ,question16,.566,.500,.505,1.000,.586,.405,.335,.317,.452,.363,.459,.430
@@ -1499,7 +1499,7 @@ Correlations,question13,1.000,.661,.600,.566,.577,.409,.286,.304,.476,.333,.564,
 ,question22,.333,.333,.369,.363,.450,.536,.484,.383,.507,1.000,.493,.444
 ,question23,.564,.565,.582,.459,.613,.569,.444,.410,.598,.493,1.000,.705
 ,question24,.454,.443,.435,.430,.521,.474,.374,.357,.500,.444,.705,1.000
-Determinant,.002,,,,,,,,,,,,
+Caption: Determinant: 0.00
 
 Table: Factor Matrix
 ,Factor,,
@@ -1767,12 +1767,12 @@ socst,1.000,.900
 
 Table: Total Variance Explained
 ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings,,
-Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
-1,3.381,67.616,67.616,3.381,67.616,67.616,2.113,42.267,42.267
-2,.557,11.148,78.764,.557,11.148,78.764,1.825,36.497,78.764
-3,.407,8.136,86.900,,,,,,
-4,.356,7.123,94.023,,,,,,
-5,.299,5.977,100.000,,,,,,
+,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
+1,3.381,67.6%,67.6%,3.381,67.6%,67.6%,2.113,42.3%,42.3%
+2,.557,11.1%,78.8%,.557,11.1%,78.8%,1.825,36.5%,78.8%
+3,.407,8.1%,86.9%,,,,,,
+4,.356,7.1%,94.0%,,,,,,
+5,.299,6.0%,100.0%,,,,,,
 
 Table: Component Matrix
 ,Component,
@@ -1848,17 +1848,17 @@ TRAIT5,7.29,2.66,7
 
 Table: Correlation Matrix
 ,,TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5
-Correlations,TRAIT1,1.00,.30,.88,1.00,.54
-,TRAIT2,.30,1.00,-.02,.33,.84
-,TRAIT3,.88,-.02,1.00,.87,.13
-,TRAIT4,1.00,.33,.87,1.00,.54
-,TRAIT5,.54,.84,.13,.54,1.00
+Correlation,TRAIT1,1.000,.296,.881,.995,.545
+,TRAIT2,.296,1.000,-.022,.326,.837
+,TRAIT3,.881,-.022,1.000,.867,.130
+,TRAIT4,.995,.326,.867,1.000,.544
+,TRAIT5,.545,.837,.130,.544,1.000
 Sig. (1-tailed),TRAIT1,,.260,.004,.000,.103
 ,TRAIT2,.260,,.482,.238,.009
 ,TRAIT3,.004,.482,,.006,.390
 ,TRAIT4,.000,.238,.006,,.103
 ,TRAIT5,.103,.009,.390,.103,
-Determinant,.00,,,,,
+Caption: Determinant: 0.00
 
 Table: Communalities
 ,Initial,Extraction
@@ -1870,12 +1870,12 @@ TRAIT5,1.00,.99
 
 Table: Total Variance Explained
 ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,
-Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
-1,3.26,65.26,65.26,3.26,65.26,65.26
-2,1.54,30.77,96.03,1.54,30.77,96.03
-3,.17,3.36,99.39,.17,3.36,99.39
-4,.03,.61,100.00,.03,.61,100.00
-5,.00,.00,100.00,,,
+,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
+1,3.26,65.3%,65.3%,3.26,65.3%,65.3%
+2,1.54,30.8%,96.0%,1.54,30.8%,96.0%
+3,.17,3.4%,99.4%,.17,3.4%,99.4%
+4,.03,.6%,100.0%,.03,.6%,100.0%
+5,.00,.0%,100.0%,,,
 
 Table: Component Matrix
 ,Component,,,
@@ -1927,10 +1927,10 @@ z,.514,.523
 
 Table: Total Variance Explained
 ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,
-Factor,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
-1,2.404,80.124,80.124,2.155,71.847,71.847
-2,.425,14.166,94.290,,,
-3,.171,5.710,100.000,,,
+,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
+1,2.404,80.1%,80.1%,2.155,71.8%,71.8%
+2,.425,14.2%,94.3%,,,
+3,.171,5.7%,100.0%,,,
 
 Table: Factor Matrix
 ,Factor
@@ -1984,26 +1984,26 @@ ZN,.208,.412
 ZS,.130,.158
 
 Table: Total Variance Explained
-,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings
-Factor,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total
-1,2.968,16.491,16.491,2.411,13.393,13.393,2.355
-2,2.026,11.253,27.744,1.271,7.059,20.452,1.209
-3,1.622,9.011,36.756,.948,5.264,25.716,1.231
-4,1.086,6.032,42.788,.283,1.574,27.290,.770
-5,.996,5.533,48.321,,,,
-6,.923,5.130,53.451,,,,
-7,.873,4.852,58.303,,,,
-8,.856,4.756,63.060,,,,
-9,.836,4.644,67.703,,,,
-10,.816,4.534,72.237,,,,
-11,.785,4.359,76.596,,,,
-12,.740,4.110,80.706,,,,
-13,.713,3.964,84.670,,,,
-14,.653,3.626,88.296,,,,
-15,.633,3.519,91.815,,,,
-16,.604,3.356,95.171,,,,
-17,.484,2.687,97.858,,,,
-18,.386,2.142,100.000,,,,
+,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,,Rotation Sums of Squared Loadings,,
+,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
+1,2.968,16.5%,16.5%,2.411,13.4%,13.4%,.   ,.  ,.  @&t@
+2,2.026,11.3%,27.7%,1.271,7.1%,20.5%,.   ,.  ,-Infinity
+3,1.622,9.0%,36.8%,.948,5.3%,25.7%,.   ,.  ,-Infinity
+4,1.086,6.0%,42.8%,.283,1.6%,27.3%,.   ,.  ,-Infinity
+5,.996,5.5%,48.3%,,,,,,
+6,.923,5.1%,53.5%,,,,,,
+7,.873,4.9%,58.3%,,,,,,
+8,.856,4.8%,63.1%,,,,,,
+9,.836,4.6%,67.7%,,,,,,
+10,.816,4.5%,72.2%,,,,,,
+11,.785,4.4%,76.6%,,,,,,
+12,.740,4.1%,80.7%,,,,,,
+13,.713,4.0%,84.7%,,,,,,
+14,.653,3.6%,88.3%,,,,,,
+15,.633,3.5%,91.8%,,,,,,
+16,.604,3.4%,95.2%,,,,,,
+17,.484,2.7%,97.9%,,,,,,
+18,.386,2.1%,100.0%,,,,,,
 
 Table: Factor Matrix
 ,Factor,,,
@@ -2140,15 +2140,15 @@ var08,2.250
 
 Table: Total Variance Explained
 ,Initial Eigenvalues,,
-Component,Total,% of Variance,Cumulative %
-1,556.895,81.881,81.881
-2,57.963,8.522,90.403
-3,23.576,3.466,93.869
-4,16.446,2.418,96.288
-5,14.603,2.147,98.435
-6,6.831,1.004,99.439
-7,2.375,.349,99.788
-8,1.440,.212,100.000
+,Total,% of Variance,Cumulative %
+1,556.895,81.9%,81.9%
+2,57.963,8.5%,90.4%
+3,23.576,3.5%,93.9%
+4,16.446,2.4%,96.3%
+5,14.603,2.1%,98.4%
+6,6.831,1.0%,99.4%
+7,2.375,.3%,99.8%
+8,1.440,.2%,100.0%
 
 Table: Component Matrix
 ,Component,,,,,,
@@ -2240,14 +2240,14 @@ bnt_actws_56,1.000,.316
 
 Table: Total Variance Explained
 ,Initial Eigenvalues,,,Extraction Sums of Squared Loadings,,
-Component,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
-1,3.914,55.908,55.908,3.914,55.908,55.908
-2,1.320,18.852,74.760,,,
-3,.716,10.223,84.983,,,
-4,.422,6.030,91.012,,,
-5,.278,3.977,94.989,,,
-6,.216,3.088,98.077,,,
-7,.135,1.923,100.000,,,
+,Total,% of Variance,Cumulative %,Total,% of Variance,Cumulative %
+1,3.914,55.9%,55.9%,3.914,55.9%,55.9%
+2,1.320,18.9%,74.8%,,,
+3,.716,10.2%,85.0%,,,
+4,.422,6.0%,91.0%,,,
+5,.278,4.0%,95.0%,,,
+6,.216,3.1%,98.1%,,,
+7,.135,1.9%,100.0%,,,
 
 Table: Component Matrix
 ,Component
index 06fb969fa56c7406cd8a5606beab21ccf7bba988..f6d665e1fef5cb111fca5df06a638c124a3ff075 100644 (file)
@@ -47,19 +47,19 @@ flip.sps:12: warning: FLIP: FLIP ignores TEMPORARY.  Temporary transformations w
 
 Table: Data List
 CASE_LBL,v,w,x,y,z
-a       ,1.00,6.00,11.00,16.00,21.00
-b       ,2.00,7.00,12.00,17.00,22.00
-c       ,3.00,8.00,13.00,18.00,23.00
-d       ,4.00,9.00,14.00,19.00,24.00
-e       ,1.00,6.00,11.00,16.00,21.00
+a,1.00,6.00,11.00,16.00,21.00
+b,2.00,7.00,12.00,17.00,22.00
+c,3.00,8.00,13.00,18.00,23.00
+d,4.00,9.00,14.00,19.00,24.00
+e,1.00,6.00,11.00,16.00,21.00
 
 Table: Data List
 CASE_LBL,a,b,c,d,e
-v       ,1.00,2.00,3.00,4.00,1.00
-w       ,6.00,7.00,8.00,9.00,6.00
-x       ,11.00,12.00,13.00,14.00,11.00
-y       ,16.00,17.00,18.00,19.00,16.00
-z       ,21.00,22.00,23.00,24.00,21.00
+v,1.00,2.00,3.00,4.00,1.00
+w,6.00,7.00,8.00,9.00,6.00
+x,11.00,12.00,13.00,14.00,11.00
+y,16.00,17.00,18.00,19.00,16.00
+z,21.00,22.00,23.00,24.00,21.00
 ])
 AT_CLEANUP
 
@@ -85,16 +85,16 @@ v1,v2,v3,v4,v5,v6,v7,v8,v9,v10
 
 Table: Data List
 CASE_LBL,VAR000,VAR001
-v1      ,1.00,4.00
-v2      ,2.00,5.00
-v3      ,3.00,6.00
-v4      ,4.00,7.00
-v5      ,5.00,8.00
-v6      ,6.00,9.00
-v7      ,7.00,10.00
-v8      ,8.00,11.00
-v9      ,9.00,12.00
-v10     ,10.00,13.00
+v1,1.00,4.00
+v2,2.00,5.00
+v3,3.00,6.00
+v4,4.00,7.00
+v5,5.00,8.00
+v6,6.00,9.00
+v7,7.00,10.00
+v8,8.00,11.00
+v9,9.00,12.00
+v10,10.00,13.00
 ])
 AT_CLEANUP
 
@@ -134,10 +134,10 @@ list.
 AT_CHECK([pspp -O format=csv flip.sps], [0], [dnl
 Table: Data List
 CASE_LBL,v,BY1
-a       ,1.00,1.00
-b       ,2.00,2.00
-c       ,3.00,3.00
-d       ,4.00,4.00
+a,1.00,1.00
+b,2.00,2.00
+c,3.00,3.00
+d,4.00,4.00
 ])
 
 AT_CLEANUP
index cf7913b40d57e8d4509f2b2b38da2437f8411679..ca0467264e84a7f63abf8cec3cc40a846c0129e5 100644 (file)
@@ -38,12 +38,12 @@ FREQUENCIES /VAR = name/ORDER=ANALYSIS.
 ])
 AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
 Table: name
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,bar     ,2,20.00,20.00,20.00
-,baz     ,4,40.00,40.00,60.00
-,foo     ,2,20.00,20.00,80.00
-,quux    ,2,20.00,20.00,100.00
-Total,,10,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,bar,2,20.0%,20.0%,20.0%
+,baz,4,40.0%,40.0%,60.0%
+,foo,2,20.0%,20.0%,80.0%
+,quux,2,20.0%,20.0%,100.0%
+Total,,10,100.0%,,
 ])
 AT_CLEANUP
 
@@ -62,38 +62,38 @@ end data.
 frequencies v1 v2/statistics=none/ORDER=VARIABLE.
 frequencies v1 v2/statistics=none.
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: v1
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,.00,1,25.00,25.00,25.00
-,2.00,1,25.00,25.00,50.00
-,3.00,1,25.00,25.00,75.00
-,4.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: v1
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,.00,1,25.0%,25.0%,25.0%
+,2.00,1,25.0%,25.0%,50.0%
+,3.00,1,25.0%,25.0%,75.0%
+,4.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 
 Table: v2
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,25.00,25.00,25.00
-,3.00,1,25.00,25.00,50.00
-,4.00,1,25.00,25.00,75.00
-,5.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,25.0%,25.0%,25.0%
+,3.00,1,25.0%,25.0%,50.0%
+,4.00,1,25.0%,25.0%,75.0%
+,5.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 
 Table: v1
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,.00,1,25.00,25.00,25.00
-,2.00,1,25.00,25.00,50.00
-,3.00,1,25.00,25.00,75.00
-,4.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,.00,1,25.0%,25.0%,25.0%
+,2.00,1,25.0%,25.0%,50.0%
+,3.00,1,25.0%,25.0%,75.0%
+,4.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 
 Table: v2
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,25.00,25.00,25.00
-,3.00,1,25.00,25.00,50.00
-,4.00,1,25.00,25.00,75.00
-,5.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,25.0%,25.0%,25.0%
+,3.00,1,25.0%,25.0%,50.0%
+,4.00,1,25.0%,25.0%,75.0%
+,5.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 ])
 AT_CLEANUP
 
@@ -112,11 +112,11 @@ frequencies v1 v2/statistics=none/FORMAT=LIMIT(3).
 ])
 AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
 Table: v2
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,25.00,25.00,25.00
-,3.00,1,25.00,25.00,50.00
-,5.00,2,50.00,50.00,100.00
-Total,,4,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,25.0%,25.0%,25.0%
+,3.00,1,25.0%,25.0%,50.0%
+,5.00,2,50.0%,50.0%,100.0%
+Total,,4,100.0%,,
 ])
 AT_CLEANUP
 
@@ -145,12 +145,12 @@ v1,v2
 3.00,4.00
 
 Table: v1
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,.00,1,25.00,25.00,25.00
-,2.00,1,25.00,25.00,50.00
-,3.00,1,25.00,25.00,75.00
-,4.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,.00,1,25.0%,25.0%,25.0%
+,2.00,1,25.0%,25.0%,50.0%
+,3.00,1,25.0%,25.0%,75.0%
+,4.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 ])
 AT_CHECK([test -s pspp.html])
 AT_CLEANUP
@@ -185,7 +185,7 @@ AT_CHECK([pspp frequencies.sps], [0], [dnl
 Reading free-form data from INLINE.
 +--------+------+
 |Variable|Format|
-#========#======#
++--------+------+
 |x       |F8.0  |
 |w       |F8.0  |
 +--------+------+
@@ -260,32 +260,35 @@ FREQUENCIES /X .
 
 FINISH
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: Reading free-form data from INLINE.
+AT_CHECK([pspp -o pspp.csv -o pspp.txt frequencies.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Reading free-form data from INLINE.
 Variable,Format
 SEX,A1
 X,F8.0
 
-Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,12.00,1,25.00,25.00,25.00
-,13.00,1,25.00,25.00,50.00
-,21.00,1,25.00,25.00,75.00
-,31.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
-
-Table: X
+Table: Statistics
+,,X
 N,Valid,4
 ,Missing,0
 Mean,,19.25
 Std Dev,,8.81
 Minimum,,12.00
 Maximum,,31.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,12.00,1,25.0%,25.0%,25.0%
+,13.00,1,25.0%,25.0%,50.0%
+,21.00,1,25.0%,25.0%,75.0%
+,31.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 ])
 AT_CLEANUP
 
-m4_define([FREQUENCIES_NTILES_OUTPUT],
-  [Table: x
+m4_define([FREQUENCIES_NTILES_OUTPUT], [dnl
+Table: Statistics
+,,x
 N,Valid,5
 ,Missing,0
 Mean,,3.00
@@ -295,7 +298,7 @@ Maximum,,5.00
 Percentiles,0,1.00
 ,25,2.00
 ,33,2.33
-,50 (Median),3.00
+,50,3.00
 ,67,3.67
 ,75,4.00
 ,100,5.00
@@ -357,17 +360,9 @@ FREQUENCIES
        /ALGORITHM=COMPATIBLE
        /PERCENTILES = 0 25 50 75 100.
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,20.00,20.00,20.00
-,2.00,1,20.00,20.00,40.00
-,3.00,1,20.00,20.00,60.00
-,4.00,1,20.00,20.00,80.00
-,5.00,1,20.00,20.00,100.00
-Total,,5,100.0,100.0,
-
-Table: X
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: Statistics
+,,X
 N,Valid,5
 ,Missing,0
 Mean,,3.00
@@ -376,9 +371,18 @@ Minimum,,1.00
 Maximum,,5.00
 Percentiles,0,1.00
 ,25,1.50
-,50 (Median),3.00
+,50,3.00
 ,75,4.50
 ,100,5.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,20.0%,20.0%,20.0%
+,2.00,1,20.0%,20.0%,40.0%
+,3.00,1,20.0%,20.0%,60.0%
+,4.00,1,20.0%,20.0%,80.0%
+,5.00,1,20.0%,20.0%,100.0%
+Total,,5,100.0%,,
 ])
 AT_CLEANUP
 
@@ -397,17 +401,9 @@ FREQUENCIES
        VAR=x
        /PERCENTILES = 0 25 50 75 100.
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,20.00,20.00,20.00
-,2.00,1,20.00,20.00,40.00
-,3.00,1,20.00,20.00,60.00
-,4.00,1,20.00,20.00,80.00
-,5.00,1,20.00,20.00,100.00
-Total,,5,100.0,100.0,
-
-Table: X
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: Statistics
+,,X
 N,Valid,5
 ,Missing,0
 Mean,,3.00
@@ -416,9 +412,18 @@ Minimum,,1.00
 Maximum,,5.00
 Percentiles,0,1.00
 ,25,2.00
-,50 (Median),3.00
+,50,3.00
 ,75,4.00
 ,100,5.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,20.0%,20.0%,20.0%
+,2.00,1,20.0%,20.0%,40.0%
+,3.00,1,20.0%,20.0%,60.0%
+,4.00,1,20.0%,20.0%,80.0%
+,5.00,1,20.0%,20.0%,100.0%
+Total,,5,100.0%,,
 ])
 AT_CLEANUP
 
@@ -441,17 +446,9 @@ FREQUENCIES
        VAR=x
        /PERCENTILES = 0 25 50 75 100.
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,2.00,20.00,20.00,20.00
-,2.00,2.00,20.00,20.00,40.00
-,3.00,2.00,20.00,20.00,60.00
-,4.00,2.00,20.00,20.00,80.00
-,5.00,2.00,20.00,20.00,100.00
-Total,,10.00,100.0,100.0,
-
-Table: X
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: Statistics
+,,X
 N,Valid,10.00
 ,Missing,.00
 Mean,,3.00
@@ -460,9 +457,18 @@ Minimum,,1.00
 Maximum,,5.00
 Percentiles,0,1.00
 ,25,2.00
-,50 (Median),3.00
+,50,3.00
 ,75,4.00
 ,100,5.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,2.00,20.0%,20.0%,20.0%
+,2.00,2.00,20.0%,20.0%,40.0%
+,3.00,2.00,20.0%,20.0%,60.0%
+,4.00,2.00,20.0%,20.0%,80.0%
+,5.00,2.00,20.0%,20.0%,100.0%
+Total,,10.00,100.0%,,
 ])
 AT_CLEANUP
 
@@ -483,16 +489,9 @@ FREQUENCIES
        VAR=x
        /PERCENTILES = 0 25 50 75 100.
 ])
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1.00,16.67,16.67,16.67
-,3.00,2.00,33.33,33.33,50.00
-,4.00,1.00,16.67,16.67,66.67
-,5.00,2.00,33.33,33.33,100.00
-Total,,6.00,100.0,100.0,
-
-Table: X
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: Statistics
+,,X
 N,Valid,6.00
 ,Missing,.00
 Mean,,3.50
@@ -501,9 +500,17 @@ Minimum,,1.00
 Maximum,,5.00
 Percentiles,0,1.00
 ,25,3.00
-,50 (Median),3.50
+,50,3.50
 ,75,4.75
 ,100,5.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1.00,16.7%,16.7%,16.7%
+,3.00,2.00,33.3%,33.3%,50.0%
+,4.00,1.00,16.7%,16.7%,66.7%
+,5.00,2.00,33.3%,33.3%,100.0%
+Total,,6.00,100.0%,,
 ])
 AT_CLEANUP
 
@@ -525,15 +532,8 @@ FREQUENCIES
        /PERCENTILES = 0 25 50 75 100.
 ])
 AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
-Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,7.00,17.50,17.50,17.50
-,2.00,16.00,40.00,40.00,57.50
-,3.00,12.00,30.00,30.00,87.50
-,4.00,5.00,12.50,12.50,100.00
-Total,,40.00,100.0,100.0,
-
-Table: X
+Table: Statistics
+,,X
 N,Valid,40.00
 ,Missing,.00
 Mean,,2.38
@@ -542,9 +542,17 @@ Minimum,,1.00
 Maximum,,4.00
 Percentiles,0,1.00
 ,25,2.00
-,50 (Median),2.00
+,50,2.00
 ,75,3.00
 ,100,4.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,7.00,17.5%,17.5%,17.5%
+,2.00,16.00,40.0%,40.0%,57.5%
+,3.00,12.00,30.0%,30.0%,87.5%
+,4.00,5.00,12.5%,12.5%,100.0%
+Total,,40.00,100.0%,,
 ])
 AT_CLEANUP
 
@@ -568,17 +576,9 @@ FREQUENCIES
        /PERCENTILES = 0 25 50 75 100.
 ])
 
-AT_CHECK([pspp -O format=csv frequencies.sps], [0],
-  [Table: X
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1.00,10.00,16.67,16.67
-,3.00,2.00,20.00,33.33,50.00
-,4.00,1.00,10.00,16.67,66.67
-,5.00,2.00,20.00,33.33,100.00
-,99.00,4.00,40.00,Missing,
-Total,,10.00,100.0,100.0,
-
-Table: X
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: Statistics
+,,X
 N,Valid,6.00
 ,Missing,4.00
 Mean,,3.50
@@ -587,9 +587,18 @@ Minimum,,1.00
 Maximum,,5.00
 Percentiles,0,1.00
 ,25,3.00
-,50 (Median),3.50
+,50,3.50
 ,75,4.75
 ,100,5.00
+
+Table: X
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1.00,10.0%,16.7%,16.7%
+,3.00,2.00,20.0%,33.3%,50.0%
+,4.00,1.00,10.0%,16.7%,66.7%
+,5.00,2.00,20.0%,33.3%,100.0%
+Missing,99.00,4.00,40.0%,,
+Total,,10.00,100.0%,,
 ])
 AT_CLEANUP
 
@@ -642,18 +651,19 @@ FREQUENCIES
        .
 ])
 
-AT_CHECK([pspp median.sps -O format=csv], [0],  [dnl
-Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,1.00,1,33.33,33.33,33.33
-,2.00,1,33.33,33.33,66.67
-,3000000.00,1,33.33,33.33,100.00
-Total,,3,100.0,100.0,
-
-Table: x
+AT_CHECK([pspp median.sps -O format=csv], [0], [dnl
+Table: Statistics
+,,x
 N,Valid,3
 ,Missing,0
-Percentiles,50 (Median),2.00
+Median,,2.00
+
+Table: x
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,1.00,1,33.3%,33.3%,33.3%
+,2.00,1,33.3%,33.3%,66.7%
+,3000000,1,33.3%,33.3%,100.0%
+Total,,3,100.0%,,
 ])
 AT_CLEANUP
 
@@ -672,19 +682,20 @@ FREQUENCIES
    /STATISTICS = VARIANCE.
 ])
 
-AT_CHECK([pspp variance.sps -O format=csv], [0],  [dnl
-Table: height
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,109.00,1,25.00,25.00,25.00
-,134.00,1,25.00,25.00,50.00
-,167.00,1,25.00,25.00,75.00
-,188.00,1,25.00,25.00,100.00
-Total,,4,100.0,100.0,
-
-Table: height
+AT_CHECK([pspp variance.sps -O format=csv], [0], [dnl
+Table: Statistics
+,,height
 N,Valid,4
 ,Missing,0
 Variance,,1223.00
+
+Table: height
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,109.00,1,25.0%,25.0%,25.0%
+,134.00,1,25.0%,25.0%,50.0%
+,167.00,1,25.0%,25.0%,75.0%
+,188.00,1,25.0%,25.0%,100.0%
+Total,,4,100.0%,,
 ])
 AT_CLEANUP
 
@@ -708,36 +719,39 @@ FREQUENCIES
        .
 ])
 
-AT_CHECK([pspp median.sps -O format=csv], [0],  [dnl
-Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,10.00,1,33.33,33.33,33.33
-,20.00,1,33.33,33.33,66.67
-,3000000.00,1,33.33,33.33,100.00
-Total,,3,100.0,100.0,
-
-Table: x
+AT_CHECK([pspp median.sps -o pspp.csv -o pspp.txt])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Statistics
+,,x
 N,Valid,3
 ,Missing,0
-Mean,,1000010.00
-Std Dev,,1732042.15
+Mean,,1000010
+Std Dev,,1732042
 Minimum,,10.00
-Maximum,,3000000.00
-
-Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,10.00,1,33.33,33.33,33.33
-,20.00,1,33.33,33.33,66.67
-,3000000.00,1,33.33,33.33,100.00
-Total,,3,100.0,100.0,
+Maximum,,3000000
 
 Table: x
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,10.00,1,33.3%,33.3%,33.3%
+,20.00,1,33.3%,33.3%,66.7%
+,3000000,1,33.3%,33.3%,100.0%
+Total,,3,100.0%,,
+
+Table: Statistics
+,,x
 N,Valid,3
 ,Missing,0
-Mean,,1000010.00
-Std Dev,,1732042.15
+Mean,,1000010
+Std Dev,,1732042
 Minimum,,10.00
-Maximum,,3000000.00
+Maximum,,3000000
+
+Table: x
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Valid,10.00,1,33.3%,33.3%,33.3%
+,20.00,1,33.3%,33.3%,66.7%
+,3000000,1,33.3%,33.3%,100.0%
+Total,,3,100.0%,,
 ])
 AT_CLEANUP
 
@@ -759,28 +773,29 @@ FREQUENCIES
 ])
 
 AT_CHECK([pspp empty.sps -O format=csv], [0],  [dnl
-Table: x
-Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
-,.  ,3,100.00,Missing,
-Total,,3,100.0,100.0,
-
-Table: x
+Table: Statistics
+,,x
 N,Valid,0
 ,Missing,3
-Mean,,.
-S.E. Mean,,.
-Mode,,.
-Std Dev,,.
-Variance,,.
-Kurtosis,,.
-S.E. Kurt,,.
-Skewness,,.
-S.E. Skew,,.
-Range,,.
-Minimum,,.
-Maximum,,.
-Sum,,.
-Percentiles,,.
+Mean,,.  @&t@
+S.E. Mean,,.  @&t@
+Median,,.  @&t@
+Mode,,.  @&t@
+Std Dev,,.  @&t@
+Variance,,.  @&t@
+Kurtosis,,.  @&t@
+S.E. Kurt,,.  @&t@
+Skewness,,.  @&t@
+S.E. Skew,,.  @&t@
+Range,,.  @&t@
+Minimum,,.  @&t@
+Maximum,,.  @&t@
+Sum,,.  @&t@
+
+Table: x
+,,Frequency,Percent,Valid Percent,Cumulative Percent
+Missing,.  ,3,100.0%,,
+Total,,3,.0%,,
 ])
 
 AT_CLEANUP
index 564c8dee402083253fe4202397f5f16908debc57..ac18c340da975ffd827fdf2552810a90ebbfe88e 100644 (file)
@@ -75,7 +75,7 @@ glm y by   b a c
 AT_CHECK([pspp -O format=csv latin.sps | sed 's/329.62[[678]]/329.62/'], [0],
   [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,263.064,15,17.538,5.269,.000
 Intercept,815.103,1,815.103,244.910,.000
 Factor A,78.869,5,15.774,4.739,.005
@@ -127,12 +127,12 @@ glm points by Factor0 Factor1
 AT_CHECK([pspp -O format=csv 2by2.sps ], [0],
   [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,8667.053,3,2889.018,5.043,.012
 Intercept,2256018.640,1,2256018.640,3937.693,.000
 Factor0,313.394,1,313.394,.547,.470
 Factor1,5157.508,1,5157.508,9.002,.008
-Factor0 * Factor1,3196.150,1,3196.150,5.579,.031
+Factor0 × Factor1,3196.150,1,3196.150,5.579,.031
 Error,9166.865,16,572.929,,
 Total,2273852.559,20,,,
 Corrected Total,17833.918,19,,,
@@ -225,23 +225,23 @@ glm dv by Agrp Bgrp
 AT_CHECK([pspp -O format=csv type1.sps], [0],
   [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type I Sum of Squares,df,Mean Square,F,Sig.
+,Type I Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,216.017,7,30.860,5.046,.001
 Intercept,,,,,
 Agrp,9.579,1,9.579,1.566,.220
 Bgrp,186.225,3,62.075,10.151,.000
-Agrp * Bgrp,20.212,3,6.737,1.102,.364
+Agrp × Bgrp,20.212,3,6.737,1.102,.364
 Error,183.457,30,6.115,,
 Total,3810.000,38,,,
 Corrected Total,399.474,37,,,
 
 Table: Tests of Between-Subjects Effects
-Source,Type I Sum of Squares,df,Mean Square,F,Sig.
+,Type I Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,216.017,7,30.860,5.046,.001
 Intercept,,,,,
 Bgrp,193.251,3,64.417,10.534,.000
 Agrp,2.553,1,2.553,.418,.523
-Bgrp * Agrp,20.212,3,6.737,1.102,.364
+Bgrp × Agrp,20.212,3,6.737,1.102,.364
 Error,183.457,30,6.115,,
 Total,3810.000,38,,,
 Corrected Total,399.474,37,,,
@@ -260,12 +260,12 @@ glm dv by Agrp Bgrp
 AT_CHECK([pspp -O format=csv type2.sps], [0],
   [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type II Sum of Squares,df,Mean Square,F,Sig.
+,Type II Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,216.017,7,30.860,5.046,.001
 Intercept,,,,,
 Agrp,2.553,1,2.553,.418,.523
 Bgrp,186.225,3,62.075,10.151,.000
-Agrp * Bgrp,20.212,3,6.737,1.102,.364
+Agrp × Bgrp,20.212,3,6.737,1.102,.364
 Error,183.457,30,6.115,,
 Total,3810.000,38,,,
 Corrected Total,399.474,37,,,
@@ -328,14 +328,14 @@ GLM depvar by A
 AT_CHECK([pspp -O format=csv intercept-exclude.sps], [0],
   [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Model,1636.826,2,818.413,43.556,.000
 A,1636.826,2,818.413,43.556,.000
 Error,338.216,18,18.790,,
 Total,1975.042,20,,,
 
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,98.568,1,98.568,5.246,.034
 Intercept,1538.258,1,1538.258,81.867,.000
 A,98.568,1,98.568,5.246,.034
@@ -405,7 +405,7 @@ glm y by   b a c
 
 AT_CHECK([pspp -O format=csv glm-miss.sps], [0],  [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,251.621,14,17.973,4.969,.002
 Intercept,628.376,1,628.376,173.737,.000
 a,72.929,4,18.232,5.041,.009
@@ -432,7 +432,7 @@ glm y by   b a c
 
 AT_CHECK([pspp -O format=csv glm-miss2.sps], [0],  [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,251.621,14,17.973,4.969,.002
 Intercept,628.376,1,628.376,173.737,.000
 a,72.929,4,18.232,5.041,.009
@@ -462,7 +462,7 @@ glm y by   b a c
 
 AT_CHECK([pspp -O format=csv glm-miss3.sps], [0],  [dnl
 Table: Tests of Between-Subjects Effects
-Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+,Type III Sum Of Squares,df,Mean Square,F,Sig.
 Corrected Model,251.621,14,17.973,4.969,.002
 Intercept,628.376,1,628.376,173.737,.000
 a,72.929,4,18.232,5.041,.009
index d604c0ad14ccbce2c27d69af26e99aea33ca1680..6952167fa0b58490156132038f10c2af01d3a3c8 100644 (file)
@@ -110,41 +110,39 @@ logistic regression
        .
 ])
 
-AT_CHECK([pspp -O format=csv lr-data.sps], [0],
-  [dnl
-Table: Dependent Variable Encoding
+AT_CHECK([pspp -o pspp.csv -o pspp.txt lr-data.sps], [0], [dnl
+note: Estimation terminated at iteration number 6 because parameter estimates changed by less than 0.001
+])
+AT_CHECK([cat pspp.csv], [0], [Table: Dependent Variable Encoding
 Original Value,Internal Value
-1.000,0
-2.000,1
+1.000,.000
+2.000,1.000
 
 Table: Case Processing Summary
 Unweighted Cases,N,Percent
-Included in Analysis,66,100.000
-Missing Cases,0,.000
-Total,66,100.000
+Included in Analysis,66,100.0%
+Missing Cases,0,.0%
+Total,66,100.0%
 
 note: Estimation terminated at iteration number 6 because parameter estimates changed by less than 0.001
 
 Table: Model Summary
-Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
-,37.323,.455,.659
+Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
+1,37.323,.455,.659
 
 Table: Classification Table
 ,,,Predicted,,
-,,,outcome,,"Percentage
-Correct"
+,,,outcome,,Percentage Correct
 ,Observed,,1.000,2.000,
-Step 1,outcome,1.000,43,5,89.583
-,,2.000,4,14,77.778
-,Overall Percentage,,,,86.364
+Step 1,outcome,1.000,43,5,89.6%
+,,2.000,4,14,77.8%
+,Overall Percentage,,,,86.4%
 
 Table: Variables in the Equation
 ,,B,S.E.,Wald,df,Sig.,Exp(B)
 Step 1,survrate,-.081,.019,17.756,1,.000,.922
 ,Constant,2.684,.811,10.941,1,.001,14.639
 ])
-
-
 AT_CLEANUP
 
 AT_SETUP([LOGISTIC REGRESSION missing values])
@@ -180,13 +178,13 @@ AT_CHECK([pspp -O format=csv lr-data.sps > run1], [0], [ignore])
 dnl Only the summary information should be different
 AT_CHECK([diff run0 run1], [1], [dnl
 8,10c8,10
-< Included in Analysis,66,100.000
-< Missing Cases,0,.000
-< Total,66,100.000
+< Included in Analysis,66,100.0%
+< Missing Cases,0,.0%
+< Total,66,100.0%
 ---
-> Included in Analysis,66,94.286
-> Missing Cases,4,5.714
-> Total,70,100.000
+> Included in Analysis,66,94.3%
+> Missing Cases,4,5.7%
+> Total,70,100.0%
 ])
 
 AT_CLEANUP
@@ -236,19 +234,19 @@ dnl The only difference should be the summary information, since
 dnl this displays the unweighted totals.
 AT_CHECK([diff unweighted-result weighted-result], [1], [dnl
 8c8
-< Included in Analysis,66,100.000
+< Included in Analysis,66,100.0%
 ---
-> Included in Analysis,63,100.000
+> Included in Analysis,63,100.0%
 10c10
-< Total,66,100.000
+< Total,66,100.0%
 ---
-> Total,63,100.000
-23,24c23,24
-< Step 1,outcome,1.000,43,5,89.583
-< ,,2.000,4,14,77.778
+> Total,63,100.0%
+22,23c22,23
+< Step 1,outcome,1.000,43,5,89.6%
+< ,,2.000,4,14,77.8%
 ---
-> Step 1,outcome,1.000,43.000,5.000,89.583
-> ,,2.000,4.000,14.000,77.778
+> Step 1,outcome,1.000,43.000,5.000,89.6%
+> ,,2.000,4.000,14.000,77.8%
 ])
 
 
@@ -277,33 +275,31 @@ compute constant = 1.
 logistic regression female with constant /noconst.
 ])
 
-AT_CHECK([pspp -O format=csv non-const.sps], [0],
- [dnl
+AT_CHECK([pspp -O format=csv non-const.sps], [0], [dnl
 Table: Dependent Variable Encoding
 Original Value,Internal Value
-.00,0
-1.00,1
+.00,.000
+1.00,1.000
 
 Table: Case Processing Summary
 Unweighted Cases,N,Percent
-Included in Analysis,200,100.000
-Missing Cases,0,.000
-Total,200,100.000
+Included in Analysis,200,100.0%
+Missing Cases,0,.0%
+Total,200,100.0%
 
 note: Estimation terminated at iteration number 2 because parameter estimates changed by less than 0.001
 
 Table: Model Summary
-Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
-,275.637,.008,.011
+Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
+1,275.637,.008,.011
 
 Table: Classification Table
 ,,,Predicted,,
-,,,female,,"Percentage
-Correct"
+,,,female,,Percentage Correct
 ,Observed,,.00,1.00,
-Step 1,female,.00,0,91,.000
-,,1.00,0,109,100.000
-,Overall Percentage,,,,54.500
+Step 1,female,.00,0,91,.0%
+,,1.00,0,109,100.0%
+,Overall Percentage,,,,54.5%
 
 Table: Variables in the Equation
 ,,B,S.E.,Wald,df,Sig.,Exp(B)
@@ -759,28 +755,27 @@ logistic regression
           .
 ])
 
-AT_CHECK([pspp -O format=csv lr-cat.sps], [0],
- [dnl
+AT_CHECK([pspp -O format=csv lr-cat.sps], [0], [dnl
 Table: Dependent Variable Encoding
 Original Value,Internal Value
-4.000,0
-9.000,1
+4.000,.000
+9.000,1.000
 
 Table: Case Processing Summary
 Unweighted Cases,N,Percent
-Included in Analysis,400,100.000
-Missing Cases,0,.000
-Total,400,100.000
+Included in Analysis,400,100.0%
+Missing Cases,0,.0%
+Total,400,100.0%
 
 note: Estimation terminated at iteration number 4 because parameter estimates changed by less than 0.001
 
 Table: Model Summary
-Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
-,458.517,.098,.138
+Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
+1,458.517,.098,.138
 
 Table: Categorical Variables' Codings
-,,,Parameter coding,,
-,,Frequency,(1),(2),(3)
+,,Frequency,Parameter coding,,
+,,,(1),(2),(3)
 bcat,1.000,61,1,0,0
 ,2.000,151,0,1,0
 ,3.000,121,0,0,1
@@ -788,12 +783,11 @@ bcat,1.000,61,1,0,0
 
 Table: Classification Table
 ,,,Predicted,,
-,,,y,,"Percentage
-Correct"
+,,,y,,Percentage Correct
 ,Observed,,4.000,9.000,
-Step 1,y,4.000,254,19,93.040
-,,9.000,97,30,23.622
-,Overall Percentage,,,,71.000
+Step 1,y,4.000,254,19,93.0%
+,,9.000,97,30,23.6%
+,Overall Percentage,,,,71.0%
 
 Table: Variables in the Equation
 ,,B,S.E.,Wald,df,Sig.,Exp(B)
@@ -805,7 +799,6 @@ Step 1,b1,.002,.001,4.284,1,.038,1.002
 ,bcat(3),.211,.393,.289,1,.591,1.235
 ,Constant,-5.541,1.138,23.709,1,.000,.004
 ])
-
 AT_CLEANUP
 
 
@@ -1029,40 +1022,38 @@ logistic regression honcomp with read science ses
 
 ])
 
-AT_CHECK([pspp -O format=csv stringcat.sps], [0],
- [dnl
+AT_CHECK([pspp -O format=csv stringcat.sps], [0], [dnl
 Table: Dependent Variable Encoding
 Original Value,Internal Value
-.000,0
-1.000,1
+.000,.000
+1.000,1.000
 
 Table: Case Processing Summary
 Unweighted Cases,N,Percent
-Included in Analysis,200,100.000
-Missing Cases,0,.000
-Total,200,100.000
+Included in Analysis,200,100.0%
+Missing Cases,0,.0%
+Total,200,100.0%
 
 note: Estimation terminated at iteration number 5 because parameter estimates changed by less than 0.001
 
 Table: Model Summary
-Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
-,165.701,.280,.408
+Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
+1,165.701,.280,.408
 
 Table: Categorical Variables' Codings
-,,,Parameter coding,
-,,Frequency,(1),(2)
+,,Frequency,Parameter coding,
+,,,(1),(2)
 ses,a,47,1,0
 ,b,95,0,1
 ,c,58,0,0
 
 Table: Classification Table
 ,,,Predicted,,
-,,,honcomp,,"Percentage
-Correct"
+,,,honcomp,,Percentage Correct
 ,Observed,,.000,1.000,
-Step 1,honcomp,.000,132,15,89.796
-,,1.000,26,27,50.943
-,Overall Percentage,,,,79.500
+Step 1,honcomp,.000,132,15,89.8%
+,,1.000,26,27,50.9%
+,Overall Percentage,,,,79.5%
 
 Table: Variables in the Equation
 ,,B,S.E.,Wald,df,Sig.,Exp(B)
@@ -1222,13 +1213,13 @@ AT_CHECK([pspp -O format=csv miss.sps > file2], [0], [ignore])
 
 AT_CHECK([diff file1 file2], [1], [dnl
 8,10c8,10
-< Included in Analysis,100,100.00
-< Missing Cases,0,.00
-< Total,100,100.00
+< Included in Analysis,100,100.0%
+< Missing Cases,0,.0%
+< Total,100,100.0%
 ---
-> Included in Analysis,100,99.01
-> Missing Cases,1,.99
-> Total,101,100.00
+> Included in Analysis,100,99.0%
+> Missing Cases,1,1.0%
+> Total,101,100.0%
 ])
 
 AT_CLEANUP
@@ -1452,24 +1443,24 @@ logistic regression
 AT_CHECK([pspp -O format=csv ci.sps], [0], [dnl
 Table: Dependent Variable Encoding
 Original Value,Internal Value
-.000,0
-1.000,1
+.000,.000
+1.000,1.000
 
 Table: Case Processing Summary
 Unweighted Cases,N,Percent
-Included in Analysis,196,100.000
-Missing Cases,0,.000
-Total,196,100.000
+Included in Analysis,196,100.0%
+Missing Cases,0,.0%
+Total,196,100.0%
 
 note: Estimation terminated at iteration number 4 because parameter estimates changed by less than 0.001
 
 Table: Model Summary
-Step 1,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
-,211.195,.120,.172
+Step,-2 Log likelihood,Cox & Snell R Square,Nagelkerke R Square
+1,211.195,.120,.172
 
 Table: Categorical Variables' Codings
-,,,Parameter coding,
-,,Frequency,(1),(2)
+,,Frequency,Parameter coding,
+,,,(1),(2)
 sciostat,1.000,77,1,0
 ,2.000,49,0,1
 ,3.000,70,0,0
@@ -1478,16 +1469,15 @@ sector,1.000,117,1,
 
 Table: Classification Table
 ,,,Predicted,,
-,,,disease,,"Percentage
-Correct"
+,,,disease,,Percentage Correct
 ,Observed,,.000,1.000,
-Step 1,disease,.000,131,8,94.245
-,,1.000,41,16,28.070
-,Overall Percentage,,,,75.000
+Step 1,disease,.000,131,8,94.2%
+,,1.000,41,16,28.1%
+,Overall Percentage,,,,75.0%
 
 Table: Variables in the Equation
-,,,,,,,,95% CI for Exp(B),
-,,B,S.E.,Wald,df,Sig.,Exp(B),Lower,Upper
+,,B,S.E.,Wald,df,Sig.,Exp(B),95% CI for Exp(B),
+,,,,,,,,Lower,Upper
 Step 1,age,.027,.009,8.647,1,.003,1.027,1.009,1.045
 ,savings,.061,.386,.025,1,.874,1.063,.499,2.264
 ,sciostat,,,.440,2,.803,,,
index d4db9ec8af3ca941b2f5e35886f072cdf0f62c05..93ef68ac70ce63d159bb65275502c87383792ac8 100644 (file)
@@ -61,8 +61,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-score: factor,26,100%,0,0%,26,100%
-score: ,26,100%,0,0%,26,100%
+score: factor,26,100.0%,0,.0%,26,100.0%
+score: ,26,100.0%,0,.0%,26,100.0%
 
 Table: Report
 ,factor,Mean,N,Std. Deviation
@@ -101,7 +101,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-score: ,4,100%,0,0%,4,100%
+score: ,4,100.0%,0,.0%,4,100.0%
 
 Table: Report
 ,Mean,N,Std. Deviation
@@ -143,16 +143,16 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1 * g2,6,75%,2,25%,8,100%
-a: g2,6,75%,2,25%,8,100%
-a: ,7,87.5%,1,12.5%,8,100%
+a: g1 × g2,6,75.0%,2,25.0%,8,100.0%
+a: g2,6,75.0%,2,25.0%,8,100.0%
+a: ,7,87.5%,1,12.5%,8,100.0%
 
 Table: Report
 ,g1,g2,Mean,N
 a,1.00,11.00,4.00,1.00
-,1.00,21.00,3.00,1.00
-,2.00,21.00,6.00,1.00
-,2.00,31.00,5.67,3.00
+,,21.00,3.00,1.00
+,2.00,,6.00,1.00
+,,31.00,5.67,3.00
 
 Table: Report
 ,g2,Mean,N
@@ -202,8 +202,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-test1: group,10,100%,0,0%,10,100%
-test1: ,10,100%,0,0%,10,100%
+test1: group,10,100.0%,0,.0%,10,100.0%
+test1: ,10,100.0%,0,.0%,10,100.0%
 
 Table: Report
 ,group,Mean,N,Std. Deviation,Sum,Min,Max,Range,Variance,Kurtosis,Skewness
@@ -248,8 +248,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-test1: group,10,100%,0,0%,10,100%
-test1: ,10,100%,0,0%,10,100%
+test1: group,10,100.0%,0,.0%,10,100.0%
+test1: ,10,100.0%,0,.0%,10,100.0%
 
 Table: Report
 ,group,Mean,N,S.E. Mean,S.E. Skew,S.E. Kurt
@@ -292,8 +292,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-x: ,5,100%,0,0%,5,100%
-y: ,5,100%,0,0%,5,100%
+x: ,5,100.0%,0,.0%,5,100.0%
+y: ,5,100.0%,0,.0%,5,100.0%
 
 Table: Report
 ,Mean,Harmonic Mean,Geom. Mean
@@ -337,7 +337,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-score: ,5,100%,0,0%,5,100%
+score: ,5,100.0%,0,.0%,5,100.0%
 
 Table: Report
 ,Mean,N,Std. Deviation,S.E. Mean,Sum,Min,Max,Range,Variance,Kurtosis,S.E. Kurt,Skewness,S.E. Skew,First,Last,Harmonic Mean,Geom. Mean
@@ -347,7 +347,7 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-score: ,5,100%,0,0%,5,100%
+score: ,5,100.0%,0,.0%,5,100.0%
 
 Table: Report
 ,Mean,N,Std. Deviation
@@ -357,11 +357,9 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-score: ,5,100%,0,0%,5,100%
+score: ,5,100.0%,0,.0%,5,100.0%
 
 Table: Report
-
-score
 ])
 
 AT_CLEANUP
@@ -397,16 +395,16 @@ MEANS a b BY g1
 ])
 
 
-AT_CHECK([pspp -O format=csv means-miss-table.sps], [0],
-  [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt means-miss-table.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
-b: g1,6,85.7143%,1,14.2857%,7,100%
-b: ,6,85.7143%,1,14.2857%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
+b: g1,6,85.7%,1,14.3%,7,100.0%
+b: ,6,85.7%,1,14.3%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -424,8 +422,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -440,10 +438,10 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
-b: g1,6,85.7143%,1,14.2857%,7,100%
-b: ,6,85.7143%,1,14.2857%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
+b: g1,6,85.7%,1,14.3%,7,100.0%
+b: ,6,85.7%,1,14.3%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -461,8 +459,8 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -473,13 +471,8 @@ Table: Report
 ,N
 a,7.00
 ])
-
 AT_CLEANUP
 
-
-
-
-
 AT_SETUP([MEANS user missing values])
 AT_KEYWORDS([categorical categoricals])
 
@@ -505,16 +498,16 @@ MEANS a b BY g1 /cells =  COUNT /missing = dependent .
 ])
 
 
-AT_CHECK([pspp -O format=csv means-missing.sps], [0],
-  [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt means-missing.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,6,85.7143%,1,14.2857%,7,100%
-a: ,7,100%,0,0%,7,100%
-b: g1,5,71.4286%,2,28.5714%,7,100%
-b: ,6,85.7143%,1,14.2857%,7,100%
+a: g1,6,85.7%,1,14.3%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
+b: g1,5,71.4%,2,28.6%,7,100.0%
+b: ,6,85.7%,1,14.3%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -532,10 +525,10 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
-b: g1,7,100%,0,0%,7,100%
-b: ,7,100%,0,0%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
+b: g1,7,100.0%,0,.0%,7,100.0%
+b: ,7,100.0%,0,.0%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -555,10 +548,10 @@ Table: Case Processing Summary
 ,Cases,,,,,
 ,Included,,Excluded,,Total,
 ,N,Percent,N,Percent,N,Percent
-a: g1,7,100%,0,0%,7,100%
-a: ,7,100%,0,0%,7,100%
-b: g1,6,85.7143%,1,14.2857%,7,100%
-b: ,6,85.7143%,1,14.2857%,7,100%
+a: g1,7,100.0%,0,.0%,7,100.0%
+a: ,7,100.0%,0,.0%,7,100.0%
+b: g1,6,85.7%,1,14.3%,7,100.0%
+b: ,6,85.7%,1,14.3%,7,100.0%
 
 Table: Report
 ,g1,N
@@ -574,7 +567,6 @@ Table: Report
 a,7.00
 b,6.00
 ])
-
 AT_CLEANUP
 
 
index 24a8cce65956b07353806a964b1af51944fc257d..10889a412356ca28f5484600a3b2ad3bcba55b29 100644 (file)
@@ -35,8 +35,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1.000,6.000,.286,.300,.551
-,Group2,2.000,15.000,.714,,
+x,Group 1,1.000,6.000,.286,.300,.551
+,Group 2,2.000,15.000,.714,,
 ,Total,,21.000,1.000,,
 ])
 AT_CLEANUP
@@ -60,8 +60,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1,7,.538,.400,.229
-,Group2,2,6,.462,,
+x,Group 1,1,7,.538,.400,.229
+,Group 2,2,6,.462,,
 ,Total,,13,1.000,,
 ])
 AT_CLEANUP
@@ -85,8 +85,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1,8,.500,.400,.284
-,Group2,2,8,.500,,
+x,Group 1,1,8,.500,.400,.284
+,Group 2,2,8,.500,,
 ,Total,,16,1.000,,
 ])
 AT_CLEANUP
@@ -110,8 +110,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1,11,.478,.600,.164
-,Group2,2,12,.522,,
+x,Group 1,1,11,.478,.600,.164
+,Group 2,2,12,.522,,
 ,Total,,23,1.000,,
 ])
 AT_CLEANUP
@@ -134,8 +134,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1,11,.550,.600,.404
-,Group2,2,9,.450,,
+x,Group 1,1,11,.550,.600,.404
+,Group 2,2,9,.450,,
 ,Total,,20,1.000,,
 ])
 AT_CLEANUP
@@ -158,8 +158,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
-x,Group1,1,11,.500,.600,.228
-,Group2,2,11,.500,,
+x,Group 1,1,11,.500,.600,.228
+,Group 2,2,11,.500,,
 ,Total,,22,1.000,,
 ])
 AT_CLEANUP
@@ -183,8 +183,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
-x,Group1,1,8,.348,.500,.210
-,Group2,2,15,.652,,
+x,Group 1,1,8,.348,.500,.210
+,Group 2,2,15,.652,,
 ,Total,,23,1.000,,
 ])
 AT_CLEANUP
@@ -207,8 +207,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
-x,Group1,1,12,.667,.500,.238
-,Group2,2,6,.333,,
+x,Group 1,1,12,.667,.500,.238
+,Group 2,2,6,.333,,
 ,Total,,18,1.000,,
 ])
 AT_CLEANUP
@@ -232,8 +232,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
-x,Group1,1,10,.500,.500,1.000
-,Group2,2,10,.500,,
+x,Group 1,1,10,.500,.500,1.000
+,Group 2,2,10,.500,,
 ,Total,,20,1.000,,
 ])
 AT_CLEANUP
@@ -258,8 +258,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
-x,Group1,<= 10,10.000,.385,.500,.327
-,Group2,,16.000,.615,,
+x,Group 1,<= 10,10.000,.385,.500,.327
+,Group 2,,16.000,.615,,
 ,Total,,26.000,1.000,,
 ])
 AT_CLEANUP
@@ -284,8 +284,8 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: Binomial Test
 ,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
-x,Group1,10.000,10.000,.435,.500,.678
-,Group2,20.000,13.000,.565,,
+x,Group 1,10.000,10.000,.435,.500,.678
+,Group 2,20.000,13.000,.565,,
 ,Total,,23.000,1.000,,
 ])
 AT_CLEANUP
@@ -344,7 +344,7 @@ NPAR TESTS
 
 AT_CHECK([pspp -O format=csv npar.sps], [0], [dnl
 Table: x
-,Observed N,Expected N,Residual
+Value,Observed N,Expected N,Residual
 1.00,3.00,2.33,.67
 2.00,3.00,2.33,.67
 3.10,4.00,2.33,1.67
@@ -354,7 +354,7 @@ Table: x
 Total,14.00,,
 
 Table: y
-,Observed N,Expected N,Residual
+Value,Observed N,Expected N,Residual
 1.00,7.00,3.50,3.50
 2.00,4.00,3.50,.50
 3.00,1.00,3.50,-2.50
@@ -362,13 +362,12 @@ Table: y
 Total,14.00,,
 
 Table: Test Statistics
-,x,y
-Chi-Square,3.14,6.00
-df,5,3
-Asymp. Sig.,.678,.112
+,Chi-square,df,Asymp. Sig.
+x,3.14,5,.678
+y,6.00,3,.112
 
 Table: y
-,Observed N,Expected N,Residual
+Value,Observed N,Expected N,Residual
 1.00,7.00,2.63,4.38
 2.00,4.00,3.50,.50
 3.00,1.00,4.38,-3.38
@@ -376,10 +375,8 @@ Table: y
 Total,14.00,,
 
 Table: Test Statistics
-,y
-Chi-Square,10.61
-df,3
-Asymp. Sig.,.014
+,Chi-square,df,Asymp. Sig.
+y,10.61,3,.014
 
 Table: Frequencies
 ,x,,,,y,,,
@@ -390,10 +387,9 @@ Table: Frequencies
 Total,,10.00,,,,7.00,,
 
 Table: Test Statistics
-,x,y
-Chi-Square,.13,4.13
-df,2,2
-Asymp. Sig.,.936,.127
+,Chi-square,df,Asymp. Sig.
+x,.13,2,.936
+y,4.13,2,.127
 ])
 
 AT_CLEANUP
@@ -420,13 +416,11 @@ NPAR TESTS
 ])
 
 AT_CHECK([pspp -O format=csv npar.sps], [1], [dnl
-"error: CHISQUARE test specified 6 expected values, but 4 distinct values were encountered in variable y."
+"error: CHISQUARE test specified 6 expected values, but variable y has 4 distinct values."
 
 Table: Test Statistics
-,y
-Chi-Square,.00
-df,0
-Asymp. Sig.,1.000
+,Chi-square,df,Asymp. Sig.
+y,.00,0,1.000
 ])
 
 AT_CLEANUP
@@ -471,14 +465,12 @@ Table: Frequencies
 Total,,12.00,,,,15.00,,
 
 Table: Test Statistics
-,x,y
-Chi-Square,17.33,22.87
-df,7,7
-Asymp. Sig.,.015,.002
+,Chi-square,df,Asymp. Sig.
+x,17.33,7,.015
+y,22.87,7,.002
 
 Table: Descriptive Statistics
 ,N,Mean,Std. Deviation,Minimum,Maximum
-,,,,,
 x,12.00,2.47,1.19,1.00,5.00
 y,15.00,2.07,1.33,1.00,5.00
 ])
@@ -524,14 +516,12 @@ Table: Frequencies
 Total,,14.00,,,,14.00,,
 
 Table: Test Statistics
-,x,y
-Chi-Square,13.43,26.00
-df,7,7
-Asymp. Sig.,.062,.001
+,Chi-square,df,Asymp. Sig.
+x,13.43,7,.062
+y,26.00,7,.001
 
 Table: Descriptive Statistics
 ,N,Mean,Std. Deviation,Minimum,Maximum
-,,,,,
 x,14.00,2.69,1.23,1.00,5.00
 y,14.00,1.86,1.10,1.00,4.00
 ])
@@ -711,20 +701,20 @@ npar tests
        .
 ])
 
-AT_CHECK([pspp -o pspp.csv kw-simple.sps])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt kw-simple.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Ranks
-,gv,N,Mean Rank
+,,N,Mean Rank
 xscore,timed out,5,4.400
 ,hit wicket,5,7.400
 ,handled the ball,4,11.500
 ,Total,14,
 
 Table: Test Statistics
-,,xscore
-Chi-Square,,6.406
-df,,2
-Asymp. Sig.,,.041
+,xscore
+Chi-Square,6.406
+df,2
+Asymp. Sig.,.041
 ])
 
 
@@ -818,7 +808,7 @@ npar tests
 AT_CHECK([pspp -o pspp.csv kw-multi.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Ranks
-,gv,N,Mean Rank
+,,N,Mean Rank
 xscore,timed out,5,4.400
 ,hit wicket,5,7.400
 ,handled the ball,4,11.500
@@ -829,10 +819,10 @@ yscore,hit wicket,5,7.400
 ,Total,14,
 
 Table: Test Statistics
-,,xscore,yscore,
-Chi-Square,,6.406,6.406,
-df,,2,2,
-Asymp. Sig.,,.041,.041,
+,xscore,yscore
+Chi-Square,6.406,6.406
+df,2,2
+Asymp. Sig.,.041,.041
 ])
 
 AT_CLEANUP
@@ -1037,9 +1027,10 @@ NPAR TESTS
 
 AT_CHECK([pspp -O format=csv npar-mann-whitney.sps], [0], [dnl
 Table: Ranks
-,N,,,Mean Rank,,Sum of Ranks,
-,0,1,Total,0,1,0,1
-height,15.0000,15.0000,30.0000,14.5333,16.4667,218.0000,247.0000
+,,N,Mean Rank,Sum of Ranks
+height,0,15,14.5333,218.0000
+,1,15,16.4667,247.0000
+,Total,30,,
 
 Table: Test Statistics
 ,Mann-Whitney U,Wilcoxon W,Z,Asymp. Sig. (2-tailed)
@@ -1077,12 +1068,19 @@ NPAR TESTS
 
 AT_CHECK([pspp -O format=csv npar-mann-whitney.sps], [0], [dnl
 Table: Ranks
-,N,,,Mean Rank,,Sum of Ranks,
-,.000,1.000,Total,.000,1.000,.000,1.000
-IOS: Familie,114.000,115.000,229.000,110.018,119.939,12542.000,13793.000
-IOS: Freunde,115.000,115.000,230.000,108.339,122.661,12459.000,14106.000
-IOS: Partner*in,97.000,91.000,188.000,95.351,93.593,9249.000,8517.000
-IOS: Bekannte,115.000,115.000,230.000,111.065,119.935,12772.500,13792.500
+,,N,Mean Rank,Sum of Ranks
+IOS: Familie,.000,114,110.018,12542.000
+,1.000,115,119.939,13793.000
+,Total,229,,
+IOS: Freunde,.000,115,108.339,12459.000
+,1.000,115,122.661,14106.000
+,Total,230,,
+IOS: Partner*in,.000,97,95.351,9249.000
+,1.000,91,93.593,8517.000
+,Total,188,,
+IOS: Bekannte,.000,115,111.065,12772.500
+,1.000,115,119.935,13792.500
+,Total,230,,
 
 Table: Test Statistics
 ,Mann-Whitney U,Wilcoxon W,Z,Asymp. Sig. (2-tailed)
@@ -1133,6 +1131,7 @@ v6,2,7
 v7,5,4
 
 Table: Test Statistics
+,Value
 N,9
 Cochran's Q,12.735
 df,6
@@ -1242,14 +1241,14 @@ npar tests
 
 AT_CHECK([pspp -O format=csv mcnemar.sps], [0], [dnl
 Table: v1 & v2
-v1,v2,
-,.000,1.000
+,v2,
+v1,.000,1.000
 .000,4,9
 1.000,2,5
 
 Table: v1 & junk
-v1,junk,
-,.000,1.000
+,junk,
+v1,.000,1.000
 .000,8,5
 1.000,2,5
 
@@ -1850,4 +1849,4 @@ NPAR TESTS
 AT_CHECK([pspp -O format=csv npar.sps], [1], [ignore])
 
 AT_CLEANUP
\ No newline at end of file
index 58fd75e289ae712c1fc47e70b38ce88afc9a7256..be9ae130e46827cbcdb5d18f38d4f9cceda2ed75 100644 (file)
@@ -51,10 +51,11 @@ ONEWAY
        .
 ])
 
-AT_CHECK([pspp -O format=csv oneway.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,Manufacturer,,,,,Lower Bound,Upper Bound,,
 Breaking Strain,Aspeger,5,2.20,1.30,.58,.58,3.82,1.00,4.00
 ,Bloggs,5,3.20,1.30,.58,1.58,4.82,2.00,5.00
 ,Charlies,5,5.00,1.58,.71,3.04,6.96,3.00,7.00
@@ -71,16 +72,16 @@ Breaking Strain,Between Groups,20.13,2,10.07,5.12,.025
 ,Total,43.73,14,,,
 
 Table: Contrast Coefficients
-,,Manufacturer,,
-,,Aspeger,Bloggs,Charlies
-Contrast,1,-2,1,1
-,2,0,-1,1
+,Manufacturer,,
+Contrast,Aspeger,Bloggs,Charlies
+1,-2,1,1
+2,0,-1,1
 
 Table: Contrast Tests
 ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed)
-Breaking Strain,Assume equal variances,1,3.80,1.54,2.47,12,.029
-,,2,1.80,.89,2.03,12,.065
-,Does not assume equal,1,3.80,1.48,2.56,8.74,.031
+Breaking Strain,Assume equal variances,1,3.80,1.54,2.47,12.00,.029
+,,2,1.80,.89,2.03,12.00,.065
+,Does not assume equal variances,1,3.80,1.48,2.56,8.74,.031
 ,,2,1.80,.92,1.96,7.72,.086
 ])
 AT_CLEANUP
@@ -123,13 +124,15 @@ ONEWAY
        .
 ])
 
-AT_CHECK([pspp -O format=csv oneway-splits.sps], [0], 
-[Variable,Value,Label
-S,1.00,
+AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-splits.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Split Values
+Variable,Value
+S,1.00
 
 Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,Manufacturer,,,,,Lower Bound,Upper Bound,,
 Breaking Strain,Aspeger,5,2.20,1.30,.58,.58,3.82,1.00,4.00
 ,Bloggs,2,3.50,2.12,1.50,-15.56,22.56,2.00,5.00
 ,Total,7,2.57,1.51,.57,1.17,3.97,1.00,5.00
@@ -145,24 +148,25 @@ Breaking Strain,Between Groups,2.41,1,2.41,1.07,.349
 ,Total,13.71,6,,,
 
 Table: Contrast Coefficients
-,,Manufacturer,
-,,Aspeger,Bloggs
-Contrast,1,-2,2
-,2,-1,1
+,Manufacturer,
+Contrast,Aspeger,Bloggs
+1,-2,2
+2,-1,1
 
 Table: Contrast Tests
 ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed)
-Breaking Strain,Assume equal variances,1,2.60,2.52,1.03,5,.349
-,,2,1.30,1.26,1.03,5,.349
-,Does not assume equal,1,2.60,3.22,.81,1.32,.539
+Breaking Strain,Assume equal variances,1,2.60,2.52,1.03,5.00,.349
+,,2,1.30,1.26,1.03,5.00,.349
+,Does not assume equal variances,1,2.60,3.22,.81,1.32,.539
 ,,2,1.30,1.61,.81,1.32,.539
 
-Variable,Value,Label
-S,2.00,
+Table: Split Values
+Variable,Value
+S,2.00
 
 Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,Manufacturer,,,,,Lower Bound,Upper Bound,,
 Breaking Strain,Bloggs,3,3.00,1.00,.58,.52,5.48,2.00,4.00
 ,Charlies,5,5.00,1.58,.71,3.04,6.96,3.00,7.00
 ,Total,8,4.25,1.67,.59,2.85,5.65,2.00,7.00
@@ -178,19 +182,18 @@ Breaking Strain,Between Groups,7.50,1,7.50,3.75,.101
 ,Total,19.50,7,,,
 
 Table: Contrast Coefficients
-,,Manufacturer,
-,,Bloggs,Charlies
-Contrast,1,-2,2
-,2,-1,1
+,Manufacturer,
+Contrast,Bloggs,Charlies
+1,-2,2
+2,-1,1
 
 Table: Contrast Tests
 ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed)
-Breaking Strain,Assume equal variances,1,4.00,2.07,1.94,6,.101
-,,2,2.00,1.03,1.94,6,.101
-,Does not assume equal,1,4.00,1.83,2.19,5.88,.072
+Breaking Strain,Assume equal variances,1,4.00,2.07,1.94,6.00,.101
+,,2,2.00,1.03,1.94,6.00,.101
+,Does not assume equal variances,1,4.00,1.83,2.19,5.88,.072
 ,,2,2.00,.91,2.19,5.88,.072
 ])
-
 AT_CLEANUP
 
 
@@ -332,8 +335,8 @@ ONEWAY
 
 AT_CHECK([pspp -O format=csv oneway-descriptives.sps], [0], 
 [Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,BRAND,,,,,Lower Bound,Upper Bound,,
 QUALITY,11.00,5,12.20,1.30,.58,10.58,13.82,11.00,14.00
 ,25.00,5,13.20,1.30,.58,11.58,14.82,12.00,15.00
 ,301.00,5,15.00,1.58,.71,13.04,16.96,13.00,17.00
@@ -437,13 +440,13 @@ ONEWAY x y z by g
        .
 ])
 
-AT_CHECK([pspp -o pspp.csv multivar.sps])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt multivar.sps])
 
 dnl Some machines return 3.88 instead of 3.87 below (see bug #31611).
-AT_CHECK([sed 's/^,Within Groups,3.88/,Within Groups,3.87/' pspp.csv], [0], [dnl
-Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+AT_CHECK([sed 's/^,Within Groups,3.88/,Within Groups,3.87/' pspp.csv], [0],
+  [Table: Descriptives
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,g,,,,,Lower Bound,Upper Bound,,
 x,10.00,3,3.67,4.62,2.67,-7.81,15.14,1.00,9.00
 ,20.00,5,.80,.45,.20,.24,1.36,.00,1.00
 ,30.00,8,.88,.64,.23,.34,1.41,.00,2.00
@@ -479,24 +482,24 @@ z,Between Groups,17.47,3,5.82,.62,.610
 ,Total,205.33,23,,,
 
 Table: Contrast Coefficients
-,,g,,,
-,,10.00,20.00,30.00,40.00
-Contrast,1,3,2,0,-5
-,2,2,-9,7,0
+,g,,,
+Contrast,10.00,20.00,30.00,40.00
+1,3,2,0,-5
+2,2,-9,7,0
 
 Table: Contrast Tests
 ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed)
-x,Assume equal variances,1,-7.40,6.67,1.11,20,.280
-,,2,6.26,12.32,.51,20,.617
-,Does not assume equal,1,-7.40,10.04,-.74,4.53,.497
+x,Assume equal variances,1,-7.40,6.67,1.11,20.00,.280
+,,2,6.26,12.32,.51,20.00,.617
+,Does not assume equal variances,1,-7.40,10.04,-.74,4.53,1.503
 ,,2,6.26,5.85,1.07,2.87,.366
-y,Assume equal variances,1,-6.88,1.16,5.94,20,.000
-,,2,3.50,2.14,1.63,20,.118
-,Does not assume equal,1,-6.88,.91,-7.51,7.00,.000
+y,Assume equal variances,1,-6.88,1.16,5.94,20.00,.000
+,,2,3.50,2.14,1.63,20.00,.118
+,Does not assume equal variances,1,-6.88,.91,-7.51,7.00,2.000
 ,,2,3.50,1.32,2.65,7.00,.033
-z,Assume equal variances,1,-9.70,8.07,1.20,20,.243
-,,2,11.73,14.91,.79,20,.440
-,Does not assume equal,1,-9.70,9.57,-1.01,3.64,.373
+z,Assume equal variances,1,-9.70,8.07,1.20,20.00,.243
+,,2,11.73,14.91,.79,20.00,.440
+,Does not assume equal variances,1,-9.70,9.57,-1.01,3.64,1.627
 ,,2,11.73,14.53,.81,9.88,.438
 ])
 
@@ -612,10 +615,11 @@ oneway pigmentation by family
         .
 ])
 
-AT_CHECK([pspp -O format=csv oneway-pig.sps], [0], 
-[Table: Descriptives
-,,,,,,95% Confidence Interval for Mean,,,
-,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-pig.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Descriptives
+,,N,Mean,Std. Deviation,Std. Error,95% Confidence Interval for Mean,,Minimum,Maximum
+,family,,,,,Lower Bound,Upper Bound,,
 pigmentation,1.000,5,38.600,2.702,1.208,35.245,41.955,36.000,43.000
 ,2.000,5,46.000,1.732,.775,43.849,48.151,43.000,47.000
 ,3.000,5,46.400,4.336,1.939,41.016,51.784,40.000,50.000
@@ -629,8 +633,8 @@ pigmentation,Between Groups,478.950,3,159.650,12.927,.000
 ,Total,676.550,19,,,
 
 Table: Multiple Comparisons (pigmentation)
-,,,Mean Difference,,,95% Confidence Interval,
-,(I) family,(J) family,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound
+,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval,
+,(J) Family,(J) Family,,,,Lower Bound,Upper Bound
 LSD,1.000,2.000,-7.400,2.223,.004,-12.112,-2.688
 ,,3.000,-7.800,2.223,.003,-12.512,-3.088
 ,,4.000,-13.800,2.223,.000,-18.512,-9.088
@@ -656,7 +660,6 @@ Bonferroni,1.000,2.000,-7.400,2.223,.025,-14.086,-.714
 ,,2.000,6.400,2.223,.065,-.286,13.086
 ,,3.000,6.000,2.223,.095,-.686,12.686
 ])
-
 AT_CLEANUP
 
 
@@ -691,23 +694,24 @@ oneway libido by dose
        /posthoc tukey gh.
 ])
 
-AT_CHECK([pspp -O format=csv oneway-tukey.sps], [0], 
-[Table: ANOVA
+AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-tukey.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: ANOVA
 ,,Sum of Squares,df,Mean Square,F,Sig.
 libido,Between Groups,20.133,2,10.067,5.119,.025
 ,Within Groups,23.600,12,1.967,,
 ,Total,43.733,14,,,
 
 Table: Multiple Comparisons (libido)
-,,,Mean Difference,,,95% Confidence Interval,
-,(I) Dose of Viagra,(J) Dose of Viagra,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound
+,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval,
+,(J) Family,(J) Family,,,,Lower Bound,Upper Bound
 Tukey HSD,Placebo,1 Dose,-1.000,.887,.516,-3.366,1.366
 ,,2 Doses,-2.800,.887,.021,-5.166,-.434
 ,1 Dose,Placebo,1.000,.887,.516,-1.366,3.366
 ,,2 Doses,-1.800,.887,.147,-4.166,.566
 ,2 Doses,Placebo,2.800,.887,.021,.434,5.166
 ,,1 Dose,1.800,.887,.147,-.566,4.166
-Games-Howell,Placebo,1 Dose,-1.000,.887,.479,-3.356,1.356
+Games-Howell,Placebo,,-1.000,.887,.479,-3.356,1.356
 ,,2 Doses,-2.800,.887,.039,-5.439,-.161
 ,1 Dose,Placebo,1.000,.887,.479,-1.356,3.356
 ,,2 Doses,-1.800,.887,.185,-4.439,.839
@@ -760,8 +764,8 @@ score,Between Groups,54.9500,3,18.3167,7.0449,.003
 ,Total,96.5500,19,,,
 
 Table: Multiple Comparisons (score)
-,,,Mean Difference,,,95% Confidence Interval,
-,(I) program,(J) program,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound
+,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval,
+,(J) Family,(J) Family,,,,Lower Bound,Upper Bound
 Šidák,1.0000,2.0000,3.0000,1.0198,.056,-.0575,6.0575
 ,,3.0000,-.4000,1.0198,.999,-3.4575,2.6575
 ,,4.0000,3.2000,1.0198,.038,.1425,6.2575
@@ -842,8 +846,8 @@ Days of Use,Between Groups,555.275,3,185.092,6.663,.001
 ,Total,1555.375,39,,,
 
 Table: Multiple Comparisons (Days of Use)
-,,,Mean Difference,,,95% Confidence Interval,
-,(I) group,(J) group,(I - J),Std. Error,Sig.,Lower Bound,Upper Bound
+,,,Mean Difference (I - J),Std. Error,Sig.,95% Confidence Interval,
+,(J) Family,(J) Family,,,,Lower Bound,Upper Bound
 Scheffé,one,two,3.800,2.357,.467,-3.112,10.712
 ,,three,10.300,2.357,.001,3.388,17.212
 ,,four,6.000,2.357,.110,-.912,12.912
@@ -886,7 +890,10 @@ ONEWAY /VARIABLES= height weight temperature BY sex
 ])
 
 
-AT_CHECK([pspp -O format=csv oneway-bad-contrast.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt oneway-bad-contrast.sps], [0], [dnl
+oneway-bad-contrast.sps:18: warning: ONEWAY: In contrast list 3, the number of coefficients (3) does not equal the number of groups (2). This contrast list will be ignored.
+])
+AT_CHECK([cat pspp.csv], [0], [dnl
 "oneway-bad-contrast.sps:18: warning: ONEWAY: In contrast list 3, the number of coefficients (3) does not equal the number of groups (2). This contrast list will be ignored."
 
 Table: ANOVA
@@ -902,34 +909,33 @@ temperature,Between Groups,1.80,1,1.80,.13,.733
 ,Total,86.36,7,,,
 
 Table: Contrast Coefficients
-,,sex,
-,,.00,1.00
-Contrast,1,-1,1
-,2,-3,3
-,3,-9,9
+,sex,
+Contrast,.00,1.00
+1,-1,1
+2,-3,3
+3,-9,9
 
 Table: Contrast Tests
 ,,Contrast,Value of Contrast,Std. Error,t,df,Sig. (2-tailed)
-height,Assume equal variances,1,-222.27,20.23,10.99,6,.000
-,,2,-666.80,60.68,10.99,6,.000
-,,3,-2000.40,182.03,10.99,6,.000
-,Does not assume equal,1,-222.27,27.67,-8.03,2.00,.015
-,,2,-666.80,83.02,-8.03,2.00,.015
-,,3,-2000.40,249.07,-8.03,2.00,.015
-weight,Assume equal variances,1,-36.16,2.74,13.21,6,.000
-,,2,-108.48,8.21,13.21,6,.000
-,,3,-325.44,24.63,13.21,6,.000
-,Does not assume equal,1,-36.16,2.19,-16.48,5.42,.000
-,,2,-108.48,6.58,-16.48,5.42,.000
-,,3,-325.44,19.75,-16.48,5.42,.000
-temperature,Assume equal variances,1,-.98,2.74,.36,6,.733
-,,2,-2.94,8.22,.36,6,.733
-,,3,-8.83,24.67,.36,6,.733
-,Does not assume equal,1,-.98,2.07,-.47,4.19,.660
-,,2,-2.94,6.22,-.47,4.19,.660
-,,3,-8.83,18.66,-.47,4.19,.660
+height,Assume equal variances,1,-222.27,20.23,10.99,6.00,.000
+,,2,-666.80,60.68,10.99,6.00,.000
+,,3,-2000.40,182.03,10.99,6.00,.000
+,Does not assume equal variances,1,-222.27,27.67,-8.03,2.00,1.985
+,,2,-666.80,83.02,-8.03,2.00,1.985
+,,3,-2000.40,249.07,-8.03,2.00,1.985
+weight,Assume equal variances,1,-36.16,2.74,13.21,6.00,.000
+,,2,-108.48,8.21,13.21,6.00,.000
+,,3,-325.44,24.63,13.21,6.00,.000
+,Does not assume equal variances,1,-36.16,2.19,-16.48,5.42,2.000
+,,2,-108.48,6.58,-16.48,5.42,2.000
+,,3,-325.44,19.75,-16.48,5.42,2.000
+temperature,Assume equal variances,1,-.98,2.74,.36,6.00,.733
+,,2,-2.94,8.22,.36,6.00,.733
+,,3,-8.83,24.67,.36,6.00,.733
+,Does not assume equal variances,1,-.98,2.07,-.47,4.19,1.340
+,,2,-2.94,6.22,-.47,4.19,1.340
+,,3,-8.83,18.66,-.47,4.19,1.340
 ])
-
 AT_CLEANUP
 
 
index ee790ac8565d707bf1867328a90267182f5748aa..34c04945e98150bbb3bc01b74b5ff4cf476e91d6 100644 (file)
@@ -45,14 +45,13 @@ z,F8.0
 
 Table: Final Cluster Centers
 ,Cluster,
-,,
 ,1,2
-,,
 x,6.50,19.20
 y,7.50,3250.00
 z,6.50,5058.00
 
 Table: Number of Cases in each Cluster
+,,Count
 Cluster,1,6
 ,2,5
 Valid,,11
@@ -75,12 +74,11 @@ AT_CHECK([pspp -o pspp.csv quick-cluster.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Final Cluster Centers
 ,Cluster,,,
-,,,,
 ,1,2,3,4
-,,,,
 x,NaN,NaN,NaN,3.00
 
 Table: Number of Cases in each Cluster
+,,Count
 Cluster,1,0
 ,2,0
 ,3,0
@@ -228,8 +226,8 @@ QUICK CLUSTER x y
 
 AT_CHECK([pspp -O format=csv quick-pw.sps  > pspp-pw.csv])
 
-AT_CHECK([head -n 18  pspp-s.csv > top-s.csv])
-AT_CHECK([head -n 18  pspp-pw.csv > top-pw.csv])
+AT_CHECK([head -n 13  pspp-s.csv > top-s.csv])
+AT_CHECK([head -n 13  pspp-pw.csv > top-pw.csv])
 AT_CHECK([diff top-s.csv top-pw.csv])
 
 
@@ -280,7 +278,7 @@ AT_CLEANUP
 
 AT_SETUP([QUICK CLUSTER /PRINT subcommand])
 AT_DATA([quick-cluster.sps], [dnl
-data list notable list /cluster (A8) x (F) y (F).
+data list notable list /cluster (A8) x y (F8.0).
 begin data.
 A 10.45 9.38
 A 10.67 9.17
@@ -349,21 +347,18 @@ QUICK CLUSTER x y
 AT_CHECK([pspp -O format=csv quick-cluster.sps], [0], [dnl
 Table: Initial Cluster Centers
 ,Cluster,,
-,,,
 ,1,2,3
-,,,
 x,-11,-12,11
 y,-12,11,11
 
 Table: Final Cluster Centers
 ,Cluster,,
-,,,
 ,1,2,3
-,,,
 x,-10,-10,10
 y,-10,10,10
 
 Table: Number of Cases in each Cluster
+,,Count
 Cluster,1,20
 ,2,19
 ,3,18
index 40c69d0f97946794572c21dd13f9211fe1b0e3ae..2194da5f861508256579e71f1e1198f812576326 100644 (file)
@@ -35,11 +35,9 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-x into Rx(RANK of x)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,Rx,RANK
 
 Table: Data List
 x,Rx
@@ -70,15 +68,11 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-x into Rx(RANK of x)
-
-y into Ry(RANK of y)
-
-z into Rz(RANK of z)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,Rx,RANK
+y,Ry,RANK
+z,Rz,RANK
 
 Table: Data List
 x,y,z,Rx,Ry,Rz
@@ -117,21 +111,14 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-a into Ra(RANK of a)
-
-b into Rb(RANK of b)
-
-a into RFR001(RFRACTION of a)
-
-b into RFR002(RFRACTION of b)
-
-a into count(N of a)
-
-b into Nb(N of b)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+a,Ra,RANK
+b,Rb,RANK
+a,RFR001,RFRACTION
+b,RFR002,RFRACTION
+a,count,N
+b,Nb,N
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -189,19 +176,13 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-a into Sa(SAVAGE of a)
-
-a into Pa(PERCENT of a)
-
-a into PRO001(PROPORTION of a using BLOM)
-
-a into Na(NTILES of a)
-
-a into NOR001(NORMAL of a using BLOM)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function,Fraction
+a,Sa,SAVAGE,
+a,Pa,PERCENT,
+a,PRO001,PROPORTION,BLOM
+a,Na,NTILES,
+a,NOR001,NORMAL,BLOM
 
 Table: Data List
 a,b,Sa,Pa,PRO001,Na,NOR001
@@ -268,21 +249,15 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-a into Ra(RANK of a BY g2 g1)
-
-a into Na(NORMAL of a using RANKIT BY g2 g1)
-
-Variables Created By RANK
-
-
-
-a into RAN001(RANK of a BY g2)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function,Fraction,Grouping Variables
+a,Ra,RANK,,g2 g1
+a,Na,NORMAL,RANKIT,g2 g1
 
-a into NOR001(NORMAL of a using RANKIT BY g2)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function,Fraction,Grouping Variables
+a,RAN001,RANK,,g2
+a,NOR001,NORMAL,RANKIT,g2
 
 Table: Data List
 a,g1,g2,Ra,Na,RAN001,NOR001
@@ -334,13 +309,10 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-a into Pa(PROPORTION of a using TUKEY)
-
-a into Sa(SAVAGE of a)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function,Fraction
+a,Pa,PROPORTION,TUKEY
+a,Sa,SAVAGE,
 
 Table: Data List
 a,w,Pa,Sa
@@ -395,29 +367,21 @@ LIST.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-x into xl(RANK of x)
-
-Variables Created By RANK
-
-
-
-x into xh(RANK of x)
-
-Variables Created By RANK
-
-
-
-x into xc(RANK of x)
-
-Variables Created By RANK
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,xl,RANK
 
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,xh,RANK
 
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,xc,RANK
 
-x into Nx(NORMAL of x using VW)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function,Fraction
+x,Nx,NORMAL,VW
 
 Table: Data List
 x,w,xl,xh,xc,Nx
@@ -460,17 +424,13 @@ RANK age /RANK INTO Rf.
 LIST.
 ])
 AT_CHECK([pspp -O format=csv rank.sps], [0], [dnl
-Variables Created By RANK
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+age,Rm,RANK
 
-
-
-age into Rm(RANK of age)
-
-Variables Created By RANK
-
-
-
-age into Rf(RANK of age)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+age,Rf,RANK
 
 Table: Data List
 age,gender,Rm,Rf
@@ -511,11 +471,9 @@ DISPLAY DICTIONARY.
 ])
 AT_CHECK([pspp -o pspp.csv rank.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
-Variables Created By RANK
-
-
-
-foo into RAN001(RANK of foo)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+foo,RAN001,RANK
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -560,11 +518,9 @@ AT_CHECK([pspp -O format=csv rank.sps], [0], [dnl
 
 "rank.sps:9: warning: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
 
-Variables Created By RANK
-
-
-
-x into RNKRA01(RANK of x)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,RNKRA01,RANK
 
 Table: Data List
 x,rx,RNKRA01
@@ -597,11 +553,9 @@ DEBUG XFORM FAIL.
 RANK x.
 ])
 AT_CHECK([pspp -O format=csv --testing-mode rank.sps], [1], [dnl
-Variables Created By RANK
-
-
-
-x into Rx(RANK of x)
+Table: Variables Created by RANK
+Existing Variable,New Variable,Function
+x,Rx,RANK
 
 rank.sps:14: error: RANK: DEBUG XFORM FAIL transformation executed
 ])
index 7461a45a033739431b5f6c77c7491a0836f6a27a..1fc5662da03e4c0e7af55a8c3623fc139aed469e 100644 (file)
@@ -41,21 +41,21 @@ AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl
 regression.sps:16: warning: REGRESSION: REGRESSION with SAVE ignores FILTER.  All cases will be processed.
 
 Table: Model Summary (v2)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.971,.942,.925,1.337
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.971,.942,.925,1.337
 
 Table: ANOVA (v2)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,202.753,2,101.376,56.754,.000
-,Residual,12.504,7,1.786,,
-,Total,215.256,9,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,202.753,2,101.376,56.754,.000
+Residual,12.504,7,1.786,,
+Total,215.256,9,,,
 
 Table: Coefficients (v2)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),2.191,2.357,.000,.930,.380
-,v0,1.813,1.053,.171,1.722,.129
-,v1,-3.427,.332,-1.026,-10.334,.000
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),2.191,2.357,.000,.930,.380
+v0,1.813,1.053,.171,1.722,.129
+v1,-3.427,.332,-1.026,-10.334,.000
 
 Table: Data List
 v0,v1,v2,RES1,PRED1
@@ -96,38 +96,38 @@ list.
 
 AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl
 Table: Model Summary (v2)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.971,.942,.925,1.337
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.971,.942,.925,1.337
 
 Table: ANOVA (v2)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,202.753,2,101.376,56.754,.000
-,Residual,12.504,7,1.786,,
-,Total,215.256,9,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,202.753,2,101.376,56.754,.000
+Residual,12.504,7,1.786,,
+Total,215.256,9,,,
 
 Table: Coefficients (v2)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),2.191,2.357,.000,.930,.380
-,v0,1.813,1.053,.171,1.722,.129
-,v1,-3.427,.332,-1.026,-10.334,.000
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),2.191,2.357,.000,.930,.380
+v0,1.813,1.053,.171,1.722,.129
+v1,-3.427,.332,-1.026,-10.334,.000
 
 Table: Model Summary (v2)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.971,.942,.925,1.337
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.971,.942,.925,1.337
 
 Table: ANOVA (v2)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,202.753,2,101.376,56.754,.000
-,Residual,12.504,7,1.786,,
-,Total,215.256,9,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,202.753,2,101.376,56.754,.000
+Residual,12.504,7,1.786,,
+Total,215.256,9,,,
 
 Table: Coefficients (v2)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),2.191,2.357,.000,.930,.380
-,v0,1.813,1.053,.171,1.722,.129
-,v1,-3.427,.332,-1.026,-10.334,.000
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),2.191,2.357,.000,.930,.380
+v0,1.813,1.053,.171,1.722,.129
+v1,-3.427,.332,-1.026,-10.334,.000
 
 Table: Data List
 v0,v1,v2,RES1,PRED1
@@ -1786,20 +1786,20 @@ v0,F8.0
 v1,F8.0
 
 Table: Model Summary (v0)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.05,.00,.00,8.11
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.05,.00,.00,8.11
 
 Table: ANOVA (v0)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,235.23,1,235.23,3.58,.059
-,Residual,98438.40,1498,65.71,,
-,Total,98673.63,1499,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,235.23,1,235.23,3.58,.059
+Residual,98438.40,1498,65.71,,
+Total,98673.63,1499,,,
 
 Table: Coefficients (v0)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),1.24,.42,.00,2.95,.003
-,v1,1.37,.72,.05,1.89,.059
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),1.24,.42,.00,2.95,.003
+v1,1.37,.72,.05,1.89,.059
 ])
 
 AT_CLEANUP
@@ -2125,23 +2125,23 @@ regression
 
 AT_CHECK([pspp -O format=csv conf.sps], [0], [dnl
 Table: Model Summary (science)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.699,.489,.479,7.148
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.699,.489,.479,7.148
 
 Table: ANOVA (science)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,9543.721,4,2385.930,46.695,.000
-,Residual,9963.779,195,51.096,,
-,Total,19507.500,199,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,9543.721,4,2385.930,46.695,.000
+Residual,9963.779,195,51.096,,
+Total,19507.500,199,,,
 
 Table: Coefficients (science)
-,,Unstandardized Coefficients,,Standardized Coefficients,,,95% Confidence Interval for B,
-,,B,Std. Error,Beta,t,Sig.,Lower Bound,Upper Bound
-,(Constant),12.325,3.194,.000,3.859,.000,6.027,18.624
-,math,.389,.074,.368,5.252,.000,.243,.535
-,female,-2.010,1.023,-.101,-1.965,.051,-4.027,.007
-,socst,.050,.062,.054,.801,.424,-.073,.173
-,read,.335,.073,.347,4.607,.000,.192,.479
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.,95% Confidence Interval for B,
+,B,Std. Error,Beta,,,Lower Bound,Upper Bound
+(Constant),12.325,3.194,.000,3.859,.000,6.027,18.624
+math,.389,.074,.368,5.252,.000,.243,.535
+female,-2.010,1.023,-.101,-1.965,.051,-4.027,.007
+socst,.050,.062,.054,.801,.424,-.073,.173
+read,.335,.073,.347,4.607,.000,.192,.479
 ])
 
 
@@ -2173,27 +2173,27 @@ LIST.
 AT_CHECK([pspp -o pspp.csv regression.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Model Summary (X1)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.95,.89,.84,15.08
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.95,.89,.84,15.08
 
 Table: ANOVA (X1)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,3820.45,1,3820.45,16.81,.055
-,Residual,454.55,2,227.27,,
-,Total,4275.00,3,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,3820.45,1,3820.45,16.81,.055
+Residual,454.55,2,227.27,,
+Total,4275.00,3,,,
 
 Table: Coefficients (X1)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),85.45,10.16,.00,8.41,.004
-,Y,-3.73,.91,-.95,-4.10,.055
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),85.45,10.16,.00,8.41,.004
+Y,-3.73,.91,-.95,-4.10,.055
 
 Table: Data List
 text,Y,X1,RES1
-V00276601               ,.00,90.00,4.55
-V00292909               ,10.00,30.00,-18.18
-V00291204               ,20.00,20.00,9.09
-V00300070               ,.00,90.00,4.55
+V00276601,.00,90.00,4.55
+V00292909,10.00,30.00,-18.18
+V00291204,20.00,20.00,9.09
+V00300070,.00,90.00,4.55
 ])
 AT_CLEANUP
 
@@ -2260,20 +2260,20 @@ REGRESSION
 
 AT_CHECK([pspp -O format=csv regression.sps], [0], [dnl
 Table: Model Summary (value)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.612,.374,.338,6.176
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.612,.374,.338,6.176
 
 Table: ANOVA (value)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,388.065,1,388.065,10.173,.005
-,Residual,648.498,17,38.147,,
-,Total,1036.563,18,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,388.065,1,388.065,10.173,.005
+Residual,648.498,17,38.147,,
+Total,1036.563,18,,,
 
 Table: Coefficients (value)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,(Constant),.927,2.247,.000,.413,.685
-,number,.611,.192,.612,3.189,.005
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),.927,2.247,.000,.413,.685
+number,.611,.192,.612,3.189,.005
 ])
 
 AT_CLEANUP 
@@ -2317,20 +2317,66 @@ REGRESSION
 
 AT_CHECK([pspp -O format=csv regression-origin.sps], [0], [dnl
 Table: Model Summary (value)
-,R,R Square,Adjusted R Square,Std. Error of the Estimate
-,.802,.643,.622,6.032
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.802,.643,.622,6.032
 
 Table: ANOVA (value)
-,,Sum of Squares,df,Mean Square,F,Sig.
-,Regression,1181.726,1,1181.726,32.475,.000
-,Residual,654.989,18,36.388,,
-,Total,1836.715,19,,,
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,1181.726,1,1181.726,32.475,.000
+Residual,654.989,18,36.388,,
+Total,1836.715,19,,,
 
 Table: Coefficients (value)
-,,Unstandardized Coefficients,,Standardized Coefficients,,
-,,B,Std. Error,Beta,t,Sig.
-,number,.672,.118,.802,5.699,.000
-,,,,,,
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+number,.672,.118,.802,5.699,.000
 ])
 
 AT_CLEANUP 
+
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([REGRESSION tutorial example])
+cp $top_srcdir/examples/repairs.sav .
+AT_DATA([regression.sps], [dnl
+GET FILE='repairs.sav'.
+REGRESSION /VARIABLES=mtbf duty_cycle /DEPENDENT=mttr.
+REGRESSION /VARIABLES=mtbf /DEPENDENT=mttr.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt regression.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Model Summary (Mean time to repair (hours) )
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.99,.99,.99,2.24
+
+Table: ANOVA (Mean time to repair (hours) )
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,5308.87,2,2654.44,530.75,.000
+Residual,60.02,12,5.00,,
+Total,5368.89,14,,,
+
+Table: Coefficients (Mean time to repair (hours) )
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),9.81,1.50,.00,6.54,.000
+Mean time between failures (months) ,3.10,.10,.99,32.43,.000
+Ratio of working to non-working time,1.09,1.78,.02,.61,.552
+
+Table: Model Summary (Mean time to repair (hours) )
+R,R Square,Adjusted R Square,Std. Error of the Estimate
+.99,.99,.99,2.18
+
+Table: ANOVA (Mean time to repair (hours) )
+,Sum of Squares,df,Mean Square,F,Sig.
+Regression,5307.00,1,5307.00,1114.73,.000
+Residual,61.89,13,4.76,,
+Total,5368.89,14,,,
+
+Table: Coefficients (Mean time to repair (hours) )
+,Unstandardized Coefficients,,Standardized Coefficients,t,Sig.
+,B,Std. Error,Beta,,
+(Constant),10.50,.96,.00,10.96,.000
+Mean time between failures (months) ,3.11,.09,.99,33.39,.000
+])
+AT_CLEANUP
index be203415813530a46c0f938cad56e36983296e95..072a48aca2339f226f2bdcdb2446dd3f0c80bac3 100644 (file)
@@ -199,17 +199,17 @@ RELIABILITY
   /VARIABLES=var6 var8 var15 var17 
   .
 ])
-AT_CHECK([pspp -o pspp.csv reliability.sps], [0],
+AT_CHECK([pspp -o pspp.csv -o pspp.txt reliability.sps], [0],
   [reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet implemented.  No statistics will be produced.
 ])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Scale: Everything
 
 Table: Case Processing Summary
-,,N,%
-Cases,Valid,131,92.91
-,Excluded,10,7.09
-,Total,141,100.00
+Cases,N,Percent
+Valid,131,92.9%
+Excluded,10,7.1%
+Total,141,100.0%
 
 Table: Reliability Statistics
 Cronbach's Alpha,N of Items
@@ -218,10 +218,10 @@ Cronbach's Alpha,N of Items
 Scale: Nothing
 
 Table: Case Processing Summary
-,,N,%
-Cases,Valid,131,92.91
-,Excluded,10,7.09
-,Total,141,100.00
+Cases,N,Percent
+Valid,131,92.9%
+Excluded,10,7.1%
+Total,141,100.0%
 
 Table: Reliability Statistics
 Cronbach's Alpha,Part 1,Value,.55
@@ -239,10 +239,10 @@ reliability.sps:174: warning: RELIABILITY: The STATISTICS subcommand is not yet
 Scale: Totals
 
 Table: Case Processing Summary
-,,N,%
-Cases,Valid,131,92.91
-,Excluded,10,7.09
-,Total,141,100.00
+Cases,N,Percent
+Valid,131,92.9%
+Excluded,10,7.1%
+Total,141,100.0%
 
 Table: Reliability Statistics
 Cronbach's Alpha,N of Items
@@ -258,10 +258,10 @@ var17,16.60,8.00,.57,.67
 Scale: ANY
 
 Table: Case Processing Summary
-,,N,%
-Cases,Valid,131,92.91
-,Excluded,10,7.09
-,Total,141,100.00
+Cases,N,Percent
+Valid,131,92.9%
+Excluded,10,7.1%
+Total,141,100.0%
 
 Table: Reliability Statistics
 Cronbach's Alpha,N of Items
@@ -335,18 +335,18 @@ reliability variables = v1 v3 v4.
 ])
 
 AT_CHECK([ln -s $top_srcdir/examples/hotel.sav .], [0])
-AT_CHECK([pspp -O format=csv tut-example.sps], [0], [dnl 
+AT_CHECK([pspp -o pspp.csv -o pspp.txt tut-example.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Scale: ANY
 
 Table: Case Processing Summary
-,,N,%
-Cases,Valid,17,100.00
-,Excluded,0,.00
-,Total,17,100.00
+Cases,N,Percent
+Valid,17,100.0%
+Excluded,0,.0%
+Total,17,100.0%
 
 Table: Reliability Statistics
 Cronbach's Alpha,N of Items
 .81,3
 ])
-
 AT_CLEANUP
index c1fa369b4496ac8e22b23d45622f427794443d6e..5725557c234c8371b3a2ac69238b913404b82228 100644 (file)
@@ -51,19 +51,19 @@ a,Unweighted,Weighted
 Positive,5,50.000
 Negative,5,50.000
 
-Table: Area Under the Curve (x)
-,,,Asymp. 99% Confidence Interval,
-Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound
-.910,.030,.000,.839,.981
-
-Table: Coordinates of the Curve (x)
-Positive if greater than or equal to,Sensitivity,1 - Specificity
-.000,1.000,1.000
-1.500,.960,.440
-2.500,.880,.160
-3.500,.680,.060
-4.500,.400,.020
-6.000,.000,.000
+Table: Area Under the Curve
+,Area,Std. Error,Asymptotic Sig.,Asymp. 99% Confidence Interval,
+Variable under test,,,,Lower Bound,Upper Bound
+x,.910,.030,.000,.839,.981
+
+Table: Coordinates of the Curve
+Test variable,Positive if greater than or equal to,Sensitivity,1 - Specificity
+x,.000,1.000,1.000
+,1.500,.960,.440
+,2.500,.880,.160
+,3.500,.680,.060
+,4.500,.400,.020
+,6.000,.000,.000
 ])
 AT_CLEANUP
 
@@ -103,8 +103,8 @@ Positive,5,50.000
 Negative,5,50.000
 
 Table: Area Under the Curve
-,,,,Asymp. 95% Confidence Interval,
-Variable under test,Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound
+,Area,Std. Error,Asymptotic Sig.,Asymp. 95% Confidence Interval,
+Variable under test,,,,Lower Bound,Upper Bound
 x,.910,.030,.000,.860,.960
 y,.697,.052,.001,.611,.783
 
@@ -166,7 +166,7 @@ roc x by a (1)
        print = se 
        .
 ])
-AT_CHECK([pspp -o pspp.csv roc.sps])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt roc.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Case Summary
 ,Valid N (listwise),
@@ -174,10 +174,10 @@ a,Unweighted,Weighted
 Positive,14,14.000
 Negative,14,14.000
 
-Table: Area Under the Curve (x)
-,,,Asymp. 95% Confidence Interval,
-Area,Std. Error,Asymptotic Sig.,Lower Bound,Upper Bound
-.490,.111,.927,.307,.673
+Table: Area Under the Curve
+,Area,Std. Error,Asymptotic Sig.,Asymp. 95% Confidence Interval,
+Variable under test,,,,Lower Bound,Upper Bound
+x,.490,.111,.927,.307,.673
 ])
 AT_CLEANUP
 
index 46492319cf04ccb623fe95a0829ec0727c1f23b1..8cd4e6cb558ac240457d6fc866c1e9005775486b 100644 (file)
@@ -30,7 +30,8 @@ end data.
 t-test /PAIRS a with b (PAIRED).
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 ID,F8.0
@@ -38,21 +39,20 @@ A,F8.0
 B,F8.0
 
 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
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,A,5,2.00,.71,.32
+,B,5,4.00,1.54,.69
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,A & B,5,.92,.028
+Pair 1,A & B,5,.918,.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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009
 ])
-
 AT_CLEANUP
 
 
@@ -81,21 +81,21 @@ c,F8.0
 d,F8.0
 
 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
-Pair 2,c,5.10,5,.69,.31
-,d,3.80,5,.16,.07
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,a,5,2.00,.71,.32
+,b,5,4.00,1.54,.69
+Pair 2,c,5,5.10,.69,.31
+,d,5,3.80,.16,.07
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,a & b,5,.92,.028
-Pair 2,c & d,5,-.92,.028
+Pair 1,a & b,5,.918,.028
+Pair 2,c & d,5,-.918,.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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,a - b,-2.00,.94,.42,-3.16,-.84,-4.78,4,.009
 Pair 2,c - d,1.30,.84,.37,.26,2.34,3.47,4,.025
 ])
@@ -145,21 +145,21 @@ c,F8.0
 d,F8.0
 
 Table: Paired Sample Statistics
-,,Mean,N,Std. Deviation,S.E. Mean
-Pair 1,a,2.00,5,.71,.32
-,c,5.10,5,.69,.31
-Pair 2,b,4.00,5,1.54,.69
-,d,3.80,5,.16,.07
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,a,5,2.00,.71,.32
+,c,5,5.10,.69,.31
+Pair 2,b,5,4.00,1.54,.69
+,d,5,3.80,.16,.07
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,a & c,5,.41,.493
-Pair 2,b & d,5,-.87,.054
+Pair 1,a & c,5,.410,.493
+Pair 2,b & d,5,-.872,.054
 
 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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,a - c,-3.10,.76,.34,-4.04,-2.16,-9.14,4,.001
 Pair 2,b - d,.20,1.68,.75,-1.89,2.29,.27,4,.803
 ])
@@ -209,23 +209,23 @@ T-TEST
         /CRITERIA=CI(0.95).
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Paired Sample Statistics
-,,Mean,N,Std. Deviation,S.E. Mean
-Pair 1,y,1.94,530.00,.96,.04
-,x,1.03,530.00,.17,.01
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,y,530.00,1.94,.96,.04
+,x,530.00,1.03,.17,.01
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,y & x,530.00,.11,.008
+Pair 1,y & x,530.00,.114,.008
 
 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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,y - x,.91,.95,.04,.83,.99,22.07,529.00,.000
 ])
-
 AT_CLEANUP
 
 
@@ -251,18 +251,18 @@ A,F8.0
 B,F8.0
 
 Table: Paired Sample Statistics
-,,Mean,N,Std. Deviation,S.E. Mean
-Pair 1,A,4.333,3,5.774,3.333
-,B,1.333,3,.577,.333
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,A,3,4.333,5.774,3.333
+,B,3,1.333,.577,.333
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
 Pair 1,A & B,3,1.000,.000
 
 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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,A - B,3.000,5.196,3.000,-9.908,15.908,1.000,2,.423
 ])
 AT_CLEANUP
@@ -290,7 +290,8 @@ end data.
 t-test /GROUPS=indep(1.1,2.1) /var=dep1 dep2.
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 ID,F8.0
@@ -299,22 +300,21 @@ DEP1,F8.0
 DEP2,F8.0
 
 Table: Group Statistics
-,INDEP,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 DEP1,1.10,5,2.00,.71,.32
 ,2.10,5,4.00,.71,.32
 DEP2,1.10,5,4.00,.71,.32
 ,2.10,5,2.00,.71,.32
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 DEP1,Equal variances assumed,.00,1.000,-4.47,8.00,.002,-2.00,.45,-3.03,-.97
 ,Equal variances not assumed,,,-4.47,8.00,.002,-2.00,.45,-3.03,-.97
 DEP2,Equal variances assumed,.00,1.000,4.47,8.00,.002,2.00,.45,.97,3.03
 ,Equal variances not assumed,,,4.47,8.00,.002,2.00,.45,.97,3.03
 ])
-
 AT_CLEANUP
 
 AT_SETUP([T-TEST /GROUPS with one value for independent variable])
@@ -347,21 +347,22 @@ end data.
 t-test /groups=indep(1.514) /var=dep.
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 INDEP,F8.0
 DEP,F8.0
 
 Table: Group Statistics
-,INDEP,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 DEP,≥    1.51,11,9.00,3.82,1.15
 ,<    1.51,11,8.00,2.86,.86
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 DEP,Equal variances assumed,.17,.683,.69,20.00,.495,1.00,1.44,-2.00,4.00
 ,Equal variances not assumed,,,.69,18.54,.496,1.00,1.44,-2.02,4.02
 ])
@@ -389,16 +390,16 @@ dep1,F8.0
 dep2,F8.0
 
 Table: Group Statistics
-,indep,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 dep1,1.00,3,2.50,.87,.50
 ,2.00,2,3.25,.35,.25
 dep2,1.00,3,5.00,1.00,.58
 ,2.00,2,2.00,1.41,1.00
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 dep1,Equal variances assumed,3.75,.148,-1.12,3.00,.346,-.75,.67,-2.89,1.39
 ,Equal variances not assumed,,,-1.34,2.78,.279,-.75,.56,-2.61,1.11
 dep2,Equal variances assumed,.60,.495,2.85,3.00,.065,3.00,1.05,-.35,6.35
@@ -451,16 +452,16 @@ dep1,F8.0
 dep2,F8.0
 
 Table: Group Statistics
-,indep,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 dep1,1.00,3,2.50,.87,.50
 ,2.00,3,3.50,.50,.29
 dep2,1.00,3,5.00,1.00,.58
 ,2.00,3,2.00,1.00,.58
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 dep1,Equal variances assumed,2.00,.230,-1.73,4.00,.158,-1.00,.58,-2.60,.60
 ,Equal variances not assumed,,,-1.73,3.20,.176,-1.00,.58,-2.77,.77
 dep2,Equal variances assumed,.00,1.000,3.67,4.00,.021,3.00,.82,.73,5.27
@@ -501,7 +502,8 @@ end data.
 
 t-test /testval=2.0 /var=abc.
 ])
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 ID,F8.0
@@ -512,9 +514,9 @@ Table: One-Sample Statistics
 ABC,6,3.00,.84,.34
 
 Table: One-Sample Test
-,Test Value = 2.000000,,,,,
-,,,,,95% Confidence Interval of the Difference,
-,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper
+,Test Value = 2,,,,,
+,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference,
+,,,,,Lower,Upper
 ABC,2.93,5,.033,1.00,.12,1.88
 ])
 AT_CLEANUP
@@ -546,9 +548,9 @@ x1,6,3.00,.84,.34
 x2,6,32.67,33.40,13.64
 
 Table: One-Sample Test
-,Test Value = 3.000000,,,,,
-,,,,,95% Confidence Interval of the Difference,
-,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper
+,Test Value = 3,,,,,
+,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference,
+,,,,,Lower,Upper
 x1,.00,5,1.000,.00,-.88,.88
 x2,2.18,5,.082,29.67,-5.39,64.72
 ])
@@ -598,9 +600,9 @@ x1,5,2.80,.76,.34
 x2,5,37.60,34.82,15.57
 
 Table: One-Sample Test
-,Test Value = 3.000000,,,,,
-,,,,,95% Confidence Interval of the Difference,
-,t,df,Sig. (2-tailed),Mean Difference,Lower,Upper
+,Test Value = 3,,,,,
+,t,df,Sig. (2-tailed),Mean Difference,95% Confidence Interval of the Difference,
+,,,,,Lower,Upper
 x1,-.59,4,.587,-.20,-1.14,.74
 x2,2.22,4,.090,34.60,-8.63,77.83
 ])
@@ -646,14 +648,14 @@ ind,F8.0
 x,F8.0
 
 Table: Group Statistics
-,ind,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 x,1.00,3,2.50,.87,.50
 ,2.00,3,3.50,.50,.29
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 x,Equal variances assumed,2.00,.230,-1.73,4.00,.158,-1.00,.58,-2.60,.60
 ,Equal variances not assumed,,,-1.73,3.20,.176,-1.00,.58,-2.77,.77
 ])
@@ -680,6 +682,36 @@ AT_CHECK([pspp -o temporary.csv temporary.sps])
 AT_CHECK([cat temporary.csv], [0], [expout])
 AT_CLEANUP
 
+dnl This is an example from doc/tutorial.texi
+dnl So if the results of this have to be changed in any way,
+dnl make sure to update that file.
+AT_SETUP([T-TEST tutorial example])
+cp $top_srcdir/examples/physiology.sav .
+AT_DATA([t-test.sps], [dnl
+GET FILE='physiology.sav'.
+RECODE height (179 = SYSMIS).
+T-TEST GROUP=sex(0,1) /VARIABLES=height temperature.
+])
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Group Statistics
+,Group,N,Mean,Std. Deviation,S.E. Mean
+Height in millimeters   ,Male,22,1796.49,49.71,10.60
+,Female,17,1610.77,25.43,6.17
+Internal body temperature in degrees Celcius,Male,22,36.68,1.95,.42
+,Female,18,37.43,1.61,.38
+
+Table: Independent Samples Test
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
+Height in millimeters   ,Equal variances assumed,.97,.331,14.02,37.00,.000,185.72,13.24,158.88,212.55
+,Equal variances not assumed,,,15.15,32.71,.000,185.72,12.26,160.76,210.67
+Internal body temperature in degrees Celcius,Equal variances assumed,.31,.581,-1.31,38.00,.198,-.75,.57,-1.91,.41
+,Equal variances not assumed,,,-1.33,37.99,.190,-.75,.56,-1.89,.39
+])
+AT_CLEANUP
+
 dnl Tests for a bug which caused T-TEST to crash when given invalid syntax.
 AT_SETUP([T-TEST invalid syntax])
 AT_DATA([t-test.sps], [dnl
@@ -725,7 +757,8 @@ end data.
 t-test /GROUPS=indep('a','b') /var=dep1 dep2.
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 ID,F8.0
@@ -734,16 +767,16 @@ DEP1,F8.0
 DEP2,F8.0
 
 Table: Group Statistics
-,INDEP,N,Mean,Std. Deviation,S.E. Mean
+,Group,N,Mean,Std. Deviation,S.E. Mean
 DEP1,a,5,2.00,.71,.32
 ,b,5,4.00,.71,.32
 DEP2,a,5,4.00,.71,.32
 ,b,5,2.00,.71,.32
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 DEP1,Equal variances assumed,.00,1.000,-4.47,8.00,.002,-2.00,.45,-3.03,-.97
 ,Equal variances not assumed,,,-4.47,8.00,.002,-2.00,.45,-3.03,-.97
 DEP2,Equal variances assumed,.00,1.000,4.47,8.00,.002,2.00,.45,.97,3.03
@@ -795,21 +828,22 @@ t-test group=gv('One', 'Two')
        /variables = x.
 ])
 
-AT_CHECK([pspp -O format=csv t-test.sps], [0], [dnl
+AT_CHECK([pspp -o pspp.csv -o pspp.txt t-test.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
 x,F8.0
 gv,A8
 
 Table: Group Statistics
-,gv,N,Mean,Std. Deviation,S.E. Mean
-x,One     ,5,2.60,.55,.24
-,Two     ,3,3.50,.50,.29
+,Group,N,Mean,Std. Deviation,S.E. Mean
+x,One,5,2.60,.55,.24
+,Two,3,3.50,.50,.29
 
 Table: Independent Samples Test
-,,Levene's Test for Equality of Variances,,t-test for Equality of Means,,,,,,
-,,,,,,,,,95% Confidence Interval of the Difference,
-,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,Lower,Upper
+,,Levene's Test for Equality of Variances,,T-Test for Equality of Means,,,,,,
+,,F,Sig.,t,df,Sig. (2-tailed),Mean Difference,Std. Error Difference,95% Confidence Interval of the Difference,
+,,,,,,,,,Lower,Upper
 x,Equal variances assumed,1.13,.329,-2.32,6.00,.060,-.90,.39,-1.85,.05
 ,Equal variances not assumed,,,-2.38,4.70,.067,-.90,.38,-1.89,.09
 ])
@@ -877,7 +911,3 @@ t-test /MISSING=listwise /PAIRS a"b with c d (PA    RED).
 AT_CHECK([pspp t.sps],[1],[ignore],[ignore])
 
 AT_CLEANUP
-
-
-
-
index 059fdfbbc34a6f83a68639c97685be70de6cffed..b6ff8187cdd126656c068a79f9bb75d5b567b13e 100644 (file)
@@ -31,9 +31,11 @@ DESCRIPTIVES /x.
 AT_CHECK([pspp -O format=csv set.pspp], [1], [dnl
 "set.pspp:7: error: SET: Output format F41.0 specifies width 41, but F requires a width between 1 and 40."
 
-Table: Valid cases = 3; cases with missing value(s) = 0.
-Variable,N,Mean,Std Dev,Minimum,Maximum
+Table: Descriptive Statistics
+,N,Mean,Std Dev,Minimum,Maximum
 x,3,2.00,1.00,1.00,3.00
+Valid N (listwise),3,,,,
+Missing N (listwise),0,,,,
 ])
 AT_CLEANUP
 
index bd8318ffb9d20495f04a7c8c3e08fdc34b25c4a7..bbfb98b69534a6ca76f3c292ef61b4b7223921fb 100644 (file)
@@ -80,76 +80,50 @@ Variable,Record,Columns,Format
 X,1,1-  1,F1.0
 Y,1,2-  2,F1.0
 
-Documents in the active dataset:
-
-document First line of a document
-
+Table: Documents
+"document First line of a document
 Second line of a document
-
 The last line should end with a period: .
+   (Entered <date>)"
 
-(Entered <date>)
-
-File label: This is a test file label
-
-Documents in the active dataset:
-
-document First line of a document
+Table: File Label
+Label,This is a test file label
 
+Table: Documents
+"document First line of a document
 Second line of a document
-
 The last line should end with a period: .
-
-(Entered <date>)
-
+   (Entered <date>)
 Line one
-
 Line two
+   (Entered <date>)"
 
-(Entered <date>)
-
-File label: This is a test file label
-
-Documents in the active dataset:
-
-document First line of a document
+Table: File Label
+Label,This is a test file label
 
+Table: Documents
+"document First line of a document
 Second line of a document
-
 The last line should end with a period: .
-
-(Entered <date>)
-
+   (Entered <date>)
 Line one
-
 Line two
-
-(Entered <date>)
-
+   (Entered <date>)
 document There should be another document now.
+   (Entered <date>)"
 
-(Entered <date>)
-
-Documents in the active dataset:
-
-document First line of a document
-
+Table: Documents
+"document First line of a document
 Second line of a document
-
 The last line should end with a period: .
-
-(Entered <date>)
-
+   (Entered <date>)
 Line one
-
 Line two
-
-(Entered <date>)
-
+   (Entered <date>)
 document There should be another document now.
+   (Entered <date>)"
 
-(Entered <date>)
-
-File label: This is a test file label
+Table: File Label
+Label,This is a test file label
 ])
 AT_CLEANUP
index 85e52caffd40edbf0f220ea587619cfb6efc3e15..12a620b798c777ff8f88007b55586416ae6d5dc8 100644 (file)
@@ -58,8 +58,8 @@ B,A3
 
 Table: Data List
 A,B
-ABC                                                                                                                                                              ,def
-GHI                                                                                                                                                              ,jkl
+ABC,def
+GHI,jkl
 ])
 AT_CLEANUP
 
index 88d842d564636d5a3726162812a0fcf9b8b191ab..6f689c2c6ad0210a1af5bc20d56607c7e342197c 100644 (file)
@@ -81,8 +81,8 @@ v2,1,3-  4,A2
 Table: Data List
 v1,v2,c
 12,34,.00
-32,1 ,1.00
-2 ,13,1.00
+32,1,1.00
+2,13,1.00
 41,21,.00
 11,04,.00
 03,4,1.00
index 05f2ef64db57da4b03dd5908b510ecb9f52fae3b..2d89c5e0b779daf9e2b580390cd8116dd06d6535 100644 (file)
@@ -155,17 +155,17 @@ LIST s t s0 TO s3 t0 TO t3.
 AT_CHECK([pspp -O format=csv recode.sps], [0],
   [Table: Data List
 s,t,s0,s1,s2,s3,t0,t1,t2,t3
-,,,,xyz ,,,,xyz       ,
-a   ,a         ,b   ,,xyz ,,b         ,,xyz       ,b         @&t@
-ab  ,ab        ,bc  ,,xyz ,,bc        ,,xyz       ,
-abc ,abc       ,,,def ,,,,def       ,
-abcd,abcd      ,,xyzw,xyz ,,,xyzw      ,xyz       ,
-123 ,123       ,,,xyz ,,,,xyz       ,
-123,123      ,,,xyz ,,,,xyz       ,
-+1  ,+1        ,,,xyz ,,,,xyz       ,
-1x  ,1x        ,,,xyz ,,,,xyz       ,
-abcd,abcdefghi ,,xyzw,xyz ,,,,xyz       ,xyz       @&t@
-xxx ,abcdefghij,,,xyz ,gone,,,xyz       ,jklmnopqr @&t@
+,,,,xyz,,,,xyz,
+a,a,b,,xyz,,b,,xyz,b
+ab,ab,bc,,xyz,,bc,,xyz,
+abc,abc,,,def,,,,def,
+abcd,abcd,,xyzw,xyz,,,xyzw,xyz,
+123,123,,,xyz,,,,xyz,
+123,123,,,xyz,,,,xyz,
++1,+1,,,xyz,,,,xyz,
+1x,1x,,,xyz,,,,xyz,
+abcd,abcdefghi,,xyzw,xyz,,,,xyz,xyz
+xxx,abcdefghij,,,xyz,gone,,,xyz,jklmnopqr
 ])
 AT_CLEANUP
 
@@ -183,17 +183,17 @@ LIST s t cs0 TO cs2 ct0 TO ct3.
 AT_CHECK([pspp -O format=csv recode.sps], [0],
   [Table: Data List
 s,t,cs0,cs1,cs2,ct0,ct1,ct2,ct3
-,,,,xyz ,,,xyz       ,
-a   ,a         ,b   ,a   ,xyz ,b         ,a         ,xyz       ,b         @&t@
-ab  ,ab        ,bc  ,ab  ,xyz ,bc        ,ab        ,xyz       ,ab        @&t@
-abc ,abc       ,abc ,abc ,def ,abc       ,abc       ,def       ,abc       @&t@
-abcd,abcd      ,abcd,xyzw,xyz ,abcd      ,xyzw      ,xyz       ,abcd      @&t@
-123 ,123       ,123 ,123 ,xyz ,123       ,123       ,xyz       ,123       @&t@
-123,123      ,123,123,xyz ,123      ,123      ,xyz       ,123      @&t@
-+1  ,+1        ,+1  ,+1  ,xyz ,+1        ,+1        ,xyz       ,+1        @&t@
-1x  ,1x        ,1x  ,1x  ,xyz ,1x        ,1x        ,xyz       ,1x        @&t@
-abcd,abcdefghi ,abcd,xyzw,xyz ,abcdefghi ,abcdefghi ,xyz       ,xyz       @&t@
-xxx ,abcdefghij,xxx ,xxx ,xyz ,abcdefghij,abcdefghij,xyz       ,jklmnopqr @&t@
+,,,,xyz,,,xyz,
+a,a,b,a,xyz,b,a,xyz,b
+ab,ab,bc,ab,xyz,bc,ab,xyz,ab
+abc,abc,abc,abc,def,abc,abc,def,abc
+abcd,abcd,abcd,xyzw,xyz,abcd,xyzw,xyz,abcd
+123,123,123,123,xyz,123,123,xyz,123
+123,123,123,123,xyz,123,123,xyz,123
++1,+1,+1,+1,xyz,+1,+1,xyz,+1
+1x,1x,1x,1x,xyz,1x,1x,xyz,1x
+abcd,abcdefghi,abcd,xyzw,xyz,abcdefghi,abcdefghi,xyz,xyz
+xxx,abcdefghij,xxx,xxx,xyz,abcdefghij,abcdefghij,xyz,jklmnopqr
 ])
 AT_CLEANUP
 
@@ -210,16 +210,16 @@ AT_CHECK([pspp -O format=csv recode.sps], [0],
   [Table: Data List
 s,t,ns0,ns1,ns2,nt0,nt1,nt2
 ,,.,0,3,.,0,3
-a   ,a         ,.,.,3,.,.,3
-ab  ,ab        ,.,.,3,.,.,3
-abc ,abc       ,.,.,3,.,.,3
-abcd,abcd      ,1,1,2,1,1,2
-123 ,123       ,123,123,3,123,123,3
-123,123      ,123,123,3,123,123,3
-+1  ,+1        ,1,1,3,1,1,3
-1x  ,1x        ,.,.,1,.,.,1
-abcd,abcdefghi ,1,1,2,.,.,3
-xxx ,abcdefghij,.,.,3,.,.,3
+a,a,.,.,3,.,.,3
+ab,ab,.,.,3,.,.,3
+abc,abc,.,.,3,.,.,3
+abcd,abcd,1,1,2,1,1,2
+123,123,123,123,3,123,123,3
+123,123,123,123,3,123,123,3
++1,+1,1,1,3,1,1,3
+1x,1x,.,.,1,.,.,1
+abcd,abcdefghi,1,1,2,.,.,3
+xxx,abcdefghij,.,.,3,.,.,3
 ])
 AT_CLEANUP
 
@@ -235,17 +235,17 @@ LIST x sx0 TO sx2.
 AT_CHECK([pspp -O format=csv recode.sps], [0],
   [Table: Data List
 x,sx0,sx1,sx2
-0,,xxx       ,foobar    @&t@
-1,abcdefghij,xxx       ,foobar    @&t@
-2,abcdefghij,,xyz       @&t@
-3,abcdefghij,xxx       ,xyz       @&t@
-4,abcdefghij,,xyz       @&t@
-5,abcdefghij,xxx       ,xyz       @&t@
-6,abcdefghij,,xyz       @&t@
-7,abcdefghij,xxx       ,foobar    @&t@
-8,abcdefghij,,foobar    @&t@
-9,abcdefghij,xxx       ,foobar    @&t@
-.,,xxx       ,xyz       @&t@
+0,,xxx,foobar
+1,abcdefghij,xxx,foobar
+2,abcdefghij,,xyz
+3,abcdefghij,xxx,xyz
+4,abcdefghij,,xyz
+5,abcdefghij,xxx,xyz
+6,abcdefghij,,xyz
+7,abcdefghij,xxx,foobar
+8,abcdefghij,,foobar
+9,abcdefghij,xxx,foobar
+.,,xxx,xyz
 ])
 AT_CLEANUP
 
@@ -334,10 +334,10 @@ AT_CHECK([pspp -O format=csv recode.sps], [1], [dnl
 
 Table: Data List
 x,y,z
-a,a       ,2.00
-a,two     ,2.00
-b,three   ,2.00
-c,b       ,2.00
+a,a,2.00
+a,two,2.00
+b,three,2.00
+c,b,2.00
 ])
 
 AT_CLEANUP
index 3f13ea8e8d1da989f397e60280a28ba6cc7a2e81..934de64662b557c3c23e3f7c4bd220f3fdf86cfc 100644 (file)
@@ -620,7 +620,7 @@ DATA LIST LIST /x * y * a (a23).
 Reading free-form data from INLINE.
 +--------+------+
 |Variable|Format|
-#========#======#
++--------+------+
 |x       |F8.0  |
 |y       |F8.0  |
 |a       |A23   |
@@ -660,12 +660,14 @@ DESCRIPTIVES X.
 
 
 AT_CHECK([pspp -O box=unicode uc.sps], [0], [dnl
-Valid cases = 3; cases with missing value(s) = 0.
-╭────────╥─┬──────┬───────┬───────┬───────╮
-│Variable║N│ Mean │Std Dev│Minimum│Maximum│
-╞════════╬═╪══════╪═══════╪═══════╪═══════╡
-│x       ║3│2.0000│ 1.0000│ 1.0000│ 3.0000│
-╰────────╨─┴──────┴───────┴───────┴───────╯
+                 Descriptive Statistics
+╭────────────────────┬─┬──────┬───────┬───────┬───────╮
+│                    │N│ Mean │Std Dev│Minimum│Maximum│
+├────────────────────┼─┼──────┼───────┼───────┼───────┤
+│x                   │3│2.0000│ 1.0000│ 1.0000│ 3.0000│
+│Valid N (listwise)  │3│      │       │       │       │
+│Missing N (listwise)│0│      │       │       │       │
+╰────────────────────┴─┴──────┴───────┴───────┴───────╯
 ])
 
 AT_CLEANUP
index d60c427a38542d295dbf641f24963d187145c5e9..bc2328063941582ec004ecb4bc8d1e893fc5be7e 100644 (file)
@@ -1387,11 +1387,13 @@ LIST.
 ])
 AT_CHECK([pspp list.sps], [0], [dnl
 Data List
-x y z
------
-1 2 3
-4 5 6
-7 8 9
++-+-+-+
+|x|y|z|
++-+-+-+
+|1|2|3|
+|4|5|6|
+|7|8|9|
++-+-+-+
 ])
 AT_CLEANUP
 
index 623d366c0cc1371e2a0ceb1d1ddbce5f26c44199..be911d1563327722afaf994953123d4264ce800a 100644 (file)
@@ -46,33 +46,33 @@ 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
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,A,5,2.00,.71,.32
+,B,5,4.00,1.54,.69
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,A & B,5,.92,.028
+Pair 1,A & B,5,.918,.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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 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
+,,N,Mean,Std. Deviation,S.E. Mean
+Pair 1,A,5,2.00,.71,.32
+,B,5,4.00,1.54,.69
 
 Table: Paired Samples Correlations
 ,,N,Correlation,Sig.
-Pair 1,A & B,5,.92,.02801
+Pair 1,A & B,5,.918,.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)
+,,Paired Differences,,,,,t,df,Sig. (2-tailed)
+,,Mean,Std. Deviation,S.E. Mean,95% Confidence Interval of the Difference,,,,
+,,,,,Lower,Upper,,,
 Pair 1,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.00877
 ])
 
@@ -100,4 +100,4 @@ t-test /PAIRS a with b (PAIRED).
 
 AT_CHECK([pspp -O format=csv prec.sps], [1], [ignore])
 
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
index 175a09aae83bceab86c0f95fb72b9a3301cc614e..cbe2a0dd33175ef9aa4b30dcf00f94bb2ebfa65e 100644 (file)
@@ -76,11 +76,11 @@ DISPLAY DOCUMENTS.
 DISPLAY DICTIONARY.
 SHOW WEIGHT.
 ])
-AT_CHECK([pspp -O format=csv dump-dict.sps], [0],
-  [File label: My Dictionary
-
-Documents in the active dataset:
+AT_CHECK([pspp -O format=csv dump-dict.sps], [0], [dnl
+Table: File Label
+Label,My Dictionary
 
+Table: Documents
 These Documents
 
 Table: Variables
@@ -160,30 +160,30 @@ Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Fo
 id,1,,Scale,Input,8,Right,F2.0,F2.0,
 name,2,,Nominal,Input,20,Left,A20,A20,
 
-File label: This is the file label
-
-Documents in the active dataset:
+Table: File Label
+Label,This is the file label
 
+Table: Documents
 This is a document line
 
 Table: Data List
 id,name
-34,frederick           @&t@
+34,frederick
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
 id,1,,Scale,Input,8,Right,F2.0,F2.0,
 name,2,,Nominal,Input,20,Left,A20,A20,
 
-File label: This is the file label
-
-Documents in the active dataset:
+Table: File Label
+Label,This is the file label
 
+Table: Documents
 This is a document line
 
 Table: Data List
 id,name
-21,wheelbarrow         @&t@
+21,wheelbarrow
 ])
 AT_CLEANUP
 
@@ -246,13 +246,13 @@ string,2,My String,Nominal,Input,8,Left,A8,A8,"""this    ""; ""that    """
 longstring,3,My Long String,Nominal,Input,9,Left,A9,A9,
 
 Table: Value Labels
-Variable,Value,Label
-integer,0,Zero
+Variable Value,,Label
+My Integer,0,Zero
 ,1,Unity
 ,2,Duality
-string,xx      ,foo
-,yy      ,bar
-longstring,xxx      ,xfoo
+My String,xx,foo
+,yy,bar
+My Long String,xxx,xfoo
 ])
 AT_CLEANUP
 
@@ -461,17 +461,20 @@ dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
 
 Table: Value Labels
-Variable,Value,Label
-string,1111    ,ones
-,2222    ,twos
-,3333    ,threes
-numeric,1,Unity
+Variable Value,,Label
+A Short String Variable,1111,ones
+,2222,twos
+,3333[a],threes
+A Numeric Variable,1,Unity
 ,2,Duality
 ,3,Thripality
 
+Footnotes:
+a,User-missing value
+
 Table: Variable and Dataset Attributes
-Variable,Name,Value
-numeric,colour[1],blue
+Variable and Name,,Value
+A Numeric Variable,colour[1],blue
 ,colour[2],pink
 ,colour[3],violet
 ,nationality,foreign
@@ -479,11 +482,11 @@ numeric,colour[1],blue
 
 Table: Data List
 string,longstring,numeric,date,dollar,datetime
-1111    ,One         ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
-2222    ,Two         ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
-3333    ,Three       ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
-.       ,.           ,.,.,.  ,.
-5555    ,Five        ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
+1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
+2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
+3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
+.,.,.,.,.  ,.
+5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
 
 Table: Variables
 Name,Position,Label,Measurement Level,Role,Width,Alignment,Print Format,Write Format,Missing Values
@@ -495,17 +498,20 @@ dollar,5,A Dollar Variable,Scale,Input,8,Right,DOLLAR11.2,DOLLAR11.2,
 datetime,6,A Datetime Variable,Scale,Input,8,Right,DATETIME17.0,DATETIME17.0,
 
 Table: Value Labels
-Variable,Value,Label
-string,1111    ,ones
-,2222    ,twos
-,3333    ,threes
-numeric,1,Unity
+Variable Value,,Label
+A Short String Variable,1111,ones
+,2222,twos
+,3333[a],threes
+A Numeric Variable,1,Unity
 ,2,Duality
 ,3,Thripality
 
+Footnotes:
+a,User-missing value
+
 Table: Variable and Dataset Attributes
-Variable,Name,Value
-numeric,colour[1],blue
+Variable and Name,,Value
+A Numeric Variable,colour[1],blue
 ,colour[2],pink
 ,colour[3],violet
 ,nationality,foreign
@@ -513,11 +519,11 @@ numeric,colour[1],blue
 
 Table: Data List
 string,longstring,numeric,date,dollar,datetime
-1111    ,One         ,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
-2222    ,Two         ,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
-3333    ,Three       ,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
-.       ,.           ,.,.,.  ,.
-5555    ,Five        ,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
+1111,One,1,01-JAN-2001,$1.00,01-JAN-2001 01:01
+2222,Two,2,02-FEB-2002,$2.00,02-FEB-2002 02:02
+3333,Three,3,03-MAR-2003,$3.00,03-MAR-2003 03:03
+.,.,.,.,.  ,.
+5555,Five,5,05-MAY-2005,$5.00,05-MAY-2005 05:05
 ]])
 AT_CLEANUP