Merge "output" into "master"
authorBen Pfaff <blp@gnu.org>
Mon, 8 Feb 2010 04:22:31 +0000 (20:22 -0800)
committerBen Pfaff <blp@gnu.org>
Mon, 8 Feb 2010 04:37:35 +0000 (20:37 -0800)
462 files changed:
.gitignore
INSTALL
Makefile.am
NEWS
README
Smake
THANKS
acinclude.m4
config/OChangeLog [deleted file]
config/automake.mk [deleted file]
config/devices [deleted file]
config/psfonts/Courier-Bold.afm [deleted file]
config/psfonts/Courier-BoldOblique.afm [deleted file]
config/psfonts/Courier-Oblique.afm [deleted file]
config/psfonts/Courier.afm [deleted file]
config/psfonts/Helvetica-Bold.afm [deleted file]
config/psfonts/Helvetica-BoldOblique.afm [deleted file]
config/psfonts/Helvetica-Oblique.afm [deleted file]
config/psfonts/Helvetica.afm [deleted file]
config/psfonts/Times-Bold.afm [deleted file]
config/psfonts/Times-BoldItalic.afm [deleted file]
config/psfonts/Times-Italic.afm [deleted file]
config/psfonts/Times-Roman.afm [deleted file]
configure.ac
doc/automake.mk
doc/configuring.texi [deleted file]
doc/data-io.texi
doc/introduction.texi
doc/invoking.texi
doc/language.texi
doc/pspp.texinfo
doc/utilities.texi
lib/automake.mk
perl-module/Makefile.PL
perl-module/automake.mk
perl-module/lib/PSPP.pm
perl-module/t/Pspp.t
src/data/automake.mk
src/data/caseproto.c
src/data/caseproto.h
src/data/casereader-project.c [new file with mode: 0644]
src/data/casereader-select.c [new file with mode: 0644]
src/data/casereader-translator.c
src/data/casereader.c
src/data/casereader.h
src/data/casewindow.c
src/data/data-in.c
src/data/datasheet.c
src/data/dictionary.c
src/data/file-name.c
src/data/file-name.h
src/data/make-file.c
src/data/make-file.h
src/data/por-file-reader.c
src/data/procedure.c
src/data/settings.c
src/data/settings.h
src/data/subcase.c
src/data/subcase.h
src/data/value-labels.c
src/data/value-labels.h
src/data/variable.c
src/language/automake.mk
src/language/command.c
src/language/control/repeat.c
src/language/data-io/data-parser.c
src/language/data-io/data-reader.c
src/language/data-io/list.q
src/language/data-io/print-space.c
src/language/data-io/print.c
src/language/dictionary/split-file.c
src/language/dictionary/sys-file-info.c
src/language/expressions/helpers.c
src/language/lexer/lexer.c
src/language/lexer/variable-parser.c
src/language/prompt.c
src/language/stats/aggregate.c
src/language/stats/automake.mk
src/language/stats/binomial.c
src/language/stats/chisquare.c
src/language/stats/correlations.c
src/language/stats/crosstabs.q
src/language/stats/descriptives.c
src/language/stats/examine.q
src/language/stats/factor.c
src/language/stats/frequencies.q
src/language/stats/glm.q
src/language/stats/npar-summary.c
src/language/stats/npar.q
src/language/stats/oneway.q
src/language/stats/rank.q
src/language/stats/regression.q
src/language/stats/reliability.q
src/language/stats/roc.c
src/language/stats/roc.h [new file with mode: 0644]
src/language/stats/sign.c
src/language/stats/t-test.q
src/language/stats/wilcoxon.c
src/language/syntax-file.c
src/language/syntax-string-source.c
src/language/tests/paper-size.c
src/language/utilities/echo.c
src/language/utilities/include.c
src/language/utilities/set.q
src/language/utilities/title.c
src/language/xforms/count.c
src/libpspp/abt.c
src/libpspp/abt.h
src/libpspp/array.c
src/libpspp/array.h
src/libpspp/automake.mk
src/libpspp/bt.c
src/libpspp/bt.h
src/libpspp/cast.h [new file with mode: 0644]
src/libpspp/compiler.h
src/libpspp/getl.c
src/libpspp/getl.h
src/libpspp/hash.h
src/libpspp/heap.h
src/libpspp/hmap.h
src/libpspp/hmapx.c
src/libpspp/hmapx.h
src/libpspp/intern.c [new file with mode: 0644]
src/libpspp/intern.h [new file with mode: 0644]
src/libpspp/ll.c
src/libpspp/ll.h
src/libpspp/llx.c
src/libpspp/llx.h
src/libpspp/message.c
src/libpspp/message.h
src/libpspp/msg-locator.c
src/libpspp/range-map.h
src/libpspp/range-set.c
src/libpspp/range-set.h
src/libpspp/sparse-array.c
src/libpspp/str.c
src/libpspp/str.h
src/libpspp/string-array.c [new file with mode: 0644]
src/libpspp/string-array.h [new file with mode: 0644]
src/libpspp/string-map.c [new file with mode: 0644]
src/libpspp/string-map.h [new file with mode: 0644]
src/libpspp/string-set.c [new file with mode: 0644]
src/libpspp/string-set.h [new file with mode: 0644]
src/libpspp/taint.c
src/libpspp/tmpfile.c
src/libpspp/tower.c
src/libpspp/tower.h
src/libpspp/verbose-msg.c [deleted file]
src/libpspp/verbose-msg.h [deleted file]
src/libpspp/version.h
src/math/box-whisker.c
src/math/box-whisker.h
src/math/histogram.c
src/math/histogram.h
src/math/levene.c
src/math/np.c
src/math/np.h
src/math/order-stats.c
src/math/percentiles.c
src/math/percentiles.h
src/math/trimmed-mean.c
src/math/trimmed-mean.h
src/math/tukey-hinges.c
src/math/tukey-hinges.h
src/output/afm.c [deleted file]
src/output/afm.h [deleted file]
src/output/ascii.c
src/output/automake.mk
src/output/cairo-chart.c [new file with mode: 0644]
src/output/cairo-chart.h [new file with mode: 0644]
src/output/cairo.c [new file with mode: 0644]
src/output/cairo.h [new file with mode: 0644]
src/output/chart-item-provider.h [new file with mode: 0644]
src/output/chart-item.c [new file with mode: 0644]
src/output/chart-item.h [new file with mode: 0644]
src/output/chart.c [deleted file]
src/output/chart.h [deleted file]
src/output/charts/Makefile [deleted file]
src/output/charts/automake.mk [deleted file]
src/output/charts/barchart.c [deleted file]
src/output/charts/barchart.h [deleted file]
src/output/charts/box-whisker.c [deleted file]
src/output/charts/box-whisker.h [deleted file]
src/output/charts/boxplot-cairo.c [new file with mode: 0644]
src/output/charts/boxplot.c [new file with mode: 0644]
src/output/charts/boxplot.h [new file with mode: 0644]
src/output/charts/cartesian.c [deleted file]
src/output/charts/cartesian.h [deleted file]
src/output/charts/dummy-chart.c [deleted file]
src/output/charts/np-plot-cairo.c [new file with mode: 0644]
src/output/charts/np-plot.c [new file with mode: 0644]
src/output/charts/np-plot.h [new file with mode: 0644]
src/output/charts/piechart-cairo.c [new file with mode: 0644]
src/output/charts/piechart.c
src/output/charts/piechart.h
src/output/charts/plot-chart.c [deleted file]
src/output/charts/plot-chart.h [deleted file]
src/output/charts/plot-hist-cairo.c [new file with mode: 0644]
src/output/charts/plot-hist.c
src/output/charts/plot-hist.h
src/output/charts/roc-chart-cairo.c [new file with mode: 0644]
src/output/charts/roc-chart.c [new file with mode: 0644]
src/output/charts/roc-chart.h [new file with mode: 0644]
src/output/charts/scree-cairo.c [new file with mode: 0644]
src/output/charts/scree.c [new file with mode: 0644]
src/output/charts/scree.h [new file with mode: 0644]
src/output/csv.c [new file with mode: 0644]
src/output/driver-provider.h [new file with mode: 0644]
src/output/driver.c [new file with mode: 0644]
src/output/driver.h [new file with mode: 0644]
src/output/dummy-chart.c [deleted file]
src/output/html.c
src/output/htmlP.h [deleted file]
src/output/journal.c
src/output/journal.h
src/output/manager.c [deleted file]
src/output/manager.h [deleted file]
src/output/measure.c [new file with mode: 0644]
src/output/measure.h [new file with mode: 0644]
src/output/message-item.c [new file with mode: 0644]
src/output/message-item.h [new file with mode: 0644]
src/output/mk-class-boilerplate [new file with mode: 0755]
src/output/msglog.c [new file with mode: 0644]
src/output/msglog.h [new file with mode: 0644]
src/output/odt.c [new file with mode: 0644]
src/output/options.c [new file with mode: 0644]
src/output/options.h [new file with mode: 0644]
src/output/output-item-provider.h [new file with mode: 0644]
src/output/output-item.c [new file with mode: 0644]
src/output/output-item.h [new file with mode: 0644]
src/output/output.c [deleted file]
src/output/output.h [deleted file]
src/output/postscript.c [deleted file]
src/output/render.c [new file with mode: 0644]
src/output/render.h [new file with mode: 0644]
src/output/tab.c [new file with mode: 0644]
src/output/tab.h [new file with mode: 0644]
src/output/table-casereader.c [new file with mode: 0644]
src/output/table-item.c [new file with mode: 0644]
src/output/table-item.h [new file with mode: 0644]
src/output/table-paste.c [new file with mode: 0644]
src/output/table-provider.h [new file with mode: 0644]
src/output/table-select.c [new file with mode: 0644]
src/output/table-transpose.c [new file with mode: 0644]
src/output/table.c
src/output/table.h
src/output/text-item.c [new file with mode: 0644]
src/output/text-item.h [new file with mode: 0644]
src/ui/automake.mk
src/ui/command-line.c [deleted file]
src/ui/command-line.h [deleted file]
src/ui/gui/automake.mk
src/ui/gui/executor.c
src/ui/gui/find-dialog.c
src/ui/gui/helper.c
src/ui/gui/main.c
src/ui/gui/message-dialog.c [deleted file]
src/ui/gui/message-dialog.h [deleted file]
src/ui/gui/message-dialog.ui [deleted file]
src/ui/gui/output-viewer.glade
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-output-window.c
src/ui/gui/psppire-output-window.h
src/ui/gui/psppire.c
src/ui/gui/psppire.h
src/ui/gui/syntax-editor-source.c
src/ui/gui/val-labs-dialog.c
src/ui/source-init-opts.c
src/ui/source-init-opts.h
src/ui/terminal/automake.mk
src/ui/terminal/main.c
src/ui/terminal/msg-ui.c
src/ui/terminal/msg-ui.h
src/ui/terminal/read-line.c
src/ui/terminal/terminal-opts.c
src/ui/terminal/terminal-opts.h
tests/.gitignore
tests/atlocal.in [new file with mode: 0644]
tests/automake.mk
tests/bugs/agg-crash-2.sh
tests/bugs/agg_crash.sh
tests/bugs/alpha-freq.sh
tests/bugs/big-input-2.sh
tests/bugs/big-input.sh
tests/bugs/case-map.sh
tests/bugs/comment-at-eof.sh
tests/bugs/compression.sh
tests/bugs/compute-fmt.sh
tests/bugs/compute-lv.sh
tests/bugs/compute-sum.sh
tests/bugs/computebug.out [deleted file]
tests/bugs/computebug.sh
tests/bugs/computebug.stat [deleted file]
tests/bugs/crosstabs-crash.sh
tests/bugs/crosstabs-crash2.sh
tests/bugs/crosstabs.sh
tests/bugs/crosstabs2.sh
tests/bugs/curtailed.sh
tests/bugs/data-crash.sh
tests/bugs/double-frequency.sh
tests/bugs/empty-do-repeat.sh
tests/bugs/examine-1sample.sh
tests/bugs/examine-crash.sh
tests/bugs/examine-crash2.sh
tests/bugs/examine-crash3.sh
tests/bugs/examine-missing.sh
tests/bugs/examine-missing2.sh
tests/bugs/freq-nolabels.sh
tests/bugs/get-no-file.sh
tests/bugs/get.sh
tests/bugs/html-frequency.sh
tests/bugs/if_crash.sh
tests/bugs/input-crash.sh
tests/bugs/keep-all.sh
tests/bugs/lag_crash.sh
tests/bugs/list-overflow.sh
tests/bugs/match-files-scratch.sh
tests/bugs/multipass.sh
tests/bugs/overwrite-input-file.sh
tests/bugs/overwrite-special-file.sh
tests/bugs/piechart.sh
tests/bugs/print-crash.sh
tests/bugs/random.sh
tests/bugs/recode-copy-bug-1.out [deleted file]
tests/bugs/recode-copy-bug-1.stat [deleted file]
tests/bugs/recode-copy-bug-2.out [deleted file]
tests/bugs/recode-copy-bug-2.stat [deleted file]
tests/bugs/recode-copy-bug.sh
tests/bugs/shbang.sh
tests/bugs/signals.sh
tests/bugs/t-test-alpha.sh
tests/bugs/t-test-alpha2.sh
tests/bugs/t-test-alpha3.sh
tests/bugs/t-test-paired.sh
tests/bugs/t-test-with-temp.sh
tests/bugs/t-test.sh
tests/bugs/temp-freq.sh
tests/bugs/temporary.sh
tests/bugs/unwritable-dir.sh
tests/bugs/val-labs-trailing-slash.sh
tests/bugs/val-labs.sh
tests/command/add-files.sh
tests/command/aggregate.sh
tests/command/attributes.sh
tests/command/autorecod.sh
tests/command/beg-data.sh
tests/command/bignum.sh
tests/command/correlation.sh
tests/command/count.sh
tests/command/data-list.sh
tests/command/do-if.sh
tests/command/do-repeat.sh
tests/command/erase.sh
tests/command/examine-extremes.sh
tests/command/examine-percentiles.sh
tests/command/examine.sh
tests/command/file-handle.sh
tests/command/file-label.sh
tests/command/filter.sh
tests/command/flip.sh
tests/command/get-data-gnm.sh
tests/command/get-data-psql.sh
tests/command/get-data-txt-examples.sh
tests/command/get-data-txt-importcases.sh
tests/command/get-data-txt.sh
tests/command/import-export.sh
tests/command/input-program.sh
tests/command/insert.sh
tests/command/lag.sh
tests/command/line-ends.sh
tests/command/list.sh
tests/command/longvars.sh
tests/command/loop.sh
tests/command/match-files.sh
tests/command/missing-values.sh
tests/command/n_of_cases.sh
tests/command/no_case_size.sh
tests/command/npar-binomial.sh
tests/command/npar-chisquare.sh
tests/command/npar-sign.sh
tests/command/npar-wilcoxon.sh
tests/command/oneway-missing.sh
tests/command/oneway-with-splits.sh
tests/command/oneway.sh
tests/command/permissions.sh
tests/command/print-strings.sh
tests/command/print.sh
tests/command/rank.sh
tests/command/regression-qr.sh
tests/command/regression.sh
tests/command/reliability.sh
tests/command/rename.sh
tests/command/roc.sh
tests/command/roc2.sh
tests/command/sample.sh
tests/command/sort.sh
tests/command/split-file.sh
tests/command/sysfile-info.sh
tests/command/sysfiles-old.sh
tests/command/sysfiles.sh
tests/command/t-test-1-indep-val.sh
tests/command/t-test-1-sample-missing-anal.sh
tests/command/t-test-1-sample-missing-list.sh
tests/command/t-test-1s.sh
tests/command/t-test-groups.sh
tests/command/t-test-indep-missing-anal.sh
tests/command/t-test-indep-missing-list.sh
tests/command/t-test-paired-missing-anal.sh
tests/command/t-test-paired-missing-list.sh
tests/command/t-test-pairs.sh
tests/command/tabs.sh
tests/command/trimmed-mean.sh
tests/command/update.sh
tests/command/use.sh
tests/command/variable-display.sh
tests/command/vector.sh
tests/command/very-long-strings.sh
tests/command/weight.sh
tests/coverage.sh
tests/data/datasheet-test.c
tests/expressions/epoch.sh
tests/expressions/expressions.sh
tests/expressions/randist.sh
tests/expressions/valuelabel.sh
tests/expressions/variables.sh
tests/expressions/vectors.sh
tests/formats/360.sh
tests/formats/bcd-in.sh
tests/formats/binhex-out.sh
tests/formats/date-in.sh
tests/formats/date-out.sh
tests/formats/float-format.sh
tests/formats/format-guesser.sh
tests/formats/ib-in.sh
tests/formats/legacy-in.sh
tests/formats/month-in.sh
tests/formats/month-out.sh
tests/formats/num-in.sh
tests/formats/num-out.sh
tests/formats/time-in.sh
tests/formats/time-out.sh
tests/formats/wkday-in.sh
tests/formats/wkday-out.sh
tests/libpspp/hmap-test.c
tests/libpspp/hmapx-test.c
tests/libpspp/llx-test.c
tests/libpspp/range-set-test.c
tests/libpspp/string-map-test.c [new file with mode: 0644]
tests/libpspp/string-set-test.c [new file with mode: 0644]
tests/output/paper-size.sh
tests/output/render-test.c [new file with mode: 0644]
tests/output/render.at [new file with mode: 0644]
tests/stats/descript-basic.sh
tests/stats/descript-mean-bug.sh
tests/stats/descript-missing.sh
tests/stats/moments.sh
tests/stats/ntiles.sh
tests/stats/percentiles-compatible.sh
tests/stats/percentiles-enhanced.sh
tests/test_template
tests/testsuite.at [new file with mode: 0644]
tests/xforms/recode.sh

index f8c59fe0c75a72c414585427f21303daca8261b7..c24b805ae8a18a367325e18fd5268672480a848c 100644 (file)
@@ -40,4 +40,5 @@ gitlog-to-changelog
 *.la
 *.libs
 /arg-nonnull.h
+/package.m4
 /unused-parameter.h
diff --git a/INSTALL b/INSTALL
index 4f1bc84cef9b3c3eda18fc9165cdbc0f5e61d5aa..0f4f5c9687567dfaa9c322407387f889ed7d19be 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -33,12 +33,13 @@ The following packages are required to install PSPP:
       If you don't have a version already, you can install GNU
       libiconv (http://www.gnu.org/software/libiconv/).
 
-The following package is required to enable PSPP's graphing features.
-If you cannot arrange to install it, you must run `configure' with
---without-libplot.
+The following packages are required to enable PSPP's graphing
+features.  If you cannot arrange to install them, you must run
+`configure' with --without-cairo.
 
-    * libplot, from GNU plotutils
-      (http://www.gnu.org/software/plotutils/).
+    * Cairo (http://cairographics.org/), version 1.5 or later.
+
+    * Pango (http://www.pango.org/), version 1.22 or later.
 
 The following packages are required to enable PSPPIRE, the graphical
 user interface for PSPP.  If you cannot install them or do not wish to
@@ -209,14 +210,17 @@ suffix on their names by giving `configure' the  option
 Optional Features
 =================
 
-`--without-libplot'
-    Don't compile in support for charts (using libplot).  This is
-    useful if your system doesn't have the libplot library.
+`--without-cairo'
+    Don't compile in support for charts (using Cairo and Pango).  This
+    is useful if your system lacks these libraries.
 
 `--without-gui'
     Don't build the PSPPIRE gui.  Use this option if you only want to
     build the command line version of PSPP.
 
+    Cairo and Pango required to build the GUI, so --without-cairo
+    implies --without-gui.
+
 `--with-gui-tools'
     Build the gui developer tools.  There is no reason to use this
     option unless you're involved with the development of PSPP
index 02ae7d5b2129e882d72e65559bf81c9d7d3ad5fd..b24afdaf7719b9575031ed8e1148ddfad4311721 100644 (file)
@@ -34,6 +34,7 @@ EXTRA_DIST = OChangeLog ONEWS config.rpath pspp-mode.el
 CLEANFILES = 
 CLEAN_LOCAL =
 ALL_LOCAL =
+CHECK_LOCAL =
 ACLOCAL_AMFLAGS = -I m4 -I gl/m4
 noinst_LIBRARIES=
 noinst_LTLIBRARIES=
@@ -60,7 +61,6 @@ DIST_HOOKS += generate-changelog
 include $(top_srcdir)/po/automake.mk
 include $(top_srcdir)/lib/automake.mk
 include $(top_srcdir)/doc/automake.mk
-include $(top_srcdir)/config/automake.mk
 include $(top_srcdir)/examples/automake.mk
 include $(top_srcdir)/src/automake.mk
 
@@ -86,6 +86,7 @@ uninstall-hook: $(UNINSTALL_DATA_HOOKS)
 
 clean-local: $(CLEAN_LOCAL)
 all-local: $(ALL_LOCAL)
+check-local: $(CHECK_LOCAL)
 
 # A convenience target to build all the binaries
 programs: $(PROGRAMS)
diff --git a/NEWS b/NEWS
index 149d1deadbad2b44269d9a6b787ac9ed9ed10c80..f1a0ee4e6348acb01b2ef4ab54b5ebb8e8c580a6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,22 @@
 PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2009-10-06 20:46:21 blp>
+Time-stamp: <2009-12-05 20:44:30 blp>
 Copyright (C) 1996-9, 2000, 2008, 2009 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
 
+Changes from 0.7.2 to 0.7.3:
+
+ * Charts are now produced with Cairo and Pango, instead of libplot.
+   Without them, the new graphing features will not work.  If you do
+   not have Cairo and Pango installed, you must run `configure' with
+   --without-cairo.
+
+ * The new "cairo" output driver supports output in PostScript, PDF,
+   and SVG formats.  Its functionality is a superset of that of the
+   "postscript" driver, which has been removed.  You must have Cairo
+   and Pango installed to build the "cairo" driver.
+
 Changes from 0.7.1 to 0.7.2:
 
  * Updated Perl module interface.
diff --git a/README b/README
index 02e81d77e9525093cc3252d38903717b6252b9eb..e54877a10fdb90c31c1c766985084c91953b4d50 100644 (file)
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ is a free replacement for the proprietary program SPSS.
 PSPP development is ongoing. It already supports a large subset of
 SPSS's syntax.  Its statistical procedure support is currently
 limited, but growing.  At your option, PSPP will produce statistical
-reports in ASCII, PostScript, or HTML formats. 
+reports in ASCII, PostScript, PDF, HTML, or SVG formats. 
 
 Instructions for PSPP installation are in INSTALL, including a list of
 prerequisite packages and other PSPP-specific information.  Full
@@ -52,8 +52,8 @@ following support to users:
 
        * Attractive output, including graphs, in a variety of human-
           and machine-readable formats.  PSPP currently produces
-          output in ASCII, PostScript, and HTML formats.  We will
-          enhance PSPP's output formatting in the future.
+          output in ASCII, PostScript, PDF, HTML, and SVG formats.  We
+          will enhance PSPP's output formatting in the future.
 
        * Good documentation.  Currently the PSPP manual describes its
           language completely, but we would like to add information on
diff --git a/Smake b/Smake
index e8ffdd5705b2802df79ef79b6ccf90b075a521c0..ad228ebaa255b8fbe85e9d116ce4734760a7cff0 100644 (file)
--- a/Smake
+++ b/Smake
@@ -5,7 +5,6 @@ GNULIB = ../gnulib
 GNULIB_TOOL = $(GNULIB)/gnulib-tool
 
 GNULIB_MODULES = \
-       argp \
        assert \
        byteswap \
        c-ctype \
@@ -81,6 +80,8 @@ GNULIB_MODULES = \
        unistr/u8-strncat \
        unlocked-io \
        vasprintf-posix \
+       version-etc \
+       version-etc-fsf \
        vfprintf-posix \
        vprintf-posix \
        vsnprintf \
diff --git a/THANKS b/THANKS
index 5af731084b7a32f5e571832a10a4e2680609afca..b5bd839e9db0e18c3cba22f313d95c1b5ef2aec6 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -12,5 +12,3 @@ Thanks to...
      * François Pinard for advice on proceeding with development.
 
      * Jim Van Zandt for Debian packaging and suggestions.
-
-     * The authors of libplot and libgsl for providing those libraries.
index 307ce149a4344f3f5e373146cac3fefea7b5a08c..14d11dc70a26e44bc22f28bac8ca5418360c4843 100644 (file)
@@ -43,40 +43,6 @@ AC_DEFUN([PSPP_PERL],
   AC_SUBST([VERSION_FOR_PERL])
 ])
 
-dnl Check that libplot is available.
-AC_DEFUN([PSPP_LIBPLOT],
-[
-  AC_ARG_WITH(
-    libplot, 
-    [AS_HELP_STRING([--without-libplot],
-                    [don't compile in support of charts (using libplot)])])
-
-  if test x"$with_libplot" != x"no" ; then 
-    # Check whether we can link against libplot without any extra libraries.
-    AC_CHECK_LIB(plot, pl_newpl_r, [LIBPLOT_LIBS="-lplot"])
-
-    # Check whether we can link against libplot if we also link X.
-    if test x"$LIBPLOT_LIBS" = x""; then
-      AC_PATH_XTRA
-      extra_libs="-lXaw -lXmu -lXt $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS -lm"
-      AC_CHECK_LIB(plot, pl_newpl_r,
-                  [LIBPLOT_LIBS="-lplot $extra_libs"
-                    LDFLAGS="$LDFLAGS $X_LIBS"],,
-                  [$extra_libs])
-    fi
-
-    # Still can't link?
-    if test x"$LIBPLOT_LIBS" = x""; then
-      PSPP_REQUIRED_PREREQ([libplot (or use --without-libplot)])
-    fi
-
-    # Set up to make everything work.
-    LIBS="$LIBPLOT_LIBS $LIBS"
-    AC_DEFINE(HAVE_LIBPLOT, 1,
-              [Define to 1 if you have the `libplot' library (-lplot).])
-  fi
-])
-
 dnl PSPP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED])
 dnl Check whether the given C compiler OPTION is accepted.
 dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED.
diff --git a/config/OChangeLog b/config/OChangeLog
deleted file mode 100644 (file)
index dbf6c3a..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-2007-09-25  Ben Pfaff  <blp@gnu.org>
-
-       * devices (tty-ascii): Set length and width to "auto", so that
-       they reflect the current size of the terminal window as it
-       changes.
-
-2007-09-22  Ben Pfaff  <blp@gnu.org>
-
-       Bug #21128.  Reviewed by John Darrington.
-
-       * papersize: Removed.
-
-       * automake.mk (dist_pkgsysconf_DATA): Remove papersize.
-
-2007-08-26  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Change raw-ascii from screen to listing device (because
-       that's how it's used).
-
-2007-07-25  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Add tty and listing devices that use VT100 (and xterm)
-       line-drawing characters.
-
-2007-07-25  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Add an "interactive" category that defaults to
-       tty-ascii.  Make the tty-ascii device more user-friendly.
-
-Tue Apr  4 20:20:49 2006  Ben Pfaff  <blp@gnu.org>
-
-       * automake.mk: Fix bugs in installation targets.
-
-Mon Apr  3 11:01:16 2006  Ben Pfaff  <blp@gnu.org>
-
-       * automake.mk: (pkgsysconf_DATA) Add AFM files in config/psfonts.
-       Remove config/html-prologue, config/ps-prologue.
-
-       * html-prologue: Removed.
-
-       * ps-prologue: Removed.
-
-       * psfonts/Courier-Bold.afm, psfonts/Courier-BoldOblique.afm,
-       psfonts/Courier-Oblique.afm, psfonts/Courier.afm,
-       psfonts/Helvetica-Bold.afm, psfonts/Helvetica-BoldOblique.afm,
-       psfonts/Helvetica-Oblique.afm, psfonts/Helvetica.afm,
-       psfonts/Times-Bold.afm, psfonts/Times-BoldItalic.afm,
-       psfonts/Times-Italic.afm, psfonts/Times-Roman.afm: New files.
-
-Sat Feb 11 21:58:29 2006  Ben Pfaff  <blp@gnu.org>
-
-       * html-prologue: Don't use ${source-file}, which is no longer
-       supported.
-
-Tue Dec 30 22:37:04 2003  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Add "squeeze=on top-margin=0 bottom-margin=0" to
-       raw-ascii to make test output more readable.
-
-Sun May 24 22:40:13 1998  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: Add %%DocumentMedia: comment.
-
-Wed May 20 00:02:51 1998  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: Comment out misleading Bounding-Box comment for
-       now.  SF arguments rearranged.  BP removed.
-
-Wed Apr 15 13:00:46 1998  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: (private-install) Make it work for separate source
-       and build directories.
-
-       * ps-prologue: New TL macro for a thick line.  New thick-width arg
-       to BP.
-
-Sun Jan  4 18:11:11 1998  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: Minor reorganization.  New GB macro to draw a gray
-       box.
-
-Wed Dec 24 22:35:13 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Added devicetype options and documentation for them.
-
-Fri Dec  5 21:51:08 1997  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: (pkgsysconf_DATA) Add html-prologue.
-       (EXTRA_DIST) Add html-prologue.
-
-       * devices: Add `html' device.  Add `listing', `screen', and
-       `printer' flags to devices as appropriate.
-
-       * html-prologue: New file.
-
-       * ps-prologue: Comment fixes.
-
-Thu Sep 18 21:31:02 1997  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: (pkgsysconfdir) Changed from $(pkgdatadir) to
-       $(sysconfdir)/$(PACKAGE).
-
-Thu Aug 14 22:05:54 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices: (tty) Define as null instead of not defining.
-
-Sun Aug  3 11:33:28 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices: tty-ascii has no bold or italic by default.
-
-Wed Jun 25 22:50:19 1997  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: (EXTRA_DIST) New target.
-
-Mon May  5 21:56:54 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices, papersize, ps-prologue: Comment fixes.
-
-Fri May  2 22:05:44 1997  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: Removed ps-fontmap.
-
-       * ps-fontmap: Removed.
-
-       * ps-prologue: Added comments.  Fixed DSC comments.
-       (BP) Two new arguments; fixed problem with SF argument conflict
-       with SF function.
-
-Thu May  1 14:57:52 1997  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: (BP) New argument, SF or scale factor.
-       
-Fri Apr 18 16:48:41 1997  Ben Pfaff  <blp@gnu.org>
-
-       * Makefile.am: New file.
-       
-       * environment: Comment fix.
-
-Sat Feb 15 21:26:53 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Added ml520 and ml520-ul printer devices.
-
-Sat Jan 11 15:44:15 1997  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Default listing device is list-ascii, not list-ibmpc.
-
-Sun Dec 29 21:36:48 1996  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Changed default devices.
-
-Sat Sep  7 22:35:12 1996  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: Added `!encodings' line to cause encodings to be
-       output.
-       (T) Fixed.  Yes, really this time.
-
-Thu Sep  5 22:05:56 1996  Ben Pfaff  <blp@gnu.org>
-
-       * ps-prologue: (T) Now works correctly.
-       (SF) Parameters changed to: size in psus, target font name,
-       encoding, PostScript font name.
-
-Wed Sep  4 21:45:35 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: Renamed ps-prologue, all references changed.
-       (T) New definition.
-
-       * ps-encodings: New PostScript configuration file (not present in
-       distribution).
-
-Sat Aug 31 23:52:38 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: One minor comment change.
-
-Thu Aug 29 21:36:41 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: Portions other than DSC comments are essentially
-       completely new.
-
-Sat Aug 24 23:26:00 1996  Ben Pfaff  <blp@gnu.org>
-
-       * devices: Added PostScript driver.
-
-Sun Aug 11 21:31:22 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: Calls `setlinecap' in setup code.
-
-Sat Aug 10 23:28:17 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: DSC comment changes.  New call to `setlinewidth' in
-       setup code.
-
-Thu Aug  8 22:31:11 1996  Ben Pfaff  <blp@gnu.org>
-
-       * prologue.ps: Changes to scaling & translating code.
-
-Sat Aug  3 20:50:35 1996  Ben Pfaff  <blp@gnu.org>
-
-       * environment: New file.  Yet another new time- and memory-hogging
-       redundant config file; why not?
-       
-       * papersize: Comment changes.
-
-       * prologue.ps: Changed vars from $varname$ to ${varname} format.
-       Miscellaneous changes.
-
-       * ps-fontmap: Comment changes.  Fixed ZC family.
-
-Sat Jul 27 22:32:38 1996  Ben Pfaff  <blp@gnu.org>
-
-       * ps-fontmap: New configuration file.  Added to Makefile.am.
-
-----------------------------------------------------------------------
-Local Variables:
-mode: change-log
-version-control: never
-End:
diff --git a/config/automake.mk b/config/automake.mk
deleted file mode 100644 (file)
index 88b63ac..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-## Process this file with automake to produce Makefile.in  -*- makefile -*-
-
-
-dist_pkgsysconf_DATA = \
-       config/devices
-
-psfontsdir = $(pkgsysconfdir)/psfonts
-dist_psfonts_DATA = \
-       config/psfonts/Helvetica-Bold.afm \
-       config/psfonts/Times-Bold.afm \
-       config/psfonts/Courier-Bold.afm \
-       config/psfonts/Helvetica-BoldOblique.afm \
-       config/psfonts/Times-BoldItalic.afm \
-       config/psfonts/Courier-BoldOblique.afm \
-       config/psfonts/Helvetica-Oblique.afm \
-       config/psfonts/Times-Italic.afm \
-       config/psfonts/Courier-Oblique.afm \
-       config/psfonts/Helvetica.afm \
-       config/psfonts/Times-Roman.afm \
-       config/psfonts/Courier.afm
-
-EXTRA_DIST += config/OChangeLog
diff --git a/config/devices b/config/devices
deleted file mode 100644 (file)
index 48513fe..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-# PSPP's standard output drivers.
-#
-# An introduction to the use of PSPP output drivers and this file
-# follows.  However, refer to PSPP's Texinfo documentation for full
-# information.
-#
-# Each output driver specification must be on a single line; however,
-# lines may be spliced with a \ at the end of a line.  Line splicing
-# is performed *before* comments (introduced by `#') are removed.
-#
-# Format is `DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS'.
-#
-# DRIVERNAME is the name that identifies the driver to the user.  It
-# is the name used on the -o command-line option.
-#
-# CLASSNAME is the internal name of the type of driver.  Device
-# classes can be listed with `pspp -l'.
-#
-# DEVICETYPE identifies what type or types the devices is.  Zero or
-# more of the following keywords may be given here: screen, printer,
-# or listing.
-#
-# OPTIONS is a list of key/value pairs to pass to the driver.  Use
-# spaces to separate pairs, and '=' to separate keys and values.
-# Quotes " or ' can be used to delimit values that contain spaces.
-# Example: paper-size="Envelope #10" charset=latin1
-#
-# Driver categories may be defined with lines of the form:
-#
-#   category=driver1 driver2 driver3 ... driverN
-#
-# To disable a driver, define a category with nothing on the right
-# side.
-#
-# Macros may be defined with lines of the form:
-#
-#   define macro-name definition
-#
-# Macros may not be recursive; they may not take arguments.  (However,
-# `definition' is macro-expanded *at time of definition*.)  Macros are
-# referenced with $var or ${var} syntax; the latter is preferred.
-
-# Preferred devices.
-default=list-ascii
-interactive=tty-ascii
-
-# Output files.
-define tty-output-file "|more"
-define list-output-file "pspp.list"
-
-# Generic ASCII devices
-tty-ascii:ascii:screen:squeeze=on headers=off top-margin=0 bottom-margin=0 \
-  paginate=off length=auto width=auto output-file=${tty-output-file}
-list-ascii:ascii:listing:length=66 width=79 output-file=${list-output-file}
-raw-ascii:ascii:listing:width=9999 length=9999 output-file=${list-output-file} \
-  emphasis=none headers=off paginate=off squeeze=on \
-  top-margin=0 bottom-margin=0
-
-# ASCII devices that support bold & underline via backspacing.
-tty-ascii-bi:ascii:screen:output-file=${tty-output-file}
-list-ascii-bi:ascii:listing:length=66 width=79 output-file=${list-output-file}
-
-# VT100 graphics devices.
-define vt100-graphics \
-  init='\033(B\033)0' \
-  box[1000]='\16q\17' box[1010]='\16q\17' box[0010]='\16q\17' \
-  box[0100]='\16x\17' box[0101]='\16x\17' box[0001]='\16x\17' \
-  box[0011]='\16j\17' box[1100]='\16l\17' box[0110]='\16k\17' \
-  box[1001]='\16m\17' box[1110]='\16w\17' box[1101]='\16t\17' \
-  box[0111]='\16u\17' box[1011]='\16v\17' box[1111]='\16n\17'
-
-tty-vt100:ascii:screen:squeeze=on headers=off top-margin=0 bottom-margin=0 \
-  paginate=off output-file=${tty-output-file} ${vt100-graphics}
-list-vt100:ascii:listing:length=66 width=79 output-file=${list-output-file} \
-  ${vt100-graphics}
-
-# HTML device.
-html:html::
-
-# PostScript device.
-list-ps:postscript::
-
-# Devices that support the IBM PC line-drawing characters.
-define ibmpc-graphics \
-  box[0000]='\x20' box[0001]='\xb3' box[0002]='\xba' \
-  box[0010]='\xc4' box[0011]='\xd9' box[0012]='\xbd' \
-  box[0020]='\xcd' box[0021]='\xbe' box[0022]='\xbc' \
-  box[0100]='\xb3' box[0101]='\xb3' box[0102]='\xc4' \
-  box[0110]='\xbf' box[0111]='\xb4' box[0112]='\xb6' \
-  box[0120]='\xb8' box[0121]='\xb5' box[0122]='\xb9' \
-  box[0200]='\xba' box[0201]='\xba' box[0202]='\xba' \
-  box[0210]='\xb7' box[0211]='\xb6' box[0212]='\xb6' \
-  box[0220]='\xbb' box[0221]='\xb9' box[0222]='\xb9' \
-  box[1000]='\xc4' box[1001]='\xc0' box[1002]='\xd3' \
-  box[1010]='\xc4' box[1011]='\xc1' box[1012]='\xd0' \
-  box[1020]='\xcd' box[1021]='\xcf' box[1022]='\xca' \
-  box[1100]='\xda' box[1101]='\xc3' box[1102]='\xc7' \
-  box[1110]='\xc2' box[1111]='\xc5' box[1112]='\xd7' \
-  box[1120]='\xd1' box[1121]='\xd8' box[1122]='\xce' \
-  box[1200]='\xd6' box[1201]='\xc7' box[1202]='\xc7' \
-  box[1210]='\xd2' box[1211]='\xd7' box[1212]='\xd7' \
-  box[1220]='\xca' box[1221]='\xce' box[1222]='\xce' \
-  box[2000]='\xcd' box[2001]='\xd4' box[2002]='\xc8' \
-  box[2010]='\xcd' box[2011]='\xcf' box[2012]='\xca' \
-  box[2020]='\xcd' box[2021]='\xcf' box[2022]='\xca' \
-  box[2100]='\xd5' box[2101]='\xc6' box[2102]='\xcc' \
-  box[2110]='\xd1' box[2111]='\xd8' box[2112]='\xce' \
-  box[2120]='\xd1' box[2121]='\xd8' box[2122]='\xce' \
-  box[2200]='\xc9' box[2201]='\xcc' box[2202]='\xcc' \
-  box[2210]='\xcb' box[2211]='\xce' box[2212]='\xce' \
-  box[2220]='\xcb' box[2221]='\xce' box[2222]='\xce'
-
-tty-ibmpc:ascii:screen:length=$viewlength width=$viewwidth ${ibmpc-graphics} \
-  output-file=${tty-output-file}
-list-ibmpc:ascii:listing:length=66 width=79 output-file=${list-output-file} \
-  ${ibmpc-graphics}
-
-# Local Variables:
-# fill-prefix: "# "
-# End:
diff --git a/config/psfonts/Courier-Bold.afm b/config/psfonts/Courier-Bold.afm
deleted file mode 100644 (file)
index dbfdddb..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 16:13:14 1990
-Comment UniqueID 27058
-Comment VMusage 28444 40812
-FontName Courier-Bold
-FullName Courier Bold
-FamilyName Courier
-Weight Bold
-ItalicAngle 0
-IsFixedPitch true
-FontBBox -40 -206 786 801
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 439
-Ascender 626
-Descender -142
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 212 -15 388 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 145 297 455 562 ;
-C 35 ; WX 600 ; N numbersign ; B 66 -45 534 651 ;
-C 36 ; WX 600 ; N dollar ; B 92 -126 509 666 ;
-C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
-C 38 ; WX 600 ; N ampersand ; B 46 -15 536 543 ;
-C 39 ; WX 600 ; N quoteright ; B 188 297 412 562 ;
-C 40 ; WX 600 ; N parenleft ; B 229 -102 451 616 ;
-C 41 ; WX 600 ; N parenright ; B 149 -102 371 616 ;
-C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
-C 43 ; WX 600 ; N plus ; B 81 0 519 439 ;
-C 44 ; WX 600 ; N comma ; B 140 -101 374 164 ;
-C 45 ; WX 600 ; N hyphen ; B 110 213 490 303 ;
-C 46 ; WX 600 ; N period ; B 206 -15 394 151 ;
-C 47 ; WX 600 ; N slash ; B 105 -77 496 626 ;
-C 48 ; WX 600 ; N zero ; B 97 -15 503 616 ;
-C 49 ; WX 600 ; N one ; B 91 0 529 616 ;
-C 50 ; WX 600 ; N two ; B 71 0 489 616 ;
-C 51 ; WX 600 ; N three ; B 73 -15 491 616 ;
-C 52 ; WX 600 ; N four ; B 63 0 497 616 ;
-C 53 ; WX 600 ; N five ; B 80 -15 511 601 ;
-C 54 ; WX 600 ; N six ; B 100 -15 511 616 ;
-C 55 ; WX 600 ; N seven ; B 65 0 484 601 ;
-C 56 ; WX 600 ; N eight ; B 93 -15 507 616 ;
-C 57 ; WX 600 ; N nine ; B 89 -15 500 616 ;
-C 58 ; WX 600 ; N colon ; B 206 -15 394 405 ;
-C 59 ; WX 600 ; N semicolon ; B 140 -101 394 405 ;
-C 60 ; WX 600 ; N less ; B 66 -15 503 453 ;
-C 61 ; WX 600 ; N equal ; B 81 89 519 349 ;
-C 62 ; WX 600 ; N greater ; B 97 -15 534 453 ;
-C 63 ; WX 600 ; N question ; B 108 -15 491 580 ;
-C 64 ; WX 600 ; N at ; B 26 -15 574 616 ;
-C 65 ; WX 600 ; N A ; B 1 0 599 562 ;
-C 66 ; WX 600 ; N B ; B 40 0 563 562 ;
-C 67 ; WX 600 ; N C ; B 32 -18 554 580 ;
-C 68 ; WX 600 ; N D ; B 40 0 584 562 ;
-C 69 ; WX 600 ; N E ; B 40 0 545 562 ;
-C 70 ; WX 600 ; N F ; B 54 0 555 562 ;
-C 71 ; WX 600 ; N G ; B 32 -18 584 580 ;
-C 72 ; WX 600 ; N H ; B 30 0 570 562 ;
-C 73 ; WX 600 ; N I ; B 87 0 513 562 ;
-C 74 ; WX 600 ; N J ; B 47 -18 591 562 ;
-C 75 ; WX 600 ; N K ; B 36 0 584 562 ;
-C 76 ; WX 600 ; N L ; B 49 0 568 562 ;
-C 77 ; WX 600 ; N M ; B 3 0 597 562 ;
-C 78 ; WX 600 ; N N ; B 18 -12 600 562 ;
-C 79 ; WX 600 ; N O ; B 32 -18 568 580 ;
-C 80 ; WX 600 ; N P ; B 58 0 549 562 ;
-C 81 ; WX 600 ; N Q ; B 32 -123 568 580 ;
-C 82 ; WX 600 ; N R ; B 34 0 589 562 ;
-C 83 ; WX 600 ; N S ; B 57 -22 543 582 ;
-C 84 ; WX 600 ; N T ; B 31 0 569 562 ;
-C 85 ; WX 600 ; N U ; B 14 -18 586 562 ;
-C 86 ; WX 600 ; N V ; B -3 0 603 562 ;
-C 87 ; WX 600 ; N W ; B -8 0 608 562 ;
-C 88 ; WX 600 ; N X ; B 22 0 578 562 ;
-C 89 ; WX 600 ; N Y ; B 22 0 579 562 ;
-C 90 ; WX 600 ; N Z ; B 72 0 529 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 255 -102 465 616 ;
-C 92 ; WX 600 ; N backslash ; B 105 -77 496 626 ;
-C 93 ; WX 600 ; N bracketright ; B 135 -102 345 616 ;
-C 94 ; WX 600 ; N asciicircum ; B 108 249 492 616 ;
-C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 188 297 412 562 ;
-C 97 ; WX 600 ; N a ; B 45 -15 560 454 ;
-C 98 ; WX 600 ; N b ; B 10 -15 574 626 ;
-C 99 ; WX 600 ; N c ; B 50 -15 539 459 ;
-C 100 ; WX 600 ; N d ; B 30 -15 581 626 ;
-C 101 ; WX 600 ; N e ; B 50 -15 553 454 ;
-C 102 ; WX 600 ; N f ; B 93 0 537 626 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 40 -146 570 454 ;
-C 104 ; WX 600 ; N h ; B 15 0 582 626 ;
-C 105 ; WX 600 ; N i ; B 87 0 513 648 ;
-C 106 ; WX 600 ; N j ; B 73 -146 430 648 ;
-C 107 ; WX 600 ; N k ; B 30 0 575 626 ;
-C 108 ; WX 600 ; N l ; B 87 0 513 626 ;
-C 109 ; WX 600 ; N m ; B -12 0 616 454 ;
-C 110 ; WX 600 ; N n ; B 28 0 582 454 ;
-C 111 ; WX 600 ; N o ; B 40 -15 560 454 ;
-C 112 ; WX 600 ; N p ; B 9 -142 560 454 ;
-C 113 ; WX 600 ; N q ; B 30 -142 581 454 ;
-C 114 ; WX 600 ; N r ; B 57 0 570 454 ;
-C 115 ; WX 600 ; N s ; B 78 -17 525 459 ;
-C 116 ; WX 600 ; N t ; B 57 -15 522 562 ;
-C 117 ; WX 600 ; N u ; B 9 -15 559 439 ;
-C 118 ; WX 600 ; N v ; B 9 0 591 439 ;
-C 119 ; WX 600 ; N w ; B -8 0 608 439 ;
-C 120 ; WX 600 ; N x ; B 16 0 584 439 ;
-C 121 ; WX 600 ; N y ; B 6 -142 591 439 ;
-C 122 ; WX 600 ; N z ; B 91 0 510 439 ;
-C 123 ; WX 600 ; N braceleft ; B 170 -102 454 616 ;
-C 124 ; WX 600 ; N bar ; B 255 -77 345 626 ;
-C 125 ; WX 600 ; N braceright ; B 146 -102 430 616 ;
-C 126 ; WX 600 ; N asciitilde ; B 81 124 520 307 ;
-C 161 ; WX 600 ; N exclamdown ; B 212 -146 388 449 ;
-C 162 ; WX 600 ; N cent ; B 76 -49 508 614 ;
-C 163 ; WX 600 ; N sterling ; B 82 -28 548 611 ;
-C 164 ; WX 600 ; N fraction ; B 30 -60 571 661 ;
-C 165 ; WX 600 ; N yen ; B 20 0 580 591 ;
-C 166 ; WX 600 ; N florin ; B -20 -131 562 616 ;
-C 167 ; WX 600 ; N section ; B 103 -70 497 580 ;
-C 168 ; WX 600 ; N currency ; B 54 49 546 517 ;
-C 169 ; WX 600 ; N quotesingle ; B 237 297 363 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 81 297 519 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
-C 174 ; WX 600 ; N fi ; B 22 0 583 626 ;
-C 175 ; WX 600 ; N fl ; B 22 0 583 626 ;
-C 177 ; WX 600 ; N endash ; B 75 213 525 303 ;
-C 178 ; WX 600 ; N dagger ; B 116 -70 484 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 116 -70 484 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 206 136 394 302 ;
-C 182 ; WX 600 ; N paragraph ; B 16 -70 566 580 ;
-C 183 ; WX 600 ; N bullet ; B 150 142 450 420 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 188 -140 412 125 ;
-C 185 ; WX 600 ; N quotedblbase ; B 81 -140 519 125 ;
-C 186 ; WX 600 ; N quotedblright ; B 81 297 519 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 36 -15 564 96 ;
-C 189 ; WX 600 ; N perthousand ; B -40 -15 786 616 ;
-C 191 ; WX 600 ; N questiondown ; B 109 -146 492 449 ;
-C 193 ; WX 600 ; N grave ; B 132 508 395 661 ;
-C 194 ; WX 600 ; N acute ; B 205 508 468 661 ;
-C 195 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
-C 196 ; WX 600 ; N tilde ; B 89 493 512 636 ;
-C 197 ; WX 600 ; N macron ; B 88 505 512 585 ;
-C 198 ; WX 600 ; N breve ; B 83 468 517 631 ;
-C 199 ; WX 600 ; N dotaccent ; B 240 505 360 625 ;
-C 200 ; WX 600 ; N dieresis ; B 148 505 452 625 ;
-C 202 ; WX 600 ; N ring ; B 198 481 402 678 ;
-C 203 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 95 508 578 661 ;
-C 206 ; WX 600 ; N ogonek ; B 169 -199 367 0 ;
-C 207 ; WX 600 ; N caron ; B 103 493 497 667 ;
-C 208 ; WX 600 ; N emdash ; B 0 213 600 303 ;
-C 225 ; WX 600 ; N AE ; B -29 0 562 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
-C 232 ; WX 600 ; N Lslash ; B 49 0 568 562 ;
-C 233 ; WX 600 ; N Oslash ; B 32 -22 568 584 ;
-C 234 ; WX 600 ; N OE ; B 0 0 570 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
-C 241 ; WX 600 ; N ae ; B 6 -15 591 454 ;
-C 245 ; WX 600 ; N dotlessi ; B 87 0 513 439 ;
-C 248 ; WX 600 ; N lslash ; B 87 0 513 626 ;
-C 249 ; WX 600 ; N oslash ; B 40 -24 560 463 ;
-C 250 ; WX 600 ; N oe ; B -8 -15 601 454 ;
-C 251 ; WX 600 ; N germandbls ; B 32 -15 586 626 ;
-C -1 ; WX 600 ; N scedilla ; B 78 -206 525 459 ;
-C -1 ; WX 600 ; N notegraphic ; B 87 -15 513 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 32 -18 568 780 ;
-C -1 ; WX 600 ; N ll ; B -2 0 590 626 ;
-C -1 ; WX 600 ; N otilde ; B 40 -15 560 636 ;
-C -1 ; WX 600 ; N scaron ; B 78 -17 525 667 ;
-C -1 ; WX 600 ; N divide ; B 81 -15 519 453 ;
-C -1 ; WX 600 ; N Thorn ; B 58 0 547 562 ;
-C -1 ; WX 600 ; N format ; B 5 -146 95 598 ;
-C -1 ; WX 600 ; N largebullet ; B 258 239 342 323 ;
-C -1 ; WX 600 ; N Eth ; B 40 0 584 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 32 -18 568 748 ;
-C -1 ; WX 600 ; N onesuperior ; B 158 230 442 616 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 582 290 ;
-C -1 ; WX 600 ; N Ydieresis ; B 22 0 579 748 ;
-C -1 ; WX 600 ; N merge ; B 144 -15 456 487 ;
-C -1 ; WX 600 ; N IJ ; B 2 -18 612 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 50 -206 539 459 ;
-C -1 ; WX 600 ; N multiply ; B 81 0 520 439 ;
-C -1 ; WX 600 ; N degree ; B 86 243 474 616 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 589 562 ;
-C -1 ; WX 600 ; N indent ; B 70 52 530 364 ;
-C -1 ; WX 600 ; N Otilde ; B 32 -18 568 759 ;
-C -1 ; WX 600 ; N thorn ; B -4 -142 560 626 ;
-C -1 ; WX 600 ; N mu ; B 9 -142 559 439 ;
-C -1 ; WX 600 ; N Yacute ; B 22 0 579 784 ;
-C -1 ; WX 600 ; N threesuperior ; B 148 222 423 616 ;
-C -1 ; WX 600 ; N logicalnot ; B 81 59 519 349 ;
-C -1 ; WX 600 ; N Ugrave ; B 14 -18 586 784 ;
-C -1 ; WX 600 ; N eth ; B 68 -27 533 626 ;
-C -1 ; WX 600 ; N left ; B 70 52 530 364 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 40 0 545 780 ;
-C -1 ; WX 600 ; N edieresis ; B 50 -15 553 625 ;
-C -1 ; WX 600 ; N Ograve ; B 32 -18 568 784 ;
-C -1 ; WX 600 ; N down ; B 144 -15 456 422 ;
-C -1 ; WX 600 ; N Agrave ; B 1 0 599 784 ;
-C -1 ; WX 600 ; N atilde ; B 45 -15 560 636 ;
-C -1 ; WX 600 ; N up ; B 144 0 456 437 ;
-C -1 ; WX 600 ; N eacute ; B 50 -15 553 661 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 525 599 ;
-C -1 ; WX 600 ; N lira ; B 82 -28 548 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 87 0 513 780 ;
-C -1 ; WX 600 ; N Adieresis ; B 1 0 599 748 ;
-C -1 ; WX 600 ; N yacute ; B 6 -142 591 661 ;
-C -1 ; WX 600 ; N icircumflex ; B 63 0 513 657 ;
-C -1 ; WX 600 ; N adieresis ; B 45 -15 560 625 ;
-C -1 ; WX 600 ; N zcaron ; B 91 0 510 667 ;
-C -1 ; WX 600 ; N Scaron ; B 57 -22 543 790 ;
-C -1 ; WX 600 ; N minus ; B 81 174 519 264 ;
-C -1 ; WX 600 ; N Aring ; B 1 0 599 801 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 14 -18 586 780 ;
-C -1 ; WX 600 ; N plusminus ; B 81 0 519 461 ;
-C -1 ; WX 600 ; N ograve ; B 40 -15 560 661 ;
-C -1 ; WX 600 ; N Edieresis ; B 40 0 545 748 ;
-C -1 ; WX 600 ; N brokenbar ; B 255 -77 345 626 ;
-C -1 ; WX 600 ; N Idieresis ; B 87 0 513 748 ;
-C -1 ; WX 600 ; N acircumflex ; B 45 -15 560 657 ;
-C -1 ; WX 600 ; N ydieresis ; B 6 -142 591 625 ;
-C -1 ; WX 600 ; N Oacute ; B 32 -18 568 784 ;
-C -1 ; WX 600 ; N Egrave ; B 40 0 545 784 ;
-C -1 ; WX 600 ; N center ; B 40 14 560 580 ;
-C -1 ; WX 600 ; N threequarters ; B -20 -60 675 661 ;
-C -1 ; WX 600 ; N tab ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 50 -15 553 657 ;
-C -1 ; WX 600 ; N Eacute ; B 40 0 545 784 ;
-C -1 ; WX 600 ; N trademark ; B -9 230 749 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N onehalf ; B -20 -60 675 661 ;
-C -1 ; WX 600 ; N onequarter ; B -20 -60 692 661 ;
-C -1 ; WX 600 ; N Uacute ; B 14 -18 586 784 ;
-C -1 ; WX 600 ; N Atilde ; B 1 0 599 759 ;
-C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N Igrave ; B 87 0 513 784 ;
-C -1 ; WX 600 ; N Iacute ; B 87 0 513 784 ;
-C -1 ; WX 600 ; N Acircumflex ; B 1 0 599 780 ;
-C -1 ; WX 600 ; N Udieresis ; B 14 -18 586 748 ;
-C -1 ; WX 600 ; N Gcaron ; B 32 -18 584 790 ;
-C -1 ; WX 600 ; N Aacute ; B 1 0 599 784 ;
-C -1 ; WX 600 ; N LL ; B -35 0 635 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 153 230 426 616 ;
-C -1 ; WX 600 ; N Scedilla ; B 57 -206 543 582 ;
-C -1 ; WX 600 ; N arrowboth ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N udieresis ; B 9 -15 559 625 ;
-C -1 ; WX 600 ; N odieresis ; B 40 -15 560 625 ;
-C -1 ; WX 600 ; N aring ; B 45 -15 560 678 ;
-C -1 ; WX 600 ; N ij ; B 16 -146 564 648 ;
-C -1 ; WX 600 ; N arrowdown ; B 144 -15 456 608 ;
-C -1 ; WX 600 ; N igrave ; B 87 0 513 661 ;
-C -1 ; WX 600 ; N aacute ; B 45 -15 560 661 ;
-C -1 ; WX 600 ; N stop ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 40 -15 560 657 ;
-C -1 ; WX 600 ; N gcaron ; B 40 -146 570 667 ;
-C -1 ; WX 600 ; N iacute ; B 87 0 513 661 ;
-C -1 ; WX 600 ; N Ntilde ; B 18 -12 600 759 ;
-C -1 ; WX 600 ; N idieresis ; B 87 0 513 625 ;
-C -1 ; WX 600 ; N Ccedilla ; B 32 -206 554 580 ;
-C -1 ; WX 600 ; N arrowright ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N ucircumflex ; B 9 -15 559 657 ;
-C -1 ; WX 600 ; N Idot ; B 87 0 513 748 ;
-C -1 ; WX 600 ; N agrave ; B 45 -15 560 661 ;
-C -1 ; WX 600 ; N ntilde ; B 28 0 582 636 ;
-C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N return ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 72 0 529 790 ;
-C -1 ; WX 600 ; N uacute ; B 9 -15 559 661 ;
-C -1 ; WX 600 ; N overscore ; B 0 579 600 629 ;
-C -1 ; WX 600 ; N egrave ; B 50 -15 553 661 ;
-C -1 ; WX 600 ; N ugrave ; B 9 -15 559 661 ;
-C -1 ; WX 600 ; N oacute ; B 40 -15 560 661 ;
-C -1 ; WX 600 ; N arrowleft ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N arrowup ; B 144 0 456 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 30 123 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -30 123 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -20 123 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -50 123 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring -10 123 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde -30 123 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 30 123 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 0 123 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 0 123 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 0 123 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 10 123 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 123 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 123 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 123 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 123 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 0 123 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 0 123 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 0 123 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 0 123 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 0 123 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 0 123 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 0 123 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 20 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 30 123 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 0 123 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 0 123 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -30 123 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 30 123 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 0 123 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 0 123 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex -20 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis -10 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave -30 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -40 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -40 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -40 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave 0 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 0 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -20 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis -20 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 30 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 0 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Courier-BoldOblique.afm b/config/psfonts/Courier-BoldOblique.afm
deleted file mode 100644 (file)
index 77e50d7..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 17:20:38 1990
-Comment UniqueID 27068
-Comment VMusage 6910 48006
-FontName Courier-BoldOblique
-FullName Courier Bold Oblique
-FamilyName Courier
-Weight Bold
-ItalicAngle -12
-IsFixedPitch true
-FontBBox -46 -206 868 801
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 439
-Ascender 626
-Descender -142
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 224 -15 484 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 226 297 574 562 ;
-C 35 ; WX 600 ; N numbersign ; B 100 -45 628 651 ;
-C 36 ; WX 600 ; N dollar ; B 97 -126 619 666 ;
-C 37 ; WX 600 ; N percent ; B 103 -15 624 616 ;
-C 38 ; WX 600 ; N ampersand ; B 72 -15 582 543 ;
-C 39 ; WX 600 ; N quoteright ; B 251 297 531 562 ;
-C 40 ; WX 600 ; N parenleft ; B 276 -102 582 616 ;
-C 41 ; WX 600 ; N parenright ; B 127 -102 434 616 ;
-C 42 ; WX 600 ; N asterisk ; B 179 219 597 601 ;
-C 43 ; WX 600 ; N plus ; B 118 0 575 439 ;
-C 44 ; WX 600 ; N comma ; B 119 -101 409 164 ;
-C 45 ; WX 600 ; N hyphen ; B 155 213 554 303 ;
-C 46 ; WX 600 ; N period ; B 219 -15 410 151 ;
-C 47 ; WX 600 ; N slash ; B 96 -77 622 626 ;
-C 48 ; WX 600 ; N zero ; B 146 -15 583 616 ;
-C 49 ; WX 600 ; N one ; B 103 0 547 616 ;
-C 50 ; WX 600 ; N two ; B 71 0 583 616 ;
-C 51 ; WX 600 ; N three ; B 82 -15 561 616 ;
-C 52 ; WX 600 ; N four ; B 92 0 544 616 ;
-C 53 ; WX 600 ; N five ; B 87 -15 611 601 ;
-C 54 ; WX 600 ; N six ; B 146 -15 642 616 ;
-C 55 ; WX 600 ; N seven ; B 157 0 612 601 ;
-C 56 ; WX 600 ; N eight ; B 125 -15 594 616 ;
-C 57 ; WX 600 ; N nine ; B 86 -15 582 616 ;
-C 58 ; WX 600 ; N colon ; B 219 -15 464 405 ;
-C 59 ; WX 600 ; N semicolon ; B 119 -101 464 405 ;
-C 60 ; WX 600 ; N less ; B 113 -15 584 453 ;
-C 61 ; WX 600 ; N equal ; B 100 89 593 349 ;
-C 62 ; WX 600 ; N greater ; B 109 -15 581 453 ;
-C 63 ; WX 600 ; N question ; B 193 -15 581 580 ;
-C 64 ; WX 600 ; N at ; B 76 -15 627 616 ;
-C 65 ; WX 600 ; N A ; B 1 0 617 562 ;
-C 66 ; WX 600 ; N B ; B 40 0 619 562 ;
-C 67 ; WX 600 ; N C ; B 85 -18 664 580 ;
-C 68 ; WX 600 ; N D ; B 40 0 654 562 ;
-C 69 ; WX 600 ; N E ; B 40 0 654 562 ;
-C 70 ; WX 600 ; N F ; B 54 0 668 562 ;
-C 71 ; WX 600 ; N G ; B 85 -18 664 580 ;
-C 72 ; WX 600 ; N H ; B 30 0 689 562 ;
-C 73 ; WX 600 ; N I ; B 87 0 632 562 ;
-C 74 ; WX 600 ; N J ; B 69 -18 710 562 ;
-C 75 ; WX 600 ; N K ; B 36 0 676 562 ;
-C 76 ; WX 600 ; N L ; B 49 0 625 562 ;
-C 77 ; WX 600 ; N M ; B 3 0 716 562 ;
-C 78 ; WX 600 ; N N ; B 18 -12 719 562 ;
-C 79 ; WX 600 ; N O ; B 84 -18 636 580 ;
-C 80 ; WX 600 ; N P ; B 58 0 634 562 ;
-C 81 ; WX 600 ; N Q ; B 84 -123 636 580 ;
-C 82 ; WX 600 ; N R ; B 34 0 607 562 ;
-C 83 ; WX 600 ; N S ; B 64 -22 662 582 ;
-C 84 ; WX 600 ; N T ; B 96 0 668 562 ;
-C 85 ; WX 600 ; N U ; B 116 -18 705 562 ;
-C 86 ; WX 600 ; N V ; B 99 0 722 562 ;
-C 87 ; WX 600 ; N W ; B 94 0 727 562 ;
-C 88 ; WX 600 ; N X ; B 22 0 679 562 ;
-C 89 ; WX 600 ; N Y ; B 124 0 698 562 ;
-C 90 ; WX 600 ; N Z ; B 72 0 626 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 233 -102 596 616 ;
-C 92 ; WX 600 ; N backslash ; B 231 -77 487 626 ;
-C 93 ; WX 600 ; N bracketright ; B 113 -102 476 616 ;
-C 94 ; WX 600 ; N asciicircum ; B 171 249 555 616 ;
-C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 251 297 531 562 ;
-C 97 ; WX 600 ; N a ; B 72 -15 578 454 ;
-C 98 ; WX 600 ; N b ; B 23 -15 626 626 ;
-C 99 ; WX 600 ; N c ; B 91 -15 621 459 ;
-C 100 ; WX 600 ; N d ; B 71 -15 634 626 ;
-C 101 ; WX 600 ; N e ; B 91 -15 594 454 ;
-C 102 ; WX 600 ; N f ; B 93 0 667 626 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 51 -146 663 454 ;
-C 104 ; WX 600 ; N h ; B 28 0 600 626 ;
-C 105 ; WX 600 ; N i ; B 87 0 531 648 ;
-C 106 ; WX 600 ; N j ; B 47 -146 568 648 ;
-C 107 ; WX 600 ; N k ; B 43 0 632 626 ;
-C 108 ; WX 600 ; N l ; B 87 0 531 626 ;
-C 109 ; WX 600 ; N m ; B -12 0 634 454 ;
-C 110 ; WX 600 ; N n ; B 28 0 600 454 ;
-C 111 ; WX 600 ; N o ; B 81 -15 612 454 ;
-C 112 ; WX 600 ; N p ; B -21 -142 612 454 ;
-C 113 ; WX 600 ; N q ; B 71 -142 674 454 ;
-C 114 ; WX 600 ; N r ; B 57 0 644 454 ;
-C 115 ; WX 600 ; N s ; B 77 -17 597 459 ;
-C 116 ; WX 600 ; N t ; B 132 -15 556 562 ;
-C 117 ; WX 600 ; N u ; B 84 -15 577 439 ;
-C 118 ; WX 600 ; N v ; B 84 0 684 439 ;
-C 119 ; WX 600 ; N w ; B 67 0 701 439 ;
-C 120 ; WX 600 ; N x ; B 16 0 660 439 ;
-C 121 ; WX 600 ; N y ; B -10 -142 684 439 ;
-C 122 ; WX 600 ; N z ; B 91 0 603 439 ;
-C 123 ; WX 600 ; N braceleft ; B 216 -102 585 616 ;
-C 124 ; WX 600 ; N bar ; B 239 -77 478 626 ;
-C 125 ; WX 600 ; N braceright ; B 124 -102 494 616 ;
-C 126 ; WX 600 ; N asciitilde ; B 120 124 573 307 ;
-C 161 ; WX 600 ; N exclamdown ; B 207 -146 468 449 ;
-C 162 ; WX 600 ; N cent ; B 131 -49 594 614 ;
-C 163 ; WX 600 ; N sterling ; B 117 -28 640 611 ;
-C 164 ; WX 600 ; N fraction ; B 27 -60 702 661 ;
-C 165 ; WX 600 ; N yen ; B 110 0 706 591 ;
-C 166 ; WX 600 ; N florin ; B -46 -131 691 616 ;
-C 167 ; WX 600 ; N section ; B 94 -70 599 580 ;
-C 168 ; WX 600 ; N currency ; B 77 49 643 517 ;
-C 169 ; WX 600 ; N quotesingle ; B 318 297 482 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 144 297 638 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 63 70 638 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 196 70 544 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 166 70 514 446 ;
-C 174 ; WX 600 ; N fi ; B 22 0 633 626 ;
-C 175 ; WX 600 ; N fl ; B 22 0 633 626 ;
-C 177 ; WX 600 ; N endash ; B 120 213 589 303 ;
-C 178 ; WX 600 ; N dagger ; B 188 -70 573 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 134 -70 574 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 251 136 442 302 ;
-C 182 ; WX 600 ; N paragraph ; B 71 -70 689 580 ;
-C 183 ; WX 600 ; N bullet ; B 207 142 513 420 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 158 -140 439 125 ;
-C 185 ; WX 600 ; N quotedblbase ; B 51 -140 546 125 ;
-C 186 ; WX 600 ; N quotedblright ; B 144 297 638 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 72 70 647 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 43 -15 574 96 ;
-C 189 ; WX 600 ; N perthousand ; B 24 -15 815 616 ;
-C 191 ; WX 600 ; N questiondown ; B 111 -146 499 449 ;
-C 193 ; WX 600 ; N grave ; B 272 508 503 661 ;
-C 194 ; WX 600 ; N acute ; B 313 508 608 661 ;
-C 195 ; WX 600 ; N circumflex ; B 212 483 606 657 ;
-C 196 ; WX 600 ; N tilde ; B 200 493 642 636 ;
-C 197 ; WX 600 ; N macron ; B 195 505 636 585 ;
-C 198 ; WX 600 ; N breve ; B 217 468 651 631 ;
-C 199 ; WX 600 ; N dotaccent ; B 359 505 482 625 ;
-C 200 ; WX 600 ; N dieresis ; B 267 505 574 625 ;
-C 202 ; WX 600 ; N ring ; B 319 481 528 678 ;
-C 203 ; WX 600 ; N cedilla ; B 169 -206 367 0 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 203 508 718 661 ;
-C 206 ; WX 600 ; N ogonek ; B 144 -199 350 0 ;
-C 207 ; WX 600 ; N caron ; B 238 493 632 667 ;
-C 208 ; WX 600 ; N emdash ; B 45 213 664 303 ;
-C 225 ; WX 600 ; N AE ; B -29 0 667 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 189 196 526 580 ;
-C 232 ; WX 600 ; N Lslash ; B 49 0 625 562 ;
-C 233 ; WX 600 ; N Oslash ; B 48 -22 672 584 ;
-C 234 ; WX 600 ; N OE ; B 51 0 675 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 189 196 542 580 ;
-C 241 ; WX 600 ; N ae ; B 30 -15 641 454 ;
-C 245 ; WX 600 ; N dotlessi ; B 87 0 531 439 ;
-C 248 ; WX 600 ; N lslash ; B 87 0 574 626 ;
-C 249 ; WX 600 ; N oslash ; B 54 -24 637 463 ;
-C 250 ; WX 600 ; N oe ; B 29 -15 651 454 ;
-C 251 ; WX 600 ; N germandbls ; B 32 -15 618 626 ;
-C -1 ; WX 600 ; N scedilla ; B 77 -206 597 459 ;
-C -1 ; WX 600 ; N notegraphic ; B 99 -15 609 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 84 -18 636 780 ;
-C -1 ; WX 600 ; N ll ; B 11 0 643 626 ;
-C -1 ; WX 600 ; N otilde ; B 81 -15 642 636 ;
-C -1 ; WX 600 ; N scaron ; B 77 -17 632 667 ;
-C -1 ; WX 600 ; N divide ; B 118 -15 575 453 ;
-C -1 ; WX 600 ; N Thorn ; B 58 0 613 562 ;
-C -1 ; WX 600 ; N format ; B -26 -146 222 598 ;
-C -1 ; WX 600 ; N largebullet ; B 317 239 403 323 ;
-C -1 ; WX 600 ; N Eth ; B 40 0 654 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 84 -18 636 748 ;
-C -1 ; WX 600 ; N onesuperior ; B 218 230 506 616 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 601 290 ;
-C -1 ; WX 600 ; N Ydieresis ; B 124 0 698 748 ;
-C -1 ; WX 600 ; N merge ; B 174 -15 526 487 ;
-C -1 ; WX 600 ; N IJ ; B 2 -18 731 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 91 -206 621 459 ;
-C -1 ; WX 600 ; N multiply ; B 94 0 600 439 ;
-C -1 ; WX 600 ; N degree ; B 173 243 569 616 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 632 562 ;
-C -1 ; WX 600 ; N indent ; B 106 52 574 364 ;
-C -1 ; WX 600 ; N Otilde ; B 84 -18 668 759 ;
-C -1 ; WX 600 ; N thorn ; B -21 -142 612 626 ;
-C -1 ; WX 600 ; N mu ; B 60 -142 577 439 ;
-C -1 ; WX 600 ; N Yacute ; B 124 0 698 784 ;
-C -1 ; WX 600 ; N threesuperior ; B 203 222 515 616 ;
-C -1 ; WX 600 ; N logicalnot ; B 136 59 593 349 ;
-C -1 ; WX 600 ; N Ugrave ; B 116 -18 705 784 ;
-C -1 ; WX 600 ; N eth ; B 103 -27 651 626 ;
-C -1 ; WX 600 ; N left ; B 114 52 582 364 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 40 0 654 780 ;
-C -1 ; WX 600 ; N edieresis ; B 91 -15 594 625 ;
-C -1 ; WX 600 ; N Ograve ; B 84 -18 636 784 ;
-C -1 ; WX 600 ; N down ; B 174 -15 486 422 ;
-C -1 ; WX 600 ; N Agrave ; B 1 0 617 784 ;
-C -1 ; WX 600 ; N atilde ; B 72 -15 642 636 ;
-C -1 ; WX 600 ; N up ; B 204 0 516 437 ;
-C -1 ; WX 600 ; N eacute ; B 91 -15 608 661 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 652 599 ;
-C -1 ; WX 600 ; N lira ; B 117 -28 640 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 87 0 632 780 ;
-C -1 ; WX 600 ; N Adieresis ; B 1 0 617 748 ;
-C -1 ; WX 600 ; N yacute ; B -10 -142 684 661 ;
-C -1 ; WX 600 ; N icircumflex ; B 87 0 566 657 ;
-C -1 ; WX 600 ; N adieresis ; B 72 -15 578 625 ;
-C -1 ; WX 600 ; N zcaron ; B 91 0 632 667 ;
-C -1 ; WX 600 ; N Scaron ; B 64 -22 662 790 ;
-C -1 ; WX 600 ; N minus ; B 118 174 575 264 ;
-C -1 ; WX 600 ; N Aring ; B 1 0 617 801 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 116 -18 705 780 ;
-C -1 ; WX 600 ; N plusminus ; B 81 0 592 461 ;
-C -1 ; WX 600 ; N ograve ; B 81 -15 612 661 ;
-C -1 ; WX 600 ; N Edieresis ; B 40 0 654 748 ;
-C -1 ; WX 600 ; N brokenbar ; B 239 -77 478 626 ;
-C -1 ; WX 600 ; N Idieresis ; B 87 0 632 748 ;
-C -1 ; WX 600 ; N acircumflex ; B 72 -15 586 657 ;
-C -1 ; WX 600 ; N ydieresis ; B -10 -142 684 625 ;
-C -1 ; WX 600 ; N Oacute ; B 84 -18 636 784 ;
-C -1 ; WX 600 ; N Egrave ; B 40 0 654 784 ;
-C -1 ; WX 600 ; N center ; B 103 14 623 580 ;
-C -1 ; WX 600 ; N threequarters ; B 35 -60 725 661 ;
-C -1 ; WX 600 ; N tab ; B 19 0 641 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 91 -15 606 657 ;
-C -1 ; WX 600 ; N Eacute ; B 40 0 665 784 ;
-C -1 ; WX 600 ; N trademark ; B 86 230 868 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N onehalf ; B 50 -60 742 661 ;
-C -1 ; WX 600 ; N onequarter ; B 50 -60 742 661 ;
-C -1 ; WX 600 ; N Uacute ; B 116 -18 705 784 ;
-C -1 ; WX 600 ; N Atilde ; B 1 0 638 759 ;
-C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N Igrave ; B 87 0 632 784 ;
-C -1 ; WX 600 ; N Iacute ; B 87 0 635 784 ;
-C -1 ; WX 600 ; N Acircumflex ; B 1 0 617 780 ;
-C -1 ; WX 600 ; N Udieresis ; B 116 -18 705 748 ;
-C -1 ; WX 600 ; N Gcaron ; B 85 -18 669 790 ;
-C -1 ; WX 600 ; N Aacute ; B 1 0 665 784 ;
-C -1 ; WX 600 ; N LL ; B -35 0 684 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 202 230 531 616 ;
-C -1 ; WX 600 ; N Scedilla ; B 64 -206 662 582 ;
-C -1 ; WX 600 ; N arrowboth ; B 40 143 688 455 ;
-C -1 ; WX 600 ; N udieresis ; B 84 -15 577 625 ;
-C -1 ; WX 600 ; N odieresis ; B 81 -15 612 625 ;
-C -1 ; WX 600 ; N aring ; B 72 -15 578 678 ;
-C -1 ; WX 600 ; N ij ; B 16 -146 702 648 ;
-C -1 ; WX 600 ; N arrowdown ; B 174 -15 486 608 ;
-C -1 ; WX 600 ; N igrave ; B 87 0 531 661 ;
-C -1 ; WX 600 ; N aacute ; B 72 -15 608 661 ;
-C -1 ; WX 600 ; N stop ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 81 -15 612 657 ;
-C -1 ; WX 600 ; N gcaron ; B 51 -146 663 667 ;
-C -1 ; WX 600 ; N iacute ; B 87 0 608 661 ;
-C -1 ; WX 600 ; N Ntilde ; B 18 -12 719 759 ;
-C -1 ; WX 600 ; N idieresis ; B 87 0 534 625 ;
-C -1 ; WX 600 ; N Ccedilla ; B 85 -206 664 580 ;
-C -1 ; WX 600 ; N arrowright ; B 32 143 688 455 ;
-C -1 ; WX 600 ; N ucircumflex ; B 84 -15 586 657 ;
-C -1 ; WX 600 ; N Idot ; B 87 0 632 748 ;
-C -1 ; WX 600 ; N agrave ; B 72 -15 578 661 ;
-C -1 ; WX 600 ; N ntilde ; B 28 0 642 636 ;
-C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N return ; B 79 0 700 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 72 0 659 790 ;
-C -1 ; WX 600 ; N uacute ; B 84 -15 608 661 ;
-C -1 ; WX 600 ; N overscore ; B 123 579 734 629 ;
-C -1 ; WX 600 ; N egrave ; B 91 -15 594 661 ;
-C -1 ; WX 600 ; N ugrave ; B 84 -15 577 661 ;
-C -1 ; WX 600 ; N oacute ; B 81 -15 612 661 ;
-C -1 ; WX 600 ; N arrowleft ; B 40 143 695 455 ;
-C -1 ; WX 600 ; N arrowup ; B 243 0 555 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 56 123 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -4 123 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 6 123 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -24 123 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 16 123 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde -4 123 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 56 123 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 26 123 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 26 123 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 26 123 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 36 123 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 26 123 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 26 123 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 26 123 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 26 123 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 26 123 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 26 123 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 26 123 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 26 123 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 26 123 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 26 123 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 26 123 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 20 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 56 123 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 26 123 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 26 123 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -4 123 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 56 123 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 26 123 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 26 123 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex -20 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis -10 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave -30 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -40 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -40 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -40 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave 0 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 0 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -20 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis -20 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 30 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 0 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Courier-Oblique.afm b/config/psfonts/Courier-Oblique.afm
deleted file mode 100644 (file)
index 4dc9419..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 18:32:01 1990
-Comment UniqueID 27082
-Comment VMusage 6415 46660
-FontName Courier-Oblique
-FullName Courier Oblique
-FamilyName Courier
-Weight Medium
-ItalicAngle -12
-IsFixedPitch true
-FontBBox -30 -157 734 805
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 426
-Ascender 629
-Descender -157
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 243 -15 457 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
-C 35 ; WX 600 ; N numbersign ; B 142 -32 587 639 ;
-C 36 ; WX 600 ; N dollar ; B 115 -126 589 662 ;
-C 37 ; WX 600 ; N percent ; B 147 -15 596 622 ;
-C 38 ; WX 600 ; N ampersand ; B 94 -15 572 543 ;
-C 39 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
-C 40 ; WX 600 ; N parenleft ; B 320 -108 565 622 ;
-C 41 ; WX 600 ; N parenright ; B 144 -108 389 622 ;
-C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
-C 43 ; WX 600 ; N plus ; B 128 0 562 426 ;
-C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
-C 45 ; WX 600 ; N hyphen ; B 161 238 549 278 ;
-C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
-C 47 ; WX 600 ; N slash ; B 111 -80 606 629 ;
-C 48 ; WX 600 ; N zero ; B 161 -15 568 622 ;
-C 49 ; WX 600 ; N one ; B 105 0 505 622 ;
-C 50 ; WX 600 ; N two ; B 77 0 561 622 ;
-C 51 ; WX 600 ; N three ; B 89 -15 531 622 ;
-C 52 ; WX 600 ; N four ; B 120 0 532 622 ;
-C 53 ; WX 600 ; N five ; B 105 -15 589 607 ;
-C 54 ; WX 600 ; N six ; B 162 -15 629 622 ;
-C 55 ; WX 600 ; N seven ; B 191 0 605 607 ;
-C 56 ; WX 600 ; N eight ; B 139 -15 581 622 ;
-C 57 ; WX 600 ; N nine ; B 100 -15 567 622 ;
-C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
-C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
-C 60 ; WX 600 ; N less ; B 86 -2 603 428 ;
-C 61 ; WX 600 ; N equal ; B 108 101 582 325 ;
-C 62 ; WX 600 ; N greater ; B 87 -2 604 428 ;
-C 63 ; WX 600 ; N question ; B 224 -15 576 572 ;
-C 64 ; WX 600 ; N at ; B 134 -15 575 622 ;
-C 65 ; WX 600 ; N A ; B 10 0 597 562 ;
-C 66 ; WX 600 ; N B ; B 50 0 609 562 ;
-C 67 ; WX 600 ; N C ; B 100 -18 651 580 ;
-C 68 ; WX 600 ; N D ; B 50 0 638 562 ;
-C 69 ; WX 600 ; N E ; B 60 0 653 562 ;
-C 70 ; WX 600 ; N F ; B 60 0 653 562 ;
-C 71 ; WX 600 ; N G ; B 90 -18 641 580 ;
-C 72 ; WX 600 ; N H ; B 39 0 680 562 ;
-C 73 ; WX 600 ; N I ; B 103 0 616 562 ;
-C 74 ; WX 600 ; N J ; B 59 -18 678 562 ;
-C 75 ; WX 600 ; N K ; B 45 0 664 562 ;
-C 76 ; WX 600 ; N L ; B 54 0 598 562 ;
-C 77 ; WX 600 ; N M ; B 11 0 708 562 ;
-C 78 ; WX 600 ; N N ; B 14 -13 705 562 ;
-C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
-C 80 ; WX 600 ; N P ; B 86 0 637 562 ;
-C 81 ; WX 600 ; N Q ; B 95 -129 625 580 ;
-C 82 ; WX 600 ; N R ; B 45 0 590 562 ;
-C 83 ; WX 600 ; N S ; B 83 -20 643 580 ;
-C 84 ; WX 600 ; N T ; B 116 0 658 562 ;
-C 85 ; WX 600 ; N U ; B 132 -18 695 562 ;
-C 86 ; WX 600 ; N V ; B 115 -13 716 562 ;
-C 87 ; WX 600 ; N W ; B 115 -13 716 562 ;
-C 88 ; WX 600 ; N X ; B 30 0 668 562 ;
-C 89 ; WX 600 ; N Y ; B 143 0 688 562 ;
-C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 253 -108 574 622 ;
-C 92 ; WX 600 ; N backslash ; B 256 -80 461 629 ;
-C 93 ; WX 600 ; N bracketright ; B 135 -108 456 622 ;
-C 94 ; WX 600 ; N asciicircum ; B 175 359 587 622 ;
-C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 294 328 506 562 ;
-C 97 ; WX 600 ; N a ; B 83 -15 559 441 ;
-C 98 ; WX 600 ; N b ; B 36 -15 618 629 ;
-C 99 ; WX 600 ; N c ; B 113 -15 607 441 ;
-C 100 ; WX 600 ; N d ; B 92 -15 633 629 ;
-C 101 ; WX 600 ; N e ; B 113 -15 591 441 ;
-C 102 ; WX 600 ; N f ; B 121 0 655 629 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 68 -157 650 441 ;
-C 104 ; WX 600 ; N h ; B 40 0 582 629 ;
-C 105 ; WX 600 ; N i ; B 102 0 505 657 ;
-C 106 ; WX 600 ; N j ; B 59 -157 543 657 ;
-C 107 ; WX 600 ; N k ; B 65 0 626 629 ;
-C 108 ; WX 600 ; N l ; B 102 0 505 629 ;
-C 109 ; WX 600 ; N m ; B 2 0 606 441 ;
-C 110 ; WX 600 ; N n ; B 33 0 575 441 ;
-C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
-C 112 ; WX 600 ; N p ; B -17 -157 598 441 ;
-C 113 ; WX 600 ; N q ; B 92 -157 675 441 ;
-C 114 ; WX 600 ; N r ; B 67 0 631 441 ;
-C 115 ; WX 600 ; N s ; B 92 -15 570 441 ;
-C 116 ; WX 600 ; N t ; B 157 -15 534 561 ;
-C 117 ; WX 600 ; N u ; B 111 -15 562 426 ;
-C 118 ; WX 600 ; N v ; B 100 -10 674 426 ;
-C 119 ; WX 600 ; N w ; B 82 -10 692 426 ;
-C 120 ; WX 600 ; N x ; B 27 0 648 426 ;
-C 121 ; WX 600 ; N y ; B -30 -157 643 426 ;
-C 122 ; WX 600 ; N z ; B 106 0 586 426 ;
-C 123 ; WX 600 ; N braceleft ; B 240 -108 562 622 ;
-C 124 ; WX 600 ; N bar ; B 265 -80 453 629 ;
-C 125 ; WX 600 ; N braceright ; B 147 -108 470 622 ;
-C 126 ; WX 600 ; N asciitilde ; B 110 160 585 269 ;
-C 161 ; WX 600 ; N exclamdown ; B 232 -157 445 430 ;
-C 162 ; WX 600 ; N cent ; B 158 -49 581 614 ;
-C 163 ; WX 600 ; N sterling ; B 131 -21 614 611 ;
-C 164 ; WX 600 ; N fraction ; B 23 -57 706 665 ;
-C 165 ; WX 600 ; N yen ; B 135 0 693 594 ;
-C 166 ; WX 600 ; N florin ; B -19 -143 664 622 ;
-C 167 ; WX 600 ; N section ; B 111 -78 583 580 ;
-C 168 ; WX 600 ; N currency ; B 99 65 621 499 ;
-C 169 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 213 328 576 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
-C 174 ; WX 600 ; N fi ; B 10 0 612 629 ;
-C 175 ; WX 600 ; N fl ; B 10 0 612 629 ;
-C 177 ; WX 600 ; N endash ; B 126 238 584 278 ;
-C 178 ; WX 600 ; N dagger ; B 226 -78 537 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 171 -78 537 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 273 152 418 276 ;
-C 182 ; WX 600 ; N paragraph ; B 107 -78 623 562 ;
-C 183 ; WX 600 ; N bullet ; B 231 137 478 376 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
-C 185 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
-C 186 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 51 -15 566 97 ;
-C 189 ; WX 600 ; N perthousand ; B 57 -15 627 622 ;
-C 191 ; WX 600 ; N questiondown ; B 112 -157 464 430 ;
-C 193 ; WX 600 ; N grave ; B 294 497 484 672 ;
-C 194 ; WX 600 ; N acute ; B 348 497 612 672 ;
-C 195 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
-C 196 ; WX 600 ; N tilde ; B 219 503 617 606 ;
-C 197 ; WX 600 ; N macron ; B 232 525 600 565 ;
-C 198 ; WX 600 ; N breve ; B 279 501 576 609 ;
-C 199 ; WX 600 ; N dotaccent ; B 379 508 452 580 ;
-C 200 ; WX 600 ; N dieresis ; B 313 508 519 580 ;
-C 202 ; WX 600 ; N ring ; B 344 483 492 627 ;
-C 203 ; WX 600 ; N cedilla ; B 221 -151 340 10 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
-C 206 ; WX 600 ; N ogonek ; B 207 -151 348 0 ;
-C 207 ; WX 600 ; N caron ; B 262 492 614 669 ;
-C 208 ; WX 600 ; N emdash ; B 51 238 659 278 ;
-C 225 ; WX 600 ; N AE ; B 10 0 648 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 216 259 504 580 ;
-C 232 ; WX 600 ; N Lslash ; B 54 0 598 562 ;
-C 233 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
-C 234 ; WX 600 ; N OE ; B 66 0 665 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 217 259 530 580 ;
-C 241 ; WX 600 ; N ae ; B 47 -15 620 441 ;
-C 245 ; WX 600 ; N dotlessi ; B 102 0 505 426 ;
-C 248 ; WX 600 ; N lslash ; B 102 0 559 629 ;
-C 249 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
-C 250 ; WX 600 ; N oe ; B 61 -15 609 441 ;
-C 251 ; WX 600 ; N germandbls ; B 55 -15 610 629 ;
-C -1 ; WX 600 ; N scedilla ; B 92 -151 570 441 ;
-C -1 ; WX 600 ; N notegraphic ; B 143 -15 557 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 94 -18 625 775 ;
-C -1 ; WX 600 ; N ll ; B 40 0 609 629 ;
-C -1 ; WX 600 ; N otilde ; B 102 -15 617 606 ;
-C -1 ; WX 600 ; N scaron ; B 92 -15 614 669 ;
-C -1 ; WX 600 ; N divide ; B 128 1 562 426 ;
-C -1 ; WX 600 ; N Thorn ; B 86 0 599 562 ;
-C -1 ; WX 600 ; N format ; B -28 -157 169 598 ;
-C -1 ; WX 600 ; N largebullet ; B 322 227 388 290 ;
-C -1 ; WX 600 ; N Eth ; B 50 0 638 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 94 -18 625 716 ;
-C -1 ; WX 600 ; N onesuperior ; B 238 249 481 622 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 590 227 ;
-C -1 ; WX 600 ; N Ydieresis ; B 143 0 688 716 ;
-C -1 ; WX 600 ; N merge ; B 192 -15 497 436 ;
-C -1 ; WX 600 ; N IJ ; B 39 -18 681 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 113 -151 607 441 ;
-C -1 ; WX 600 ; N multiply ; B 93 -1 599 426 ;
-C -1 ; WX 600 ; N degree ; B 214 269 576 622 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 610 562 ;
-C -1 ; WX 600 ; N indent ; B 110 75 574 341 ;
-C -1 ; WX 600 ; N Otilde ; B 94 -18 644 732 ;
-C -1 ; WX 600 ; N thorn ; B -17 -157 598 629 ;
-C -1 ; WX 600 ; N mu ; B 79 -157 562 426 ;
-C -1 ; WX 600 ; N Yacute ; B 143 0 688 793 ;
-C -1 ; WX 600 ; N threesuperior ; B 220 240 494 622 ;
-C -1 ; WX 600 ; N logicalnot ; B 148 64 582 325 ;
-C -1 ; WX 600 ; N Ugrave ; B 132 -18 695 793 ;
-C -1 ; WX 600 ; N eth ; B 102 -15 629 629 ;
-C -1 ; WX 600 ; N left ; B 114 75 578 341 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 60 0 653 775 ;
-C -1 ; WX 600 ; N edieresis ; B 113 -15 591 580 ;
-C -1 ; WX 600 ; N Ograve ; B 94 -18 625 793 ;
-C -1 ; WX 600 ; N down ; B 192 -15 458 422 ;
-C -1 ; WX 600 ; N Agrave ; B 10 0 597 793 ;
-C -1 ; WX 600 ; N atilde ; B 83 -15 617 606 ;
-C -1 ; WX 600 ; N up ; B 232 0 498 437 ;
-C -1 ; WX 600 ; N eacute ; B 113 -15 612 672 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 652 599 ;
-C -1 ; WX 600 ; N lira ; B 125 -21 614 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 103 0 616 775 ;
-C -1 ; WX 600 ; N Adieresis ; B 10 0 597 716 ;
-C -1 ; WX 600 ; N yacute ; B -30 -157 643 672 ;
-C -1 ; WX 600 ; N icircumflex ; B 102 0 551 654 ;
-C -1 ; WX 600 ; N adieresis ; B 83 -15 559 580 ;
-C -1 ; WX 600 ; N zcaron ; B 106 0 624 669 ;
-C -1 ; WX 600 ; N Scaron ; B 83 -20 673 805 ;
-C -1 ; WX 600 ; N minus ; B 128 195 562 232 ;
-C -1 ; WX 600 ; N Aring ; B 10 0 597 753 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 132 -18 695 775 ;
-C -1 ; WX 600 ; N plusminus ; B 87 0 583 514 ;
-C -1 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
-C -1 ; WX 600 ; N Edieresis ; B 60 0 653 716 ;
-C -1 ; WX 600 ; N brokenbar ; B 265 -80 453 629 ;
-C -1 ; WX 600 ; N Idieresis ; B 103 0 616 716 ;
-C -1 ; WX 600 ; N acircumflex ; B 83 -15 581 654 ;
-C -1 ; WX 600 ; N ydieresis ; B -30 -157 643 580 ;
-C -1 ; WX 600 ; N Oacute ; B 94 -18 638 793 ;
-C -1 ; WX 600 ; N Egrave ; B 60 0 653 793 ;
-C -1 ; WX 600 ; N center ; B 103 14 623 580 ;
-C -1 ; WX 600 ; N threequarters ; B 28 -57 711 665 ;
-C -1 ; WX 600 ; N tab ; B 19 0 641 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 113 -15 591 654 ;
-C -1 ; WX 600 ; N Eacute ; B 60 0 668 793 ;
-C -1 ; WX 600 ; N trademark ; B 108 263 710 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N onehalf ; B 42 -57 725 665 ;
-C -1 ; WX 600 ; N onequarter ; B 48 -57 731 665 ;
-C -1 ; WX 600 ; N Uacute ; B 132 -18 695 793 ;
-C -1 ; WX 600 ; N Atilde ; B 10 0 644 732 ;
-C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N Igrave ; B 103 0 616 793 ;
-C -1 ; WX 600 ; N Iacute ; B 103 0 638 793 ;
-C -1 ; WX 600 ; N Acircumflex ; B 10 0 597 775 ;
-C -1 ; WX 600 ; N Udieresis ; B 132 -18 695 716 ;
-C -1 ; WX 600 ; N Gcaron ; B 90 -18 643 805 ;
-C -1 ; WX 600 ; N Aacute ; B 10 0 658 793 ;
-C -1 ; WX 600 ; N LL ; B 15 0 640 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 237 249 528 622 ;
-C -1 ; WX 600 ; N Scedilla ; B 83 -151 643 580 ;
-C -1 ; WX 600 ; N arrowboth ; B 36 122 692 476 ;
-C -1 ; WX 600 ; N udieresis ; B 111 -15 562 580 ;
-C -1 ; WX 600 ; N odieresis ; B 102 -15 588 580 ;
-C -1 ; WX 600 ; N aring ; B 83 -15 559 627 ;
-C -1 ; WX 600 ; N ij ; B 44 -157 623 657 ;
-C -1 ; WX 600 ; N arrowdown ; B 157 -15 511 608 ;
-C -1 ; WX 600 ; N igrave ; B 102 0 505 672 ;
-C -1 ; WX 600 ; N aacute ; B 83 -15 612 672 ;
-C -1 ; WX 600 ; N stop ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
-C -1 ; WX 600 ; N gcaron ; B 68 -157 650 669 ;
-C -1 ; WX 600 ; N iacute ; B 102 0 612 672 ;
-C -1 ; WX 600 ; N Ntilde ; B 14 -13 705 732 ;
-C -1 ; WX 600 ; N idieresis ; B 102 0 505 580 ;
-C -1 ; WX 600 ; N Ccedilla ; B 100 -151 651 580 ;
-C -1 ; WX 600 ; N arrowright ; B 35 122 688 476 ;
-C -1 ; WX 600 ; N ucircumflex ; B 111 -15 571 654 ;
-C -1 ; WX 600 ; N Idot ; B 103 0 616 716 ;
-C -1 ; WX 600 ; N agrave ; B 83 -15 559 672 ;
-C -1 ; WX 600 ; N ntilde ; B 33 0 617 606 ;
-C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N return ; B 79 0 700 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 86 0 643 805 ;
-C -1 ; WX 600 ; N uacute ; B 111 -15 602 672 ;
-C -1 ; WX 600 ; N overscore ; B 123 579 734 629 ;
-C -1 ; WX 600 ; N egrave ; B 113 -15 591 672 ;
-C -1 ; WX 600 ; N ugrave ; B 111 -15 562 672 ;
-C -1 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
-C -1 ; WX 600 ; N arrowleft ; B 40 122 692 476 ;
-C -1 ; WX 600 ; N arrowup ; B 218 0 572 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 46 121 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -4 121 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -1 136 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -4 121 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 12 126 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 27 126 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 56 121 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 26 121 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 29 136 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 26 121 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 29 136 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 26 121 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 26 121 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 29 136 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 26 121 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 27 126 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 26 121 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 26 121 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 29 136 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 26 121 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 27 126 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 59 136 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 0 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 56 121 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 26 121 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 29 136 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -4 121 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 56 121 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 29 136 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 29 136 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 0 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 0 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 0 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -30 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -30 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -30 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -30 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute -10 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -10 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 0 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute -20 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis -10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 10 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Courier.afm b/config/psfonts/Courier.afm
deleted file mode 100644 (file)
index 3688908..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 17:48:17 1990
-Comment UniqueID 27077
-Comment VMusage 27874 40242
-FontName Courier
-FullName Courier
-FamilyName Courier
-Weight Medium
-ItalicAngle 0
-IsFixedPitch true
-FontBBox -28 -157 628 805
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 426
-Ascender 629
-Descender -157
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
-C 35 ; WX 600 ; N numbersign ; B 100 -32 500 639 ;
-C 36 ; WX 600 ; N dollar ; B 112 -126 489 662 ;
-C 37 ; WX 600 ; N percent ; B 97 -15 515 622 ;
-C 38 ; WX 600 ; N ampersand ; B 70 -15 531 543 ;
-C 39 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
-C 40 ; WX 600 ; N parenleft ; B 276 -108 433 622 ;
-C 41 ; WX 600 ; N parenright ; B 167 -108 324 622 ;
-C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
-C 43 ; WX 600 ; N plus ; B 87 0 513 426 ;
-C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
-C 45 ; WX 600 ; N hyphen ; B 110 238 490 278 ;
-C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
-C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
-C 48 ; WX 600 ; N zero ; B 113 -15 487 622 ;
-C 49 ; WX 600 ; N one ; B 102 0 498 622 ;
-C 50 ; WX 600 ; N two ; B 77 0 464 622 ;
-C 51 ; WX 600 ; N three ; B 82 -15 459 622 ;
-C 52 ; WX 600 ; N four ; B 88 0 493 622 ;
-C 53 ; WX 600 ; N five ; B 99 -15 490 607 ;
-C 54 ; WX 600 ; N six ; B 118 -15 497 622 ;
-C 55 ; WX 600 ; N seven ; B 89 0 476 607 ;
-C 56 ; WX 600 ; N eight ; B 109 -15 491 622 ;
-C 57 ; WX 600 ; N nine ; B 103 -15 482 622 ;
-C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
-C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
-C 60 ; WX 600 ; N less ; B 41 -2 519 428 ;
-C 61 ; WX 600 ; N equal ; B 87 101 513 325 ;
-C 62 ; WX 600 ; N greater ; B 81 -2 559 428 ;
-C 63 ; WX 600 ; N question ; B 136 -15 485 572 ;
-C 64 ; WX 600 ; N at ; B 84 -15 526 622 ;
-C 65 ; WX 600 ; N A ; B 10 0 590 562 ;
-C 66 ; WX 600 ; N B ; B 50 0 552 562 ;
-C 67 ; WX 600 ; N C ; B 48 -18 533 580 ;
-C 68 ; WX 600 ; N D ; B 50 0 567 562 ;
-C 69 ; WX 600 ; N E ; B 60 0 543 562 ;
-C 70 ; WX 600 ; N F ; B 60 0 538 562 ;
-C 71 ; WX 600 ; N G ; B 38 -18 568 580 ;
-C 72 ; WX 600 ; N H ; B 39 0 561 562 ;
-C 73 ; WX 600 ; N I ; B 103 0 497 562 ;
-C 74 ; WX 600 ; N J ; B 41 -18 559 562 ;
-C 75 ; WX 600 ; N K ; B 45 0 575 562 ;
-C 76 ; WX 600 ; N L ; B 54 0 547 562 ;
-C 77 ; WX 600 ; N M ; B 11 0 589 562 ;
-C 78 ; WX 600 ; N N ; B 14 -13 586 562 ;
-C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
-C 80 ; WX 600 ; N P ; B 86 0 551 562 ;
-C 81 ; WX 600 ; N Q ; B 43 -129 557 580 ;
-C 82 ; WX 600 ; N R ; B 45 0 581 562 ;
-C 83 ; WX 600 ; N S ; B 79 -20 522 580 ;
-C 84 ; WX 600 ; N T ; B 45 0 556 562 ;
-C 85 ; WX 600 ; N U ; B 24 -18 576 562 ;
-C 86 ; WX 600 ; N V ; B 3 -13 597 562 ;
-C 87 ; WX 600 ; N W ; B 3 -13 597 562 ;
-C 88 ; WX 600 ; N X ; B 30 0 570 562 ;
-C 89 ; WX 600 ; N Y ; B 31 0 569 562 ;
-C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 276 -108 442 622 ;
-C 92 ; WX 600 ; N backslash ; B 125 -80 475 629 ;
-C 93 ; WX 600 ; N bracketright ; B 158 -108 324 622 ;
-C 94 ; WX 600 ; N asciicircum ; B 94 359 506 622 ;
-C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
-C 97 ; WX 600 ; N a ; B 60 -15 552 441 ;
-C 98 ; WX 600 ; N b ; B 21 -15 568 629 ;
-C 99 ; WX 600 ; N c ; B 73 -15 522 441 ;
-C 100 ; WX 600 ; N d ; B 52 -15 584 629 ;
-C 101 ; WX 600 ; N e ; B 73 -15 541 441 ;
-C 102 ; WX 600 ; N f ; B 121 0 524 629 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 52 -157 559 441 ;
-C 104 ; WX 600 ; N h ; B 25 0 575 629 ;
-C 105 ; WX 600 ; N i ; B 102 0 498 657 ;
-C 106 ; WX 600 ; N j ; B 89 -157 403 657 ;
-C 107 ; WX 600 ; N k ; B 50 0 573 629 ;
-C 108 ; WX 600 ; N l ; B 102 0 498 629 ;
-C 109 ; WX 600 ; N m ; B 2 0 598 441 ;
-C 110 ; WX 600 ; N n ; B 33 0 568 441 ;
-C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
-C 112 ; WX 600 ; N p ; B 16 -157 548 441 ;
-C 113 ; WX 600 ; N q ; B 52 -157 584 441 ;
-C 114 ; WX 600 ; N r ; B 67 0 552 441 ;
-C 115 ; WX 600 ; N s ; B 94 -15 506 441 ;
-C 116 ; WX 600 ; N t ; B 74 -15 503 561 ;
-C 117 ; WX 600 ; N u ; B 28 -15 555 426 ;
-C 118 ; WX 600 ; N v ; B 17 -10 583 426 ;
-C 119 ; WX 600 ; N w ; B -1 -10 601 426 ;
-C 120 ; WX 600 ; N x ; B 27 0 573 426 ;
-C 121 ; WX 600 ; N y ; B -12 -157 552 426 ;
-C 122 ; WX 600 ; N z ; B 106 0 495 426 ;
-C 123 ; WX 600 ; N braceleft ; B 189 -108 430 622 ;
-C 124 ; WX 600 ; N bar ; B 282 -80 319 629 ;
-C 125 ; WX 600 ; N braceright ; B 170 -108 411 622 ;
-C 126 ; WX 600 ; N asciitilde ; B 67 160 534 269 ;
-C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
-C 162 ; WX 600 ; N cent ; B 103 -49 493 614 ;
-C 163 ; WX 600 ; N sterling ; B 91 -21 518 611 ;
-C 164 ; WX 600 ; N fraction ; B 31 -57 569 665 ;
-C 165 ; WX 600 ; N yen ; B 33 0 567 594 ;
-C 166 ; WX 600 ; N florin ; B 11 -143 532 622 ;
-C 167 ; WX 600 ; N section ; B 120 -78 481 580 ;
-C 168 ; WX 600 ; N currency ; B 80 65 520 499 ;
-C 169 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 143 328 457 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
-C 174 ; WX 600 ; N fi ; B 10 0 590 629 ;
-C 175 ; WX 600 ; N fl ; B 10 0 590 629 ;
-C 177 ; WX 600 ; N endash ; B 75 238 525 278 ;
-C 178 ; WX 600 ; N dagger ; B 148 -78 452 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 148 -78 452 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 229 152 371 276 ;
-C 182 ; WX 600 ; N paragraph ; B 57 -78 504 562 ;
-C 183 ; WX 600 ; N bullet ; B 179 137 421 376 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
-C 185 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
-C 186 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 44 -15 556 97 ;
-C 189 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
-C 191 ; WX 600 ; N questiondown ; B 115 -157 464 430 ;
-C 193 ; WX 600 ; N grave ; B 151 497 378 672 ;
-C 194 ; WX 600 ; N acute ; B 242 497 469 672 ;
-C 195 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
-C 196 ; WX 600 ; N tilde ; B 109 503 491 606 ;
-C 197 ; WX 600 ; N macron ; B 120 525 480 565 ;
-C 198 ; WX 600 ; N breve ; B 153 501 447 609 ;
-C 199 ; WX 600 ; N dotaccent ; B 264 508 336 580 ;
-C 200 ; WX 600 ; N dieresis ; B 198 508 402 580 ;
-C 202 ; WX 600 ; N ring ; B 228 483 372 627 ;
-C 203 ; WX 600 ; N cedilla ; B 249 -151 358 10 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
-C 206 ; WX 600 ; N ogonek ; B 227 -151 370 0 ;
-C 207 ; WX 600 ; N caron ; B 124 492 476 669 ;
-C 208 ; WX 600 ; N emdash ; B 0 238 600 278 ;
-C 225 ; WX 600 ; N AE ; B 10 0 543 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 161 259 437 580 ;
-C 232 ; WX 600 ; N Lslash ; B 54 0 547 562 ;
-C 233 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
-C 234 ; WX 600 ; N OE ; B 14 0 560 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 162 259 438 580 ;
-C 241 ; WX 600 ; N ae ; B 26 -15 563 441 ;
-C 245 ; WX 600 ; N dotlessi ; B 102 0 498 426 ;
-C 248 ; WX 600 ; N lslash ; B 102 0 498 629 ;
-C 249 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
-C 250 ; WX 600 ; N oe ; B 26 -15 552 441 ;
-C 251 ; WX 600 ; N germandbls ; B 55 -15 581 629 ;
-C -1 ; WX 600 ; N scedilla ; B 94 -151 506 441 ;
-C -1 ; WX 600 ; N notegraphic ; B 136 -15 464 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 43 -18 557 775 ;
-C -1 ; WX 600 ; N ll ; B 25 0 560 629 ;
-C -1 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
-C -1 ; WX 600 ; N scaron ; B 94 -15 506 669 ;
-C -1 ; WX 600 ; N divide ; B 87 1 513 426 ;
-C -1 ; WX 600 ; N Thorn ; B 86 0 531 562 ;
-C -1 ; WX 600 ; N format ; B 5 -157 42 598 ;
-C -1 ; WX 600 ; N largebullet ; B 268 227 332 290 ;
-C -1 ; WX 600 ; N Eth ; B 30 0 567 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 43 -18 557 716 ;
-C -1 ; WX 600 ; N onesuperior ; B 179 249 421 622 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 582 227 ;
-C -1 ; WX 600 ; N Ydieresis ; B 31 0 569 716 ;
-C -1 ; WX 600 ; N merge ; B 167 -15 433 436 ;
-C -1 ; WX 600 ; N IJ ; B 39 -18 562 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 73 -151 522 441 ;
-C -1 ; WX 600 ; N multiply ; B 87 -1 514 426 ;
-C -1 ; WX 600 ; N degree ; B 123 269 477 622 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 570 562 ;
-C -1 ; WX 600 ; N indent ; B 70 75 530 341 ;
-C -1 ; WX 600 ; N Otilde ; B 43 -18 557 732 ;
-C -1 ; WX 600 ; N thorn ; B 1 -157 548 629 ;
-C -1 ; WX 600 ; N mu ; B 28 -157 555 426 ;
-C -1 ; WX 600 ; N Yacute ; B 31 0 569 793 ;
-C -1 ; WX 600 ; N threesuperior ; B 162 240 399 622 ;
-C -1 ; WX 600 ; N logicalnot ; B 87 64 513 325 ;
-C -1 ; WX 600 ; N Ugrave ; B 24 -18 576 793 ;
-C -1 ; WX 600 ; N eth ; B 62 -15 538 629 ;
-C -1 ; WX 600 ; N left ; B 70 75 530 341 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 60 0 543 775 ;
-C -1 ; WX 600 ; N edieresis ; B 73 -15 541 580 ;
-C -1 ; WX 600 ; N Ograve ; B 43 -18 557 793 ;
-C -1 ; WX 600 ; N down ; B 167 -15 433 422 ;
-C -1 ; WX 600 ; N Agrave ; B 10 0 590 793 ;
-C -1 ; WX 600 ; N atilde ; B 60 -15 552 606 ;
-C -1 ; WX 600 ; N up ; B 167 0 433 437 ;
-C -1 ; WX 600 ; N eacute ; B 73 -15 541 672 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 525 599 ;
-C -1 ; WX 600 ; N lira ; B 80 -21 518 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 103 0 497 775 ;
-C -1 ; WX 600 ; N Adieresis ; B 10 0 590 716 ;
-C -1 ; WX 600 ; N yacute ; B -12 -157 552 672 ;
-C -1 ; WX 600 ; N icircumflex ; B 94 0 498 654 ;
-C -1 ; WX 600 ; N adieresis ; B 60 -15 552 580 ;
-C -1 ; WX 600 ; N zcaron ; B 106 0 495 669 ;
-C -1 ; WX 600 ; N Scaron ; B 79 -20 522 805 ;
-C -1 ; WX 600 ; N minus ; B 87 195 513 232 ;
-C -1 ; WX 600 ; N Aring ; B 10 0 590 753 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 24 -18 576 775 ;
-C -1 ; WX 600 ; N plusminus ; B 87 0 513 514 ;
-C -1 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
-C -1 ; WX 600 ; N Edieresis ; B 60 0 543 716 ;
-C -1 ; WX 600 ; N brokenbar ; B 282 -80 319 629 ;
-C -1 ; WX 600 ; N Idieresis ; B 103 0 497 716 ;
-C -1 ; WX 600 ; N acircumflex ; B 60 -15 552 654 ;
-C -1 ; WX 600 ; N ydieresis ; B -12 -157 552 580 ;
-C -1 ; WX 600 ; N Oacute ; B 43 -18 557 793 ;
-C -1 ; WX 600 ; N Egrave ; B 60 0 543 793 ;
-C -1 ; WX 600 ; N center ; B 40 14 560 580 ;
-C -1 ; WX 600 ; N threequarters ; B 22 -57 574 665 ;
-C -1 ; WX 600 ; N tab ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 73 -15 541 654 ;
-C -1 ; WX 600 ; N Eacute ; B 60 0 543 793 ;
-C -1 ; WX 600 ; N trademark ; B 10 263 591 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
-C -1 ; WX 600 ; N onequarter ; B 6 -57 594 665 ;
-C -1 ; WX 600 ; N Uacute ; B 24 -18 576 793 ;
-C -1 ; WX 600 ; N Atilde ; B 10 0 590 732 ;
-C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N Igrave ; B 103 0 497 793 ;
-C -1 ; WX 600 ; N Iacute ; B 103 0 497 793 ;
-C -1 ; WX 600 ; N Acircumflex ; B 10 0 590 775 ;
-C -1 ; WX 600 ; N Udieresis ; B 24 -18 576 716 ;
-C -1 ; WX 600 ; N Gcaron ; B 38 -18 568 805 ;
-C -1 ; WX 600 ; N Aacute ; B 10 0 590 793 ;
-C -1 ; WX 600 ; N LL ; B 15 0 585 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 184 249 417 622 ;
-C -1 ; WX 600 ; N Scedilla ; B 79 -151 522 580 ;
-C -1 ; WX 600 ; N arrowboth ; B -28 122 628 476 ;
-C -1 ; WX 600 ; N udieresis ; B 28 -15 555 580 ;
-C -1 ; WX 600 ; N odieresis ; B 62 -15 538 580 ;
-C -1 ; WX 600 ; N aring ; B 60 -15 552 627 ;
-C -1 ; WX 600 ; N ij ; B 44 -157 483 657 ;
-C -1 ; WX 600 ; N arrowdown ; B 123 -15 477 608 ;
-C -1 ; WX 600 ; N igrave ; B 102 0 498 672 ;
-C -1 ; WX 600 ; N aacute ; B 60 -15 552 672 ;
-C -1 ; WX 600 ; N stop ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
-C -1 ; WX 600 ; N gcaron ; B 52 -157 559 669 ;
-C -1 ; WX 600 ; N iacute ; B 102 0 498 672 ;
-C -1 ; WX 600 ; N Ntilde ; B 14 -13 586 732 ;
-C -1 ; WX 600 ; N idieresis ; B 102 0 498 580 ;
-C -1 ; WX 600 ; N Ccedilla ; B 48 -151 533 580 ;
-C -1 ; WX 600 ; N arrowright ; B -24 122 624 476 ;
-C -1 ; WX 600 ; N ucircumflex ; B 28 -15 555 654 ;
-C -1 ; WX 600 ; N Idot ; B 103 0 497 716 ;
-C -1 ; WX 600 ; N agrave ; B 60 -15 552 672 ;
-C -1 ; WX 600 ; N ntilde ; B 33 0 568 606 ;
-C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N return ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 86 0 514 805 ;
-C -1 ; WX 600 ; N uacute ; B 28 -15 555 672 ;
-C -1 ; WX 600 ; N overscore ; B 0 579 600 629 ;
-C -1 ; WX 600 ; N egrave ; B 73 -15 541 672 ;
-C -1 ; WX 600 ; N ugrave ; B 28 -15 555 672 ;
-C -1 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
-C -1 ; WX 600 ; N arrowleft ; B -24 122 624 476 ;
-C -1 ; WX 600 ; N arrowup ; B 123 0 477 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 20 121 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -30 121 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -30 136 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -30 121 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring -15 126 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 0 126 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 30 121 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 0 121 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 0 136 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 0 121 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 0 136 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 121 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 121 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 136 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 121 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 0 126 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 0 121 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 0 121 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 0 136 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 0 121 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 0 126 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 30 136 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 0 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 30 121 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 0 121 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 0 136 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -30 121 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 30 121 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 0 136 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 0 136 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 0 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 0 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 0 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -30 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -30 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -30 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -30 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute -10 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -10 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 0 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute -20 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis -10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 10 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Helvetica-Bold.afm b/config/psfonts/Helvetica-Bold.afm
deleted file mode 100644 (file)
index a1e1b33..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Thu Mar 15 09:43:00 1990
-Comment UniqueID 28357
-Comment VMusage 26878 33770
-FontName Helvetica-Bold
-FullName Helvetica Bold
-FamilyName Helvetica
-Weight Bold
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -170 -228 1003 962
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 90 0 244 718 ;
-C 34 ; WX 474 ; N quotedbl ; B 98 447 376 718 ;
-C 35 ; WX 556 ; N numbersign ; B 18 0 538 698 ;
-C 36 ; WX 556 ; N dollar ; B 30 -115 523 775 ;
-C 37 ; WX 889 ; N percent ; B 28 -19 861 710 ;
-C 38 ; WX 722 ; N ampersand ; B 54 -19 701 718 ;
-C 39 ; WX 278 ; N quoteright ; B 69 445 209 718 ;
-C 40 ; WX 333 ; N parenleft ; B 35 -208 314 734 ;
-C 41 ; WX 333 ; N parenright ; B 19 -208 298 734 ;
-C 42 ; WX 389 ; N asterisk ; B 27 387 362 718 ;
-C 43 ; WX 584 ; N plus ; B 40 0 544 506 ;
-C 44 ; WX 278 ; N comma ; B 64 -168 214 146 ;
-C 45 ; WX 333 ; N hyphen ; B 27 215 306 345 ;
-C 46 ; WX 278 ; N period ; B 64 0 214 146 ;
-C 47 ; WX 278 ; N slash ; B -33 -19 311 737 ;
-C 48 ; WX 556 ; N zero ; B 32 -19 524 710 ;
-C 49 ; WX 556 ; N one ; B 69 0 378 710 ;
-C 50 ; WX 556 ; N two ; B 26 0 511 710 ;
-C 51 ; WX 556 ; N three ; B 27 -19 516 710 ;
-C 52 ; WX 556 ; N four ; B 27 0 526 710 ;
-C 53 ; WX 556 ; N five ; B 27 -19 516 698 ;
-C 54 ; WX 556 ; N six ; B 31 -19 520 710 ;
-C 55 ; WX 556 ; N seven ; B 25 0 528 698 ;
-C 56 ; WX 556 ; N eight ; B 32 -19 524 710 ;
-C 57 ; WX 556 ; N nine ; B 30 -19 522 710 ;
-C 58 ; WX 333 ; N colon ; B 92 0 242 512 ;
-C 59 ; WX 333 ; N semicolon ; B 92 -168 242 512 ;
-C 60 ; WX 584 ; N less ; B 38 -8 546 514 ;
-C 61 ; WX 584 ; N equal ; B 40 87 544 419 ;
-C 62 ; WX 584 ; N greater ; B 38 -8 546 514 ;
-C 63 ; WX 611 ; N question ; B 60 0 556 727 ;
-C 64 ; WX 975 ; N at ; B 118 -19 856 737 ;
-C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
-C 66 ; WX 722 ; N B ; B 76 0 669 718 ;
-C 67 ; WX 722 ; N C ; B 44 -19 684 737 ;
-C 68 ; WX 722 ; N D ; B 76 0 685 718 ;
-C 69 ; WX 667 ; N E ; B 76 0 621 718 ;
-C 70 ; WX 611 ; N F ; B 76 0 587 718 ;
-C 71 ; WX 778 ; N G ; B 44 -19 713 737 ;
-C 72 ; WX 722 ; N H ; B 71 0 651 718 ;
-C 73 ; WX 278 ; N I ; B 64 0 214 718 ;
-C 74 ; WX 556 ; N J ; B 22 -18 484 718 ;
-C 75 ; WX 722 ; N K ; B 87 0 722 718 ;
-C 76 ; WX 611 ; N L ; B 76 0 583 718 ;
-C 77 ; WX 833 ; N M ; B 69 0 765 718 ;
-C 78 ; WX 722 ; N N ; B 69 0 654 718 ;
-C 79 ; WX 778 ; N O ; B 44 -19 734 737 ;
-C 80 ; WX 667 ; N P ; B 76 0 627 718 ;
-C 81 ; WX 778 ; N Q ; B 44 -52 737 737 ;
-C 82 ; WX 722 ; N R ; B 76 0 677 718 ;
-C 83 ; WX 667 ; N S ; B 39 -19 629 737 ;
-C 84 ; WX 611 ; N T ; B 14 0 598 718 ;
-C 85 ; WX 722 ; N U ; B 72 -19 651 718 ;
-C 86 ; WX 667 ; N V ; B 19 0 648 718 ;
-C 87 ; WX 944 ; N W ; B 16 0 929 718 ;
-C 88 ; WX 667 ; N X ; B 14 0 653 718 ;
-C 89 ; WX 667 ; N Y ; B 15 0 653 718 ;
-C 90 ; WX 611 ; N Z ; B 25 0 586 718 ;
-C 91 ; WX 333 ; N bracketleft ; B 63 -196 309 722 ;
-C 92 ; WX 278 ; N backslash ; B -33 -19 311 737 ;
-C 93 ; WX 333 ; N bracketright ; B 24 -196 270 722 ;
-C 94 ; WX 584 ; N asciicircum ; B 62 323 522 698 ;
-C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
-C 96 ; WX 278 ; N quoteleft ; B 69 454 209 727 ;
-C 97 ; WX 556 ; N a ; B 29 -14 527 546 ;
-C 98 ; WX 611 ; N b ; B 61 -14 578 718 ;
-C 99 ; WX 556 ; N c ; B 34 -14 524 546 ;
-C 100 ; WX 611 ; N d ; B 34 -14 551 718 ;
-C 101 ; WX 556 ; N e ; B 23 -14 528 546 ;
-C 102 ; WX 333 ; N f ; B 10 0 318 727 ; L i fi ; L l fl ;
-C 103 ; WX 611 ; N g ; B 40 -217 553 546 ;
-C 104 ; WX 611 ; N h ; B 65 0 546 718 ;
-C 105 ; WX 278 ; N i ; B 69 0 209 725 ;
-C 106 ; WX 278 ; N j ; B 3 -214 209 725 ;
-C 107 ; WX 556 ; N k ; B 69 0 562 718 ;
-C 108 ; WX 278 ; N l ; B 69 0 209 718 ;
-C 109 ; WX 889 ; N m ; B 64 0 826 546 ;
-C 110 ; WX 611 ; N n ; B 65 0 546 546 ;
-C 111 ; WX 611 ; N o ; B 34 -14 578 546 ;
-C 112 ; WX 611 ; N p ; B 62 -207 578 546 ;
-C 113 ; WX 611 ; N q ; B 34 -207 552 546 ;
-C 114 ; WX 389 ; N r ; B 64 0 373 546 ;
-C 115 ; WX 556 ; N s ; B 30 -14 519 546 ;
-C 116 ; WX 333 ; N t ; B 10 -6 309 676 ;
-C 117 ; WX 611 ; N u ; B 66 -14 545 532 ;
-C 118 ; WX 556 ; N v ; B 13 0 543 532 ;
-C 119 ; WX 778 ; N w ; B 10 0 769 532 ;
-C 120 ; WX 556 ; N x ; B 15 0 541 532 ;
-C 121 ; WX 556 ; N y ; B 10 -214 539 532 ;
-C 122 ; WX 500 ; N z ; B 20 0 480 532 ;
-C 123 ; WX 389 ; N braceleft ; B 48 -196 365 722 ;
-C 124 ; WX 280 ; N bar ; B 84 -19 196 737 ;
-C 125 ; WX 389 ; N braceright ; B 24 -196 341 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 61 163 523 343 ;
-C 161 ; WX 333 ; N exclamdown ; B 90 -186 244 532 ;
-C 162 ; WX 556 ; N cent ; B 34 -118 524 628 ;
-C 163 ; WX 556 ; N sterling ; B 28 -16 541 718 ;
-C 164 ; WX 167 ; N fraction ; B -170 -19 336 710 ;
-C 165 ; WX 556 ; N yen ; B -9 0 565 698 ;
-C 166 ; WX 556 ; N florin ; B -10 -210 516 737 ;
-C 167 ; WX 556 ; N section ; B 34 -184 522 727 ;
-C 168 ; WX 556 ; N currency ; B -3 76 559 636 ;
-C 169 ; WX 238 ; N quotesingle ; B 70 447 168 718 ;
-C 170 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ;
-C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ;
-C 173 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ;
-C 174 ; WX 611 ; N fi ; B 10 0 542 727 ;
-C 175 ; WX 611 ; N fl ; B 10 0 542 727 ;
-C 177 ; WX 556 ; N endash ; B 0 227 556 333 ;
-C 178 ; WX 556 ; N dagger ; B 36 -171 520 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 36 -171 520 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 58 172 220 334 ;
-C 182 ; WX 556 ; N paragraph ; B -8 -191 539 700 ;
-C 183 ; WX 350 ; N bullet ; B 10 194 340 524 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 69 -146 209 127 ;
-C 185 ; WX 500 ; N quotedblbase ; B 64 -146 436 127 ;
-C 186 ; WX 500 ; N quotedblright ; B 64 445 436 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 88 76 468 484 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ;
-C 189 ; WX 1000 ; N perthousand ; B -3 -19 1003 710 ;
-C 191 ; WX 611 ; N questiondown ; B 55 -195 551 532 ;
-C 193 ; WX 333 ; N grave ; B -23 604 225 750 ;
-C 194 ; WX 333 ; N acute ; B 108 604 356 750 ;
-C 195 ; WX 333 ; N circumflex ; B -10 604 343 750 ;
-C 196 ; WX 333 ; N tilde ; B -17 610 350 737 ;
-C 197 ; WX 333 ; N macron ; B -6 604 339 678 ;
-C 198 ; WX 333 ; N breve ; B -2 604 335 750 ;
-C 199 ; WX 333 ; N dotaccent ; B 104 614 230 729 ;
-C 200 ; WX 333 ; N dieresis ; B 6 614 327 729 ;
-C 202 ; WX 333 ; N ring ; B 59 568 275 776 ;
-C 203 ; WX 333 ; N cedilla ; B 6 -228 245 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 9 604 486 750 ;
-C 206 ; WX 333 ; N ogonek ; B 71 -228 304 0 ;
-C 207 ; WX 333 ; N caron ; B -10 604 343 750 ;
-C 208 ; WX 1000 ; N emdash ; B 0 227 1000 333 ;
-C 225 ; WX 1000 ; N AE ; B 5 0 954 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 22 276 347 737 ;
-C 232 ; WX 611 ; N Lslash ; B -20 0 583 718 ;
-C 233 ; WX 778 ; N Oslash ; B 33 -27 744 745 ;
-C 234 ; WX 1000 ; N OE ; B 37 -19 961 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 6 276 360 737 ;
-C 241 ; WX 889 ; N ae ; B 29 -14 858 546 ;
-C 245 ; WX 278 ; N dotlessi ; B 69 0 209 532 ;
-C 248 ; WX 278 ; N lslash ; B -18 0 296 718 ;
-C 249 ; WX 611 ; N oslash ; B 22 -29 589 560 ;
-C 250 ; WX 944 ; N oe ; B 34 -14 912 546 ;
-C 251 ; WX 611 ; N germandbls ; B 69 -14 579 731 ;
-C -1 ; WX 611 ; N Zcaron ; B 25 0 586 936 ;
-C -1 ; WX 556 ; N ccedilla ; B 34 -228 524 546 ;
-C -1 ; WX 556 ; N ydieresis ; B 10 -214 539 729 ;
-C -1 ; WX 556 ; N atilde ; B 29 -14 527 737 ;
-C -1 ; WX 278 ; N icircumflex ; B -37 0 316 750 ;
-C -1 ; WX 333 ; N threesuperior ; B 8 271 326 710 ;
-C -1 ; WX 556 ; N ecircumflex ; B 23 -14 528 750 ;
-C -1 ; WX 611 ; N thorn ; B 62 -208 578 718 ;
-C -1 ; WX 556 ; N egrave ; B 23 -14 528 750 ;
-C -1 ; WX 333 ; N twosuperior ; B 9 283 324 710 ;
-C -1 ; WX 556 ; N eacute ; B 23 -14 528 750 ;
-C -1 ; WX 611 ; N otilde ; B 34 -14 578 737 ;
-C -1 ; WX 722 ; N Aacute ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N ocircumflex ; B 34 -14 578 750 ;
-C -1 ; WX 556 ; N yacute ; B 10 -214 539 750 ;
-C -1 ; WX 611 ; N udieresis ; B 66 -14 545 729 ;
-C -1 ; WX 834 ; N threequarters ; B 16 -19 799 710 ;
-C -1 ; WX 556 ; N acircumflex ; B 29 -14 527 750 ;
-C -1 ; WX 722 ; N Eth ; B -5 0 685 718 ;
-C -1 ; WX 556 ; N edieresis ; B 23 -14 528 729 ;
-C -1 ; WX 611 ; N ugrave ; B 66 -14 545 750 ;
-C -1 ; WX 1000 ; N trademark ; B 44 306 956 718 ;
-C -1 ; WX 611 ; N ograve ; B 34 -14 578 750 ;
-C -1 ; WX 556 ; N scaron ; B 30 -14 519 750 ;
-C -1 ; WX 278 ; N Idieresis ; B -21 0 300 915 ;
-C -1 ; WX 611 ; N uacute ; B 66 -14 545 750 ;
-C -1 ; WX 556 ; N agrave ; B 29 -14 527 750 ;
-C -1 ; WX 611 ; N ntilde ; B 65 0 546 737 ;
-C -1 ; WX 556 ; N aring ; B 29 -14 527 776 ;
-C -1 ; WX 500 ; N zcaron ; B 20 0 480 750 ;
-C -1 ; WX 278 ; N Icircumflex ; B -37 0 316 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 69 0 654 923 ;
-C -1 ; WX 611 ; N ucircumflex ; B 66 -14 545 750 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 76 0 621 936 ;
-C -1 ; WX 278 ; N Iacute ; B 64 0 329 936 ;
-C -1 ; WX 722 ; N Ccedilla ; B 44 -228 684 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 44 -19 734 915 ;
-C -1 ; WX 667 ; N Scaron ; B 39 -19 629 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 76 0 621 915 ;
-C -1 ; WX 278 ; N Igrave ; B -50 0 214 936 ;
-C -1 ; WX 556 ; N adieresis ; B 29 -14 527 729 ;
-C -1 ; WX 778 ; N Ograve ; B 44 -19 734 936 ;
-C -1 ; WX 667 ; N Egrave ; B 76 0 621 936 ;
-C -1 ; WX 667 ; N Ydieresis ; B 15 0 653 915 ;
-C -1 ; WX 737 ; N registered ; B -11 -19 748 737 ;
-C -1 ; WX 778 ; N Otilde ; B 44 -19 734 923 ;
-C -1 ; WX 834 ; N onequarter ; B 26 -19 766 710 ;
-C -1 ; WX 722 ; N Ugrave ; B 72 -19 651 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 72 -19 651 936 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 627 718 ;
-C -1 ; WX 584 ; N divide ; B 40 -42 544 548 ;
-C -1 ; WX 722 ; N Atilde ; B 20 0 702 923 ;
-C -1 ; WX 722 ; N Uacute ; B 72 -19 651 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 44 -19 734 936 ;
-C -1 ; WX 584 ; N logicalnot ; B 40 108 544 419 ;
-C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
-C -1 ; WX 278 ; N idieresis ; B -21 0 300 729 ;
-C -1 ; WX 278 ; N iacute ; B 69 0 329 750 ;
-C -1 ; WX 556 ; N aacute ; B 29 -14 527 750 ;
-C -1 ; WX 584 ; N plusminus ; B 40 0 544 506 ;
-C -1 ; WX 584 ; N multiply ; B 40 1 545 505 ;
-C -1 ; WX 722 ; N Udieresis ; B 72 -19 651 915 ;
-C -1 ; WX 584 ; N minus ; B 40 197 544 309 ;
-C -1 ; WX 333 ; N onesuperior ; B 26 283 237 710 ;
-C -1 ; WX 667 ; N Eacute ; B 76 0 621 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 20 0 702 936 ;
-C -1 ; WX 737 ; N copyright ; B -11 -19 749 737 ;
-C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N odieresis ; B 34 -14 578 729 ;
-C -1 ; WX 611 ; N oacute ; B 34 -14 578 750 ;
-C -1 ; WX 400 ; N degree ; B 57 426 343 712 ;
-C -1 ; WX 278 ; N igrave ; B -50 0 209 750 ;
-C -1 ; WX 611 ; N mu ; B 66 -207 545 532 ;
-C -1 ; WX 778 ; N Oacute ; B 44 -19 734 936 ;
-C -1 ; WX 611 ; N eth ; B 34 -14 578 737 ;
-C -1 ; WX 722 ; N Adieresis ; B 20 0 702 915 ;
-C -1 ; WX 667 ; N Yacute ; B 15 0 653 936 ;
-C -1 ; WX 280 ; N brokenbar ; B 84 -19 196 737 ;
-C -1 ; WX 834 ; N onehalf ; B 26 -19 794 710 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 209
-
-KPX A y -30
-KPX A w -30
-KPX A v -40
-KPX A u -30
-KPX A Y -110
-KPX A W -60
-KPX A V -80
-KPX A U -50
-KPX A T -90
-KPX A Q -40
-KPX A O -40
-KPX A G -50
-KPX A C -40
-
-KPX B U -10
-KPX B A -30
-
-KPX D period -30
-KPX D comma -30
-KPX D Y -70
-KPX D W -40
-KPX D V -40
-KPX D A -40
-
-KPX F period -100
-KPX F comma -100
-KPX F a -20
-KPX F A -80
-
-KPX J u -20
-KPX J period -20
-KPX J comma -20
-KPX J A -20
-
-KPX K y -40
-KPX K u -30
-KPX K o -35
-KPX K e -15
-KPX K O -30
-
-KPX L y -30
-KPX L quoteright -140
-KPX L quotedblright -140
-KPX L Y -120
-KPX L W -80
-KPX L V -110
-KPX L T -90
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -50
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -50
-
-KPX P period -120
-KPX P o -40
-KPX P e -30
-KPX P comma -120
-KPX P a -30
-KPX P A -100
-
-KPX Q period 20
-KPX Q comma 20
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -40
-KPX R V -50
-KPX R U -20
-KPX R T -20
-KPX R O -20
-
-KPX T y -60
-KPX T w -60
-KPX T u -90
-KPX T semicolon -40
-KPX T r -80
-KPX T period -80
-KPX T o -80
-KPX T hyphen -120
-KPX T e -60
-KPX T comma -80
-KPX T colon -40
-KPX T a -80
-KPX T O -40
-KPX T A -90
-
-KPX U period -30
-KPX U comma -30
-KPX U A -50
-
-KPX V u -60
-KPX V semicolon -40
-KPX V period -120
-KPX V o -90
-KPX V hyphen -80
-KPX V e -50
-KPX V comma -120
-KPX V colon -40
-KPX V a -60
-KPX V O -50
-KPX V G -50
-KPX V A -80
-
-KPX W y -20
-KPX W u -45
-KPX W semicolon -10
-KPX W period -80
-KPX W o -60
-KPX W hyphen -40
-KPX W e -35
-KPX W comma -80
-KPX W colon -10
-KPX W a -40
-KPX W O -20
-KPX W A -60
-
-KPX Y u -100
-KPX Y semicolon -50
-KPX Y period -100
-KPX Y o -100
-KPX Y e -80
-KPX Y comma -100
-KPX Y colon -50
-KPX Y a -90
-KPX Y O -70
-KPX Y A -110
-
-KPX a y -20
-KPX a w -15
-KPX a v -15
-KPX a g -10
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b l -10
-
-KPX c y -10
-KPX c l -20
-KPX c k -20
-KPX c h -10
-
-KPX colon space -40
-
-KPX comma space -40
-KPX comma quoteright -120
-KPX comma quotedblright -120
-
-KPX d y -15
-KPX d w -15
-KPX d v -15
-KPX d d -10
-
-KPX e y -15
-KPX e x -15
-KPX e w -15
-KPX e v -15
-KPX e period 20
-KPX e comma 10
-
-KPX f quoteright 30
-KPX f quotedblright 30
-KPX f period -10
-KPX f o -20
-KPX f e -10
-KPX f comma -10
-
-KPX g g -10
-KPX g e 10
-
-KPX h y -20
-
-KPX k o -15
-
-KPX l y -15
-KPX l w -15
-
-KPX m y -30
-KPX m u -20
-
-KPX n y -20
-KPX n v -40
-KPX n u -10
-
-KPX o y -20
-KPX o x -30
-KPX o w -15
-KPX o v -20
-
-KPX p y -15
-
-KPX period space -40
-KPX period quoteright -120
-KPX period quotedblright -120
-
-KPX quotedblright space -80
-
-KPX quoteleft quoteleft -46
-
-KPX quoteright v -20
-KPX quoteright space -80
-KPX quoteright s -60
-KPX quoteright r -40
-KPX quoteright quoteright -46
-KPX quoteright l -20
-KPX quoteright d -80
-
-KPX r y 10
-KPX r v 10
-KPX r t 20
-KPX r s -15
-KPX r q -20
-KPX r period -60
-KPX r o -20
-KPX r hyphen -20
-KPX r g -15
-KPX r d -20
-KPX r comma -60
-KPX r c -20
-
-KPX s w -15
-
-KPX semicolon space -40
-
-KPX space quoteleft -60
-KPX space quotedblleft -80
-KPX space Y -120
-KPX space W -80
-KPX space V -80
-KPX space T -100
-
-KPX v period -80
-KPX v o -30
-KPX v comma -80
-KPX v a -20
-
-KPX w period -40
-KPX w o -20
-KPX w comma -40
-
-KPX x e -10
-
-KPX y period -80
-KPX y o -25
-KPX y e -10
-KPX y comma -80
-KPX y a -30
-
-KPX z e 10
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 195 186 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 195 186 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 195 186 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 195 186 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 195 186 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 195 186 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 215 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 167 186 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 167 186 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 167 186 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 167 186 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute -27 186 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex -27 186 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis -27 186 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave -27 186 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 186 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 186 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 186 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 186 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 186 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 186 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 167 186 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 186 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 186 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 186 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 186 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 167 186 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 167 186 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 186 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 112 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 132 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 139 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 139 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 139 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 139 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 139 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 139 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 112 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 139 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 139 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 139 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 139 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 112 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 112 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Helvetica-BoldOblique.afm b/config/psfonts/Helvetica-BoldOblique.afm
deleted file mode 100644 (file)
index b6cff41..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Thu Mar 15 10:44:33 1990
-Comment UniqueID 28371
-Comment VMusage 7614 43068
-FontName Helvetica-BoldOblique
-FullName Helvetica Bold Oblique
-FamilyName Helvetica
-Weight Bold
-ItalicAngle -12
-IsFixedPitch false
-FontBBox -174 -228 1114 962
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 94 0 397 718 ;
-C 34 ; WX 474 ; N quotedbl ; B 193 447 529 718 ;
-C 35 ; WX 556 ; N numbersign ; B 60 0 644 698 ;
-C 36 ; WX 556 ; N dollar ; B 67 -115 622 775 ;
-C 37 ; WX 889 ; N percent ; B 136 -19 901 710 ;
-C 38 ; WX 722 ; N ampersand ; B 89 -19 732 718 ;
-C 39 ; WX 278 ; N quoteright ; B 167 445 362 718 ;
-C 40 ; WX 333 ; N parenleft ; B 76 -208 470 734 ;
-C 41 ; WX 333 ; N parenright ; B -25 -208 369 734 ;
-C 42 ; WX 389 ; N asterisk ; B 146 387 481 718 ;
-C 43 ; WX 584 ; N plus ; B 82 0 610 506 ;
-C 44 ; WX 278 ; N comma ; B 28 -168 245 146 ;
-C 45 ; WX 333 ; N hyphen ; B 73 215 379 345 ;
-C 46 ; WX 278 ; N period ; B 64 0 245 146 ;
-C 47 ; WX 278 ; N slash ; B -37 -19 468 737 ;
-C 48 ; WX 556 ; N zero ; B 86 -19 617 710 ;
-C 49 ; WX 556 ; N one ; B 173 0 529 710 ;
-C 50 ; WX 556 ; N two ; B 26 0 619 710 ;
-C 51 ; WX 556 ; N three ; B 65 -19 608 710 ;
-C 52 ; WX 556 ; N four ; B 60 0 598 710 ;
-C 53 ; WX 556 ; N five ; B 64 -19 636 698 ;
-C 54 ; WX 556 ; N six ; B 85 -19 619 710 ;
-C 55 ; WX 556 ; N seven ; B 125 0 676 698 ;
-C 56 ; WX 556 ; N eight ; B 69 -19 616 710 ;
-C 57 ; WX 556 ; N nine ; B 78 -19 615 710 ;
-C 58 ; WX 333 ; N colon ; B 92 0 351 512 ;
-C 59 ; WX 333 ; N semicolon ; B 56 -168 351 512 ;
-C 60 ; WX 584 ; N less ; B 82 -8 655 514 ;
-C 61 ; WX 584 ; N equal ; B 58 87 633 419 ;
-C 62 ; WX 584 ; N greater ; B 36 -8 609 514 ;
-C 63 ; WX 611 ; N question ; B 165 0 671 727 ;
-C 64 ; WX 975 ; N at ; B 186 -19 954 737 ;
-C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
-C 66 ; WX 722 ; N B ; B 76 0 764 718 ;
-C 67 ; WX 722 ; N C ; B 107 -19 789 737 ;
-C 68 ; WX 722 ; N D ; B 76 0 777 718 ;
-C 69 ; WX 667 ; N E ; B 76 0 757 718 ;
-C 70 ; WX 611 ; N F ; B 76 0 740 718 ;
-C 71 ; WX 778 ; N G ; B 108 -19 817 737 ;
-C 72 ; WX 722 ; N H ; B 71 0 804 718 ;
-C 73 ; WX 278 ; N I ; B 64 0 367 718 ;
-C 74 ; WX 556 ; N J ; B 60 -18 637 718 ;
-C 75 ; WX 722 ; N K ; B 87 0 858 718 ;
-C 76 ; WX 611 ; N L ; B 76 0 611 718 ;
-C 77 ; WX 833 ; N M ; B 69 0 918 718 ;
-C 78 ; WX 722 ; N N ; B 69 0 807 718 ;
-C 79 ; WX 778 ; N O ; B 107 -19 823 737 ;
-C 80 ; WX 667 ; N P ; B 76 0 738 718 ;
-C 81 ; WX 778 ; N Q ; B 107 -52 823 737 ;
-C 82 ; WX 722 ; N R ; B 76 0 778 718 ;
-C 83 ; WX 667 ; N S ; B 81 -19 718 737 ;
-C 84 ; WX 611 ; N T ; B 140 0 751 718 ;
-C 85 ; WX 722 ; N U ; B 116 -19 804 718 ;
-C 86 ; WX 667 ; N V ; B 172 0 801 718 ;
-C 87 ; WX 944 ; N W ; B 169 0 1082 718 ;
-C 88 ; WX 667 ; N X ; B 14 0 791 718 ;
-C 89 ; WX 667 ; N Y ; B 168 0 806 718 ;
-C 90 ; WX 611 ; N Z ; B 25 0 737 718 ;
-C 91 ; WX 333 ; N bracketleft ; B 21 -196 462 722 ;
-C 92 ; WX 278 ; N backslash ; B 124 -19 307 737 ;
-C 93 ; WX 333 ; N bracketright ; B -18 -196 423 722 ;
-C 94 ; WX 584 ; N asciicircum ; B 131 323 591 698 ;
-C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
-C 96 ; WX 278 ; N quoteleft ; B 165 454 361 727 ;
-C 97 ; WX 556 ; N a ; B 55 -14 583 546 ;
-C 98 ; WX 611 ; N b ; B 61 -14 645 718 ;
-C 99 ; WX 556 ; N c ; B 79 -14 599 546 ;
-C 100 ; WX 611 ; N d ; B 82 -14 704 718 ;
-C 101 ; WX 556 ; N e ; B 70 -14 593 546 ;
-C 102 ; WX 333 ; N f ; B 87 0 469 727 ; L i fi ; L l fl ;
-C 103 ; WX 611 ; N g ; B 38 -217 666 546 ;
-C 104 ; WX 611 ; N h ; B 65 0 629 718 ;
-C 105 ; WX 278 ; N i ; B 69 0 363 725 ;
-C 106 ; WX 278 ; N j ; B -42 -214 363 725 ;
-C 107 ; WX 556 ; N k ; B 69 0 670 718 ;
-C 108 ; WX 278 ; N l ; B 69 0 362 718 ;
-C 109 ; WX 889 ; N m ; B 64 0 909 546 ;
-C 110 ; WX 611 ; N n ; B 65 0 629 546 ;
-C 111 ; WX 611 ; N o ; B 82 -14 643 546 ;
-C 112 ; WX 611 ; N p ; B 18 -207 645 546 ;
-C 113 ; WX 611 ; N q ; B 80 -207 665 546 ;
-C 114 ; WX 389 ; N r ; B 64 0 489 546 ;
-C 115 ; WX 556 ; N s ; B 63 -14 584 546 ;
-C 116 ; WX 333 ; N t ; B 100 -6 422 676 ;
-C 117 ; WX 611 ; N u ; B 98 -14 658 532 ;
-C 118 ; WX 556 ; N v ; B 126 0 656 532 ;
-C 119 ; WX 778 ; N w ; B 123 0 882 532 ;
-C 120 ; WX 556 ; N x ; B 15 0 648 532 ;
-C 121 ; WX 556 ; N y ; B 42 -214 652 532 ;
-C 122 ; WX 500 ; N z ; B 20 0 583 532 ;
-C 123 ; WX 389 ; N braceleft ; B 94 -196 518 722 ;
-C 124 ; WX 280 ; N bar ; B 80 -19 353 737 ;
-C 125 ; WX 389 ; N braceright ; B -18 -196 407 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 115 163 577 343 ;
-C 161 ; WX 333 ; N exclamdown ; B 50 -186 353 532 ;
-C 162 ; WX 556 ; N cent ; B 79 -118 599 628 ;
-C 163 ; WX 556 ; N sterling ; B 50 -16 635 718 ;
-C 164 ; WX 167 ; N fraction ; B -174 -19 487 710 ;
-C 165 ; WX 556 ; N yen ; B 60 0 713 698 ;
-C 166 ; WX 556 ; N florin ; B -50 -210 669 737 ;
-C 167 ; WX 556 ; N section ; B 61 -184 598 727 ;
-C 168 ; WX 556 ; N currency ; B 27 76 680 636 ;
-C 169 ; WX 238 ; N quotesingle ; B 165 447 321 718 ;
-C 170 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ;
-C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ;
-C 173 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ;
-C 174 ; WX 611 ; N fi ; B 87 0 696 727 ;
-C 175 ; WX 611 ; N fl ; B 87 0 695 727 ;
-C 177 ; WX 556 ; N endash ; B 48 227 627 333 ;
-C 178 ; WX 556 ; N dagger ; B 118 -171 626 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 46 -171 628 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 110 172 276 334 ;
-C 182 ; WX 556 ; N paragraph ; B 98 -191 688 700 ;
-C 183 ; WX 350 ; N bullet ; B 83 194 420 524 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 41 -146 236 127 ;
-C 185 ; WX 500 ; N quotedblbase ; B 36 -146 463 127 ;
-C 186 ; WX 500 ; N quotedblright ; B 162 445 589 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 104 76 540 484 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ;
-C 189 ; WX 1000 ; N perthousand ; B 76 -19 1038 710 ;
-C 191 ; WX 611 ; N questiondown ; B 53 -195 559 532 ;
-C 193 ; WX 333 ; N grave ; B 136 604 353 750 ;
-C 194 ; WX 333 ; N acute ; B 236 604 515 750 ;
-C 195 ; WX 333 ; N circumflex ; B 118 604 471 750 ;
-C 196 ; WX 333 ; N tilde ; B 113 610 507 737 ;
-C 197 ; WX 333 ; N macron ; B 122 604 483 678 ;
-C 198 ; WX 333 ; N breve ; B 156 604 494 750 ;
-C 199 ; WX 333 ; N dotaccent ; B 235 614 385 729 ;
-C 200 ; WX 333 ; N dieresis ; B 137 614 482 729 ;
-C 202 ; WX 333 ; N ring ; B 200 568 420 776 ;
-C 203 ; WX 333 ; N cedilla ; B -37 -228 220 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 137 604 645 750 ;
-C 206 ; WX 333 ; N ogonek ; B 41 -228 264 0 ;
-C 207 ; WX 333 ; N caron ; B 149 604 502 750 ;
-C 208 ; WX 1000 ; N emdash ; B 48 227 1071 333 ;
-C 225 ; WX 1000 ; N AE ; B 5 0 1100 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 92 276 465 737 ;
-C 232 ; WX 611 ; N Lslash ; B 34 0 611 718 ;
-C 233 ; WX 778 ; N Oslash ; B 35 -27 894 745 ;
-C 234 ; WX 1000 ; N OE ; B 99 -19 1114 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 92 276 485 737 ;
-C 241 ; WX 889 ; N ae ; B 56 -14 923 546 ;
-C 245 ; WX 278 ; N dotlessi ; B 69 0 322 532 ;
-C 248 ; WX 278 ; N lslash ; B 40 0 407 718 ;
-C 249 ; WX 611 ; N oslash ; B 22 -29 701 560 ;
-C 250 ; WX 944 ; N oe ; B 82 -14 977 546 ;
-C 251 ; WX 611 ; N germandbls ; B 69 -14 657 731 ;
-C -1 ; WX 611 ; N Zcaron ; B 25 0 737 936 ;
-C -1 ; WX 556 ; N ccedilla ; B 79 -228 599 546 ;
-C -1 ; WX 556 ; N ydieresis ; B 42 -214 652 729 ;
-C -1 ; WX 556 ; N atilde ; B 55 -14 619 737 ;
-C -1 ; WX 278 ; N icircumflex ; B 69 0 444 750 ;
-C -1 ; WX 333 ; N threesuperior ; B 91 271 441 710 ;
-C -1 ; WX 556 ; N ecircumflex ; B 70 -14 593 750 ;
-C -1 ; WX 611 ; N thorn ; B 18 -208 645 718 ;
-C -1 ; WX 556 ; N egrave ; B 70 -14 593 750 ;
-C -1 ; WX 333 ; N twosuperior ; B 69 283 449 710 ;
-C -1 ; WX 556 ; N eacute ; B 70 -14 627 750 ;
-C -1 ; WX 611 ; N otilde ; B 82 -14 646 737 ;
-C -1 ; WX 722 ; N Aacute ; B 20 0 750 936 ;
-C -1 ; WX 611 ; N ocircumflex ; B 82 -14 643 750 ;
-C -1 ; WX 556 ; N yacute ; B 42 -214 652 750 ;
-C -1 ; WX 611 ; N udieresis ; B 98 -14 658 729 ;
-C -1 ; WX 834 ; N threequarters ; B 99 -19 839 710 ;
-C -1 ; WX 556 ; N acircumflex ; B 55 -14 583 750 ;
-C -1 ; WX 722 ; N Eth ; B 62 0 777 718 ;
-C -1 ; WX 556 ; N edieresis ; B 70 -14 594 729 ;
-C -1 ; WX 611 ; N ugrave ; B 98 -14 658 750 ;
-C -1 ; WX 1000 ; N trademark ; B 179 306 1109 718 ;
-C -1 ; WX 611 ; N ograve ; B 82 -14 643 750 ;
-C -1 ; WX 556 ; N scaron ; B 63 -14 614 750 ;
-C -1 ; WX 278 ; N Idieresis ; B 64 0 494 915 ;
-C -1 ; WX 611 ; N uacute ; B 98 -14 658 750 ;
-C -1 ; WX 556 ; N agrave ; B 55 -14 583 750 ;
-C -1 ; WX 611 ; N ntilde ; B 65 0 646 737 ;
-C -1 ; WX 556 ; N aring ; B 55 -14 583 776 ;
-C -1 ; WX 500 ; N zcaron ; B 20 0 586 750 ;
-C -1 ; WX 278 ; N Icircumflex ; B 64 0 484 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 69 0 807 923 ;
-C -1 ; WX 611 ; N ucircumflex ; B 98 -14 658 750 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 76 0 757 936 ;
-C -1 ; WX 278 ; N Iacute ; B 64 0 528 936 ;
-C -1 ; WX 722 ; N Ccedilla ; B 107 -228 789 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 107 -19 823 915 ;
-C -1 ; WX 667 ; N Scaron ; B 81 -19 718 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 76 0 757 915 ;
-C -1 ; WX 278 ; N Igrave ; B 64 0 367 936 ;
-C -1 ; WX 556 ; N adieresis ; B 55 -14 594 729 ;
-C -1 ; WX 778 ; N Ograve ; B 107 -19 823 936 ;
-C -1 ; WX 667 ; N Egrave ; B 76 0 757 936 ;
-C -1 ; WX 667 ; N Ydieresis ; B 168 0 806 915 ;
-C -1 ; WX 737 ; N registered ; B 55 -19 834 737 ;
-C -1 ; WX 778 ; N Otilde ; B 107 -19 823 923 ;
-C -1 ; WX 834 ; N onequarter ; B 132 -19 806 710 ;
-C -1 ; WX 722 ; N Ugrave ; B 116 -19 804 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 116 -19 804 936 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 716 718 ;
-C -1 ; WX 584 ; N divide ; B 82 -42 610 548 ;
-C -1 ; WX 722 ; N Atilde ; B 20 0 741 923 ;
-C -1 ; WX 722 ; N Uacute ; B 116 -19 804 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 107 -19 823 936 ;
-C -1 ; WX 584 ; N logicalnot ; B 105 108 633 419 ;
-C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
-C -1 ; WX 278 ; N idieresis ; B 69 0 455 729 ;
-C -1 ; WX 278 ; N iacute ; B 69 0 488 750 ;
-C -1 ; WX 556 ; N aacute ; B 55 -14 627 750 ;
-C -1 ; WX 584 ; N plusminus ; B 40 0 625 506 ;
-C -1 ; WX 584 ; N multiply ; B 57 1 635 505 ;
-C -1 ; WX 722 ; N Udieresis ; B 116 -19 804 915 ;
-C -1 ; WX 584 ; N minus ; B 82 197 610 309 ;
-C -1 ; WX 333 ; N onesuperior ; B 148 283 388 710 ;
-C -1 ; WX 667 ; N Eacute ; B 76 0 757 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 20 0 706 936 ;
-C -1 ; WX 737 ; N copyright ; B 56 -19 835 737 ;
-C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N odieresis ; B 82 -14 643 729 ;
-C -1 ; WX 611 ; N oacute ; B 82 -14 654 750 ;
-C -1 ; WX 400 ; N degree ; B 175 426 467 712 ;
-C -1 ; WX 278 ; N igrave ; B 69 0 326 750 ;
-C -1 ; WX 611 ; N mu ; B 22 -207 658 532 ;
-C -1 ; WX 778 ; N Oacute ; B 107 -19 823 936 ;
-C -1 ; WX 611 ; N eth ; B 82 -14 670 737 ;
-C -1 ; WX 722 ; N Adieresis ; B 20 0 716 915 ;
-C -1 ; WX 667 ; N Yacute ; B 168 0 806 936 ;
-C -1 ; WX 280 ; N brokenbar ; B 80 -19 353 737 ;
-C -1 ; WX 834 ; N onehalf ; B 132 -19 858 710 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 209
-
-KPX A y -30
-KPX A w -30
-KPX A v -40
-KPX A u -30
-KPX A Y -110
-KPX A W -60
-KPX A V -80
-KPX A U -50
-KPX A T -90
-KPX A Q -40
-KPX A O -40
-KPX A G -50
-KPX A C -40
-
-KPX B U -10
-KPX B A -30
-
-KPX D period -30
-KPX D comma -30
-KPX D Y -70
-KPX D W -40
-KPX D V -40
-KPX D A -40
-
-KPX F period -100
-KPX F comma -100
-KPX F a -20
-KPX F A -80
-
-KPX J u -20
-KPX J period -20
-KPX J comma -20
-KPX J A -20
-
-KPX K y -40
-KPX K u -30
-KPX K o -35
-KPX K e -15
-KPX K O -30
-
-KPX L y -30
-KPX L quoteright -140
-KPX L quotedblright -140
-KPX L Y -120
-KPX L W -80
-KPX L V -110
-KPX L T -90
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -50
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -50
-
-KPX P period -120
-KPX P o -40
-KPX P e -30
-KPX P comma -120
-KPX P a -30
-KPX P A -100
-
-KPX Q period 20
-KPX Q comma 20
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -40
-KPX R V -50
-KPX R U -20
-KPX R T -20
-KPX R O -20
-
-KPX T y -60
-KPX T w -60
-KPX T u -90
-KPX T semicolon -40
-KPX T r -80
-KPX T period -80
-KPX T o -80
-KPX T hyphen -120
-KPX T e -60
-KPX T comma -80
-KPX T colon -40
-KPX T a -80
-KPX T O -40
-KPX T A -90
-
-KPX U period -30
-KPX U comma -30
-KPX U A -50
-
-KPX V u -60
-KPX V semicolon -40
-KPX V period -120
-KPX V o -90
-KPX V hyphen -80
-KPX V e -50
-KPX V comma -120
-KPX V colon -40
-KPX V a -60
-KPX V O -50
-KPX V G -50
-KPX V A -80
-
-KPX W y -20
-KPX W u -45
-KPX W semicolon -10
-KPX W period -80
-KPX W o -60
-KPX W hyphen -40
-KPX W e -35
-KPX W comma -80
-KPX W colon -10
-KPX W a -40
-KPX W O -20
-KPX W A -60
-
-KPX Y u -100
-KPX Y semicolon -50
-KPX Y period -100
-KPX Y o -100
-KPX Y e -80
-KPX Y comma -100
-KPX Y colon -50
-KPX Y a -90
-KPX Y O -70
-KPX Y A -110
-
-KPX a y -20
-KPX a w -15
-KPX a v -15
-KPX a g -10
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b l -10
-
-KPX c y -10
-KPX c l -20
-KPX c k -20
-KPX c h -10
-
-KPX colon space -40
-
-KPX comma space -40
-KPX comma quoteright -120
-KPX comma quotedblright -120
-
-KPX d y -15
-KPX d w -15
-KPX d v -15
-KPX d d -10
-
-KPX e y -15
-KPX e x -15
-KPX e w -15
-KPX e v -15
-KPX e period 20
-KPX e comma 10
-
-KPX f quoteright 30
-KPX f quotedblright 30
-KPX f period -10
-KPX f o -20
-KPX f e -10
-KPX f comma -10
-
-KPX g g -10
-KPX g e 10
-
-KPX h y -20
-
-KPX k o -15
-
-KPX l y -15
-KPX l w -15
-
-KPX m y -30
-KPX m u -20
-
-KPX n y -20
-KPX n v -40
-KPX n u -10
-
-KPX o y -20
-KPX o x -30
-KPX o w -15
-KPX o v -20
-
-KPX p y -15
-
-KPX period space -40
-KPX period quoteright -120
-KPX period quotedblright -120
-
-KPX quotedblright space -80
-
-KPX quoteleft quoteleft -46
-
-KPX quoteright v -20
-KPX quoteright space -80
-KPX quoteright s -60
-KPX quoteright r -40
-KPX quoteright quoteright -46
-KPX quoteright l -20
-KPX quoteright d -80
-
-KPX r y 10
-KPX r v 10
-KPX r t 20
-KPX r s -15
-KPX r q -20
-KPX r period -60
-KPX r o -20
-KPX r hyphen -20
-KPX r g -15
-KPX r d -20
-KPX r comma -60
-KPX r c -20
-
-KPX s w -15
-
-KPX semicolon space -40
-
-KPX space quoteleft -60
-KPX space quotedblleft -80
-KPX space Y -120
-KPX space W -80
-KPX space V -80
-KPX space T -100
-
-KPX v period -80
-KPX v o -30
-KPX v comma -80
-KPX v a -20
-
-KPX w period -40
-KPX w o -20
-KPX w comma -40
-
-KPX x e -10
-
-KPX y period -80
-KPX y o -25
-KPX y e -10
-KPX y comma -80
-KPX y a -30
-
-KPX z e 10
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 235 186 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 235 186 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 235 186 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 235 186 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 235 186 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 235 186 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 215 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 207 186 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 207 186 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 207 186 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 207 186 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 13 186 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 13 186 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 13 186 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 13 186 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 235 186 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 263 186 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 263 186 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 263 186 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 263 186 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 263 186 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 207 186 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 235 186 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 235 186 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 235 186 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 235 186 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 207 186 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 207 186 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 179 186 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 112 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 132 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 139 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 139 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 139 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 139 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 139 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 139 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 112 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 139 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 139 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 139 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 139 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 112 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 112 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Helvetica-Oblique.afm b/config/psfonts/Helvetica-Oblique.afm
deleted file mode 100644 (file)
index 3d69eb7..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All rights reserved.
-Comment Creation Date: Thu Mar 15 10:24:18 1990
-Comment UniqueID 28362
-Comment VMusage 7572 42473
-FontName Helvetica-Oblique
-FullName Helvetica Oblique
-FamilyName Helvetica
-Weight Medium
-ItalicAngle -12
-IsFixedPitch false
-FontBBox -170 -225 1116 931
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.006
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All rights reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 90 0 340 718 ;
-C 34 ; WX 355 ; N quotedbl ; B 168 463 438 718 ;
-C 35 ; WX 556 ; N numbersign ; B 73 0 631 688 ;
-C 36 ; WX 556 ; N dollar ; B 69 -115 617 775 ;
-C 37 ; WX 889 ; N percent ; B 147 -19 889 703 ;
-C 38 ; WX 667 ; N ampersand ; B 77 -15 647 718 ;
-C 39 ; WX 222 ; N quoteright ; B 151 463 310 718 ;
-C 40 ; WX 333 ; N parenleft ; B 108 -207 454 733 ;
-C 41 ; WX 333 ; N parenright ; B -9 -207 337 733 ;
-C 42 ; WX 389 ; N asterisk ; B 165 431 475 718 ;
-C 43 ; WX 584 ; N plus ; B 85 0 606 505 ;
-C 44 ; WX 278 ; N comma ; B 56 -147 214 106 ;
-C 45 ; WX 333 ; N hyphen ; B 93 232 357 322 ;
-C 46 ; WX 278 ; N period ; B 87 0 214 106 ;
-C 47 ; WX 278 ; N slash ; B -21 -19 452 737 ;
-C 48 ; WX 556 ; N zero ; B 93 -19 608 703 ;
-C 49 ; WX 556 ; N one ; B 207 0 508 703 ;
-C 50 ; WX 556 ; N two ; B 26 0 617 703 ;
-C 51 ; WX 556 ; N three ; B 75 -19 610 703 ;
-C 52 ; WX 556 ; N four ; B 61 0 576 703 ;
-C 53 ; WX 556 ; N five ; B 68 -19 621 688 ;
-C 54 ; WX 556 ; N six ; B 91 -19 615 703 ;
-C 55 ; WX 556 ; N seven ; B 137 0 669 688 ;
-C 56 ; WX 556 ; N eight ; B 74 -19 607 703 ;
-C 57 ; WX 556 ; N nine ; B 82 -19 609 703 ;
-C 58 ; WX 278 ; N colon ; B 87 0 301 516 ;
-C 59 ; WX 278 ; N semicolon ; B 56 -147 301 516 ;
-C 60 ; WX 584 ; N less ; B 94 11 641 495 ;
-C 61 ; WX 584 ; N equal ; B 63 115 628 390 ;
-C 62 ; WX 584 ; N greater ; B 50 11 597 495 ;
-C 63 ; WX 556 ; N question ; B 161 0 610 727 ;
-C 64 ; WX 1015 ; N at ; B 215 -19 965 737 ;
-C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
-C 66 ; WX 667 ; N B ; B 74 0 712 718 ;
-C 67 ; WX 722 ; N C ; B 108 -19 782 737 ;
-C 68 ; WX 722 ; N D ; B 81 0 764 718 ;
-C 69 ; WX 667 ; N E ; B 86 0 762 718 ;
-C 70 ; WX 611 ; N F ; B 86 0 736 718 ;
-C 71 ; WX 778 ; N G ; B 111 -19 799 737 ;
-C 72 ; WX 722 ; N H ; B 77 0 799 718 ;
-C 73 ; WX 278 ; N I ; B 91 0 341 718 ;
-C 74 ; WX 500 ; N J ; B 47 -19 581 718 ;
-C 75 ; WX 667 ; N K ; B 76 0 808 718 ;
-C 76 ; WX 556 ; N L ; B 76 0 555 718 ;
-C 77 ; WX 833 ; N M ; B 73 0 914 718 ;
-C 78 ; WX 722 ; N N ; B 76 0 799 718 ;
-C 79 ; WX 778 ; N O ; B 105 -19 826 737 ;
-C 80 ; WX 667 ; N P ; B 86 0 737 718 ;
-C 81 ; WX 778 ; N Q ; B 105 -56 826 737 ;
-C 82 ; WX 722 ; N R ; B 88 0 773 718 ;
-C 83 ; WX 667 ; N S ; B 90 -19 713 737 ;
-C 84 ; WX 611 ; N T ; B 148 0 750 718 ;
-C 85 ; WX 722 ; N U ; B 123 -19 797 718 ;
-C 86 ; WX 667 ; N V ; B 173 0 800 718 ;
-C 87 ; WX 944 ; N W ; B 169 0 1081 718 ;
-C 88 ; WX 667 ; N X ; B 19 0 790 718 ;
-C 89 ; WX 667 ; N Y ; B 167 0 806 718 ;
-C 90 ; WX 611 ; N Z ; B 23 0 741 718 ;
-C 91 ; WX 278 ; N bracketleft ; B 21 -196 403 722 ;
-C 92 ; WX 278 ; N backslash ; B 140 -19 291 737 ;
-C 93 ; WX 278 ; N bracketright ; B -14 -196 368 722 ;
-C 94 ; WX 469 ; N asciicircum ; B 42 264 539 688 ;
-C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
-C 96 ; WX 222 ; N quoteleft ; B 165 470 323 725 ;
-C 97 ; WX 556 ; N a ; B 61 -15 559 538 ;
-C 98 ; WX 556 ; N b ; B 58 -15 584 718 ;
-C 99 ; WX 500 ; N c ; B 74 -15 553 538 ;
-C 100 ; WX 556 ; N d ; B 84 -15 652 718 ;
-C 101 ; WX 556 ; N e ; B 84 -15 578 538 ;
-C 102 ; WX 278 ; N f ; B 86 0 416 728 ; L i fi ; L l fl ;
-C 103 ; WX 556 ; N g ; B 42 -220 610 538 ;
-C 104 ; WX 556 ; N h ; B 65 0 573 718 ;
-C 105 ; WX 222 ; N i ; B 67 0 308 718 ;
-C 106 ; WX 222 ; N j ; B -60 -210 308 718 ;
-C 107 ; WX 500 ; N k ; B 67 0 600 718 ;
-C 108 ; WX 222 ; N l ; B 67 0 308 718 ;
-C 109 ; WX 833 ; N m ; B 65 0 852 538 ;
-C 110 ; WX 556 ; N n ; B 65 0 573 538 ;
-C 111 ; WX 556 ; N o ; B 83 -14 585 538 ;
-C 112 ; WX 556 ; N p ; B 14 -207 584 538 ;
-C 113 ; WX 556 ; N q ; B 84 -207 605 538 ;
-C 114 ; WX 333 ; N r ; B 77 0 446 538 ;
-C 115 ; WX 500 ; N s ; B 63 -15 529 538 ;
-C 116 ; WX 278 ; N t ; B 102 -7 368 669 ;
-C 117 ; WX 556 ; N u ; B 94 -15 600 523 ;
-C 118 ; WX 500 ; N v ; B 119 0 603 523 ;
-C 119 ; WX 722 ; N w ; B 125 0 820 523 ;
-C 120 ; WX 500 ; N x ; B 11 0 594 523 ;
-C 121 ; WX 500 ; N y ; B 15 -214 600 523 ;
-C 122 ; WX 500 ; N z ; B 31 0 571 523 ;
-C 123 ; WX 334 ; N braceleft ; B 92 -196 445 722 ;
-C 124 ; WX 260 ; N bar ; B 90 -19 324 737 ;
-C 125 ; WX 334 ; N braceright ; B 0 -196 354 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 111 180 580 326 ;
-C 161 ; WX 333 ; N exclamdown ; B 77 -195 326 523 ;
-C 162 ; WX 556 ; N cent ; B 95 -115 584 623 ;
-C 163 ; WX 556 ; N sterling ; B 49 -16 634 718 ;
-C 164 ; WX 167 ; N fraction ; B -170 -19 482 703 ;
-C 165 ; WX 556 ; N yen ; B 81 0 699 688 ;
-C 166 ; WX 556 ; N florin ; B -52 -207 654 737 ;
-C 167 ; WX 556 ; N section ; B 76 -191 584 737 ;
-C 168 ; WX 556 ; N currency ; B 60 99 646 603 ;
-C 169 ; WX 191 ; N quotesingle ; B 157 463 285 718 ;
-C 170 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ;
-C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ;
-C 173 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ;
-C 174 ; WX 500 ; N fi ; B 86 0 587 728 ;
-C 175 ; WX 500 ; N fl ; B 86 0 585 728 ;
-C 177 ; WX 556 ; N endash ; B 51 240 623 313 ;
-C 178 ; WX 556 ; N dagger ; B 135 -159 622 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 52 -159 623 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 129 190 257 315 ;
-C 182 ; WX 537 ; N paragraph ; B 126 -173 650 718 ;
-C 183 ; WX 350 ; N bullet ; B 91 202 413 517 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 21 -149 180 106 ;
-C 185 ; WX 333 ; N quotedblbase ; B -6 -149 318 106 ;
-C 186 ; WX 333 ; N quotedblright ; B 124 463 448 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 120 108 528 446 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 908 106 ;
-C 189 ; WX 1000 ; N perthousand ; B 88 -19 1029 703 ;
-C 191 ; WX 611 ; N questiondown ; B 85 -201 534 525 ;
-C 193 ; WX 333 ; N grave ; B 170 593 337 734 ;
-C 194 ; WX 333 ; N acute ; B 248 593 475 734 ;
-C 195 ; WX 333 ; N circumflex ; B 147 593 438 734 ;
-C 196 ; WX 333 ; N tilde ; B 125 606 490 722 ;
-C 197 ; WX 333 ; N macron ; B 143 627 468 684 ;
-C 198 ; WX 333 ; N breve ; B 167 595 476 731 ;
-C 199 ; WX 333 ; N dotaccent ; B 249 604 362 706 ;
-C 200 ; WX 333 ; N dieresis ; B 168 604 443 706 ;
-C 202 ; WX 333 ; N ring ; B 214 572 402 756 ;
-C 203 ; WX 333 ; N cedilla ; B 2 -225 232 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 157 593 565 734 ;
-C 206 ; WX 333 ; N ogonek ; B 43 -225 249 0 ;
-C 207 ; WX 333 ; N caron ; B 177 593 468 734 ;
-C 208 ; WX 1000 ; N emdash ; B 51 240 1067 313 ;
-C 225 ; WX 1000 ; N AE ; B 8 0 1097 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 100 304 449 737 ;
-C 232 ; WX 556 ; N Lslash ; B 41 0 555 718 ;
-C 233 ; WX 778 ; N Oslash ; B 43 -19 890 737 ;
-C 234 ; WX 1000 ; N OE ; B 98 -19 1116 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 100 304 468 737 ;
-C 241 ; WX 889 ; N ae ; B 61 -15 909 538 ;
-C 245 ; WX 278 ; N dotlessi ; B 95 0 294 523 ;
-C 248 ; WX 222 ; N lslash ; B 41 0 347 718 ;
-C 249 ; WX 611 ; N oslash ; B 29 -22 647 545 ;
-C 250 ; WX 944 ; N oe ; B 83 -15 964 538 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -15 658 728 ;
-C -1 ; WX 611 ; N Zcaron ; B 23 0 741 929 ;
-C -1 ; WX 500 ; N ccedilla ; B 74 -225 553 538 ;
-C -1 ; WX 500 ; N ydieresis ; B 15 -214 600 706 ;
-C -1 ; WX 556 ; N atilde ; B 61 -15 592 722 ;
-C -1 ; WX 278 ; N icircumflex ; B 95 0 411 734 ;
-C -1 ; WX 333 ; N threesuperior ; B 90 270 436 703 ;
-C -1 ; WX 556 ; N ecircumflex ; B 84 -15 578 734 ;
-C -1 ; WX 556 ; N thorn ; B 14 -207 584 718 ;
-C -1 ; WX 556 ; N egrave ; B 84 -15 578 734 ;
-C -1 ; WX 333 ; N twosuperior ; B 64 281 449 703 ;
-C -1 ; WX 556 ; N eacute ; B 84 -15 587 734 ;
-C -1 ; WX 556 ; N otilde ; B 83 -14 602 722 ;
-C -1 ; WX 667 ; N Aacute ; B 14 0 683 929 ;
-C -1 ; WX 556 ; N ocircumflex ; B 83 -14 585 734 ;
-C -1 ; WX 500 ; N yacute ; B 15 -214 600 734 ;
-C -1 ; WX 556 ; N udieresis ; B 94 -15 600 706 ;
-C -1 ; WX 834 ; N threequarters ; B 130 -19 861 703 ;
-C -1 ; WX 556 ; N acircumflex ; B 61 -15 559 734 ;
-C -1 ; WX 722 ; N Eth ; B 69 0 764 718 ;
-C -1 ; WX 556 ; N edieresis ; B 84 -15 578 706 ;
-C -1 ; WX 556 ; N ugrave ; B 94 -15 600 734 ;
-C -1 ; WX 1000 ; N trademark ; B 186 306 1056 718 ;
-C -1 ; WX 556 ; N ograve ; B 83 -14 585 734 ;
-C -1 ; WX 500 ; N scaron ; B 63 -15 552 734 ;
-C -1 ; WX 278 ; N Idieresis ; B 91 0 458 901 ;
-C -1 ; WX 556 ; N uacute ; B 94 -15 600 734 ;
-C -1 ; WX 556 ; N agrave ; B 61 -15 559 734 ;
-C -1 ; WX 556 ; N ntilde ; B 65 0 592 722 ;
-C -1 ; WX 556 ; N aring ; B 61 -15 559 756 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 571 734 ;
-C -1 ; WX 278 ; N Icircumflex ; B 91 0 452 929 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 799 917 ;
-C -1 ; WX 556 ; N ucircumflex ; B 94 -15 600 734 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 86 0 762 929 ;
-C -1 ; WX 278 ; N Iacute ; B 91 0 489 929 ;
-C -1 ; WX 722 ; N Ccedilla ; B 108 -225 782 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 105 -19 826 901 ;
-C -1 ; WX 667 ; N Scaron ; B 90 -19 713 929 ;
-C -1 ; WX 667 ; N Edieresis ; B 86 0 762 901 ;
-C -1 ; WX 278 ; N Igrave ; B 91 0 351 929 ;
-C -1 ; WX 556 ; N adieresis ; B 61 -15 559 706 ;
-C -1 ; WX 778 ; N Ograve ; B 105 -19 826 929 ;
-C -1 ; WX 667 ; N Egrave ; B 86 0 762 929 ;
-C -1 ; WX 667 ; N Ydieresis ; B 167 0 806 901 ;
-C -1 ; WX 737 ; N registered ; B 54 -19 837 737 ;
-C -1 ; WX 778 ; N Otilde ; B 105 -19 826 917 ;
-C -1 ; WX 834 ; N onequarter ; B 150 -19 802 703 ;
-C -1 ; WX 722 ; N Ugrave ; B 123 -19 797 929 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 123 -19 797 929 ;
-C -1 ; WX 667 ; N Thorn ; B 86 0 712 718 ;
-C -1 ; WX 584 ; N divide ; B 85 -19 606 524 ;
-C -1 ; WX 667 ; N Atilde ; B 14 0 699 917 ;
-C -1 ; WX 722 ; N Uacute ; B 123 -19 797 929 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 105 -19 826 929 ;
-C -1 ; WX 584 ; N logicalnot ; B 106 108 628 390 ;
-C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
-C -1 ; WX 278 ; N idieresis ; B 95 0 416 706 ;
-C -1 ; WX 278 ; N iacute ; B 95 0 448 734 ;
-C -1 ; WX 556 ; N aacute ; B 61 -15 587 734 ;
-C -1 ; WX 584 ; N plusminus ; B 39 0 618 506 ;
-C -1 ; WX 584 ; N multiply ; B 50 0 642 506 ;
-C -1 ; WX 722 ; N Udieresis ; B 123 -19 797 901 ;
-C -1 ; WX 584 ; N minus ; B 85 216 606 289 ;
-C -1 ; WX 333 ; N onesuperior ; B 166 281 371 703 ;
-C -1 ; WX 667 ; N Eacute ; B 86 0 762 929 ;
-C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
-C -1 ; WX 737 ; N copyright ; B 54 -19 837 737 ;
-C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N odieresis ; B 83 -14 585 706 ;
-C -1 ; WX 556 ; N oacute ; B 83 -14 587 734 ;
-C -1 ; WX 400 ; N degree ; B 169 411 468 703 ;
-C -1 ; WX 278 ; N igrave ; B 95 0 310 734 ;
-C -1 ; WX 556 ; N mu ; B 24 -207 600 523 ;
-C -1 ; WX 778 ; N Oacute ; B 105 -19 826 929 ;
-C -1 ; WX 556 ; N eth ; B 81 -15 617 737 ;
-C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
-C -1 ; WX 667 ; N Yacute ; B 167 0 806 929 ;
-C -1 ; WX 260 ; N brokenbar ; B 90 -19 324 737 ;
-C -1 ; WX 834 ; N onehalf ; B 114 -19 839 703 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 250
-
-KPX A y -40
-KPX A w -40
-KPX A v -40
-KPX A u -30
-KPX A Y -100
-KPX A W -50
-KPX A V -70
-KPX A U -50
-KPX A T -120
-KPX A Q -30
-KPX A O -30
-KPX A G -30
-KPX A C -30
-
-KPX B period -20
-KPX B comma -20
-KPX B U -10
-
-KPX C period -30
-KPX C comma -30
-
-KPX D period -70
-KPX D comma -70
-KPX D Y -90
-KPX D W -40
-KPX D V -70
-KPX D A -40
-
-KPX F r -45
-KPX F period -150
-KPX F o -30
-KPX F e -30
-KPX F comma -150
-KPX F a -50
-KPX F A -80
-
-KPX J u -20
-KPX J period -30
-KPX J comma -30
-KPX J a -20
-KPX J A -20
-
-KPX K y -50
-KPX K u -30
-KPX K o -40
-KPX K e -40
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -160
-KPX L quotedblright -140
-KPX L Y -140
-KPX L W -70
-KPX L V -110
-KPX L T -110
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -60
-KPX O W -30
-KPX O V -50
-KPX O T -40
-KPX O A -20
-
-KPX P period -180
-KPX P o -50
-KPX P e -50
-KPX P comma -180
-KPX P a -40
-KPX P A -120
-
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -30
-KPX R V -50
-KPX R U -40
-KPX R T -30
-KPX R O -20
-
-KPX S period -20
-KPX S comma -20
-
-KPX T y -120
-KPX T w -120
-KPX T u -120
-KPX T semicolon -20
-KPX T r -120
-KPX T period -120
-KPX T o -120
-KPX T hyphen -140
-KPX T e -120
-KPX T comma -120
-KPX T colon -20
-KPX T a -120
-KPX T O -40
-KPX T A -120
-
-KPX U period -40
-KPX U comma -40
-KPX U A -40
-
-KPX V u -70
-KPX V semicolon -40
-KPX V period -125
-KPX V o -80
-KPX V hyphen -80
-KPX V e -80
-KPX V comma -125
-KPX V colon -40
-KPX V a -70
-KPX V O -40
-KPX V G -40
-KPX V A -80
-
-KPX W y -20
-KPX W u -30
-KPX W period -80
-KPX W o -30
-KPX W hyphen -40
-KPX W e -30
-KPX W comma -80
-KPX W a -40
-KPX W O -20
-KPX W A -50
-
-KPX Y u -110
-KPX Y semicolon -60
-KPX Y period -140
-KPX Y o -140
-KPX Y i -20
-KPX Y hyphen -140
-KPX Y e -140
-KPX Y comma -140
-KPX Y colon -60
-KPX Y a -140
-KPX Y O -85
-KPX Y A -110
-
-KPX a y -30
-KPX a w -20
-KPX a v -20
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b period -40
-KPX b l -20
-KPX b comma -40
-KPX b b -10
-
-KPX c k -20
-KPX c comma -15
-
-KPX colon space -50
-
-KPX comma quoteright -100
-KPX comma quotedblright -100
-
-KPX e y -20
-KPX e x -30
-KPX e w -20
-KPX e v -30
-KPX e period -15
-KPX e comma -15
-
-KPX f quoteright 50
-KPX f quotedblright 60
-KPX f period -30
-KPX f o -30
-KPX f e -30
-KPX f dotlessi -28
-KPX f comma -30
-KPX f a -30
-
-KPX g r -10
-
-KPX h y -30
-
-KPX k o -20
-KPX k e -20
-
-KPX m y -15
-KPX m u -10
-
-KPX n y -15
-KPX n v -20
-KPX n u -10
-
-KPX o y -30
-KPX o x -30
-KPX o w -15
-KPX o v -15
-KPX o period -40
-KPX o comma -40
-
-KPX oslash z -55
-KPX oslash y -70
-KPX oslash x -85
-KPX oslash w -70
-KPX oslash v -70
-KPX oslash u -55
-KPX oslash t -55
-KPX oslash s -55
-KPX oslash r -55
-KPX oslash q -55
-KPX oslash period -95
-KPX oslash p -55
-KPX oslash o -55
-KPX oslash n -55
-KPX oslash m -55
-KPX oslash l -55
-KPX oslash k -55
-KPX oslash j -55
-KPX oslash i -55
-KPX oslash h -55
-KPX oslash g -55
-KPX oslash f -55
-KPX oslash e -55
-KPX oslash d -55
-KPX oslash comma -95
-KPX oslash c -55
-KPX oslash b -55
-KPX oslash a -55
-
-KPX p y -30
-KPX p period -35
-KPX p comma -35
-
-KPX period space -60
-KPX period quoteright -100
-KPX period quotedblright -100
-
-KPX quotedblright space -40
-
-KPX quoteleft quoteleft -57
-
-KPX quoteright space -70
-KPX quoteright s -50
-KPX quoteright r -50
-KPX quoteright quoteright -57
-KPX quoteright d -50
-
-KPX r y 30
-KPX r v 30
-KPX r u 15
-KPX r t 40
-KPX r semicolon 30
-KPX r period -50
-KPX r p 30
-KPX r n 25
-KPX r m 25
-KPX r l 15
-KPX r k 15
-KPX r i 15
-KPX r comma -50
-KPX r colon 30
-KPX r a -10
-
-KPX s w -30
-KPX s period -15
-KPX s comma -15
-
-KPX semicolon space -50
-
-KPX space quoteleft -60
-KPX space quotedblleft -30
-KPX space Y -90
-KPX space W -40
-KPX space V -50
-KPX space T -50
-
-KPX v period -80
-KPX v o -25
-KPX v e -25
-KPX v comma -80
-KPX v a -25
-
-KPX w period -60
-KPX w o -10
-KPX w e -10
-KPX w comma -60
-KPX w a -15
-
-KPX x e -30
-
-KPX y period -100
-KPX y o -20
-KPX y e -20
-KPX y comma -100
-KPX y a -20
-
-KPX z o -15
-KPX z e -15
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 208 195 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 208 195 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 208 195 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 208 195 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 204 175 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 208 195 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 195 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 208 195 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 208 195 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 208 195 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 208 195 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 14 195 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 14 195 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 14 195 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 14 195 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 246 195 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 264 195 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 264 195 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 264 195 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 264 195 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 264 195 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 208 195 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 236 195 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 236 195 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 236 195 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 236 195 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 208 195 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 208 195 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 180 195 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 102 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 84 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 102 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 112 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 112 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 112 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 112 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 112 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 84 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 112 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 112 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Helvetica.afm b/config/psfonts/Helvetica.afm
deleted file mode 100644 (file)
index 1eb3b44..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All rights reserved.
-Comment Creation Date: Thu Mar 15 08:58:00 1990
-Comment UniqueID 28352
-Comment VMusage 26389 33281
-FontName Helvetica
-FullName Helvetica
-FamilyName Helvetica
-Weight Medium
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -166 -225 1000 931
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.006
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All rights reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ;
-C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ;
-C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ;
-C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ;
-C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ;
-C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ;
-C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
-C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ;
-C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ;
-C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ;
-C 43 ; WX 584 ; N plus ; B 39 0 545 505 ;
-C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ;
-C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ;
-C 46 ; WX 278 ; N period ; B 87 0 191 106 ;
-C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ;
-C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ;
-C 49 ; WX 556 ; N one ; B 101 0 359 703 ;
-C 50 ; WX 556 ; N two ; B 26 0 507 703 ;
-C 51 ; WX 556 ; N three ; B 34 -19 522 703 ;
-C 52 ; WX 556 ; N four ; B 25 0 523 703 ;
-C 53 ; WX 556 ; N five ; B 32 -19 514 688 ;
-C 54 ; WX 556 ; N six ; B 38 -19 518 703 ;
-C 55 ; WX 556 ; N seven ; B 37 0 523 688 ;
-C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ;
-C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ;
-C 58 ; WX 278 ; N colon ; B 87 0 191 516 ;
-C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ;
-C 60 ; WX 584 ; N less ; B 48 11 536 495 ;
-C 61 ; WX 584 ; N equal ; B 39 115 545 390 ;
-C 62 ; WX 584 ; N greater ; B 48 11 536 495 ;
-C 63 ; WX 556 ; N question ; B 56 0 492 727 ;
-C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ;
-C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
-C 66 ; WX 667 ; N B ; B 74 0 627 718 ;
-C 67 ; WX 722 ; N C ; B 44 -19 681 737 ;
-C 68 ; WX 722 ; N D ; B 81 0 674 718 ;
-C 69 ; WX 667 ; N E ; B 86 0 616 718 ;
-C 70 ; WX 611 ; N F ; B 86 0 583 718 ;
-C 71 ; WX 778 ; N G ; B 48 -19 704 737 ;
-C 72 ; WX 722 ; N H ; B 77 0 646 718 ;
-C 73 ; WX 278 ; N I ; B 91 0 188 718 ;
-C 74 ; WX 500 ; N J ; B 17 -19 428 718 ;
-C 75 ; WX 667 ; N K ; B 76 0 663 718 ;
-C 76 ; WX 556 ; N L ; B 76 0 537 718 ;
-C 77 ; WX 833 ; N M ; B 73 0 761 718 ;
-C 78 ; WX 722 ; N N ; B 76 0 646 718 ;
-C 79 ; WX 778 ; N O ; B 39 -19 739 737 ;
-C 80 ; WX 667 ; N P ; B 86 0 622 718 ;
-C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ;
-C 82 ; WX 722 ; N R ; B 88 0 684 718 ;
-C 83 ; WX 667 ; N S ; B 49 -19 620 737 ;
-C 84 ; WX 611 ; N T ; B 14 0 597 718 ;
-C 85 ; WX 722 ; N U ; B 79 -19 644 718 ;
-C 86 ; WX 667 ; N V ; B 20 0 647 718 ;
-C 87 ; WX 944 ; N W ; B 16 0 928 718 ;
-C 88 ; WX 667 ; N X ; B 19 0 648 718 ;
-C 89 ; WX 667 ; N Y ; B 14 0 653 718 ;
-C 90 ; WX 611 ; N Z ; B 23 0 588 718 ;
-C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ;
-C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ;
-C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ;
-C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ;
-C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
-C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ;
-C 97 ; WX 556 ; N a ; B 36 -15 530 538 ;
-C 98 ; WX 556 ; N b ; B 58 -15 517 718 ;
-C 99 ; WX 500 ; N c ; B 30 -15 477 538 ;
-C 100 ; WX 556 ; N d ; B 35 -15 499 718 ;
-C 101 ; WX 556 ; N e ; B 40 -15 516 538 ;
-C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ;
-C 103 ; WX 556 ; N g ; B 40 -220 499 538 ;
-C 104 ; WX 556 ; N h ; B 65 0 491 718 ;
-C 105 ; WX 222 ; N i ; B 67 0 155 718 ;
-C 106 ; WX 222 ; N j ; B -16 -210 155 718 ;
-C 107 ; WX 500 ; N k ; B 67 0 501 718 ;
-C 108 ; WX 222 ; N l ; B 67 0 155 718 ;
-C 109 ; WX 833 ; N m ; B 65 0 769 538 ;
-C 110 ; WX 556 ; N n ; B 65 0 491 538 ;
-C 111 ; WX 556 ; N o ; B 35 -14 521 538 ;
-C 112 ; WX 556 ; N p ; B 58 -207 517 538 ;
-C 113 ; WX 556 ; N q ; B 35 -207 494 538 ;
-C 114 ; WX 333 ; N r ; B 77 0 332 538 ;
-C 115 ; WX 500 ; N s ; B 32 -15 464 538 ;
-C 116 ; WX 278 ; N t ; B 14 -7 257 669 ;
-C 117 ; WX 556 ; N u ; B 68 -15 489 523 ;
-C 118 ; WX 500 ; N v ; B 8 0 492 523 ;
-C 119 ; WX 722 ; N w ; B 14 0 709 523 ;
-C 120 ; WX 500 ; N x ; B 11 0 490 523 ;
-C 121 ; WX 500 ; N y ; B 11 -214 489 523 ;
-C 122 ; WX 500 ; N z ; B 31 0 469 523 ;
-C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ;
-C 124 ; WX 260 ; N bar ; B 94 -19 167 737 ;
-C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ;
-C 161 ; WX 333 ; N exclamdown ; B 118 -195 215 523 ;
-C 162 ; WX 556 ; N cent ; B 51 -115 513 623 ;
-C 163 ; WX 556 ; N sterling ; B 33 -16 539 718 ;
-C 164 ; WX 167 ; N fraction ; B -166 -19 333 703 ;
-C 165 ; WX 556 ; N yen ; B 3 0 553 688 ;
-C 166 ; WX 556 ; N florin ; B -11 -207 501 737 ;
-C 167 ; WX 556 ; N section ; B 43 -191 512 737 ;
-C 168 ; WX 556 ; N currency ; B 28 99 528 603 ;
-C 169 ; WX 191 ; N quotesingle ; B 59 463 132 718 ;
-C 170 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ;
-C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ;
-C 173 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ;
-C 174 ; WX 500 ; N fi ; B 14 0 434 728 ;
-C 175 ; WX 500 ; N fl ; B 14 0 432 728 ;
-C 177 ; WX 556 ; N endash ; B 0 240 556 313 ;
-C 178 ; WX 556 ; N dagger ; B 43 -159 514 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 43 -159 514 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 77 190 202 315 ;
-C 182 ; WX 537 ; N paragraph ; B 18 -173 497 718 ;
-C 183 ; WX 350 ; N bullet ; B 18 202 333 517 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 53 -149 157 106 ;
-C 185 ; WX 333 ; N quotedblbase ; B 26 -149 295 106 ;
-C 186 ; WX 333 ; N quotedblright ; B 26 463 295 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 97 108 459 446 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 106 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 703 ;
-C 191 ; WX 611 ; N questiondown ; B 91 -201 527 525 ;
-C 193 ; WX 333 ; N grave ; B 14 593 211 734 ;
-C 194 ; WX 333 ; N acute ; B 122 593 319 734 ;
-C 195 ; WX 333 ; N circumflex ; B 21 593 312 734 ;
-C 196 ; WX 333 ; N tilde ; B -4 606 337 722 ;
-C 197 ; WX 333 ; N macron ; B 10 627 323 684 ;
-C 198 ; WX 333 ; N breve ; B 13 595 321 731 ;
-C 199 ; WX 333 ; N dotaccent ; B 121 604 212 706 ;
-C 200 ; WX 333 ; N dieresis ; B 40 604 293 706 ;
-C 202 ; WX 333 ; N ring ; B 75 572 259 756 ;
-C 203 ; WX 333 ; N cedilla ; B 45 -225 259 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 31 593 409 734 ;
-C 206 ; WX 333 ; N ogonek ; B 73 -225 287 0 ;
-C 207 ; WX 333 ; N caron ; B 21 593 312 734 ;
-C 208 ; WX 1000 ; N emdash ; B 0 240 1000 313 ;
-C 225 ; WX 1000 ; N AE ; B 8 0 951 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 24 304 346 737 ;
-C 232 ; WX 556 ; N Lslash ; B -20 0 537 718 ;
-C 233 ; WX 778 ; N Oslash ; B 39 -19 740 737 ;
-C 234 ; WX 1000 ; N OE ; B 36 -19 965 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 25 304 341 737 ;
-C 241 ; WX 889 ; N ae ; B 36 -15 847 538 ;
-C 245 ; WX 278 ; N dotlessi ; B 95 0 183 523 ;
-C 248 ; WX 222 ; N lslash ; B -20 0 242 718 ;
-C 249 ; WX 611 ; N oslash ; B 28 -22 537 545 ;
-C 250 ; WX 944 ; N oe ; B 35 -15 902 538 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -15 571 728 ;
-C -1 ; WX 611 ; N Zcaron ; B 23 0 588 929 ;
-C -1 ; WX 500 ; N ccedilla ; B 30 -225 477 538 ;
-C -1 ; WX 500 ; N ydieresis ; B 11 -214 489 706 ;
-C -1 ; WX 556 ; N atilde ; B 36 -15 530 722 ;
-C -1 ; WX 278 ; N icircumflex ; B -6 0 285 734 ;
-C -1 ; WX 333 ; N threesuperior ; B 5 270 325 703 ;
-C -1 ; WX 556 ; N ecircumflex ; B 40 -15 516 734 ;
-C -1 ; WX 556 ; N thorn ; B 58 -207 517 718 ;
-C -1 ; WX 556 ; N egrave ; B 40 -15 516 734 ;
-C -1 ; WX 333 ; N twosuperior ; B 4 281 323 703 ;
-C -1 ; WX 556 ; N eacute ; B 40 -15 516 734 ;
-C -1 ; WX 556 ; N otilde ; B 35 -14 521 722 ;
-C -1 ; WX 667 ; N Aacute ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N ocircumflex ; B 35 -14 521 734 ;
-C -1 ; WX 500 ; N yacute ; B 11 -214 489 734 ;
-C -1 ; WX 556 ; N udieresis ; B 68 -15 489 706 ;
-C -1 ; WX 834 ; N threequarters ; B 45 -19 810 703 ;
-C -1 ; WX 556 ; N acircumflex ; B 36 -15 530 734 ;
-C -1 ; WX 722 ; N Eth ; B 0 0 674 718 ;
-C -1 ; WX 556 ; N edieresis ; B 40 -15 516 706 ;
-C -1 ; WX 556 ; N ugrave ; B 68 -15 489 734 ;
-C -1 ; WX 1000 ; N trademark ; B 46 306 903 718 ;
-C -1 ; WX 556 ; N ograve ; B 35 -14 521 734 ;
-C -1 ; WX 500 ; N scaron ; B 32 -15 464 734 ;
-C -1 ; WX 278 ; N Idieresis ; B 13 0 266 901 ;
-C -1 ; WX 556 ; N uacute ; B 68 -15 489 734 ;
-C -1 ; WX 556 ; N agrave ; B 36 -15 530 734 ;
-C -1 ; WX 556 ; N ntilde ; B 65 0 491 722 ;
-C -1 ; WX 556 ; N aring ; B 36 -15 530 756 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 469 734 ;
-C -1 ; WX 278 ; N Icircumflex ; B -6 0 285 929 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 646 917 ;
-C -1 ; WX 556 ; N ucircumflex ; B 68 -15 489 734 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 86 0 616 929 ;
-C -1 ; WX 278 ; N Iacute ; B 91 0 292 929 ;
-C -1 ; WX 722 ; N Ccedilla ; B 44 -225 681 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 39 -19 739 901 ;
-C -1 ; WX 667 ; N Scaron ; B 49 -19 620 929 ;
-C -1 ; WX 667 ; N Edieresis ; B 86 0 616 901 ;
-C -1 ; WX 278 ; N Igrave ; B -13 0 188 929 ;
-C -1 ; WX 556 ; N adieresis ; B 36 -15 530 706 ;
-C -1 ; WX 778 ; N Ograve ; B 39 -19 739 929 ;
-C -1 ; WX 667 ; N Egrave ; B 86 0 616 929 ;
-C -1 ; WX 667 ; N Ydieresis ; B 14 0 653 901 ;
-C -1 ; WX 737 ; N registered ; B -14 -19 752 737 ;
-C -1 ; WX 778 ; N Otilde ; B 39 -19 739 917 ;
-C -1 ; WX 834 ; N onequarter ; B 73 -19 756 703 ;
-C -1 ; WX 722 ; N Ugrave ; B 79 -19 644 929 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 79 -19 644 929 ;
-C -1 ; WX 667 ; N Thorn ; B 86 0 622 718 ;
-C -1 ; WX 584 ; N divide ; B 39 -19 545 524 ;
-C -1 ; WX 667 ; N Atilde ; B 14 0 654 917 ;
-C -1 ; WX 722 ; N Uacute ; B 79 -19 644 929 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 39 -19 739 929 ;
-C -1 ; WX 584 ; N logicalnot ; B 39 108 545 390 ;
-C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
-C -1 ; WX 278 ; N idieresis ; B 13 0 266 706 ;
-C -1 ; WX 278 ; N iacute ; B 95 0 292 734 ;
-C -1 ; WX 556 ; N aacute ; B 36 -15 530 734 ;
-C -1 ; WX 584 ; N plusminus ; B 39 0 545 506 ;
-C -1 ; WX 584 ; N multiply ; B 39 0 545 506 ;
-C -1 ; WX 722 ; N Udieresis ; B 79 -19 644 901 ;
-C -1 ; WX 584 ; N minus ; B 39 216 545 289 ;
-C -1 ; WX 333 ; N onesuperior ; B 43 281 222 703 ;
-C -1 ; WX 667 ; N Eacute ; B 86 0 616 929 ;
-C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
-C -1 ; WX 737 ; N copyright ; B -14 -19 752 737 ;
-C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N odieresis ; B 35 -14 521 706 ;
-C -1 ; WX 556 ; N oacute ; B 35 -14 521 734 ;
-C -1 ; WX 400 ; N degree ; B 54 411 346 703 ;
-C -1 ; WX 278 ; N igrave ; B -13 0 184 734 ;
-C -1 ; WX 556 ; N mu ; B 68 -207 489 523 ;
-C -1 ; WX 778 ; N Oacute ; B 39 -19 739 929 ;
-C -1 ; WX 556 ; N eth ; B 35 -15 522 737 ;
-C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
-C -1 ; WX 667 ; N Yacute ; B 14 0 653 929 ;
-C -1 ; WX 260 ; N brokenbar ; B 94 -19 167 737 ;
-C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 250
-
-KPX A y -40
-KPX A w -40
-KPX A v -40
-KPX A u -30
-KPX A Y -100
-KPX A W -50
-KPX A V -70
-KPX A U -50
-KPX A T -120
-KPX A Q -30
-KPX A O -30
-KPX A G -30
-KPX A C -30
-
-KPX B period -20
-KPX B comma -20
-KPX B U -10
-
-KPX C period -30
-KPX C comma -30
-
-KPX D period -70
-KPX D comma -70
-KPX D Y -90
-KPX D W -40
-KPX D V -70
-KPX D A -40
-
-KPX F r -45
-KPX F period -150
-KPX F o -30
-KPX F e -30
-KPX F comma -150
-KPX F a -50
-KPX F A -80
-
-KPX J u -20
-KPX J period -30
-KPX J comma -30
-KPX J a -20
-KPX J A -20
-
-KPX K y -50
-KPX K u -30
-KPX K o -40
-KPX K e -40
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -160
-KPX L quotedblright -140
-KPX L Y -140
-KPX L W -70
-KPX L V -110
-KPX L T -110
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -60
-KPX O W -30
-KPX O V -50
-KPX O T -40
-KPX O A -20
-
-KPX P period -180
-KPX P o -50
-KPX P e -50
-KPX P comma -180
-KPX P a -40
-KPX P A -120
-
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -30
-KPX R V -50
-KPX R U -40
-KPX R T -30
-KPX R O -20
-
-KPX S period -20
-KPX S comma -20
-
-KPX T y -120
-KPX T w -120
-KPX T u -120
-KPX T semicolon -20
-KPX T r -120
-KPX T period -120
-KPX T o -120
-KPX T hyphen -140
-KPX T e -120
-KPX T comma -120
-KPX T colon -20
-KPX T a -120
-KPX T O -40
-KPX T A -120
-
-KPX U period -40
-KPX U comma -40
-KPX U A -40
-
-KPX V u -70
-KPX V semicolon -40
-KPX V period -125
-KPX V o -80
-KPX V hyphen -80
-KPX V e -80
-KPX V comma -125
-KPX V colon -40
-KPX V a -70
-KPX V O -40
-KPX V G -40
-KPX V A -80
-
-KPX W y -20
-KPX W u -30
-KPX W period -80
-KPX W o -30
-KPX W hyphen -40
-KPX W e -30
-KPX W comma -80
-KPX W a -40
-KPX W O -20
-KPX W A -50
-
-KPX Y u -110
-KPX Y semicolon -60
-KPX Y period -140
-KPX Y o -140
-KPX Y i -20
-KPX Y hyphen -140
-KPX Y e -140
-KPX Y comma -140
-KPX Y colon -60
-KPX Y a -140
-KPX Y O -85
-KPX Y A -110
-
-KPX a y -30
-KPX a w -20
-KPX a v -20
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b period -40
-KPX b l -20
-KPX b comma -40
-KPX b b -10
-
-KPX c k -20
-KPX c comma -15
-
-KPX colon space -50
-
-KPX comma quoteright -100
-KPX comma quotedblright -100
-
-KPX e y -20
-KPX e x -30
-KPX e w -20
-KPX e v -30
-KPX e period -15
-KPX e comma -15
-
-KPX f quoteright 50
-KPX f quotedblright 60
-KPX f period -30
-KPX f o -30
-KPX f e -30
-KPX f dotlessi -28
-KPX f comma -30
-KPX f a -30
-
-KPX g r -10
-
-KPX h y -30
-
-KPX k o -20
-KPX k e -20
-
-KPX m y -15
-KPX m u -10
-
-KPX n y -15
-KPX n v -20
-KPX n u -10
-
-KPX o y -30
-KPX o x -30
-KPX o w -15
-KPX o v -15
-KPX o period -40
-KPX o comma -40
-
-KPX oslash z -55
-KPX oslash y -70
-KPX oslash x -85
-KPX oslash w -70
-KPX oslash v -70
-KPX oslash u -55
-KPX oslash t -55
-KPX oslash s -55
-KPX oslash r -55
-KPX oslash q -55
-KPX oslash period -95
-KPX oslash p -55
-KPX oslash o -55
-KPX oslash n -55
-KPX oslash m -55
-KPX oslash l -55
-KPX oslash k -55
-KPX oslash j -55
-KPX oslash i -55
-KPX oslash h -55
-KPX oslash g -55
-KPX oslash f -55
-KPX oslash e -55
-KPX oslash d -55
-KPX oslash comma -95
-KPX oslash c -55
-KPX oslash b -55
-KPX oslash a -55
-
-KPX p y -30
-KPX p period -35
-KPX p comma -35
-
-KPX period space -60
-KPX period quoteright -100
-KPX period quotedblright -100
-
-KPX quotedblright space -40
-
-KPX quoteleft quoteleft -57
-
-KPX quoteright space -70
-KPX quoteright s -50
-KPX quoteright r -50
-KPX quoteright quoteright -57
-KPX quoteright d -50
-
-KPX r y 30
-KPX r v 30
-KPX r u 15
-KPX r t 40
-KPX r semicolon 30
-KPX r period -50
-KPX r p 30
-KPX r n 25
-KPX r m 25
-KPX r l 15
-KPX r k 15
-KPX r i 15
-KPX r comma -50
-KPX r colon 30
-KPX r a -10
-
-KPX s w -30
-KPX s period -15
-KPX s comma -15
-
-KPX semicolon space -50
-
-KPX space quoteleft -60
-KPX space quotedblleft -30
-KPX space Y -90
-KPX space W -40
-KPX space V -50
-KPX space T -50
-
-KPX v period -80
-KPX v o -25
-KPX v e -25
-KPX v comma -80
-KPX v a -25
-
-KPX w period -60
-KPX w o -10
-KPX w e -10
-KPX w comma -60
-KPX w a -15
-
-KPX x e -30
-
-KPX y period -100
-KPX y o -20
-KPX y e -20
-KPX y comma -100
-KPX y a -20
-
-KPX z o -15
-KPX z e -15
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 167 195 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 167 195 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 167 195 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 167 195 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 167 175 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 167 195 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 195 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 167 195 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 167 195 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 167 195 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 167 195 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute -27 195 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex -27 195 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis -27 195 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave -27 195 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 205 195 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 195 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 195 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 195 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 195 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 195 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 167 195 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 195 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 195 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 195 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 195 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 167 195 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 167 195 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 195 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 102 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 84 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 102 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 112 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 112 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 112 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 112 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 112 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 84 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 112 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 112 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Times-Bold.afm b/config/psfonts/Times-Bold.afm
deleted file mode 100644 (file)
index 55207f9..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Tue Mar 20 12:17:14 1990
-Comment UniqueID 28417
-Comment VMusage 30458 37350
-FontName Times-Bold
-FullName Times Bold
-FamilyName Times
-Weight Bold
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -168 -218 1000 935
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 676
-XHeight 461
-Ascender 676
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 81 -13 251 691 ;
-C 34 ; WX 555 ; N quotedbl ; B 83 404 472 691 ;
-C 35 ; WX 500 ; N numbersign ; B 4 0 496 700 ;
-C 36 ; WX 500 ; N dollar ; B 29 -99 472 750 ;
-C 37 ; WX 1000 ; N percent ; B 124 -14 877 692 ;
-C 38 ; WX 833 ; N ampersand ; B 62 -16 787 691 ;
-C 39 ; WX 333 ; N quoteright ; B 79 356 263 691 ;
-C 40 ; WX 333 ; N parenleft ; B 46 -168 306 694 ;
-C 41 ; WX 333 ; N parenright ; B 27 -168 287 694 ;
-C 42 ; WX 500 ; N asterisk ; B 56 255 447 691 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B 39 -180 223 155 ;
-C 45 ; WX 333 ; N hyphen ; B 44 171 287 287 ;
-C 46 ; WX 250 ; N period ; B 41 -13 210 156 ;
-C 47 ; WX 278 ; N slash ; B -24 -19 302 691 ;
-C 48 ; WX 500 ; N zero ; B 24 -13 476 688 ;
-C 49 ; WX 500 ; N one ; B 65 0 442 688 ;
-C 50 ; WX 500 ; N two ; B 17 0 478 688 ;
-C 51 ; WX 500 ; N three ; B 16 -14 468 688 ;
-C 52 ; WX 500 ; N four ; B 19 0 475 688 ;
-C 53 ; WX 500 ; N five ; B 22 -8 470 676 ;
-C 54 ; WX 500 ; N six ; B 28 -13 475 688 ;
-C 55 ; WX 500 ; N seven ; B 17 0 477 676 ;
-C 56 ; WX 500 ; N eight ; B 28 -13 472 688 ;
-C 57 ; WX 500 ; N nine ; B 26 -13 473 688 ;
-C 58 ; WX 333 ; N colon ; B 82 -13 251 472 ;
-C 59 ; WX 333 ; N semicolon ; B 82 -180 266 472 ;
-C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
-C 63 ; WX 500 ; N question ; B 57 -13 445 689 ;
-C 64 ; WX 930 ; N at ; B 108 -19 822 691 ;
-C 65 ; WX 722 ; N A ; B 9 0 689 690 ;
-C 66 ; WX 667 ; N B ; B 16 0 619 676 ;
-C 67 ; WX 722 ; N C ; B 49 -19 687 691 ;
-C 68 ; WX 722 ; N D ; B 14 0 690 676 ;
-C 69 ; WX 667 ; N E ; B 16 0 641 676 ;
-C 70 ; WX 611 ; N F ; B 16 0 583 676 ;
-C 71 ; WX 778 ; N G ; B 37 -19 755 691 ;
-C 72 ; WX 778 ; N H ; B 21 0 759 676 ;
-C 73 ; WX 389 ; N I ; B 20 0 370 676 ;
-C 74 ; WX 500 ; N J ; B 3 -96 479 676 ;
-C 75 ; WX 778 ; N K ; B 30 0 769 676 ;
-C 76 ; WX 667 ; N L ; B 19 0 638 676 ;
-C 77 ; WX 944 ; N M ; B 14 0 921 676 ;
-C 78 ; WX 722 ; N N ; B 16 -18 701 676 ;
-C 79 ; WX 778 ; N O ; B 35 -19 743 691 ;
-C 80 ; WX 611 ; N P ; B 16 0 600 676 ;
-C 81 ; WX 778 ; N Q ; B 35 -176 743 691 ;
-C 82 ; WX 722 ; N R ; B 26 0 715 676 ;
-C 83 ; WX 556 ; N S ; B 35 -19 513 692 ;
-C 84 ; WX 667 ; N T ; B 31 0 636 676 ;
-C 85 ; WX 722 ; N U ; B 16 -19 701 676 ;
-C 86 ; WX 722 ; N V ; B 16 -18 701 676 ;
-C 87 ; WX 1000 ; N W ; B 19 -15 981 676 ;
-C 88 ; WX 722 ; N X ; B 16 0 699 676 ;
-C 89 ; WX 722 ; N Y ; B 15 0 699 676 ;
-C 90 ; WX 667 ; N Z ; B 28 0 634 676 ;
-C 91 ; WX 333 ; N bracketleft ; B 67 -149 301 678 ;
-C 92 ; WX 278 ; N backslash ; B -25 -19 303 691 ;
-C 93 ; WX 333 ; N bracketright ; B 32 -149 266 678 ;
-C 94 ; WX 581 ; N asciicircum ; B 73 311 509 676 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 70 356 254 691 ;
-C 97 ; WX 500 ; N a ; B 25 -14 488 473 ;
-C 98 ; WX 556 ; N b ; B 17 -14 521 676 ;
-C 99 ; WX 444 ; N c ; B 25 -14 430 473 ;
-C 100 ; WX 556 ; N d ; B 25 -14 534 676 ;
-C 101 ; WX 444 ; N e ; B 25 -14 426 473 ;
-C 102 ; WX 333 ; N f ; B 14 0 389 691 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 28 -206 483 473 ;
-C 104 ; WX 556 ; N h ; B 16 0 534 676 ;
-C 105 ; WX 278 ; N i ; B 16 0 255 691 ;
-C 106 ; WX 333 ; N j ; B -57 -203 263 691 ;
-C 107 ; WX 556 ; N k ; B 22 0 543 676 ;
-C 108 ; WX 278 ; N l ; B 16 0 255 676 ;
-C 109 ; WX 833 ; N m ; B 16 0 814 473 ;
-C 110 ; WX 556 ; N n ; B 21 0 539 473 ;
-C 111 ; WX 500 ; N o ; B 25 -14 476 473 ;
-C 112 ; WX 556 ; N p ; B 19 -205 524 473 ;
-C 113 ; WX 556 ; N q ; B 34 -205 536 473 ;
-C 114 ; WX 444 ; N r ; B 29 0 434 473 ;
-C 115 ; WX 389 ; N s ; B 25 -14 361 473 ;
-C 116 ; WX 333 ; N t ; B 20 -12 332 630 ;
-C 117 ; WX 556 ; N u ; B 16 -14 537 461 ;
-C 118 ; WX 500 ; N v ; B 21 -14 485 461 ;
-C 119 ; WX 722 ; N w ; B 23 -14 707 461 ;
-C 120 ; WX 500 ; N x ; B 12 0 484 461 ;
-C 121 ; WX 500 ; N y ; B 16 -205 480 461 ;
-C 122 ; WX 444 ; N z ; B 21 0 420 461 ;
-C 123 ; WX 394 ; N braceleft ; B 22 -175 340 698 ;
-C 124 ; WX 220 ; N bar ; B 66 -19 154 691 ;
-C 125 ; WX 394 ; N braceright ; B 54 -175 372 698 ;
-C 126 ; WX 520 ; N asciitilde ; B 29 173 491 333 ;
-C 161 ; WX 333 ; N exclamdown ; B 82 -203 252 501 ;
-C 162 ; WX 500 ; N cent ; B 53 -140 458 588 ;
-C 163 ; WX 500 ; N sterling ; B 21 -14 477 684 ;
-C 164 ; WX 167 ; N fraction ; B -168 -12 329 688 ;
-C 165 ; WX 500 ; N yen ; B -64 0 547 676 ;
-C 166 ; WX 500 ; N florin ; B 0 -155 498 706 ;
-C 167 ; WX 500 ; N section ; B 57 -132 443 691 ;
-C 168 ; WX 500 ; N currency ; B -26 61 526 613 ;
-C 169 ; WX 278 ; N quotesingle ; B 75 404 204 691 ;
-C 170 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ;
-C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ;
-C 174 ; WX 556 ; N fi ; B 14 0 536 691 ;
-C 175 ; WX 556 ; N fl ; B 14 0 536 691 ;
-C 177 ; WX 500 ; N endash ; B 0 181 500 271 ;
-C 178 ; WX 500 ; N dagger ; B 47 -134 453 691 ;
-C 179 ; WX 500 ; N daggerdbl ; B 45 -132 456 691 ;
-C 180 ; WX 250 ; N periodcentered ; B 41 248 210 417 ;
-C 182 ; WX 540 ; N paragraph ; B 0 -186 519 676 ;
-C 183 ; WX 350 ; N bullet ; B 35 198 315 478 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -180 263 155 ;
-C 185 ; WX 500 ; N quotedblbase ; B 14 -180 468 155 ;
-C 186 ; WX 500 ; N quotedblright ; B 14 356 468 691 ;
-C 187 ; WX 500 ; N guillemotright ; B 27 36 477 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 82 -13 917 156 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 995 706 ;
-C 191 ; WX 500 ; N questiondown ; B 55 -201 443 501 ;
-C 193 ; WX 333 ; N grave ; B 8 528 246 713 ;
-C 194 ; WX 333 ; N acute ; B 86 528 324 713 ;
-C 195 ; WX 333 ; N circumflex ; B -2 528 335 704 ;
-C 196 ; WX 333 ; N tilde ; B -16 547 349 674 ;
-C 197 ; WX 333 ; N macron ; B 1 565 331 637 ;
-C 198 ; WX 333 ; N breve ; B 15 528 318 691 ;
-C 199 ; WX 333 ; N dotaccent ; B 103 537 230 667 ;
-C 200 ; WX 333 ; N dieresis ; B -2 537 335 667 ;
-C 202 ; WX 333 ; N ring ; B 60 527 273 740 ;
-C 203 ; WX 333 ; N cedilla ; B 68 -218 294 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -13 528 425 713 ;
-C 206 ; WX 333 ; N ogonek ; B 90 -173 319 44 ;
-C 207 ; WX 333 ; N caron ; B -2 528 335 704 ;
-C 208 ; WX 1000 ; N emdash ; B 0 181 1000 271 ;
-C 225 ; WX 1000 ; N AE ; B 4 0 951 676 ;
-C 227 ; WX 300 ; N ordfeminine ; B -1 397 301 688 ;
-C 232 ; WX 667 ; N Lslash ; B 19 0 638 676 ;
-C 233 ; WX 778 ; N Oslash ; B 35 -74 743 737 ;
-C 234 ; WX 1000 ; N OE ; B 22 -5 981 684 ;
-C 235 ; WX 330 ; N ordmasculine ; B 18 397 312 688 ;
-C 241 ; WX 722 ; N ae ; B 33 -14 693 473 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 255 461 ;
-C 248 ; WX 278 ; N lslash ; B -22 0 303 676 ;
-C 249 ; WX 500 ; N oslash ; B 25 -92 476 549 ;
-C 250 ; WX 722 ; N oe ; B 22 -14 696 473 ;
-C 251 ; WX 556 ; N germandbls ; B 19 -12 517 691 ;
-C -1 ; WX 667 ; N Zcaron ; B 28 0 634 914 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -218 430 473 ;
-C -1 ; WX 500 ; N ydieresis ; B 16 -205 480 667 ;
-C -1 ; WX 500 ; N atilde ; B 25 -14 488 674 ;
-C -1 ; WX 278 ; N icircumflex ; B -36 0 301 704 ;
-C -1 ; WX 300 ; N threesuperior ; B 3 268 297 688 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -14 426 704 ;
-C -1 ; WX 556 ; N thorn ; B 19 -205 524 676 ;
-C -1 ; WX 444 ; N egrave ; B 25 -14 426 713 ;
-C -1 ; WX 300 ; N twosuperior ; B 0 275 300 688 ;
-C -1 ; WX 444 ; N eacute ; B 25 -14 426 713 ;
-C -1 ; WX 500 ; N otilde ; B 25 -14 476 674 ;
-C -1 ; WX 722 ; N Aacute ; B 9 0 689 923 ;
-C -1 ; WX 500 ; N ocircumflex ; B 25 -14 476 704 ;
-C -1 ; WX 500 ; N yacute ; B 16 -205 480 713 ;
-C -1 ; WX 556 ; N udieresis ; B 16 -14 537 667 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -12 733 688 ;
-C -1 ; WX 500 ; N acircumflex ; B 25 -14 488 704 ;
-C -1 ; WX 722 ; N Eth ; B 6 0 690 676 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -14 426 667 ;
-C -1 ; WX 556 ; N ugrave ; B 16 -14 537 713 ;
-C -1 ; WX 1000 ; N trademark ; B 24 271 977 676 ;
-C -1 ; WX 500 ; N ograve ; B 25 -14 476 713 ;
-C -1 ; WX 389 ; N scaron ; B 25 -14 363 704 ;
-C -1 ; WX 389 ; N Idieresis ; B 20 0 370 877 ;
-C -1 ; WX 556 ; N uacute ; B 16 -14 537 713 ;
-C -1 ; WX 500 ; N agrave ; B 25 -14 488 713 ;
-C -1 ; WX 556 ; N ntilde ; B 21 0 539 674 ;
-C -1 ; WX 500 ; N aring ; B 25 -14 488 740 ;
-C -1 ; WX 444 ; N zcaron ; B 21 0 420 704 ;
-C -1 ; WX 389 ; N Icircumflex ; B 20 0 370 914 ;
-C -1 ; WX 722 ; N Ntilde ; B 16 -18 701 884 ;
-C -1 ; WX 556 ; N ucircumflex ; B 16 -14 537 704 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 16 0 641 914 ;
-C -1 ; WX 389 ; N Iacute ; B 20 0 370 923 ;
-C -1 ; WX 722 ; N Ccedilla ; B 49 -218 687 691 ;
-C -1 ; WX 778 ; N Odieresis ; B 35 -19 743 877 ;
-C -1 ; WX 556 ; N Scaron ; B 35 -19 513 914 ;
-C -1 ; WX 667 ; N Edieresis ; B 16 0 641 877 ;
-C -1 ; WX 389 ; N Igrave ; B 20 0 370 923 ;
-C -1 ; WX 500 ; N adieresis ; B 25 -14 488 667 ;
-C -1 ; WX 778 ; N Ograve ; B 35 -19 743 923 ;
-C -1 ; WX 667 ; N Egrave ; B 16 0 641 923 ;
-C -1 ; WX 722 ; N Ydieresis ; B 15 0 699 877 ;
-C -1 ; WX 747 ; N registered ; B 26 -19 721 691 ;
-C -1 ; WX 778 ; N Otilde ; B 35 -19 743 884 ;
-C -1 ; WX 750 ; N onequarter ; B 28 -12 743 688 ;
-C -1 ; WX 722 ; N Ugrave ; B 16 -19 701 923 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 16 -19 701 914 ;
-C -1 ; WX 611 ; N Thorn ; B 16 0 600 676 ;
-C -1 ; WX 570 ; N divide ; B 33 -31 537 537 ;
-C -1 ; WX 722 ; N Atilde ; B 9 0 689 884 ;
-C -1 ; WX 722 ; N Uacute ; B 16 -19 701 923 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 35 -19 743 914 ;
-C -1 ; WX 570 ; N logicalnot ; B 33 108 537 399 ;
-C -1 ; WX 722 ; N Aring ; B 9 0 689 935 ;
-C -1 ; WX 278 ; N idieresis ; B -36 0 301 667 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 713 ;
-C -1 ; WX 500 ; N aacute ; B 25 -14 488 713 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 722 ; N Udieresis ; B 16 -19 701 877 ;
-C -1 ; WX 570 ; N minus ; B 33 209 537 297 ;
-C -1 ; WX 300 ; N onesuperior ; B 28 275 273 688 ;
-C -1 ; WX 667 ; N Eacute ; B 16 0 641 923 ;
-C -1 ; WX 722 ; N Acircumflex ; B 9 0 689 914 ;
-C -1 ; WX 747 ; N copyright ; B 26 -19 721 691 ;
-C -1 ; WX 722 ; N Agrave ; B 9 0 689 923 ;
-C -1 ; WX 500 ; N odieresis ; B 25 -14 476 667 ;
-C -1 ; WX 500 ; N oacute ; B 25 -14 476 713 ;
-C -1 ; WX 400 ; N degree ; B 57 402 343 688 ;
-C -1 ; WX 278 ; N igrave ; B -26 0 255 713 ;
-C -1 ; WX 556 ; N mu ; B 33 -206 536 461 ;
-C -1 ; WX 778 ; N Oacute ; B 35 -19 743 923 ;
-C -1 ; WX 500 ; N eth ; B 25 -14 476 691 ;
-C -1 ; WX 722 ; N Adieresis ; B 9 0 689 877 ;
-C -1 ; WX 722 ; N Yacute ; B 15 0 699 928 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -19 154 691 ;
-C -1 ; WX 750 ; N onehalf ; B -7 -12 775 688 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -74
-KPX A w -90
-KPX A v -100
-KPX A u -50
-KPX A quoteright -74
-KPX A quotedblright 0
-KPX A p -25
-KPX A Y -100
-KPX A W -130
-KPX A V -145
-KPX A U -50
-KPX A T -95
-KPX A Q -45
-KPX A O -45
-KPX A G -55
-KPX A C -55
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -30
-
-KPX D period -20
-KPX D comma 0
-KPX D Y -40
-KPX D W -40
-KPX D V -40
-KPX D A -35
-
-KPX F r 0
-KPX F period -110
-KPX F o -25
-KPX F i 0
-KPX F e -25
-KPX F comma -92
-KPX F a -25
-KPX F A -90
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -15
-KPX J period -20
-KPX J o -15
-KPX J e -15
-KPX J comma 0
-KPX J a -15
-KPX J A -30
-
-KPX K y -45
-KPX K u -15
-KPX K o -25
-KPX K e -25
-KPX K O -30
-
-KPX L y -55
-KPX L quoteright -110
-KPX L quotedblright -20
-KPX L Y -92
-KPX L W -92
-KPX L V -92
-KPX L T -92
-
-KPX N period 0
-KPX N comma 0
-KPX N A -20
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -40
-
-KPX P period -110
-KPX P o -20
-KPX P e -20
-KPX P comma -92
-KPX P a -10
-KPX P A -74
-
-KPX Q period -20
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -35
-KPX R W -35
-KPX R V -55
-KPX R U -30
-KPX R T -40
-KPX R O -30
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -74
-KPX T w -74
-KPX T u -92
-KPX T semicolon -74
-KPX T r -74
-KPX T period -90
-KPX T o -92
-KPX T i -18
-KPX T hyphen -92
-KPX T h 0
-KPX T e -92
-KPX T comma -74
-KPX T colon -74
-KPX T a -92
-KPX T O -18
-KPX T A -90
-
-KPX U period -50
-KPX U comma -50
-KPX U A -60
-
-KPX V u -92
-KPX V semicolon -92
-KPX V period -145
-KPX V o -100
-KPX V i -37
-KPX V hyphen -74
-KPX V e -100
-KPX V comma -129
-KPX V colon -92
-KPX V a -92
-KPX V O -45
-KPX V G -30
-KPX V A -135
-
-KPX W y -60
-KPX W u -50
-KPX W semicolon -55
-KPX W period -92
-KPX W o -75
-KPX W i -18
-KPX W hyphen -37
-KPX W h 0
-KPX W e -65
-KPX W comma -92
-KPX W colon -55
-KPX W a -65
-KPX W O -10
-KPX W A -120
-
-KPX Y u -92
-KPX Y semicolon -92
-KPX Y period -92
-KPX Y o -111
-KPX Y i -37
-KPX Y hyphen -92
-KPX Y e -111
-KPX Y comma -92
-KPX Y colon -92
-KPX Y a -85
-KPX Y O -35
-KPX Y A -110
-
-KPX a y 0
-KPX a w 0
-KPX a v -25
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v -15
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b -10
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k 0
-KPX c h 0
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -55
-KPX comma quotedblright -45
-
-KPX d y 0
-KPX d w -15
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y 0
-KPX e x 0
-KPX e w 0
-KPX e v -15
-KPX e period 0
-KPX e p 0
-KPX e g 0
-KPX e comma 0
-KPX e b 0
-
-KPX f quoteright 55
-KPX f quotedblright 50
-KPX f period -15
-KPX f o -25
-KPX f l 0
-KPX f i -25
-KPX f f 0
-KPX f e 0
-KPX f dotlessi -35
-KPX f comma -15
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period -15
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a 0
-
-KPX h y -15
-
-KPX i v -10
-
-KPX k y -15
-KPX k o -15
-KPX k e -10
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y 0
-KPX o x 0
-KPX o w -10
-KPX o v -10
-KPX o g 0
-
-KPX p y 0
-
-KPX period quoteright -55
-KPX period quotedblright -55
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A -10
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -63
-KPX quoteleft A -10
-
-KPX quoteright v -20
-KPX quoteright t 0
-KPX quoteright space -74
-KPX quoteright s -37
-KPX quoteright r -20
-KPX quoteright quoteright -63
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -20
-
-KPX r y 0
-KPX r v -10
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q -18
-KPX r period -100
-KPX r p -10
-KPX r o -18
-KPX r n -15
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -37
-KPX r g -10
-KPX r e -18
-KPX r d 0
-KPX r comma -92
-KPX r c -18
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -55
-KPX space W -30
-KPX space V -45
-KPX space T -30
-KPX space A -55
-
-KPX v period -70
-KPX v o -10
-KPX v e -10
-KPX v comma -55
-KPX v a -10
-
-KPX w period -70
-KPX w o -10
-KPX w h 0
-KPX w e 0
-KPX w comma -55
-KPX w a 0
-
-KPX x e 0
-
-KPX y period -70
-KPX y o -25
-KPX y e -10
-KPX y comma -55
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 188 210 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 188 210 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 188 210 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 188 210 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 180 195 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 188 210 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 208 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 174 210 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 174 210 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 174 210 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 174 210 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 28 210 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 28 210 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 28 210 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 28 210 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 210 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 210 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 210 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 210 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 210 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 210 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 210 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 222 210 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 222 210 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 222 210 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 222 210 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 210 215 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 215 210 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 167 210 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 77 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 77 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 77 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 77 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 77 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 77 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 69 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 62 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 62 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 62 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 62 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -34 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -34 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -34 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -34 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 112 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 105 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 105 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 105 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 105 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 56 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Times-BoldItalic.afm b/config/psfonts/Times-BoldItalic.afm
deleted file mode 100644 (file)
index 25ab54e..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Tue Mar 20 13:14:55 1990
-Comment UniqueID 28425
-Comment VMusage 32721 39613
-FontName Times-BoldItalic
-FullName Times Bold Italic
-FamilyName Times
-Weight Bold
-ItalicAngle -15
-IsFixedPitch false
-FontBBox -200 -218 996 921
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.009
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 669
-XHeight 462
-Ascender 699
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 389 ; N exclam ; B 67 -13 370 684 ;
-C 34 ; WX 555 ; N quotedbl ; B 136 398 536 685 ;
-C 35 ; WX 500 ; N numbersign ; B -33 0 533 700 ;
-C 36 ; WX 500 ; N dollar ; B -20 -100 497 733 ;
-C 37 ; WX 833 ; N percent ; B 39 -10 793 692 ;
-C 38 ; WX 778 ; N ampersand ; B 5 -19 699 682 ;
-C 39 ; WX 333 ; N quoteright ; B 98 369 302 685 ;
-C 40 ; WX 333 ; N parenleft ; B 28 -179 344 685 ;
-C 41 ; WX 333 ; N parenright ; B -44 -179 271 685 ;
-C 42 ; WX 500 ; N asterisk ; B 65 249 456 685 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B -60 -182 144 134 ;
-C 45 ; WX 333 ; N hyphen ; B 2 166 271 282 ;
-C 46 ; WX 250 ; N period ; B -9 -13 139 135 ;
-C 47 ; WX 278 ; N slash ; B -64 -18 342 685 ;
-C 48 ; WX 500 ; N zero ; B 17 -14 477 683 ;
-C 49 ; WX 500 ; N one ; B 5 0 419 683 ;
-C 50 ; WX 500 ; N two ; B -27 0 446 683 ;
-C 51 ; WX 500 ; N three ; B -15 -13 450 683 ;
-C 52 ; WX 500 ; N four ; B -15 0 503 683 ;
-C 53 ; WX 500 ; N five ; B -11 -13 487 669 ;
-C 54 ; WX 500 ; N six ; B 23 -15 509 679 ;
-C 55 ; WX 500 ; N seven ; B 52 0 525 669 ;
-C 56 ; WX 500 ; N eight ; B 3 -13 476 683 ;
-C 57 ; WX 500 ; N nine ; B -12 -10 475 683 ;
-C 58 ; WX 333 ; N colon ; B 23 -13 264 459 ;
-C 59 ; WX 333 ; N semicolon ; B -25 -183 264 459 ;
-C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
-C 63 ; WX 500 ; N question ; B 79 -13 470 684 ;
-C 64 ; WX 832 ; N at ; B 63 -18 770 685 ;
-C 65 ; WX 667 ; N A ; B -67 0 593 683 ;
-C 66 ; WX 667 ; N B ; B -24 0 624 669 ;
-C 67 ; WX 667 ; N C ; B 32 -18 677 685 ;
-C 68 ; WX 722 ; N D ; B -46 0 685 669 ;
-C 69 ; WX 667 ; N E ; B -27 0 653 669 ;
-C 70 ; WX 667 ; N F ; B -13 0 660 669 ;
-C 71 ; WX 722 ; N G ; B 21 -18 706 685 ;
-C 72 ; WX 778 ; N H ; B -24 0 799 669 ;
-C 73 ; WX 389 ; N I ; B -32 0 406 669 ;
-C 74 ; WX 500 ; N J ; B -46 -99 524 669 ;
-C 75 ; WX 667 ; N K ; B -21 0 702 669 ;
-C 76 ; WX 611 ; N L ; B -22 0 590 669 ;
-C 77 ; WX 889 ; N M ; B -29 -12 917 669 ;
-C 78 ; WX 722 ; N N ; B -27 -15 748 669 ;
-C 79 ; WX 722 ; N O ; B 27 -18 691 685 ;
-C 80 ; WX 611 ; N P ; B -27 0 613 669 ;
-C 81 ; WX 722 ; N Q ; B 27 -208 691 685 ;
-C 82 ; WX 667 ; N R ; B -29 0 623 669 ;
-C 83 ; WX 556 ; N S ; B 2 -18 526 685 ;
-C 84 ; WX 611 ; N T ; B 50 0 650 669 ;
-C 85 ; WX 722 ; N U ; B 67 -18 744 669 ;
-C 86 ; WX 667 ; N V ; B 65 -18 715 669 ;
-C 87 ; WX 889 ; N W ; B 65 -18 940 669 ;
-C 88 ; WX 667 ; N X ; B -24 0 694 669 ;
-C 89 ; WX 611 ; N Y ; B 73 0 659 669 ;
-C 90 ; WX 611 ; N Z ; B -11 0 590 669 ;
-C 91 ; WX 333 ; N bracketleft ; B -37 -159 362 674 ;
-C 92 ; WX 278 ; N backslash ; B -1 -18 279 685 ;
-C 93 ; WX 333 ; N bracketright ; B -56 -157 343 674 ;
-C 94 ; WX 570 ; N asciicircum ; B 67 304 503 669 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 128 369 332 685 ;
-C 97 ; WX 500 ; N a ; B -21 -14 455 462 ;
-C 98 ; WX 500 ; N b ; B -14 -13 444 699 ;
-C 99 ; WX 444 ; N c ; B -5 -13 392 462 ;
-C 100 ; WX 500 ; N d ; B -21 -13 517 699 ;
-C 101 ; WX 444 ; N e ; B 5 -13 398 462 ;
-C 102 ; WX 333 ; N f ; B -169 -205 446 698 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B -52 -203 478 462 ;
-C 104 ; WX 556 ; N h ; B -13 -9 498 699 ;
-C 105 ; WX 278 ; N i ; B 2 -9 263 684 ;
-C 106 ; WX 278 ; N j ; B -189 -207 279 684 ;
-C 107 ; WX 500 ; N k ; B -23 -8 483 699 ;
-C 108 ; WX 278 ; N l ; B 2 -9 290 699 ;
-C 109 ; WX 778 ; N m ; B -14 -9 722 462 ;
-C 110 ; WX 556 ; N n ; B -6 -9 493 462 ;
-C 111 ; WX 500 ; N o ; B -3 -13 441 462 ;
-C 112 ; WX 500 ; N p ; B -120 -205 446 462 ;
-C 113 ; WX 500 ; N q ; B 1 -205 471 462 ;
-C 114 ; WX 389 ; N r ; B -21 0 389 462 ;
-C 115 ; WX 389 ; N s ; B -19 -13 333 462 ;
-C 116 ; WX 278 ; N t ; B -11 -9 281 594 ;
-C 117 ; WX 556 ; N u ; B 15 -9 492 462 ;
-C 118 ; WX 444 ; N v ; B 16 -13 401 462 ;
-C 119 ; WX 667 ; N w ; B 16 -13 614 462 ;
-C 120 ; WX 500 ; N x ; B -46 -13 469 462 ;
-C 121 ; WX 444 ; N y ; B -94 -205 392 462 ;
-C 122 ; WX 389 ; N z ; B -43 -78 368 449 ;
-C 123 ; WX 348 ; N braceleft ; B 5 -187 436 686 ;
-C 124 ; WX 220 ; N bar ; B 66 -18 154 685 ;
-C 125 ; WX 348 ; N braceright ; B -129 -187 302 686 ;
-C 126 ; WX 570 ; N asciitilde ; B 54 173 516 333 ;
-C 161 ; WX 389 ; N exclamdown ; B 19 -205 322 492 ;
-C 162 ; WX 500 ; N cent ; B 42 -143 439 576 ;
-C 163 ; WX 500 ; N sterling ; B -32 -12 510 683 ;
-C 164 ; WX 167 ; N fraction ; B -169 -14 324 683 ;
-C 165 ; WX 500 ; N yen ; B 33 0 628 669 ;
-C 166 ; WX 500 ; N florin ; B -87 -156 537 707 ;
-C 167 ; WX 500 ; N section ; B 36 -143 459 685 ;
-C 168 ; WX 500 ; N currency ; B -26 34 526 586 ;
-C 169 ; WX 278 ; N quotesingle ; B 128 398 268 685 ;
-C 170 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ;
-C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ;
-C 174 ; WX 556 ; N fi ; B -188 -205 514 703 ;
-C 175 ; WX 556 ; N fl ; B -186 -205 553 704 ;
-C 177 ; WX 500 ; N endash ; B -40 178 477 269 ;
-C 178 ; WX 500 ; N dagger ; B 91 -145 494 685 ;
-C 179 ; WX 500 ; N daggerdbl ; B 10 -139 493 685 ;
-C 180 ; WX 250 ; N periodcentered ; B 51 257 199 405 ;
-C 182 ; WX 500 ; N paragraph ; B -57 -193 562 669 ;
-C 183 ; WX 350 ; N bullet ; B 0 175 350 525 ;
-C 184 ; WX 333 ; N quotesinglbase ; B -5 -182 199 134 ;
-C 185 ; WX 500 ; N quotedblbase ; B -57 -182 403 134 ;
-C 186 ; WX 500 ; N quotedblright ; B 53 369 513 685 ;
-C 187 ; WX 500 ; N guillemotright ; B 12 32 468 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 40 -13 852 135 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 996 706 ;
-C 191 ; WX 500 ; N questiondown ; B 30 -205 421 492 ;
-C 193 ; WX 333 ; N grave ; B 85 516 297 697 ;
-C 194 ; WX 333 ; N acute ; B 139 516 379 697 ;
-C 195 ; WX 333 ; N circumflex ; B 40 516 367 690 ;
-C 196 ; WX 333 ; N tilde ; B 48 536 407 655 ;
-C 197 ; WX 333 ; N macron ; B 51 553 393 623 ;
-C 198 ; WX 333 ; N breve ; B 71 516 387 678 ;
-C 199 ; WX 333 ; N dotaccent ; B 163 525 293 655 ;
-C 200 ; WX 333 ; N dieresis ; B 55 525 397 655 ;
-C 202 ; WX 333 ; N ring ; B 127 516 340 729 ;
-C 203 ; WX 333 ; N cedilla ; B -80 -218 156 5 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 69 516 498 697 ;
-C 206 ; WX 333 ; N ogonek ; B -40 -173 189 44 ;
-C 207 ; WX 333 ; N caron ; B 79 516 411 690 ;
-C 208 ; WX 1000 ; N emdash ; B -40 178 977 269 ;
-C 225 ; WX 944 ; N AE ; B -64 0 918 669 ;
-C 227 ; WX 266 ; N ordfeminine ; B 16 399 330 685 ;
-C 232 ; WX 611 ; N Lslash ; B -22 0 590 669 ;
-C 233 ; WX 722 ; N Oslash ; B 27 -125 691 764 ;
-C 234 ; WX 944 ; N OE ; B 23 -8 946 677 ;
-C 235 ; WX 300 ; N ordmasculine ; B 56 400 347 685 ;
-C 241 ; WX 722 ; N ae ; B -5 -13 673 462 ;
-C 245 ; WX 278 ; N dotlessi ; B 2 -9 238 462 ;
-C 248 ; WX 278 ; N lslash ; B -13 -9 301 699 ;
-C 249 ; WX 500 ; N oslash ; B -3 -119 441 560 ;
-C 250 ; WX 722 ; N oe ; B 6 -13 674 462 ;
-C 251 ; WX 500 ; N germandbls ; B -200 -200 473 705 ;
-C -1 ; WX 611 ; N Zcaron ; B -11 0 590 897 ;
-C -1 ; WX 444 ; N ccedilla ; B -24 -218 392 462 ;
-C -1 ; WX 444 ; N ydieresis ; B -94 -205 438 655 ;
-C -1 ; WX 500 ; N atilde ; B -21 -14 491 655 ;
-C -1 ; WX 278 ; N icircumflex ; B -2 -9 325 690 ;
-C -1 ; WX 300 ; N threesuperior ; B 17 265 321 683 ;
-C -1 ; WX 444 ; N ecircumflex ; B 5 -13 423 690 ;
-C -1 ; WX 500 ; N thorn ; B -120 -205 446 699 ;
-C -1 ; WX 444 ; N egrave ; B 5 -13 398 697 ;
-C -1 ; WX 300 ; N twosuperior ; B 2 274 313 683 ;
-C -1 ; WX 444 ; N eacute ; B 5 -13 435 697 ;
-C -1 ; WX 500 ; N otilde ; B -3 -13 491 655 ;
-C -1 ; WX 667 ; N Aacute ; B -67 0 593 904 ;
-C -1 ; WX 500 ; N ocircumflex ; B -3 -13 451 690 ;
-C -1 ; WX 444 ; N yacute ; B -94 -205 435 697 ;
-C -1 ; WX 556 ; N udieresis ; B 15 -9 494 655 ;
-C -1 ; WX 750 ; N threequarters ; B 7 -14 726 683 ;
-C -1 ; WX 500 ; N acircumflex ; B -21 -14 455 690 ;
-C -1 ; WX 722 ; N Eth ; B -31 0 700 669 ;
-C -1 ; WX 444 ; N edieresis ; B 5 -13 443 655 ;
-C -1 ; WX 556 ; N ugrave ; B 15 -9 492 697 ;
-C -1 ; WX 1000 ; N trademark ; B 32 263 968 669 ;
-C -1 ; WX 500 ; N ograve ; B -3 -13 441 697 ;
-C -1 ; WX 389 ; N scaron ; B -19 -13 439 690 ;
-C -1 ; WX 389 ; N Idieresis ; B -32 0 445 862 ;
-C -1 ; WX 556 ; N uacute ; B 15 -9 492 697 ;
-C -1 ; WX 500 ; N agrave ; B -21 -14 455 697 ;
-C -1 ; WX 556 ; N ntilde ; B -6 -9 504 655 ;
-C -1 ; WX 500 ; N aring ; B -21 -14 455 729 ;
-C -1 ; WX 389 ; N zcaron ; B -43 -78 424 690 ;
-C -1 ; WX 389 ; N Icircumflex ; B -32 0 420 897 ;
-C -1 ; WX 722 ; N Ntilde ; B -27 -15 748 862 ;
-C -1 ; WX 556 ; N ucircumflex ; B 15 -9 492 690 ;
-C -1 ; WX 667 ; N Ecircumflex ; B -27 0 653 897 ;
-C -1 ; WX 389 ; N Iacute ; B -32 0 412 904 ;
-C -1 ; WX 667 ; N Ccedilla ; B 32 -218 677 685 ;
-C -1 ; WX 722 ; N Odieresis ; B 27 -18 691 862 ;
-C -1 ; WX 556 ; N Scaron ; B 2 -18 526 897 ;
-C -1 ; WX 667 ; N Edieresis ; B -27 0 653 862 ;
-C -1 ; WX 389 ; N Igrave ; B -32 0 406 904 ;
-C -1 ; WX 500 ; N adieresis ; B -21 -14 471 655 ;
-C -1 ; WX 722 ; N Ograve ; B 27 -18 691 904 ;
-C -1 ; WX 667 ; N Egrave ; B -27 0 653 904 ;
-C -1 ; WX 611 ; N Ydieresis ; B 73 0 659 862 ;
-C -1 ; WX 747 ; N registered ; B 30 -18 718 685 ;
-C -1 ; WX 722 ; N Otilde ; B 27 -18 691 862 ;
-C -1 ; WX 750 ; N onequarter ; B 7 -14 721 683 ;
-C -1 ; WX 722 ; N Ugrave ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 67 -18 744 897 ;
-C -1 ; WX 611 ; N Thorn ; B -27 0 573 669 ;
-C -1 ; WX 570 ; N divide ; B 33 -29 537 535 ;
-C -1 ; WX 667 ; N Atilde ; B -67 0 593 862 ;
-C -1 ; WX 722 ; N Uacute ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 27 -18 691 897 ;
-C -1 ; WX 606 ; N logicalnot ; B 51 108 555 399 ;
-C -1 ; WX 667 ; N Aring ; B -67 0 593 921 ;
-C -1 ; WX 278 ; N idieresis ; B 2 -9 360 655 ;
-C -1 ; WX 278 ; N iacute ; B 2 -9 352 697 ;
-C -1 ; WX 500 ; N aacute ; B -21 -14 463 697 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 722 ; N Udieresis ; B 67 -18 744 862 ;
-C -1 ; WX 606 ; N minus ; B 51 209 555 297 ;
-C -1 ; WX 300 ; N onesuperior ; B 30 274 301 683 ;
-C -1 ; WX 667 ; N Eacute ; B -27 0 653 904 ;
-C -1 ; WX 667 ; N Acircumflex ; B -67 0 593 897 ;
-C -1 ; WX 747 ; N copyright ; B 30 -18 718 685 ;
-C -1 ; WX 667 ; N Agrave ; B -67 0 593 904 ;
-C -1 ; WX 500 ; N odieresis ; B -3 -13 466 655 ;
-C -1 ; WX 500 ; N oacute ; B -3 -13 463 697 ;
-C -1 ; WX 400 ; N degree ; B 83 397 369 683 ;
-C -1 ; WX 278 ; N igrave ; B 2 -9 260 697 ;
-C -1 ; WX 576 ; N mu ; B -60 -207 516 449 ;
-C -1 ; WX 722 ; N Oacute ; B 27 -18 691 904 ;
-C -1 ; WX 500 ; N eth ; B -3 -13 454 699 ;
-C -1 ; WX 667 ; N Adieresis ; B -67 0 593 862 ;
-C -1 ; WX 611 ; N Yacute ; B 73 0 659 904 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -18 154 685 ;
-C -1 ; WX 750 ; N onehalf ; B -9 -14 723 683 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -74
-KPX A w -74
-KPX A v -74
-KPX A u -30
-KPX A quoteright -74
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -70
-KPX A W -100
-KPX A V -95
-KPX A U -50
-KPX A T -55
-KPX A Q -55
-KPX A O -50
-KPX A G -60
-KPX A C -65
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -25
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -50
-KPX D W -40
-KPX D V -50
-KPX D A -25
-
-KPX F r -50
-KPX F period -129
-KPX F o -70
-KPX F i -40
-KPX F e -100
-KPX F comma -129
-KPX F a -95
-KPX F A -100
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -40
-KPX J period -10
-KPX J o -40
-KPX J e -40
-KPX J comma -10
-KPX J a -40
-KPX J A -25
-
-KPX K y -20
-KPX K u -20
-KPX K o -25
-KPX K e -25
-KPX K O -30
-
-KPX L y -37
-KPX L quoteright -55
-KPX L quotedblright 0
-KPX L Y -37
-KPX L W -37
-KPX L V -37
-KPX L T -18
-
-KPX N period 0
-KPX N comma 0
-KPX N A -30
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -40
-
-KPX P period -129
-KPX P o -55
-KPX P e -50
-KPX P comma -129
-KPX P a -40
-KPX P A -85
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -18
-KPX R W -18
-KPX R V -18
-KPX R U -40
-KPX R T -30
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -37
-KPX T w -37
-KPX T u -37
-KPX T semicolon -74
-KPX T r -37
-KPX T period -92
-KPX T o -95
-KPX T i -37
-KPX T hyphen -92
-KPX T h 0
-KPX T e -92
-KPX T comma -92
-KPX T colon -74
-KPX T a -92
-KPX T O -18
-KPX T A -55
-
-KPX U period 0
-KPX U comma 0
-KPX U A -45
-
-KPX V u -55
-KPX V semicolon -74
-KPX V period -129
-KPX V o -111
-KPX V i -55
-KPX V hyphen -70
-KPX V e -111
-KPX V comma -129
-KPX V colon -74
-KPX V a -111
-KPX V O -30
-KPX V G -10
-KPX V A -85
-
-KPX W y -55
-KPX W u -55
-KPX W semicolon -55
-KPX W period -74
-KPX W o -80
-KPX W i -37
-KPX W hyphen -50
-KPX W h 0
-KPX W e -90
-KPX W comma -74
-KPX W colon -55
-KPX W a -85
-KPX W O -15
-KPX W A -74
-
-KPX Y u -92
-KPX Y semicolon -92
-KPX Y period -74
-KPX Y o -111
-KPX Y i -55
-KPX Y hyphen -92
-KPX Y e -111
-KPX Y comma -92
-KPX Y colon -92
-KPX Y a -92
-KPX Y O -25
-KPX Y A -74
-
-KPX a y 0
-KPX a w 0
-KPX a v 0
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v 0
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b -10
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k -10
-KPX c h -10
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -95
-KPX comma quotedblright -95
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y 0
-KPX e x 0
-KPX e w 0
-KPX e v 0
-KPX e period 0
-KPX e p 0
-KPX e g 0
-KPX e comma 0
-KPX e b -10
-
-KPX f quoteright 55
-KPX f quotedblright 0
-KPX f period -10
-KPX f o -10
-KPX f l 0
-KPX f i 0
-KPX f f -18
-KPX f e -10
-KPX f dotlessi -30
-KPX f comma -10
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period 0
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a 0
-
-KPX h y 0
-
-KPX i v 0
-
-KPX k y 0
-KPX k o -10
-KPX k e -30
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y -10
-KPX o x -10
-KPX o w -25
-KPX o v -15
-KPX o g 0
-
-KPX p y 0
-
-KPX period quoteright -95
-KPX period quotedblright -95
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A 0
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -74
-KPX quoteleft A 0
-
-KPX quoteright v -15
-KPX quoteright t -37
-KPX quoteright space -74
-KPX quoteright s -74
-KPX quoteright r -15
-KPX quoteright quoteright -74
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -15
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q 0
-KPX r period -65
-KPX r p 0
-KPX r o 0
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen 0
-KPX r g 0
-KPX r e 0
-KPX r d 0
-KPX r comma -65
-KPX r c 0
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -70
-KPX space W -70
-KPX space V -70
-KPX space T 0
-KPX space A -37
-
-KPX v period -37
-KPX v o -15
-KPX v e -15
-KPX v comma -37
-KPX v a 0
-
-KPX w period -37
-KPX w o -15
-KPX w h 0
-KPX w e -10
-KPX w comma -37
-KPX w a -10
-
-KPX x e -10
-
-KPX y period -37
-KPX y o 0
-KPX y e 0
-KPX y comma -37
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 172 207 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 187 207 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 167 207 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 172 207 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 157 192 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 167 207 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 172 207 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 187 207 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 187 207 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 172 207 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 33 207 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 53 207 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 48 207 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 33 207 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 210 207 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 200 207 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 230 207 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 215 207 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 200 207 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 215 207 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 207 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 210 207 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 230 207 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 230 207 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 200 207 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 154 207 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 169 207 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 207 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 84 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 84 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 74 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 74 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 84 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 84 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 46 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 46 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -42 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -37 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -37 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 97 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 69 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 74 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 97 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 102 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 56 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 41 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 13 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Times-Italic.afm b/config/psfonts/Times-Italic.afm
deleted file mode 100644 (file)
index 6d7a003..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Tue Mar 20 13:14:56 1990
-Comment UniqueID 28427
-Comment VMusage 32912 39804
-FontName Times-Italic
-FullName Times Italic
-FamilyName Times
-Weight Medium
-ItalicAngle -15.5
-IsFixedPitch false
-FontBBox -169 -217 1010 883
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 653
-XHeight 441
-Ascender 683
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 39 -11 302 667 ;
-C 34 ; WX 420 ; N quotedbl ; B 144 421 432 666 ;
-C 35 ; WX 500 ; N numbersign ; B 2 0 540 676 ;
-C 36 ; WX 500 ; N dollar ; B 31 -89 497 731 ;
-C 37 ; WX 833 ; N percent ; B 79 -13 790 676 ;
-C 38 ; WX 778 ; N ampersand ; B 76 -18 723 666 ;
-C 39 ; WX 333 ; N quoteright ; B 151 436 290 666 ;
-C 40 ; WX 333 ; N parenleft ; B 42 -181 315 669 ;
-C 41 ; WX 333 ; N parenright ; B 16 -180 289 669 ;
-C 42 ; WX 500 ; N asterisk ; B 128 255 492 666 ;
-C 43 ; WX 675 ; N plus ; B 86 0 590 506 ;
-C 44 ; WX 250 ; N comma ; B -4 -129 135 101 ;
-C 45 ; WX 333 ; N hyphen ; B 49 192 282 255 ;
-C 46 ; WX 250 ; N period ; B 27 -11 138 100 ;
-C 47 ; WX 278 ; N slash ; B -65 -18 386 666 ;
-C 48 ; WX 500 ; N zero ; B 32 -7 497 676 ;
-C 49 ; WX 500 ; N one ; B 49 0 409 676 ;
-C 50 ; WX 500 ; N two ; B 12 0 452 676 ;
-C 51 ; WX 500 ; N three ; B 15 -7 465 676 ;
-C 52 ; WX 500 ; N four ; B 1 0 479 676 ;
-C 53 ; WX 500 ; N five ; B 15 -7 491 666 ;
-C 54 ; WX 500 ; N six ; B 30 -7 521 686 ;
-C 55 ; WX 500 ; N seven ; B 75 -8 537 666 ;
-C 56 ; WX 500 ; N eight ; B 30 -7 493 676 ;
-C 57 ; WX 500 ; N nine ; B 23 -17 492 676 ;
-C 58 ; WX 333 ; N colon ; B 50 -11 261 441 ;
-C 59 ; WX 333 ; N semicolon ; B 27 -129 261 441 ;
-C 60 ; WX 675 ; N less ; B 84 -8 592 514 ;
-C 61 ; WX 675 ; N equal ; B 86 120 590 386 ;
-C 62 ; WX 675 ; N greater ; B 84 -8 592 514 ;
-C 63 ; WX 500 ; N question ; B 132 -12 472 664 ;
-C 64 ; WX 920 ; N at ; B 118 -18 806 666 ;
-C 65 ; WX 611 ; N A ; B -51 0 564 668 ;
-C 66 ; WX 611 ; N B ; B -8 0 588 653 ;
-C 67 ; WX 667 ; N C ; B 66 -18 689 666 ;
-C 68 ; WX 722 ; N D ; B -8 0 700 653 ;
-C 69 ; WX 611 ; N E ; B -1 0 634 653 ;
-C 70 ; WX 611 ; N F ; B 8 0 645 653 ;
-C 71 ; WX 722 ; N G ; B 52 -18 722 666 ;
-C 72 ; WX 722 ; N H ; B -8 0 767 653 ;
-C 73 ; WX 333 ; N I ; B -8 0 384 653 ;
-C 74 ; WX 444 ; N J ; B -6 -18 491 653 ;
-C 75 ; WX 667 ; N K ; B 7 0 722 653 ;
-C 76 ; WX 556 ; N L ; B -8 0 559 653 ;
-C 77 ; WX 833 ; N M ; B -18 0 873 653 ;
-C 78 ; WX 667 ; N N ; B -20 -15 727 653 ;
-C 79 ; WX 722 ; N O ; B 60 -18 699 666 ;
-C 80 ; WX 611 ; N P ; B 0 0 605 653 ;
-C 81 ; WX 722 ; N Q ; B 59 -182 699 666 ;
-C 82 ; WX 611 ; N R ; B -13 0 588 653 ;
-C 83 ; WX 500 ; N S ; B 17 -18 508 667 ;
-C 84 ; WX 556 ; N T ; B 59 0 633 653 ;
-C 85 ; WX 722 ; N U ; B 102 -18 765 653 ;
-C 86 ; WX 611 ; N V ; B 76 -18 688 653 ;
-C 87 ; WX 833 ; N W ; B 71 -18 906 653 ;
-C 88 ; WX 611 ; N X ; B -29 0 655 653 ;
-C 89 ; WX 556 ; N Y ; B 78 0 633 653 ;
-C 90 ; WX 556 ; N Z ; B -6 0 606 653 ;
-C 91 ; WX 389 ; N bracketleft ; B 21 -153 391 663 ;
-C 92 ; WX 278 ; N backslash ; B -41 -18 319 666 ;
-C 93 ; WX 389 ; N bracketright ; B 12 -153 382 663 ;
-C 94 ; WX 422 ; N asciicircum ; B 0 301 422 666 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 171 436 310 666 ;
-C 97 ; WX 500 ; N a ; B 17 -11 476 441 ;
-C 98 ; WX 500 ; N b ; B 23 -11 473 683 ;
-C 99 ; WX 444 ; N c ; B 30 -11 425 441 ;
-C 100 ; WX 500 ; N d ; B 15 -13 527 683 ;
-C 101 ; WX 444 ; N e ; B 31 -11 412 441 ;
-C 102 ; WX 278 ; N f ; B -147 -207 424 678 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 8 -206 472 441 ;
-C 104 ; WX 500 ; N h ; B 19 -9 478 683 ;
-C 105 ; WX 278 ; N i ; B 49 -11 264 654 ;
-C 106 ; WX 278 ; N j ; B -124 -207 276 654 ;
-C 107 ; WX 444 ; N k ; B 14 -11 461 683 ;
-C 108 ; WX 278 ; N l ; B 41 -11 279 683 ;
-C 109 ; WX 722 ; N m ; B 12 -9 704 441 ;
-C 110 ; WX 500 ; N n ; B 14 -9 474 441 ;
-C 111 ; WX 500 ; N o ; B 27 -11 468 441 ;
-C 112 ; WX 500 ; N p ; B -75 -205 469 441 ;
-C 113 ; WX 500 ; N q ; B 25 -209 483 441 ;
-C 114 ; WX 389 ; N r ; B 45 0 412 441 ;
-C 115 ; WX 389 ; N s ; B 16 -13 366 442 ;
-C 116 ; WX 278 ; N t ; B 37 -11 296 546 ;
-C 117 ; WX 500 ; N u ; B 42 -11 475 441 ;
-C 118 ; WX 444 ; N v ; B 21 -18 426 441 ;
-C 119 ; WX 667 ; N w ; B 16 -18 648 441 ;
-C 120 ; WX 444 ; N x ; B -27 -11 447 441 ;
-C 121 ; WX 444 ; N y ; B -24 -206 426 441 ;
-C 122 ; WX 389 ; N z ; B -2 -81 380 428 ;
-C 123 ; WX 400 ; N braceleft ; B 51 -177 407 687 ;
-C 124 ; WX 275 ; N bar ; B 105 -18 171 666 ;
-C 125 ; WX 400 ; N braceright ; B -7 -177 349 687 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
-C 161 ; WX 389 ; N exclamdown ; B 59 -205 322 473 ;
-C 162 ; WX 500 ; N cent ; B 77 -143 472 560 ;
-C 163 ; WX 500 ; N sterling ; B 10 -6 517 670 ;
-C 164 ; WX 167 ; N fraction ; B -169 -10 337 676 ;
-C 165 ; WX 500 ; N yen ; B 27 0 603 653 ;
-C 166 ; WX 500 ; N florin ; B 25 -182 507 682 ;
-C 167 ; WX 500 ; N section ; B 53 -162 461 666 ;
-C 168 ; WX 500 ; N currency ; B -22 53 522 597 ;
-C 169 ; WX 214 ; N quotesingle ; B 132 421 241 666 ;
-C 170 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ;
-C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ;
-C 173 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ;
-C 174 ; WX 500 ; N fi ; B -141 -207 481 681 ;
-C 175 ; WX 500 ; N fl ; B -141 -204 518 682 ;
-C 177 ; WX 500 ; N endash ; B -6 197 505 243 ;
-C 178 ; WX 500 ; N dagger ; B 101 -159 488 666 ;
-C 179 ; WX 500 ; N daggerdbl ; B 22 -143 491 666 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 523 ; N paragraph ; B 55 -123 616 653 ;
-C 183 ; WX 350 ; N bullet ; B 40 191 310 461 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 44 -129 183 101 ;
-C 185 ; WX 556 ; N quotedblbase ; B 57 -129 405 101 ;
-C 186 ; WX 556 ; N quotedblright ; B 151 436 499 666 ;
-C 187 ; WX 500 ; N guillemotright ; B 55 37 447 403 ;
-C 188 ; WX 889 ; N ellipsis ; B 57 -11 762 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 25 -19 1010 706 ;
-C 191 ; WX 500 ; N questiondown ; B 28 -205 368 471 ;
-C 193 ; WX 333 ; N grave ; B 121 492 311 664 ;
-C 194 ; WX 333 ; N acute ; B 180 494 403 664 ;
-C 195 ; WX 333 ; N circumflex ; B 91 492 385 661 ;
-C 196 ; WX 333 ; N tilde ; B 100 517 427 624 ;
-C 197 ; WX 333 ; N macron ; B 99 532 411 583 ;
-C 198 ; WX 333 ; N breve ; B 117 492 418 650 ;
-C 199 ; WX 333 ; N dotaccent ; B 207 508 305 606 ;
-C 200 ; WX 333 ; N dieresis ; B 107 508 405 606 ;
-C 202 ; WX 333 ; N ring ; B 155 492 355 691 ;
-C 203 ; WX 333 ; N cedilla ; B -30 -217 182 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 93 494 486 664 ;
-C 206 ; WX 333 ; N ogonek ; B -20 -169 200 40 ;
-C 207 ; WX 333 ; N caron ; B 121 492 426 661 ;
-C 208 ; WX 889 ; N emdash ; B -6 197 894 243 ;
-C 225 ; WX 889 ; N AE ; B -27 0 911 653 ;
-C 227 ; WX 276 ; N ordfeminine ; B 42 406 352 676 ;
-C 232 ; WX 556 ; N Lslash ; B -8 0 559 653 ;
-C 233 ; WX 722 ; N Oslash ; B 60 -105 699 722 ;
-C 234 ; WX 944 ; N OE ; B 49 -8 964 666 ;
-C 235 ; WX 310 ; N ordmasculine ; B 67 406 362 676 ;
-C 241 ; WX 667 ; N ae ; B 23 -11 640 441 ;
-C 245 ; WX 278 ; N dotlessi ; B 49 -11 235 441 ;
-C 248 ; WX 278 ; N lslash ; B 37 -11 307 683 ;
-C 249 ; WX 500 ; N oslash ; B 28 -135 469 554 ;
-C 250 ; WX 667 ; N oe ; B 20 -12 646 441 ;
-C 251 ; WX 500 ; N germandbls ; B -168 -207 493 679 ;
-C -1 ; WX 556 ; N Zcaron ; B -6 0 606 873 ;
-C -1 ; WX 444 ; N ccedilla ; B 26 -217 425 441 ;
-C -1 ; WX 444 ; N ydieresis ; B -24 -206 441 606 ;
-C -1 ; WX 500 ; N atilde ; B 17 -11 511 624 ;
-C -1 ; WX 278 ; N icircumflex ; B 34 -11 328 661 ;
-C -1 ; WX 300 ; N threesuperior ; B 43 268 339 676 ;
-C -1 ; WX 444 ; N ecircumflex ; B 31 -11 441 661 ;
-C -1 ; WX 500 ; N thorn ; B -75 -205 469 683 ;
-C -1 ; WX 444 ; N egrave ; B 31 -11 412 664 ;
-C -1 ; WX 300 ; N twosuperior ; B 33 271 324 676 ;
-C -1 ; WX 444 ; N eacute ; B 31 -11 459 664 ;
-C -1 ; WX 500 ; N otilde ; B 27 -11 496 624 ;
-C -1 ; WX 611 ; N Aacute ; B -51 0 564 876 ;
-C -1 ; WX 500 ; N ocircumflex ; B 27 -11 468 661 ;
-C -1 ; WX 444 ; N yacute ; B -24 -206 459 664 ;
-C -1 ; WX 500 ; N udieresis ; B 42 -11 479 606 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -10 736 676 ;
-C -1 ; WX 500 ; N acircumflex ; B 17 -11 476 661 ;
-C -1 ; WX 722 ; N Eth ; B -8 0 700 653 ;
-C -1 ; WX 444 ; N edieresis ; B 31 -11 451 606 ;
-C -1 ; WX 500 ; N ugrave ; B 42 -11 475 664 ;
-C -1 ; WX 980 ; N trademark ; B 30 247 957 653 ;
-C -1 ; WX 500 ; N ograve ; B 27 -11 468 664 ;
-C -1 ; WX 389 ; N scaron ; B 16 -13 454 661 ;
-C -1 ; WX 333 ; N Idieresis ; B -8 0 435 818 ;
-C -1 ; WX 500 ; N uacute ; B 42 -11 477 664 ;
-C -1 ; WX 500 ; N agrave ; B 17 -11 476 664 ;
-C -1 ; WX 500 ; N ntilde ; B 14 -9 476 624 ;
-C -1 ; WX 500 ; N aring ; B 17 -11 476 691 ;
-C -1 ; WX 389 ; N zcaron ; B -2 -81 434 661 ;
-C -1 ; WX 333 ; N Icircumflex ; B -8 0 425 873 ;
-C -1 ; WX 667 ; N Ntilde ; B -20 -15 727 836 ;
-C -1 ; WX 500 ; N ucircumflex ; B 42 -11 475 661 ;
-C -1 ; WX 611 ; N Ecircumflex ; B -1 0 634 873 ;
-C -1 ; WX 333 ; N Iacute ; B -8 0 413 876 ;
-C -1 ; WX 667 ; N Ccedilla ; B 66 -217 689 666 ;
-C -1 ; WX 722 ; N Odieresis ; B 60 -18 699 818 ;
-C -1 ; WX 500 ; N Scaron ; B 17 -18 520 873 ;
-C -1 ; WX 611 ; N Edieresis ; B -1 0 634 818 ;
-C -1 ; WX 333 ; N Igrave ; B -8 0 384 876 ;
-C -1 ; WX 500 ; N adieresis ; B 17 -11 489 606 ;
-C -1 ; WX 722 ; N Ograve ; B 60 -18 699 876 ;
-C -1 ; WX 611 ; N Egrave ; B -1 0 634 876 ;
-C -1 ; WX 556 ; N Ydieresis ; B 78 0 633 818 ;
-C -1 ; WX 760 ; N registered ; B 41 -18 719 666 ;
-C -1 ; WX 722 ; N Otilde ; B 60 -18 699 836 ;
-C -1 ; WX 750 ; N onequarter ; B 33 -10 736 676 ;
-C -1 ; WX 722 ; N Ugrave ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 102 -18 765 873 ;
-C -1 ; WX 611 ; N Thorn ; B 0 0 569 653 ;
-C -1 ; WX 675 ; N divide ; B 86 -11 590 517 ;
-C -1 ; WX 611 ; N Atilde ; B -51 0 566 836 ;
-C -1 ; WX 722 ; N Uacute ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 60 -18 699 873 ;
-C -1 ; WX 675 ; N logicalnot ; B 86 108 590 386 ;
-C -1 ; WX 611 ; N Aring ; B -51 0 564 883 ;
-C -1 ; WX 278 ; N idieresis ; B 49 -11 353 606 ;
-C -1 ; WX 278 ; N iacute ; B 49 -11 356 664 ;
-C -1 ; WX 500 ; N aacute ; B 17 -11 487 664 ;
-C -1 ; WX 675 ; N plusminus ; B 86 0 590 506 ;
-C -1 ; WX 675 ; N multiply ; B 93 8 582 497 ;
-C -1 ; WX 722 ; N Udieresis ; B 102 -18 765 818 ;
-C -1 ; WX 675 ; N minus ; B 86 220 590 286 ;
-C -1 ; WX 300 ; N onesuperior ; B 43 271 284 676 ;
-C -1 ; WX 611 ; N Eacute ; B -1 0 634 876 ;
-C -1 ; WX 611 ; N Acircumflex ; B -51 0 564 873 ;
-C -1 ; WX 760 ; N copyright ; B 41 -18 719 666 ;
-C -1 ; WX 611 ; N Agrave ; B -51 0 564 876 ;
-C -1 ; WX 500 ; N odieresis ; B 27 -11 489 606 ;
-C -1 ; WX 500 ; N oacute ; B 27 -11 487 664 ;
-C -1 ; WX 400 ; N degree ; B 101 390 387 676 ;
-C -1 ; WX 278 ; N igrave ; B 49 -11 284 664 ;
-C -1 ; WX 500 ; N mu ; B -30 -209 497 428 ;
-C -1 ; WX 722 ; N Oacute ; B 60 -18 699 876 ;
-C -1 ; WX 500 ; N eth ; B 27 -11 482 683 ;
-C -1 ; WX 611 ; N Adieresis ; B -51 0 564 818 ;
-C -1 ; WX 556 ; N Yacute ; B 78 0 633 876 ;
-C -1 ; WX 275 ; N brokenbar ; B 105 -18 171 666 ;
-C -1 ; WX 750 ; N onehalf ; B 34 -10 749 676 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -55
-KPX A w -55
-KPX A v -55
-KPX A u -20
-KPX A quoteright -37
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -55
-KPX A W -95
-KPX A V -105
-KPX A U -50
-KPX A T -37
-KPX A Q -40
-KPX A O -40
-KPX A G -35
-KPX A C -30
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -25
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -40
-KPX D W -40
-KPX D V -40
-KPX D A -35
-
-KPX F r -55
-KPX F period -135
-KPX F o -105
-KPX F i -45
-KPX F e -75
-KPX F comma -135
-KPX F a -75
-KPX F A -115
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -35
-KPX J period -25
-KPX J o -25
-KPX J e -25
-KPX J comma -25
-KPX J a -35
-KPX J A -40
-
-KPX K y -40
-KPX K u -40
-KPX K o -40
-KPX K e -35
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -37
-KPX L quotedblright 0
-KPX L Y -20
-KPX L W -55
-KPX L V -55
-KPX L T -20
-
-KPX N period 0
-KPX N comma 0
-KPX N A -27
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -55
-
-KPX P period -135
-KPX P o -80
-KPX P e -80
-KPX P comma -135
-KPX P a -80
-KPX P A -90
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -18
-KPX R W -18
-KPX R V -18
-KPX R U -40
-KPX R T 0
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -74
-KPX T w -74
-KPX T u -55
-KPX T semicolon -65
-KPX T r -55
-KPX T period -74
-KPX T o -92
-KPX T i -55
-KPX T hyphen -74
-KPX T h 0
-KPX T e -92
-KPX T comma -74
-KPX T colon -55
-KPX T a -92
-KPX T O -18
-KPX T A -50
-
-KPX U period -25
-KPX U comma -25
-KPX U A -40
-
-KPX V u -74
-KPX V semicolon -74
-KPX V period -129
-KPX V o -111
-KPX V i -74
-KPX V hyphen -55
-KPX V e -111
-KPX V comma -129
-KPX V colon -65
-KPX V a -111
-KPX V O -30
-KPX V G 0
-KPX V A -60
-
-KPX W y -70
-KPX W u -55
-KPX W semicolon -65
-KPX W period -92
-KPX W o -92
-KPX W i -55
-KPX W hyphen -37
-KPX W h 0
-KPX W e -92
-KPX W comma -92
-KPX W colon -65
-KPX W a -92
-KPX W O -25
-KPX W A -60
-
-KPX Y u -92
-KPX Y semicolon -65
-KPX Y period -92
-KPX Y o -92
-KPX Y i -74
-KPX Y hyphen -74
-KPX Y e -92
-KPX Y comma -92
-KPX Y colon -65
-KPX Y a -92
-KPX Y O -15
-KPX Y A -50
-
-KPX a y 0
-KPX a w 0
-KPX a v 0
-KPX a t 0
-KPX a p 0
-KPX a g -10
-KPX a b 0
-
-KPX b y 0
-KPX b v 0
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b 0
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k -20
-KPX c h -15
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -140
-KPX comma quotedblright -140
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y -30
-KPX e x -20
-KPX e w -15
-KPX e v -15
-KPX e period -15
-KPX e p 0
-KPX e g -40
-KPX e comma -10
-KPX e b 0
-
-KPX f quoteright 92
-KPX f quotedblright 0
-KPX f period -15
-KPX f o 0
-KPX f l 0
-KPX f i -20
-KPX f f -18
-KPX f e 0
-KPX f dotlessi -60
-KPX f comma -10
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period -15
-KPX g o 0
-KPX g i 0
-KPX g g -10
-KPX g e -10
-KPX g comma -10
-KPX g a 0
-
-KPX h y 0
-
-KPX i v 0
-
-KPX k y -10
-KPX k o -10
-KPX k e -10
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y 0
-KPX o x 0
-KPX o w 0
-KPX o v -10
-KPX o g -10
-
-KPX p y 0
-
-KPX period quoteright -140
-KPX period quotedblright -140
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A 0
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -111
-KPX quoteleft A 0
-
-KPX quoteright v -10
-KPX quoteright t -30
-KPX quoteright space -111
-KPX quoteright s -40
-KPX quoteright r -25
-KPX quoteright quoteright -111
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -25
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s -10
-KPX r r 0
-KPX r q -37
-KPX r period -111
-KPX r p 0
-KPX r o -45
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -20
-KPX r g -37
-KPX r e -37
-KPX r d -37
-KPX r comma -111
-KPX r c -37
-KPX r a -15
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -75
-KPX space W -40
-KPX space V -35
-KPX space T -18
-KPX space A -18
-
-KPX v period -74
-KPX v o 0
-KPX v e 0
-KPX v comma -74
-KPX v a 0
-
-KPX w period -74
-KPX w o 0
-KPX w h 0
-KPX w e 0
-KPX w comma -74
-KPX w a 0
-
-KPX x e 0
-
-KPX y period -55
-KPX y o 0
-KPX y e 0
-KPX y comma -55
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 139 212 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 144 212 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 139 212 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 149 212 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 129 192 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 139 212 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 149 212 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 169 212 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 159 212 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 149 212 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 10 212 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 40 212 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 30 212 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 10 212 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 177 212 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 195 212 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 230 212 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 230 212 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 205 212 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 215 212 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 94 212 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 212 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 215 212 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 225 212 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 215 212 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 132 212 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 142 212 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 112 212 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 84 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 84 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 84 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 84 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 84 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 84 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 46 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 56 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -47 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -57 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -52 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 49 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 74 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 69 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 74 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 74 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 74 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 84 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 56 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 36 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 8 0 ;
-EndComposites
-EndFontMetrics
diff --git a/config/psfonts/Times-Roman.afm b/config/psfonts/Times-Roman.afm
deleted file mode 100644 (file)
index e5092b5..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.
-Comment Creation Date: Tue Mar 20 12:15:44 1990
-Comment UniqueID 28416
-Comment VMusage 30487 37379
-FontName Times-Roman
-FullName Times Roman
-FamilyName Times
-Weight Roman
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -168 -218 1000 898
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated.  All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 662
-XHeight 450
-Ascender 683
-Descender -217
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 130 -9 238 676 ;
-C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ;
-C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ;
-C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ;
-C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ;
-C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ;
-C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ;
-C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ;
-C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ;
-C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ;
-C 43 ; WX 564 ; N plus ; B 30 0 534 506 ;
-C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ;
-C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ;
-C 46 ; WX 250 ; N period ; B 70 -11 181 100 ;
-C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ;
-C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ;
-C 49 ; WX 500 ; N one ; B 111 0 394 676 ;
-C 50 ; WX 500 ; N two ; B 30 0 475 676 ;
-C 51 ; WX 500 ; N three ; B 43 -14 431 676 ;
-C 52 ; WX 500 ; N four ; B 12 0 472 676 ;
-C 53 ; WX 500 ; N five ; B 32 -14 438 688 ;
-C 54 ; WX 500 ; N six ; B 34 -14 468 684 ;
-C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ;
-C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ;
-C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ;
-C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ;
-C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ;
-C 60 ; WX 564 ; N less ; B 28 -8 536 514 ;
-C 61 ; WX 564 ; N equal ; B 30 120 534 386 ;
-C 62 ; WX 564 ; N greater ; B 28 -8 536 514 ;
-C 63 ; WX 444 ; N question ; B 68 -8 414 676 ;
-C 64 ; WX 921 ; N at ; B 116 -14 809 676 ;
-C 65 ; WX 722 ; N A ; B 15 0 706 674 ;
-C 66 ; WX 667 ; N B ; B 17 0 593 662 ;
-C 67 ; WX 667 ; N C ; B 28 -14 633 676 ;
-C 68 ; WX 722 ; N D ; B 16 0 685 662 ;
-C 69 ; WX 611 ; N E ; B 12 0 597 662 ;
-C 70 ; WX 556 ; N F ; B 12 0 546 662 ;
-C 71 ; WX 722 ; N G ; B 32 -14 709 676 ;
-C 72 ; WX 722 ; N H ; B 19 0 702 662 ;
-C 73 ; WX 333 ; N I ; B 18 0 315 662 ;
-C 74 ; WX 389 ; N J ; B 10 -14 370 662 ;
-C 75 ; WX 722 ; N K ; B 34 0 723 662 ;
-C 76 ; WX 611 ; N L ; B 12 0 598 662 ;
-C 77 ; WX 889 ; N M ; B 12 0 863 662 ;
-C 78 ; WX 722 ; N N ; B 12 -11 707 662 ;
-C 79 ; WX 722 ; N O ; B 34 -14 688 676 ;
-C 80 ; WX 556 ; N P ; B 16 0 542 662 ;
-C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ;
-C 82 ; WX 667 ; N R ; B 17 0 659 662 ;
-C 83 ; WX 556 ; N S ; B 42 -14 491 676 ;
-C 84 ; WX 611 ; N T ; B 17 0 593 662 ;
-C 85 ; WX 722 ; N U ; B 14 -14 705 662 ;
-C 86 ; WX 722 ; N V ; B 16 -11 697 662 ;
-C 87 ; WX 944 ; N W ; B 5 -11 932 662 ;
-C 88 ; WX 722 ; N X ; B 10 0 704 662 ;
-C 89 ; WX 722 ; N Y ; B 22 0 703 662 ;
-C 90 ; WX 611 ; N Z ; B 9 0 597 662 ;
-C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ;
-C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ;
-C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ;
-C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ;
-C 97 ; WX 444 ; N a ; B 37 -10 442 460 ;
-C 98 ; WX 500 ; N b ; B 3 -10 468 683 ;
-C 99 ; WX 444 ; N c ; B 25 -10 412 460 ;
-C 100 ; WX 500 ; N d ; B 27 -10 491 683 ;
-C 101 ; WX 444 ; N e ; B 25 -10 424 460 ;
-C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 28 -218 470 460 ;
-C 104 ; WX 500 ; N h ; B 9 0 487 683 ;
-C 105 ; WX 278 ; N i ; B 16 0 253 683 ;
-C 106 ; WX 278 ; N j ; B -70 -218 194 683 ;
-C 107 ; WX 500 ; N k ; B 7 0 505 683 ;
-C 108 ; WX 278 ; N l ; B 19 0 257 683 ;
-C 109 ; WX 778 ; N m ; B 16 0 775 460 ;
-C 110 ; WX 500 ; N n ; B 16 0 485 460 ;
-C 111 ; WX 500 ; N o ; B 29 -10 470 460 ;
-C 112 ; WX 500 ; N p ; B 5 -217 470 460 ;
-C 113 ; WX 500 ; N q ; B 24 -217 488 460 ;
-C 114 ; WX 333 ; N r ; B 5 0 335 460 ;
-C 115 ; WX 389 ; N s ; B 51 -10 348 460 ;
-C 116 ; WX 278 ; N t ; B 13 -10 279 579 ;
-C 117 ; WX 500 ; N u ; B 9 -10 479 450 ;
-C 118 ; WX 500 ; N v ; B 19 -14 477 450 ;
-C 119 ; WX 722 ; N w ; B 21 -14 694 450 ;
-C 120 ; WX 500 ; N x ; B 17 0 479 450 ;
-C 121 ; WX 500 ; N y ; B 14 -218 475 450 ;
-C 122 ; WX 444 ; N z ; B 27 0 418 450 ;
-C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ;
-C 124 ; WX 200 ; N bar ; B 67 -14 133 676 ;
-C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
-C 161 ; WX 333 ; N exclamdown ; B 97 -218 205 467 ;
-C 162 ; WX 500 ; N cent ; B 53 -138 448 579 ;
-C 163 ; WX 500 ; N sterling ; B 12 -8 490 676 ;
-C 164 ; WX 167 ; N fraction ; B -168 -14 331 676 ;
-C 165 ; WX 500 ; N yen ; B -53 0 512 662 ;
-C 166 ; WX 500 ; N florin ; B 7 -189 490 676 ;
-C 167 ; WX 500 ; N section ; B 70 -148 426 676 ;
-C 168 ; WX 500 ; N currency ; B -22 58 522 602 ;
-C 169 ; WX 180 ; N quotesingle ; B 48 431 133 676 ;
-C 170 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ;
-C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ;
-C 173 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ;
-C 174 ; WX 556 ; N fi ; B 31 0 521 683 ;
-C 175 ; WX 556 ; N fl ; B 32 0 521 683 ;
-C 177 ; WX 500 ; N endash ; B 0 201 500 250 ;
-C 178 ; WX 500 ; N dagger ; B 59 -149 442 676 ;
-C 179 ; WX 500 ; N daggerdbl ; B 58 -153 442 676 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 453 ; N paragraph ; B -22 -154 450 662 ;
-C 183 ; WX 350 ; N bullet ; B 40 196 310 466 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -141 218 102 ;
-C 185 ; WX 444 ; N quotedblbase ; B 45 -141 416 102 ;
-C 186 ; WX 444 ; N quotedblright ; B 30 433 401 676 ;
-C 187 ; WX 500 ; N guillemotright ; B 44 33 458 416 ;
-C 188 ; WX 1000 ; N ellipsis ; B 111 -11 888 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 706 ;
-C 191 ; WX 444 ; N questiondown ; B 30 -218 376 466 ;
-C 193 ; WX 333 ; N grave ; B 19 507 242 678 ;
-C 194 ; WX 333 ; N acute ; B 93 507 317 678 ;
-C 195 ; WX 333 ; N circumflex ; B 11 507 322 674 ;
-C 196 ; WX 333 ; N tilde ; B 1 532 331 638 ;
-C 197 ; WX 333 ; N macron ; B 11 547 322 601 ;
-C 198 ; WX 333 ; N breve ; B 26 507 307 664 ;
-C 199 ; WX 333 ; N dotaccent ; B 118 523 216 623 ;
-C 200 ; WX 333 ; N dieresis ; B 18 523 315 623 ;
-C 202 ; WX 333 ; N ring ; B 67 512 266 711 ;
-C 203 ; WX 333 ; N cedilla ; B 52 -215 261 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -3 507 377 678 ;
-C 206 ; WX 333 ; N ogonek ; B 64 -165 249 0 ;
-C 207 ; WX 333 ; N caron ; B 11 507 322 674 ;
-C 208 ; WX 1000 ; N emdash ; B 0 201 1000 250 ;
-C 225 ; WX 889 ; N AE ; B 0 0 863 662 ;
-C 227 ; WX 276 ; N ordfeminine ; B 4 394 270 676 ;
-C 232 ; WX 611 ; N Lslash ; B 12 0 598 662 ;
-C 233 ; WX 722 ; N Oslash ; B 34 -80 688 734 ;
-C 234 ; WX 889 ; N OE ; B 30 -6 885 668 ;
-C 235 ; WX 310 ; N ordmasculine ; B 6 394 304 676 ;
-C 241 ; WX 667 ; N ae ; B 38 -10 632 460 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 253 460 ;
-C 248 ; WX 278 ; N lslash ; B 19 0 259 683 ;
-C 249 ; WX 500 ; N oslash ; B 29 -112 470 551 ;
-C 250 ; WX 722 ; N oe ; B 30 -10 690 460 ;
-C 251 ; WX 500 ; N germandbls ; B 12 -9 468 683 ;
-C -1 ; WX 611 ; N Zcaron ; B 9 0 597 886 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -215 412 460 ;
-C -1 ; WX 500 ; N ydieresis ; B 14 -218 475 623 ;
-C -1 ; WX 444 ; N atilde ; B 37 -10 442 638 ;
-C -1 ; WX 278 ; N icircumflex ; B -16 0 295 674 ;
-C -1 ; WX 300 ; N threesuperior ; B 15 262 291 676 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -10 424 674 ;
-C -1 ; WX 500 ; N thorn ; B 5 -217 470 683 ;
-C -1 ; WX 444 ; N egrave ; B 25 -10 424 678 ;
-C -1 ; WX 300 ; N twosuperior ; B 1 270 296 676 ;
-C -1 ; WX 444 ; N eacute ; B 25 -10 424 678 ;
-C -1 ; WX 500 ; N otilde ; B 29 -10 470 638 ;
-C -1 ; WX 722 ; N Aacute ; B 15 0 706 890 ;
-C -1 ; WX 500 ; N ocircumflex ; B 29 -10 470 674 ;
-C -1 ; WX 500 ; N yacute ; B 14 -218 475 678 ;
-C -1 ; WX 500 ; N udieresis ; B 9 -10 479 623 ;
-C -1 ; WX 750 ; N threequarters ; B 15 -14 718 676 ;
-C -1 ; WX 444 ; N acircumflex ; B 37 -10 442 674 ;
-C -1 ; WX 722 ; N Eth ; B 16 0 685 662 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -10 424 623 ;
-C -1 ; WX 500 ; N ugrave ; B 9 -10 479 678 ;
-C -1 ; WX 980 ; N trademark ; B 30 256 957 662 ;
-C -1 ; WX 500 ; N ograve ; B 29 -10 470 678 ;
-C -1 ; WX 389 ; N scaron ; B 39 -10 350 674 ;
-C -1 ; WX 333 ; N Idieresis ; B 18 0 315 835 ;
-C -1 ; WX 500 ; N uacute ; B 9 -10 479 678 ;
-C -1 ; WX 444 ; N agrave ; B 37 -10 442 678 ;
-C -1 ; WX 500 ; N ntilde ; B 16 0 485 638 ;
-C -1 ; WX 444 ; N aring ; B 37 -10 442 711 ;
-C -1 ; WX 444 ; N zcaron ; B 27 0 418 674 ;
-C -1 ; WX 333 ; N Icircumflex ; B 11 0 322 886 ;
-C -1 ; WX 722 ; N Ntilde ; B 12 -11 707 850 ;
-C -1 ; WX 500 ; N ucircumflex ; B 9 -10 479 674 ;
-C -1 ; WX 611 ; N Ecircumflex ; B 12 0 597 886 ;
-C -1 ; WX 333 ; N Iacute ; B 18 0 317 890 ;
-C -1 ; WX 667 ; N Ccedilla ; B 28 -215 633 676 ;
-C -1 ; WX 722 ; N Odieresis ; B 34 -14 688 835 ;
-C -1 ; WX 556 ; N Scaron ; B 42 -14 491 886 ;
-C -1 ; WX 611 ; N Edieresis ; B 12 0 597 835 ;
-C -1 ; WX 333 ; N Igrave ; B 18 0 315 890 ;
-C -1 ; WX 444 ; N adieresis ; B 37 -10 442 623 ;
-C -1 ; WX 722 ; N Ograve ; B 34 -14 688 890 ;
-C -1 ; WX 611 ; N Egrave ; B 12 0 597 890 ;
-C -1 ; WX 722 ; N Ydieresis ; B 22 0 703 835 ;
-C -1 ; WX 760 ; N registered ; B 38 -14 722 676 ;
-C -1 ; WX 722 ; N Otilde ; B 34 -14 688 850 ;
-C -1 ; WX 750 ; N onequarter ; B 37 -14 718 676 ;
-C -1 ; WX 722 ; N Ugrave ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 14 -14 705 886 ;
-C -1 ; WX 556 ; N Thorn ; B 16 0 542 662 ;
-C -1 ; WX 564 ; N divide ; B 30 -10 534 516 ;
-C -1 ; WX 722 ; N Atilde ; B 15 0 706 850 ;
-C -1 ; WX 722 ; N Uacute ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 34 -14 688 886 ;
-C -1 ; WX 564 ; N logicalnot ; B 30 108 534 386 ;
-C -1 ; WX 722 ; N Aring ; B 15 0 706 898 ;
-C -1 ; WX 278 ; N idieresis ; B -9 0 288 623 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 678 ;
-C -1 ; WX 444 ; N aacute ; B 37 -10 442 678 ;
-C -1 ; WX 564 ; N plusminus ; B 30 0 534 506 ;
-C -1 ; WX 564 ; N multiply ; B 38 8 527 497 ;
-C -1 ; WX 722 ; N Udieresis ; B 14 -14 705 835 ;
-C -1 ; WX 564 ; N minus ; B 30 220 534 286 ;
-C -1 ; WX 300 ; N onesuperior ; B 57 270 248 676 ;
-C -1 ; WX 611 ; N Eacute ; B 12 0 597 890 ;
-C -1 ; WX 722 ; N Acircumflex ; B 15 0 706 886 ;
-C -1 ; WX 760 ; N copyright ; B 38 -14 722 676 ;
-C -1 ; WX 722 ; N Agrave ; B 15 0 706 890 ;
-C -1 ; WX 500 ; N odieresis ; B 29 -10 470 623 ;
-C -1 ; WX 500 ; N oacute ; B 29 -10 470 678 ;
-C -1 ; WX 400 ; N degree ; B 57 390 343 676 ;
-C -1 ; WX 278 ; N igrave ; B -8 0 253 678 ;
-C -1 ; WX 500 ; N mu ; B 36 -218 512 450 ;
-C -1 ; WX 722 ; N Oacute ; B 34 -14 688 890 ;
-C -1 ; WX 500 ; N eth ; B 29 -10 471 686 ;
-C -1 ; WX 722 ; N Adieresis ; B 15 0 706 835 ;
-C -1 ; WX 722 ; N Yacute ; B 22 0 703 890 ;
-C -1 ; WX 200 ; N brokenbar ; B 67 -14 133 676 ;
-C -1 ; WX 750 ; N onehalf ; B 31 -14 746 676 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -92
-KPX A w -92
-KPX A v -74
-KPX A u 0
-KPX A quoteright -111
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -105
-KPX A W -90
-KPX A V -135
-KPX A U -55
-KPX A T -111
-KPX A Q -55
-KPX A O -55
-KPX A G -40
-KPX A C -40
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -35
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -55
-KPX D W -30
-KPX D V -40
-KPX D A -40
-
-KPX F r 0
-KPX F period -80
-KPX F o -15
-KPX F i 0
-KPX F e 0
-KPX F comma -80
-KPX F a -15
-KPX F A -74
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u 0
-KPX J period 0
-KPX J o 0
-KPX J e 0
-KPX J comma 0
-KPX J a 0
-KPX J A -60
-
-KPX K y -25
-KPX K u -15
-KPX K o -35
-KPX K e -25
-KPX K O -30
-
-KPX L y -55
-KPX L quoteright -92
-KPX L quotedblright 0
-KPX L Y -100
-KPX L W -74
-KPX L V -100
-KPX L T -92
-
-KPX N period 0
-KPX N comma 0
-KPX N A -35
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -35
-KPX O V -50
-KPX O T -40
-KPX O A -35
-
-KPX P period -111
-KPX P o 0
-KPX P e 0
-KPX P comma -111
-KPX P a -15
-KPX P A -92
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -65
-KPX R W -55
-KPX R V -80
-KPX R U -40
-KPX R T -60
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -80
-KPX T w -80
-KPX T u -45
-KPX T semicolon -55
-KPX T r -35
-KPX T period -74
-KPX T o -80
-KPX T i -35
-KPX T hyphen -92
-KPX T h 0
-KPX T e -70
-KPX T comma -74
-KPX T colon -50
-KPX T a -80
-KPX T O -18
-KPX T A -93
-
-KPX U period 0
-KPX U comma 0
-KPX U A -40
-
-KPX V u -75
-KPX V semicolon -74
-KPX V period -129
-KPX V o -129
-KPX V i -60
-KPX V hyphen -100
-KPX V e -111
-KPX V comma -129
-KPX V colon -74
-KPX V a -111
-KPX V O -40
-KPX V G -15
-KPX V A -135
-
-KPX W y -73
-KPX W u -50
-KPX W semicolon -37
-KPX W period -92
-KPX W o -80
-KPX W i -40
-KPX W hyphen -65
-KPX W h 0
-KPX W e -80
-KPX W comma -92
-KPX W colon -37
-KPX W a -80
-KPX W O -10
-KPX W A -120
-
-KPX Y u -111
-KPX Y semicolon -92
-KPX Y period -129
-KPX Y o -110
-KPX Y i -55
-KPX Y hyphen -111
-KPX Y e -100
-KPX Y comma -129
-KPX Y colon -92
-KPX Y a -100
-KPX Y O -30
-KPX Y A -120
-
-KPX a y 0
-KPX a w -15
-KPX a v -20
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v -15
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b 0
-
-KPX c y -15
-KPX c period 0
-KPX c l 0
-KPX c k 0
-KPX c h 0
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -70
-KPX comma quotedblright -70
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y -15
-KPX e x -15
-KPX e w -25
-KPX e v -25
-KPX e period 0
-KPX e p 0
-KPX e g -15
-KPX e comma 0
-KPX e b 0
-
-KPX f quoteright 55
-KPX f quotedblright 0
-KPX f period 0
-KPX f o 0
-KPX f l 0
-KPX f i -20
-KPX f f -25
-KPX f e 0
-KPX f dotlessi -50
-KPX f comma 0
-KPX f a -10
-
-KPX g y 0
-KPX g r 0
-KPX g period 0
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a -5
-
-KPX h y -5
-
-KPX i v -25
-
-KPX k y -15
-KPX k o -10
-KPX k e -10
-
-KPX l y 0
-KPX l w -10
-
-KPX m y 0
-KPX m u 0
-
-KPX n y -15
-KPX n v -40
-KPX n u 0
-
-KPX o y -10
-KPX o x 0
-KPX o w -25
-KPX o v -15
-KPX o g 0
-
-KPX p y -10
-
-KPX period quoteright -70
-KPX period quotedblright -70
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A -80
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -74
-KPX quoteleft A -80
-
-KPX quoteright v -50
-KPX quoteright t -18
-KPX quoteright space -74
-KPX quoteright s -55
-KPX quoteright r -50
-KPX quoteright quoteright -74
-KPX quoteright quotedblright 0
-KPX quoteright l -10
-KPX quoteright d -50
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q 0
-KPX r period -55
-KPX r p 0
-KPX r o 0
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -20
-KPX r g -18
-KPX r e 0
-KPX r d 0
-KPX r comma -40
-KPX r c 0
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -90
-KPX space W -30
-KPX space V -50
-KPX space T -18
-KPX space A -55
-
-KPX v period -65
-KPX v o -20
-KPX v e -15
-KPX v comma -65
-KPX v a -25
-
-KPX w period -65
-KPX w o -10
-KPX w h 0
-KPX w e 0
-KPX w comma -65
-KPX w a -10
-
-KPX x e -15
-
-KPX y period -65
-KPX y o 0
-KPX y e 0
-KPX y comma -65
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 195 212 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 195 212 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 195 212 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 195 212 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 185 187 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 195 212 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 139 212 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 139 212 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 139 212 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 139 212 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 212 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 212 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 212 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 212 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 212 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 195 212 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 195 212 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 195 212 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 195 212 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 195 212 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 212 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 212 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 212 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 212 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 212 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 195 212 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 195 212 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 212 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 56 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 56 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 56 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 56 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 56 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 56 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 56 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 56 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 84 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 84 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 84 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 84 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 84 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 56 0 ;
-EndComposites
-EndFontMetrics
index dad55e2cb032ad1b0e7ef5f57504eadfb72f2672..e5eb13a9ada57ffbfa7426469005cb4207593709 100644 (file)
@@ -1,9 +1,10 @@
 dnl Process this file with autoconf to produce a configure script.
 
 dnl Initialize.
-AC_PREREQ(2.60)
-AC_INIT([pspp],[0.7.2],[bug-gnu-pspp@gnu.org])
+AC_PREREQ(2.63)
+AC_INIT([GNU PSPP], [0.7.3], [bug-gnu-pspp@gnu.org], [pspp])
 AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_TESTDIR([tests])
 AM_INIT_AUTOMAKE
 
 dnl Checks for programs.
@@ -41,29 +42,41 @@ dnl Checks for libraries.
 AC_SYS_LARGEFILE
 AC_SEARCH_LIBS([sin], [m])
 AC_SEARCH_LIBS([dcgettext], [intl])
-PSPP_LIBPLOT
 PSPP_LC_PAPER
-AM_CONDITIONAL(WITHCHARTS, test x"$with_libplot" != x"no")
 
 
 AC_ARG_VAR([PSPP_LDFLAGS], [linker flags to be used for linking the pspp binary only])
 AC_ARG_VAR([PSPPIRE_LDFLAGS], [linker flags to be used for linking the psppire binary only])
 
-
-AC_ARG_WITH(
-  gui, 
-  [AS_HELP_STRING([--without-gui], [don't build the PSPPIRE gui])])
-
-required_gtk_version=2.12
-
-if test x"$with_gui" != x"no" ; then 
-  PKG_CHECK_MODULES(GTK, gtk+-2.0 >= $required_gtk_version,,
-    [PSPP_REQUIRED_PREREQ([gtk+ 2.0 v$required_gtk_version or later (or use --without-gui)])])
+# Support for Cairo and Pango.
+AC_ARG_WITH([cairo],
+  [AS_HELP_STRING(
+    [--without-cairo], 
+    [Don't build support for charts (using Cairo and Pango);
+     implies --without-gui])],
+  [], [with_cairo=yes])
+AM_CONDITIONAL([HAVE_CAIRO], [test "$with_cairo" != no])
+if test "$with_cairo" != no; then
+  PKG_CHECK_MODULES([CAIRO], [cairo >= 1.5 pango >= 1.20 pangocairo], 
+    [CPPFLAGS="$CPPFLAGS $CAIRO_CFLAGS"
+     AC_DEFINE([HAVE_CAIRO], 1, 
+       [Define to 1 if Cairo and Pango are available.])],
+    [PSPP_REQUIRED_PREREQ([cairo 1.5 or later and pango 1.20 or later (or use --without-cairo)])])
   AC_PATH_PROG([XMLLINT], [xmllint], [echo], [$PATH])
   AC_SUBST(XMLLINT)
 fi
-AM_CONDITIONAL(WITHGUI, test x"$with_gui" != x"no")
 
+# Support for GUI.
+AC_ARG_WITH([gui], 
+  [AS_HELP_STRING([--without-gui], 
+                  [Don't build the PSPPIRE GUI (using GTK+)])],
+  [], [with_gui=yes])
+AM_CONDITIONAL([HAVE_GUI], 
+               [test "$with_cairo" != no && test "$with_gui" != "no"])
+if test "$with_cairo" != no && test "$with_gui" != "no"; then
+  PKG_CHECK_MODULES([GTK], [gtk+-2.0 >= 2.12], [],
+    [PSPP_REQUIRED_PREREQ([gtk+ 2.0 version 2.12 or later (or use --without-gui)])])
+fi
 
 dnl Checks needed for psql reader
 
@@ -216,7 +229,7 @@ RELOCATABLE_STRIP=:
 
 PSPP_CHECK_PREREQS
 
-AC_CONFIG_FILES([Makefile gl/Makefile])
+AC_CONFIG_FILES([Makefile gl/Makefile tests/atlocal])
 
 AC_OUTPUT
 echo "PSPP configured successfully."
index 504fb8a7bd7522ef1a74335d5392f60087f5c387..7645925bddf83cb65de71550ea5ff1fcd3d540d5 100644 (file)
@@ -6,7 +6,6 @@ doc_pspp_TEXINFOS = doc/version.texi \
        doc/bugs.texi \
        doc/command-index.texi \
        doc/concept-index.texi \
-       doc/configuring.texi \
        doc/data-io.texi \
        doc/data-selection.texi \
        doc/expressions.texi \
diff --git a/doc/configuring.texi b/doc/configuring.texi
deleted file mode 100644 (file)
index 164d9ab..0000000
+++ /dev/null
@@ -1,897 +0,0 @@
-@node Configuration
-@appendix Configuring PSPP
-@cindex configuration
-@cindex PSPP, configuring
-
-This chapter describe how to configure PSPP for your system.
-
-@menu
-* File locations::              How PSPP finds config files.
-* Configuration techniques::    Many different methods of configuration...
-* Configuration files::         How configuration files are read.
-* Environment variables::       All about environment variables.
-* Output devices::              Describing your terminal(s) and printer(s).
-* PostScript driver class::     Configuration of PostScript devices.
-* ASCII driver class::          Configuration of character-code devices.
-* HTML driver class::           Configuration for HTML output.
-* Miscellaneous configuring::   Even more configuration variables.
-@end menu
-
-@node File locations
-@section Locating configuration files
-
-PSPP searches each directory in the configuration file path for most
-configuration files.  The default configuration file path searches first
-@file{$HOME/.pspp}, then the package system configuration directory (usually
-@file{/usr/local/etc/pspp} or @file{/etc/pspp}).  The value of
-environment variable @env{PSPP_CONFIG_PATH}, if defined, overrides this
-default path.  Finally, @samp{-B @var{path}} or
-@samp{--config-dir=@var{path}} specified on the command line has highest
-priority.
-
-@node Configuration techniques
-@section Configuration techniques
-
-There are many ways that PSPP can be configured.  These are
-described in the list below.  Values given by earlier items take
-precedence over those given by later items.
-
-@enumerate
-@item
-Syntax commands that modify settings, such as @cmd{SET}.  @xref{SET}.
-
-@item
-Command-line options.  @xref{Invocation}.
-
-@item
-PSPP-specific environment variable contents.  @xref{Environment
-variables}.
-
-@item
-General environment variable contents.  @xref{Environment variables}.
-
-@item
-Configuration file contents.  @xref{Configuration files}.
-
-@item
-Fallback defaults.
-@end enumerate
-
-Some of the above may not apply to a particular setting.
-
-@node Configuration files
-@section Configuration files
-
-Most configuration files have a common form:
-
-@itemize @bullet
-@item
-Each line forms a separate command or directive.  This means that lines
-cannot be broken up, unless they are spliced together with a trailing
-backslash, as described below.
-
-@item
-Before anything else is done, trailing white space is removed.
-
-@item
-When a line ends in a backslash (@samp{\}), the backslash is removed,
-and the next line is read and appended to the current line.
-
-@itemize @minus
-@item
-White space preceding the backslash is retained.
-
-@item
-This rule continues to be applied until the line read does not end in a
-backslash.
-
-@item
-It is an error if the last line in the file ends in a backslash.
-@end itemize
-
-@item
-Comments are introduced by an octothorpe (@samp{#}), and continue until the
-end of the line.
-
-@itemize @minus
-@item
-An octothorpe inside balanced pairs of double quotation marks (@samp{"})
-or single quotation marks (@samp{'}) does not introduce a comment.
-
-@item
-The backslash character can be used inside balanced quotes of either
-type to escape the following character as a literal character.  
-
-(This is distinct from the use of a backslash as a line-splicing
-character.)
-
-@item
-Line splicing takes place before comment removal.
-@end itemize
-
-@item
-Blank lines, and lines that contain only white space, are ignored.
-@end itemize
-
-@node Environment variables
-@section Environment variables
-
-You may think the concept of environment variables is a fairly simple
-one.  However, the author of PSPP has found a way to complicate
-even something so simple.  Environment variables are further described
-in the sections below:
-
-@menu
-* Environment substitutions::   How environment substitutions are made.
-* Predefined variables::        A few variables are automatically defined.
-@end menu
-
-@node Environment substitutions
-@subsection Environment substitutions
-
-Much of the power of environment variables lies in the way that they may
-be substituted into configuration files.  Variable substitutions are
-described below.
-
-The line is scanned from left to right.  In this scan, all characters
-other than dollar signs (@samp{$}) are retained without change.  Dollar
-signs introduce environment variable references.  References
-take three forms:
-
-@table @code
-@item $@var{var}
-Replaced by the value of environment variable @var{var}.  @var{var} must
-consist of either one or more letters, or exactly one non-alphabetic
-character other than a left brace (@samp{@{}).
-
-@item $@{@var{var}@}
-Same as above, but @var{var} may contain any character (except
-@samp{@}}).
-
-@item $$
-Replaced by a single dollar sign.
-@end table
-
-Undefined variables expand to a empty value.
-
-@node Predefined variables
-@subsection Predefined environment variables
-
-There are two environment variables predefined for use in environment
-substitutions:
-
-@table @samp
-@item VER
-Defined as the version number of PSPP, as a string, in a format
-something like @samp{0.9.4}.
-
-@item ARCH
-Defined as the host architecture of PSPP, as a string, in standard
-cpu-manufacturer-OS format.  For instance, Debian GNU/Linux 1.1 on an
-Intel machine defines this as @samp{i586-unknown-linux}.  This is
-somewhat dependent on the system used to compile PSPP.
-@end table
-
-Nothing prevents these values from being overridden, although it's a
-good idea not to do so.
-
-@node Output devices
-@section Output devices
-
-Configuring output devices is the most complicated aspect of configuring
-PSPP.  The output device configuration file is named
-@file{devices}.  It is searched for using the usual algorithm for
-finding configuration files (@pxref{File locations}).  Each line in the
-file is read in the usual manner for configuration files
-(@pxref{Configuration files}).
-
-Lines in @file{devices} are divided into three categories, described
-briefly in the table below:
-
-@table @i
-@item driver category definitions
-Define a driver in terms of other drivers.
-
-@item macro definitions
-Define environment variables local to the output driver
-configuration file.
-
-@item device definitions
-Describe the configuration of an output device.
-@end table
-
-The following sections further elaborate the contents of the
-@file{devices} file.
-
-@menu
-* Driver categories::           How to organize the driver namespace.
-* Macro definitions::           Environment variables local to @file{devices}.
-* Device definitions::          Output device descriptions.
-* Dimensions::                  Lengths, widths, sizes, @enddots{}
-* Distinguishing line types::   Details on @file{devices} parsing.
-* Tokenizing lines::            Dividing @file{devices} lines into tokens.
-@end menu
-
-@node Driver categories
-@subsection Driver categories
-
-Drivers can be divided into categories.  Drivers are specified by their
-names, or by the names of the categories that they are contained in.
-Only certain drivers are enabled each time PSPP is run; by
-default, these are the drivers in the category `default'.  To enable a
-different set of drivers, use the @samp{-o @var{device}} command-line
-option (@pxref{Invocation}).
-
-Categories are specified with a line of the form
-@samp{@var{category}=@var{driver1} @var{driver2} @var{driver3} @var{@dots{}}
-@var{driver@var{n}}}.  This line specifies that the category
-@var{category} is composed of drivers named @var{driver1},
-@var{driver2}, and so on.  There may be any number of drivers in the
-category, from zero on up.
-
-Categories may also be specified on the command line
-(@pxref{Invocation}).
-
-This is all you need to know about categories.  If you're still curious,
-read on.
-
-First of all, the term `categories' is a bit of a misnomer.  In fact,
-the internal representation is nothing like the hierarchy that the term
-seems to imply: a linear list is used to keep track of the enabled
-drivers.
-
-When PSPP first begins reading @file{devices}, this list contains
-the name of any drivers or categories specified on the command line, or
-the single item `default' if none were specified.
-
-Each time a category definition is specified, the list is searched for
-an item with the value of @var{category}.  If a matching item is found,
-it is deleted.  If there was a match, the list of drivers (@var{driver1}
-through @var{driver@var{n}}) is then appended to the list.
-
-Each time a driver definition line is encountered, the list is searched.
-If the list contains an item with that driver's name, the driver is
-enabled and the item is deleted from the list.  Otherwise, the driver
-is not enabled.
-
-It is an error if the list is not empty when the end of @file{devices}
-is reached.
-
-@node Macro definitions
-@subsection Macro definitions
-
-Macro definitions take the form @samp{define @var{macroname}
-@var{definition}}.  In such a macro definition, the environment variable
-@var{macroname} is defined to expand to the value @var{definition}.
-Before the definition is made, however, any macros used in
-@var{definition} are expanded.
-
-Please note the following nuances of macro usage:
-
-@itemize @bullet
-@item
-For the purposes of this section, @dfn{macro} and @dfn{environment
-variable} are synonyms.
-
-@item
-Macros may not take arguments.
-
-@item
-Macros may not recurse.
-
-@item
-Macros are just environment variable definitions like other environment
-variable definitions, with the exception that they are limited in scope
-to the @file{devices} configuration file.
-
-@item
-Macros override other all environment variables of the same name (within
-the scope of @file{devices}).
-
-@item
-Earlier macro definitions for a particular @var{key} override later
-ones.  In particular, macro definitions on the command line override
-those in the device definition file.  @xref{Non-option Arguments}.
-
-@item
-There are two predefined macros, whose values are determined at runtime:
-
-@table @samp
-@item viewwidth
-Defined as the width of the console screen, in columns of text.
-
-@item viewlength
-Defined as the length of the console screen, in lines of text.
-@end table
-@end itemize
-
-@node Device definitions
-@subsection Driver definitions
-
-Driver definitions are the ultimate purpose of the @file{devices}
-configuration file.  These are where the real action is.  Driver
-definitions tell PSPP where it should send its output.
-
-Each driver definition line is divided into four fields.  These fields
-are delimited by colons (@samp{:}).  Each line is subjected to
-environment variable interpolation before it is processed further
-(@pxref{Environment substitutions}).  From left to right, the four
-fields are, in brief:
-
-@table @i
-@item driver name
-A unique identifier, used to determine whether to enable the driver.
-
-@item class name
-One of the predefined driver classes supported by PSPP.  The
-currently supported driver classes include `postscript' and `ascii'.
-
-@item device type(s)
-Zero or more of the following keywords, delimited by spaces:
-
-@table @code
-@item screen
-
-Indicates that the device is a screen display.  This may reduce the
-amount of buffering done by the driver, to make interactive use more
-convenient.
-
-@item printer
-
-Indicates that the device is a printer.
-
-@item listing
-
-Indicates that the device is a listing file.
-@end table
-
-These options are just hints to PSPP and do not cause the output to be
-directed to the screen, or to the printer, or to a listing file---those
-must be set elsewhere in the options.  They are used primarily to decide
-which devices should be enabled at any given time.  @xref{SET}, for more
-information.
-
-@item options
-An optional set of options to pass to the driver itself.  The exact
-format for the options varies among drivers.
-@end table
-
-The driver is enabled if:
-
-@enumerate
-@item
-Its driver name is specified on the command line, or
-
-@item
-It's in a category specified on the command line, or
-
-@item
-If no categories or driver names are specified on the command line, it
-is in category @code{default}.
-@end enumerate
-
-For more information on driver names, see @ref{Driver categories}.
-
-The class name must be one of those supported by PSPP.  The
-classes supported depend on the options with which PSPP was
-compiled.  See later sections in this chapter for descriptions of the
-available driver classes.
-
-Options are dependent on the driver.  See the driver descriptions for
-details.
-
-@node Dimensions
-@subsection Dimensions
-
-Quite often in configuration it is necessary to specify a length or a
-size.  PSPP uses a common syntax for all such, calling them
-collectively by the name @dfn{dimensions}.
-
-@itemize @bullet
-@item
-You can specify dimensions in decimal form (@samp{12.5}) or as
-fractions, either as mixed numbers (@samp{12-1/2}) or raw fractions
-(@samp{25/2}).
-
-@item 
-A number of different units are available.  These are suffixed to the
-numeric part of the dimension.  There must be no spaces between the
-number and the unit.  The available units are identical to those offered
-by the popular typesetting system @TeX{}:
-
-@table @code
-@item in
-inch (1 @code{in} = 2.54 @code{cm})
-
-@item "
-inch (1 @code{in} = 2.54 @code{cm})
-
-@item pt
-printer's point (1 @code{in} = 72.27 @code{pt})
-
-@item pc
-pica (12 @code{pt} = 1 @code{pc})
-
-@item bp
-PostScript point (1 @code{in} = 72 @code{bp})
-
-@item cm
-centimeter
-
-@item mm
-millimeter (10 @code{mm} = 1 @code{cm})
-
-@item dd
-didot point (1157 @code{dd} = 1238 @code{pt})
-
-@item cc
-cicero (1 @code{cc} = 12 @code{dd})
-
-@item sp
-scaled point (65536 @code{sp} = 1 @code{pt})
-@end table
-
-@item
-If no explicit unit is given, PSPP attempts to guess the best unit:
-
-@itemize @minus
-@item
-Numbers less than 50 are assumed to be in inches.
-
-@item
-Numbers 50 or greater are assumed to be in millimeters.
-@end itemize
-@end itemize
-
-@node Distinguishing line types
-@subsection How lines are divided into types
-
-The lines in @file{devices} are distinguished in the following manner:
-
-@enumerate
-@item
-Leading white space is removed.
-
-@item
-If the resulting line begins with the exact string @code{define},
-followed by one or more white space characters, the line is processed as
-a macro definition.
-
-@item
-Otherwise, the line is scanned for the first instance of a colon
-(@samp{:}) or an equals sign (@samp{=}).
-
-@item
-If a colon is encountered first, the line is processed as a driver
-definition.
-
-@item
-Otherwise, if an equals sign is encountered, the line is processed as a
-macro definition.
-
-@item
-Otherwise, the line is ill-formed.
-@end enumerate
-
-@node Tokenizing lines
-@subsection How lines are divided into tokens
-
-Each driver definition line is run through a simple tokenizer.  This
-tokenizer recognizes two basic types of tokens.
-
-The first type is an equals sign (@samp{=}).  Equals signs are both
-delimiters between tokens and tokens in themselves.
-
-The second type is an identifier or string token.  Identifiers and
-strings are equivalent after tokenization, though they are written
-differently.  An identifier is any string of characters other than
-white space or equals sign.
-
-A string is introduced by a single- or double-quote character (@samp{'}
-or @samp{"}) and, in general, continues until the next occurrence of
-that same character.  The following standard C escapes can also be
-embedded within strings:
-
-@table @code
-@item \'
-A single-quote (@samp{'}).
-
-@item \"
-A double-quote (@samp{"}).
-
-@item \?
-A question mark (@samp{?}).  Included for hysterical raisins.
-
-@item \\
-A backslash (@samp{\}).
-
-@item \a
-Audio bell (ASCII 7).
-
-@item \b
-Backspace (ASCII 8).
-
-@item \f
-Formfeed (ASCII 12).
-
-@item \n
-New-line (ASCII 10)
-
-@item \r
-Carriage return (ASCII 13).
-
-@item \t
-Tab (ASCII 9).
-
-@item \v
-Vertical tab (ASCII 11).
-
-@item \@var{o}@var{o}@var{o}
-Each @samp{o} must be an octal digit.  The character is the one having
-the octal value specified.  Any number of octal digits is read and
-interpreted; only the lower 8 bits are used.
-
-@item \x@var{h}@var{h}
-Each @samp{h} must be a hex digit.  The character is the one having the
-hexadecimal value specified.  Any number of hex digits is read and
-interpreted; only the lower 8 bits are used.
-@end table
-
-Tokens, outside of quoted strings, are delimited by white space or equals
-signs.
-
-@node PostScript driver class
-@section The PostScript driver class
-
-The @code{postscript} driver class is used to produce output that is
-acceptable to PostScript printers and other interpreters.
-
-The available options are listed below.
-
-@table @code
-@item output-file=@var{file-name}
-
-File to which output should be sent.  This can be an ordinary file name
-(i.e., @code{"pspp.ps"}), a pipe (i.e., @code{"|lpr"}), or
-stdout (@code{"-"}).  Default: @code{"pspp.ps"}.
-
-@item headers=@var{boolean}
-
-Controls whether the standard headers showing the time and date and
-title and subtitle are printed at the top of each page.  Default:
-@code{on}.
-
-@item paper-size=@var{paper-size}
-
-Paper size.  You may specify a name (e.g.@: @code{a4}, @code{letter})
-or measurements (e.g.@: @code{210x297}, @code{8.5x11in}).
-
-The default paper size is taken from the @env{PAPERSIZE} environment
-variable or the file indicated by the @env{PAPERCONF} environment
-variable, if either variable is set.  If not, and your system supports
-the @code{LC_PAPER} locale category, then the default paper size is
-taken from the locale.  Otherwise, if @file{/etc/papersize} exists,
-the default paper size is read from it.  As a last resort, A4 paper is
-assumed.
-
-@item orientation=@var{orientation}
-
-Either @code{portrait} or @code{landscape}.  Default: @code{portrait}.
-
-@item left-margin=@var{dimension}
-@itemx right-margin=@var{dimension}
-@itemx top-margin=@var{dimension}
-@itemx bottom-margin=@var{dimension}
-
-Sets the margins around the page.  The headers, if enabled, are not
-included in the margins; they are in addition to the margins.  For a
-description of dimensions, see @ref{Dimensions}.  Default: @code{0.5in}.
-
-@item prop-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
-@itemx emph-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
-@itemx fixed-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
-
-Sets the font used for proportional, emphasized, or fixed-pitch text.
-The only required value is @var{afm-file}, the AFM file for the font.
-
-If specified, @var{font-file} will be downloaded to the printer at the
-beginning of the print job.  The font file may be in PFA or PFB format.
-
-The font is reencoded as specified in @var{encoding-file}, if specified.
-Each line in @var{encoding-file} should consist of a PostScript
-character name and a decimal encoding value (between 0 and 255),
-separated by white space.  Blank lines and comments introduced by
-@samp{#} are also allowed.
-
-The files specified on these options are located as follows.  If
-the file name begins with @samp{/}, then it is taken as an absolute
-path.  Otherwise, PSPP searches its configuration path for the specified
-name prefixed by @code{psfonts/} (@pxref{File locations}).
-
-Default: proportional font @code{Times-Roman.afm}, emphasis font
-@code{Times-Italic.afm}, fixed-pitch font @code{Courier.afm}.
-
-@item font-size=@var{font-size}
-
-Sets the size of the default fonts, in thousandths of a point.  Default:
-10000 (10 point).
-
-@item line-gutter=@var{dimension}
-
-Sets the width of white space on either side of lines that border text
-or graphics objects.  @xref{Dimensions}.  Default: @code{1pt}.
-
-@item line-spacing=@var{dimension}
-
-Sets the spacing between the lines in a double line in a table.
-Default: @code{1pt}.
-
-@item line-width=@var{dimension}
-
-Sets the width of the lines used in tables.  Default: @code{0.5pt}.
-@end table
-
-@node ASCII driver class
-@section The ASCII driver class
-
-The ASCII driver class produces output that can be displayed on a
-terminal or output to printers.  The ASCII driver has class name
-@samp{ascii}.
-
-The available options are listed below.
-
-@table @code
-@item output-file=@var{file-name}
-
-File to which output should be sent.  This can be an ordinary file name
-(e.g., @code{"pspp.txt"}), a pipe (e.g., @code{"|more"}), or
-stdout (@code{"-"}).  Default: @code{"pspp.list"}.
-
-@item chart-files=@var{file-name-template}
-Template for the file names used for charts.  The name should contain
-a single @samp{#}, which is replaced by the chart number.  Default:
-@file{"pspp-#.png"}.
-
-@item chart-type=@var{type}.
-Type of charts to output.  Available types typically include @samp{X},
-@samp{png}, @samp{gif}, @samp{svg}, @samp{ps}, @samp{cgm}, @samp{fig},
-@samp{pcl}, @samp{hpgl}, @samp{regis}, @samp{tek}, and @samp{meta}.
-Default: @samp{png}.
-
-You may specify @samp{none} to disable chart output.  Charts are also
-disabled if your installation of PSPP was compiled without
-@code{libplot}.
-
-@item paginate=@var{boolean}
-
-If set, a formfeed will be written at the end of every page.  Default:
-@code{on}.
-
-@item tab-width=@var{tab-width-value}
-
-The distance between tab stops for this device.  If set to 0, tabs will
-not be used in the output.  Default: @code{8}.
-
-@item headers=@var{boolean}
-
-If enabled, two lines of header information giving title and subtitle,
-page number, date and time, and PSPP version are printed at the top of
-every page.  These two lines are in addition to any top margin
-requested.  Default: @code{on}.
-
-@item length=@var{line-count}
-
-Physical length of a page.  Headers and margins are subtracted from
-this value.  You may specify the number of lines as a number, or for
-screen output you may specify @code{auto} to track the height of the
-terminal as it changes.  Default: @code{66}.
-
-@item width=@var{character-count}
-
-Physical width of a page.  Margins are subtracted from this value.
-You may specify the width as a number of characters, or for screen
-output you may specify @code{auto} to track the width of the terminal
-as it changes.  Default: @code{79}.
-
-@item top-margin=@var{top-margin-lines}
-
-Length of the top margin, in lines.  PSPP subtracts this value from
-the page length.  Default: @code{2}.
-
-@item bottom-margin=@var{bottom-margin-lines}
-
-Length of the bottom margin, in lines.  PSPP subtracts this value from
-the page length.  Default: @code{2}.
-
-@item box[@var{line-type}]=@var{box-chars}
-
-The characters used for lines in tables produced by the ASCII driver can
-be changed using this option.  @var{line-type} is used to indicate which
-type of line to change; @var{box-chars} is the character or string of
-characters to use for this type of line.
-
-@var{line-type} must be a 4-digit number.  The digits are in the order
-`right', `bottom', `left', `top'.  The possibilities for each digit are:
-
-@table @asis
-@item 0
-No line.
-
-@item 1
-Single line.
-
-@item 2
-Double line.
-@end table
-
-Examples:
-
-@table @code
-@item box[0101]="|"
-
-Sets @samp{|} as the character to use for a single-width line with
-bottom and top components.
-
-@item box[2222]="#"
-
-Sets @samp{#} as the character to use for the intersection of four
-double-width lines, one each from the top, bottom, left and right.
-
-@item box[1100]="\xda"
-
-Sets @samp{"\xda"}, which under MS-DOS is a box character suitable for
-the top-left corner of a box, as the character for the intersection of
-two single-width lines, one each from the right and bottom.
-
-@end table
-
-Defaults:
-
-@itemize @bullet
-@item
-@code{box[0000]=" "}
-
-@item
-@code{box[1000]="-"}
-@*@code{box[0010]="-"}
-@*@code{box[1010]="-"}
-
-@item
-@code{box[0100]="|"}
-@*@code{box[0001]="|"}
-@*@code{box[0101]="|"}
-
-@item
-@code{box[2000]="="}
-@*@code{box[0020]="="}
-@*@code{box[2020]="="}
-
-@item
-@code{box[3000]="="}
-@*@code{box[0030]="="}
-@*@code{box[3030]="="}
-
-@item
-For all others, @samp{+} is used unless there are double lines or
-special lines, in which case @samp{#} is used.
-@end itemize
-
-@item init=@var{init-string}
-If set, this string is written at the beginning of each output file.
-It can be used to initialize device features, e.g.@: to enable VT100
-line-drawing characters.
-
-@item emphasis=@var{emphasis-style}
-
-How to emphasize text.  Your choices are @code{bold}, @code{underline},
-or @code{none}.  Bold and underline emphasis are achieved with
-overstriking, which may not be supported by all the software to which
-you might pass the output.
-@end table
-
-@node HTML driver class
-@section The HTML driver class
-
-The @code{html} driver class is used to produce output for viewing in
-tables-capable web browsers such as Emacs' w3-mode.  Its configuration
-is very simple.  Currently, the output has a very plain format.  In the
-future, further work may be done on improving the output appearance.
-
-There are only a few options:
-
-@table @code
-@item output-file=@var{file-name}
-
-File to which output should be sent.  This can be an ordinary file name
-(i.e., @code{"pspp.ps"}), a pipe (i.e., @code{"|lpr"}), or
-stdout (@code{"-"}).  Default: @file{"pspp.html"}.
-
-@item chart-files=@var{file-name-template}
-Template for the file names used for charts, which are output in PNG
-format.  The name should contain a single @samp{#}, which is replaced by
-the chart number.  Default: @file{"pspp-#.png"}.
-@end table
-
-@node Miscellaneous configuring
-@section Miscellaneous configuration
-
-The following environment variables can be used to further configure
-PSPP:
-
-@table @code
-@item HOME
-
-Used to determine the user's home directory.  No default value.
-
-@item STAT_INCLUDE_PATH
-
-Path used to find include files in PSPP syntax files.  Defaults vary
-across operating systems:
-
-@table @asis
-@item UNIX
-
-@itemize @bullet
-@item
-@file{.}
-
-@item
-@file{$HOME/.pspp/include}
-
-@item
-@file{/usr/local/lib/pspp/include}
-
-@item
-@file{/usr/lib/pspp/include}
-
-@item
-@file{/usr/local/share/pspp/include}
-
-@item
-@file{/usr/share/pspp/include}
-@end itemize
-
-@item MS-DOS
-
-@itemize @bullet
-@item
-@file{.}
-
-@item
-@file{C:\PSPP\INCLUDE}
-
-@item
-@file{$PATH}
-@end itemize
-
-@item Other OSes
-No default path.
-@end table
-
-@item TERM
-
-The terminal type @code{termcap} or @code{ncurses} will use, if such
-support was compiled into PSPP.
-
-@item STAT_OUTPUT_INIT_FILE
-
-The basename used to search for the driver definition file.
-@xref{Output devices}.  @xref{File locations}.  Default: @code{devices}.
-
-@item STAT_OUTPUT_INIT_PATH
-
-The path used to search for the driver definition file.
-@xref{File locations}.  Default: the standard configuration path.
-
-@item TMPDIR
-
-The directory in which PSPP stores its temporary files (used when sorting 
-cases or concatenating large numbers of cases).
-Default: (UNIX) @file{/tmp}, (MS-DOS) @file{\}, (other OSes) empty string.
-
-@item TEMP
-@item TMP
-
-Under MS-DOS only, these variables are consulted after TMPDIR, in this
-order.
-@end table
index 1bad334e95b60a1dc0c7872ada8f2bff4b28b5a8..fc521caee6beb8411803b4196fc850ec90fc04db 100644 (file)
@@ -826,8 +826,7 @@ random variates between 0 and 10.
 LIST
         /VARIABLES=var_list
         /CASES=FROM start_index TO end_index BY incr_index
-        /FORMAT=@{UNNUMBERED,NUMBERED@} @{WRAP,SINGLE@} 
-                @{NOWEIGHT,WEIGHT@}
+        /FORMAT=@{UNNUMBERED,NUMBERED@} @{WRAP,SINGLE@}
 @end display
 
 The @cmd{LIST} procedure prints the values of specified variables to the
@@ -846,9 +845,7 @@ settings.  If CASES is not specified then all cases are printed.
 The FORMAT subcommand can be used to change the output format.  NUMBERED
 will print case numbers along with each case; UNNUMBERED, the default,
 causes the case numbers to be omitted.  The WRAP and SINGLE settings are
-currently not used.  WEIGHT will cause case weights to be printed along
-with variable values; NOWEIGHT, the default, causes case weights to be
-omitted from the output.
+currently not used.
 
 Case numbers start from 1.  They are counted after all transformations
 have been considered.
index 735a54c5a20720859c62c4103f3b4ff1afb5b253..f96a2329e3747afa6b6cafc7e5142626a4208ead 100644 (file)
@@ -15,15 +15,15 @@ later in this manual.
 @cindex files, PSPP
 @cindex output, PSPP
 @cindex PostScript
+@cindex PDF
+@cindex HTML
+@cindex SVG
 @cindex graphics
 @cindex Ghostscript
 @cindex Free Software Foundation
-PSPP produces output in two forms: tables and charts.  Both of these can
-be written in several formats; currently, ASCII, PostScript, and HTML
-are supported.  In the future, more drivers, such as PCL and X Window
-System drivers, may be developed.  For now, Ghostscript, available from
-the Free Software Foundation, may be used to convert PostScript chart
-output to other formats.
+PSPP produces tables and charts as output, which it can produce in
+several formats; currently, ASCII, PostScript, PDF, HTML, and SVG are
+supported.
 
 The current version of PSPP, @value{VERSION}, is woefully incomplete in
 terms of its statistical procedure support.  PSPP is a work in progress.
index 3052162fddbfac4af381b3e3e1966c7f3e0704f8..86ddc31f12516c79424aa92ad40ecfbc7d5c703f 100644 (file)
-@node Invocation
-
-@chapter Starting PSPP
+@node Invoking PSPP
+@chapter Invoking @command{pspp}
 @cindex invocation
 @cindex PSPP, invoking
 
-There are two separate user interfaces for PSPP.
-There is the command line interface, which responds to commands
-typed by the user.
-The command line interface is generally available on more platforms
-than the graphic user interface and since it doesn't require a
-graphics device it can be used from a remote terminal.
-Platforms which have a windowing system may also be able to support
-the graphic user interface.
-The graphic user interface can perform all functionality of the
-command line interface.
-In addition it gives an instantaneous view of the data, variables and
-statistical output.
-
-Whichever interface you choose, a basic understanding of the concepts
-used by PSPP is necessary before effective use of the system can be achieved.
+PSPP has two separate user interfaces.  This chapter describes
+@command{pspp}, PSPP's command-line driven text-based user interface.
+The following chapter briefly describes PSPPIRE, the graphical user
+interface to PSPP.
 
+The sections below describe the @command{pspp} program's command-line
+interface.
 
 @menu
-* The command line user interface::  
-* The graphic user interface::  
+* Main Options::                
+* PDF PostScript and SVG Output Options::  
+* Plain Text Output Options::   
+* HTML Output Options::         
+* OpenDocument Output Options::  
+* Comma-Separated Value Output Options::  
 @end menu
 
+@node Main Options
+@section Main Options
 
-@node The command line user interface
-@section The command line user interface
+Here is a summary of all the options, grouped by type, followed by
+explanations in the same order.
 
-@cindex command line, options
-@cindex options, command-line
+In the table, arguments to long options also apply to any
+corresponding short options.
 
+@table @emph
+@item Non-option arguments
 @example
-pspp [ -B @var{dir} | --config-dir=@var{dir} ] [ -o @var{device} | --device=@var{device} ]
-       [ -a @{compatible|enhanced@} | --algorithm=@{compatible|enhanced@}]
-       [ -x @{compatible|enhanced@} | --syntax=@{compatible|enhanced@}]
-       [ -I- | --no-include ]
-       [ -I @var{dir} | --include=@var{dir} ] [ -i | --interactive ] 
-       [ -r | --no-statrc ] [ -h | --help ] [ -l | --list ] 
-       [ -s | --safer ]
-       [ --testing-mode ] [ -V | --version ] [ -v | --verbose ] 
-       [ @var{key}=@var{value} ] @var{file}@enddots{}
+@var{syntax-file}
 @end example
 
-@menu
-* Non-option Arguments::        Specifying syntax files and output devices.
-* Configuration Options::       Change the configuration for the current run.
-* Input and output options::    Controlling input and output files.
-* Language control options::    Language variants.
-* Informational options::       Helpful information about PSPP.
-@end menu
-
-@node Non-option Arguments
-@subsection Non-option Arguments
-
-Syntax files and output device substitutions can be specified on
-PSPP's command line:
-
-@table @code
-@item @var{file}
-
-A file by itself on the command line will be executed as a syntax file.
-If multiple files are specified, they are executed in order, as if
-their contents had been given in a single file.
-PSPP terminates after the syntax files run, unless the @code{-i} or
-@code{--interactive} option is given (@pxref{Language control options}).
-
-@item @var{key}=@var{value}
-
-Defines an output device macro @var{key} to expand to @var{value},
-overriding any macro having the same @var{key} defined in the device
-configuration file.  @xref{Macro definitions}.
-
-@end table
-
-There is one other way to specify a syntax file, if your operating
-system supports it.  If you have a syntax file @file{foobar.stat}, put
-the notation
-
+@item Output options
 @example
-#! /usr/local/bin/pspp
+-o, --output=@var{output-file}
+-O @var{option}=@var{value}
+-O format=@var{format}
+-O device=@{terminal|listing@}
+-e, --error-file=@var{error-file}
 @end example
 
-at the top, and mark the file as executable with @code{chmod +x
-foobar.stat}.  (If PSPP is not installed in @file{/usr/local/bin},
-then insert its actual installation directory into the syntax file
-instead.)  Now you should be able to invoke the syntax file just by
-typing its name.  You can include any options on the command line as
-usual.  PSPP entirely ignores any lines beginning with @samp{#!}.
-
-@node Configuration Options
-@subsection Configuration Options
-
-Configuration options are used to change PSPP's configuration for the
-current run.  The configuration options are:
-
-@table @code
-@item -a @{compatible|enhanced@}
-@itemx --algorithm=@{compatible|enhanced@}
-
-If you chose @code{compatible}, then PSPP will use the same  algorithms 
-as used by some proprietary statistical analysis packages.
-This is not recommended, as  these algorithms are inferior and in some cases 
-compeletely broken.
-The default setting is @code{enhanced}.
-Certain commands have subcommands which allow you to override this setting on 
-a per command basis.
-
-@item -B @var{dir}
-@itemx --config-dir=@var{dir}
-
-Sets the configuration directory to @var{dir}.  @xref{File locations}.
+@item Language options
+@example
+-I, --include=@var{dir}
+-I-, --no-include
+-i, --interactive
+-r, --no-statrc
+-a, --algorithm=@{compatible|enhanced@}
+-x, --syntax=@{compatible|enhanced@}
+@end example
 
-@item -o @var{device}
-@itemx --device=@var{device}
+@item Informational options
+@example
+-h, --help
+-V, --version
+@end example
 
-Selects the output device with name @var{device}.  If this option is
-given more than once, then all devices mentioned are selected.  This
-option disables all devices besides those mentioned on the command line.
+@item Other options
+@example
+-s, --safer
+--testing-mode
+@end example
 @end table
 
-@node Input and output options
-@subsection Input and output options
-
-Input and output options affect how PSPP reads input and writes
-output.  These are the input and output options:
-
 @table @code
-@item -I-
-@itemx --no-include
-
-Clears all directories from the include path.  This includes all
-directories put in the include path by default.  @xref{Miscellaneous
-configuring}.
+@item @var{syntax-file}
+Read and execute the named syntax file.  If no syntax files are
+specified, PSPP prompts for commands.  If any syntax files are
+specified, PSPP by default exits after it runs them, but you may make
+it prompt for commands by specifying @samp{-} as an additional syntax
+file.
+
+@item -o @var{output-file}
+Write output to @var{output-file}.  PSPP has several different output
+drivers that support output in various formats (use @option{--help} to
+list the available formats).  Specify this option more than once to
+produce multiple output files, presumably in different formats.
+
+Use @samp{-} as @var{output-file} to write output to standard output.
+
+If no @option{-o} option is used, then PSPP writes output to standard
+output in plain text format.
+
+@item -O @var{option}=@var{value}
+Sets an option for the output file configured by a preceding
+@option{-o}.  Most options are specific to particular output formats.
+A few options that apply generically are listed below.
+
+@item -O format=@var{format}
+PSPP uses the extension of the file name given on @option{-o} to
+select an output format.  Use this option to override this choice by
+specifying an alternate format, e.g.@: @option{-o pspp.out -O html} to
+write HTML to a file named @file{pspp.out}.  Use @option{--help} to
+list the available formats.
+
+@item -O device=@{terminal|listing@}
+Sets whether PSPP considers the output device configured by the
+preceding @option{-o} to be a terminal or a listing device.  This
+affects what output will be sent to the device, as configured by the
+SET command's output routing subcommands (@pxref{SET}).  By default,
+output written to standard output is considered a terminal device and
+other output is considered a listing device.
+
+@item -e @var{error-file}
+@itemx --error-file=@var{error-file}
+Configures a file to receive PSPP error, warning, and note messages in
+plain text format.  Use @samp{-} as @var{error-file} to write messages
+to standard output.  The default error file is standard output in the
+absence of these options, but this is suppressed if an output device
+writes to standard output (or another terminal), to avoid printing
+every message twice.  Use @samp{none} as @var{error-file} to
+explicitly suppress the default.
 
 @item -I @var{dir}
 @itemx --include=@var{dir}
+Appends @var{dir} to the set of directories searched by INCLUDE
+(@pxref{INCLUDE}) and INSERT (@pxref{INSERT}).
 
-Appends directory @var{dir} to the path that is searched for include
-files in PSPP syntax files.
-
-@item --testing-mode
-
-Invoke heuristics to assist with testing PSPP.  For use by @code{make
-check} and similar scripts.
-@end table
-
-@node Language control options
-@subsection Language control options
-
-Language control options control how PSPP syntax files are parsed and
-interpreted.  The available language control options are:
+@item -I-
+@itemx --no-include
+Clears all directories from the include path, including directories
+inserted in the include path by default.  The default include path is
+@file{.} (the current directory), followed by @file{.pspp} in the
+user's home directory, followed by PSPP's system configuration
+directory (usually @file{/etc/pspp} or @file{/usr/local/etc/pspp}).
 
-@table @code
 @item -i
 @itemx --interactive
-
-When a syntax file is specified on the command line, PSPP normally
-terminates after processing it.  Giving this option will cause PSPP to
-bring up a command prompt after processing the syntax file.
-
-In addition, this forces syntax files to be interpreted in interactive
-mode, rather than the default batch mode.  @xref{Tokenizing lines}, for
-information on the differences between batch mode and interactive mode
-command interpretation.
+This option forces syntax files to be interpreted in interactive
+mode, rather than the default batch mode.  @xref{Syntax Variants}, for
+a description of the differences.
 
 @item -r
 @itemx --no-statrc
+Disables running @file{rc} at PSPP startup time.
+
+@item -a @{enhanced|compatible@}
+@itemx --algorithm=@{enhanced|compatible@}
+With @code{enhanced}, the default, PSPP uses the best implemented
+algorithms for statistical procedures.  With @code{compatible},
+however, PSPP will in some cases use inferior algorithms to produce
+the same results as the proprietary program SPSS.
+
+Some commands have subcommands that override this setting on a per
+command basis.
+
+@item -x @{enhanced|compatible@}
+@itemx --syntax=@{enhanced|compatible@}
+With @code{enhanced}, the default, PSPP accepts its own extensions
+beyond those compatible with the proprietary program SPSS.  With
+@code{compatible}, PSPP rejects syntax that uses these extensions.
+
+@item -?
+@itemx --help
+Prints a message describing PSPP command-line syntax and the available
+device formats, then exits.
 
-Prevents the execution of the PSPP startup syntax file.
+@item -V
+@itemx --version
+Prints a brief message listing PSPP's version, warranties you don't
+have, copying conditions and copyright, and e-mail address for bug
+reports, then exits.
 
 @item -s
 @itemx --safer
-
 Disables certain unsafe operations.  This includes the ERASE and
 HOST commands, as well as use of pipes as input and output files.
-@end table
-
-@node Informational options
-@subsection Informational options
-
-Informational options cause information about PSPP to be written to
-the terminal.  Here are the available options:
-
-@table @code
-@item -h
-@item --help
-
-Prints a message describing PSPP command-line syntax and the available
-device driver classes, then terminates.
 
-@item -l
-@item --list
-
-Lists the available device driver classes, then terminates.
+@item --testing-mode
+Invoke heuristics to assist with testing PSPP.  For use by @code{make
+check} and similar scripts.
+@end table
 
-@item -x @{compatible|enhanced@}
-@itemx --syntax=@{compatible|enhanced@}
+@node PDF PostScript and SVG Output Options
+@section PDF, PostScript, and SVG Output Options
 
-If you chose @code{compatible}, then PSPP will only accept command syntax that 
-is compatible with the proprietary program SPSS.
-If you choose @code{enhanced} then additional syntax will be available.
-The default is @code{enhanced}.
+To produce output in PDF, PostScript, and SVG formats, specify
+@option{-o @var{file}} on the PSPP command line, optionally followed
+by any of the options shown in the table below to customize the output
+format.
 
+PDF, PostScript, and SVG output is only available if your installation
+of PSPP was compiled with the Cairo library.
 
-@item -V
-@item --version
+@table @code
+@item -O format=@{pdf|ps|svg@}
+Specify the output format.  This is only necessary if the file name
+given on @option{-o} does not end in @file{.pdf}, @file{.ps}, or
+@file{.svg}.
+
+@item -O paper-size=@var{paper-size}
+Paper size, as a name (e.g.@: @code{a4}, @code{letter}) or
+measurements (e.g.@: @code{210x297}, @code{8.5x11in}).
+
+The default paper size is taken from the @env{PAPERSIZE} environment
+variable or the file indicated by the @env{PAPERCONF} environment
+variable, if either variable is set.  If not, and your system supports
+the @code{LC_PAPER} locale category, then the default paper size is
+taken from the locale.  Otherwise, if @file{/etc/papersize} exists,
+the default paper size is read from it.  As a last resort, A4 paper is
+assumed.
+
+@item -O orientation=@var{orientation}
+Either @code{portrait} or @code{landscape}.  Default: @code{portrait}.
+
+@item -O headers=@var{boolean}
+When enabled, headers showing the time and date, title and subtitle,
+and page number are printed at the top of each page.  Default:
+@code{on}.
+
+@item -O left-margin=@var{dimension}
+@itemx -O right-margin=@var{dimension}
+@itemx -O top-margin=@var{dimension}
+@itemx -O bottom-margin=@var{dimension}
+Sets the margins around the page.  The headers, if enabled, are not
+included in the margins; they are in addition to the margins.  See
+below for the allowed forms of @var{dimension} Default: @code{0.5in}.
+
+@item -O prop-font=@var{font-name}
+@itemx -O emph-font=@var{font-name}
+@itemx -O fixed-font=@var{font-name}
+Sets the font used for proportional, emphasized, or fixed-pitch text.
+Most systems support CSS-like font names such as ``serif'' and
+``monospace'', but a wide range of system-specific font are likely to
+be supported as well.
+
+Default: proportional font @code{serif}, emphasis font @code{serif
+italic}, fixed-pitch font @code{monospace}.
+
+@item -O font-size=@var{font-size}
+Sets the size of the default fonts, in thousandths of a point.  Default:
+10000 (10 point).
+
+@item -O line-gutter=@var{dimension}
+Sets the width of white space on either side of lines that border text
+or graphics objects.  Default: @code{1pt}.
+
+@item -O line-spacing=@var{dimension}
+Sets the spacing between the lines in a double line in a table.
+Default: @code{1pt}.
+
+@item -O line-width=@var{dimension}
+Sets the width of the lines used in tables.  Default: @code{0.5pt}.
+@end table
 
-Prints a brief message listing PSPP's version, warranties you don't
-have, copying conditions and copyright, and e-mail address for bug
-reports, then terminates.
+Each @var{dimension} value above may be specified in various units
+based on its suffix: @samp{mm} for millimeters, @samp{in} for inches,
+or @samp{pt} for points.  Lacking a suffix, numbers below 50 are
+assumed to be in inches and those about 50 are assumed to be in
+millimeters.
 
-@item -v
-@item --verbose
+@node Plain Text Output Options
+@section Plain Text Output Options
 
-Increments PSPP's verbosity level.  Higher verbosity levels cause
-PSPP to display greater amounts of information about what it is
-doing.  Often useful for debugging PSPP's configuration.  
+PSPP can produce plain text output, drawing boxes using ASCII or
+Unicode line drawing characters.  To produce plain text output,
+specify @option{-o @var{file}} on the PSPP command line, optionally
+followed by options from the table below to customize the output
+format.
 
-This option can be given multiple times to set the verbosity level to
-that value.  The default verbosity level is 0, in which no informational
-messages will be displayed.
+@table @code
+@item -O format=txt
+Specify the output format.  This is only necessary if the file name
+given on @option{-o} does not end in @file{.txt} or @file{.list}.
+
+@item -O charts=@{@var{template}.png|none@}
+Name for chart files included in output.  The value should be a file
+name that includes a single @samp{#} and ends in @file{png}.  When a
+chart is output, the @samp{#} is replaced by the chart number.  The
+default is the file name specified on @option{-o} with the extension
+stripped off and replaced by @file{-#.png}.
+
+Specify @code{none} to disable chart output.  Charts are always
+disabled if your installation of PSPP was compiled without the
+Cairo library.
+
+@item -O paginate=@var{boolean}
+If set, PSPP writes an ASCII formfeed the end of every page.  Default:
+@code{off}.
+
+@item -O headers=@var{boolean}
+If enabled, PSPP prints two lines of header information giving title
+and subtitle, page number, date and time, and PSPP version are printed
+at the top of every page.  These two lines are in addition to any top
+margin requested.  Default: @code{off}.
+
+@item -O length=@var{line-count}
+Physical length of a page.  Headers and margins are subtracted from
+this value.  You may specify the number of lines as a number, or for
+screen output you may specify @code{auto} to track the height of the
+terminal as it changes.  Default: @code{66}.
+
+@item -O width=@var{character-count}
+Width of a page, in characters.  Margins are subtracted from this
+value.  For screen output you may specify @code{auto} in place of a
+number to track the width of the terminal as it changes.  Default:
+@code{79}.
+
+@item -O top-margin=@var{top-margin-lines}
+Length of the top margin, in lines.  PSPP subtracts this value from
+the page length.  Default: @code{0}.
+
+@item -O bottom-margin=@var{bottom-margin-lines}
+Length of the bottom margin, in lines.  PSPP subtracts this value from
+the page length.  Default: @code{0}.
+
+@item -O box[@var{line-type}]=@var{box-chars}
+Sets the characters used for lines in tables.  @var{line-type} is a
+4-digit number that indicates the type of line to change, in the order
+`right', `bottom', `left', `top'.  Each digit is 0 for ``no line'', 1
+for a single line, and 2 for a double line.  @var{box-chars} is the
+character or string of characters to use for this type of line.
+
+For example, @code{box[0101]="|"} sets @samp{|} as the character to
+use for a single-width vertical line, and @code{box[1100]="\xda"} sets
+@samp{"\xda"}, which on MS-DOS is suitable for the top-left corner of
+a box, as the character for the intersection of two single-width
+lines, one each from the right and bottom.
+
+The defaults use @samp{-}, @samp{|}, and @samp{+} for single-width
+lines and @samp{=} and @samp{#} for double-width lines.
+
+@item -O init=@var{init-string}
+If set, this string is written at the beginning of each output file.
+It can be used to initialize device features, e.g.@: to enable VT100
+line-drawing characters.
+
+@item -O emphasis=@{none|bold|underline@}
+How to emphasize text.  Bold and underline emphasis are achieved with
+overstriking, which may not be supported by all the software to which
+you might pass the output.  Default: @code{none}.
+@end table
 
-Higher verbosity levels cause messages to be displayed when the
-corresponding events take place.
+@node HTML Output Options
+@section HTML Output Options
 
-@table @asis
-@item 1
+To produce output in HTML format, specify @option{-o @var{file}} on
+the PSPP command line, optionally followed by any of the options shown
+in the table below to customize the output format.
 
-Driver and subsystem initializations.
+@table @code
+@item -O format=html
+Specify the output format.  This is only necessary if the file name
+given on @option{-o} does not end in @file{.html}.
 
-@item 2
+@item -O charts=@{@var{template}.png|none@}
+Sets the name used for chart files.  @xref{Plain Text Output Options},
+for details.
+@end table
 
-Completion of driver initializations.  Beginning of driver closings.
+@node OpenDocument Output Options
+@section OpenDocument Output Options
 
-@item 3
+To produce output as an OpenDocument text (ODT) document, specify
+@option{-o @var{file}} on the PSPP command line.  If @var{file} does
+not end in @file{.odt}, you must also specify @option{-O format=odt}.
 
-Completion of driver closings.
+The OpenDocument output format does not have any configurable options.
 
-@item 4
+@node Comma-Separated Value Output Options
+@section Comma-Separated Value Output Options
 
-Files searched for; success of searches.
+To produce output in comma-separated value (CSV) format, specify
+@option{-o @var{file}} on the PSPP command line, optionally followed
+by any of the options shown in the table below to customize the output
+format.
 
-@item 5
+@table @code
+@item -O format=csv
+Specify the output format.  This is only necessary if the file name
+given on @option{-o} does not end in @file{.csv}.
 
-Individual directories included in file searches.
+@item -O separator=@var{field-separator}
+Sets the character used to separate fields.  The default is a comma
+(@samp{,}).
 @end table
 
-Each verbosity level also includes messages from lower verbosity levels.
+The CSV format used is an extension to that specified in RFC 4180:
 
+@table @asis
+@item Tables
+Each table row is output on a separate line, and each column is output
+as a field.  The contents of a cell that spans multiple rows or
+columns is output only for the top-left row and column; the rest are
+output as empty fields.  When a table has a caption, it is output just
+above the table as a single field prefixed by @samp{Table:}.
+
+@item Text
+Text in output is printed as a field on a line by itself.  The TITLE
+and SUBTITLE produce similar output, prefixed by @samp{Title:} or
+@samp{Subtitle:}, respectively.
+
+@item Messages
+Errors, warnings, and notes are printed the same way as text.
+
+@item Charts
+Charts are not included in CSV output.
 @end table
 
+Successive output items are separated by a blank line.
 
-@node The graphic user interface
+@node Invoking PSPPIRE
+@chapter Invoking @command{psppire}
 @section The graphic user interface
-
 @cindex Graphic user interface
 @cindex PSPPIRE
 
+The PSPPIRE graphic user interface for PSPP can perform all
+functionality of the command line interface.  In addition it gives an
+instantaneous view of the data, variables and statistical output.
+
 The graphic user interface can be started by typing @command{psppire} at a 
 command prompt.
 Alternatively many systems have a system of interactive menus or buttons 
index e23a558028805dbc9babcb360811d34c87258434..19c9a6b9dc72593d76ec80ba7ba4722bf71e3772 100644 (file)
@@ -3,10 +3,6 @@
 @cindex language, PSPP
 @cindex PSPP, language
 
-@note{PSPP is not even close to completion.
-Only a few statistical procedures are implemented.  PSPP
-is a work in progress.}
-
 This chapter discusses elements common to many PSPP commands.
 Later chapters will describe individual commands in detail.
 
@@ -212,9 +208,9 @@ new command, which allows for visual indentation of a command without
 that command being considered part of the previous command. 
 The period terminating the end of a command is optional but recommended.
 
-In interactive mode, each command must  either be terminated with a period,
-or an empty line must follow the command.
-The use of (@samp{+} and @samp{@minus{}} as continuation characters is not
+In interactive mode, each command must be terminated with a period
+or by a blank line.
+The use of @samp{+} and @samp{@minus{}} as continuation characters is not
 permitted.
 
 @node Types of Commands
index 830e82e4619393ac8c6c9512eb5fe079842e6830..ae3db342b9bdf27c4d682f7980d01b096090685e 100644 (file)
@@ -33,6 +33,7 @@
 @dircategory Math
 @direntry
 * PSPP: (pspp).             Statistical analysis package.
+* PSPPIRE: (pspp).          Graphical user interface to PSPP.
 @end direntry
 
 @copying
@@ -86,7 +87,8 @@ in the production of this manual.
 * Introduction::                Description of the package.
 * License::                     Your rights and obligations.
 
-* Invocation::                  Starting and running PSPP.
+* Invoking PSPP::               Starting the PSPP text-based interface.
+* Invoking PSPPIRE::            Starting the PSPP graphical user interface.
 * Using PSPP::                  How to use PSPP --- A brief tutorial.
 * Language::                    Basics of the PSPP command language.
 * Expressions::                 Numeric and string expression syntax.
@@ -108,8 +110,6 @@ in the production of this manual.
 * Command Index::               Index of PSPP procedures.
 * Concept Index::               Index of concepts.
 
-* Configuration::               Configuring PSPP.
-
 * GNU Free Documentation License:: License for copying this manual.
 @end menu
 
@@ -136,8 +136,6 @@ in the production of this manual.
 @include command-index.texi
 @include concept-index.texi
 
-@include configuring.texi
-
 @include fdl.texi
 
 @bye
index 6882aa2165f525aa2b12ae466da5d762eabe95af..fabec248b6aed6f894ea3afdd11ddf4243fe22a0 100644 (file)
@@ -330,7 +330,6 @@ SET
 (interaction)
         /CPROMPT='cprompt_string'
         /DPROMPT='dprompt_string'
-        /ERRORBREAK=@{OFF,ON@}
         /MXERRS=max_errs
         /MXWARNS=max_warnings
         /PROMPT='prompt'
@@ -353,17 +352,14 @@ SET
         /WRB=@{NATIVE,ISL,ISB,IDL,IDB,VF,VD,VG,ZS,ZL@}
 
 (output routing)
-        /ECHO=@{ON,OFF@}
         /ERRORS=@{ON,OFF,TERMINAL,LISTING,BOTH,NONE@}
-        /INCLUDE=@{ON,OFF@}
         /MESSAGES=@{ON,OFF,TERMINAL,LISTING,BOTH,NONE@}
-        /PRINTBACK=@{ON,OFF@}
+        /PRINTBACK=@{ON,OFF,TERMINAL,LISTING,BOTH,NONE@}
         /RESULTS=@{ON,OFF,TERMINAL,LISTING,BOTH,NONE@}
 
 (output driver options)
         /HEADERS=@{NO,YES,BLANK@}
         /LENGTH=@{NONE,length_in_lines@}
-        /LISTING=@{ON,OFF,'file-name'@}
         /MORE=@{ON,OFF@}
         /WIDTH=@{NARROW,WIDTH,n_characters@}
 
@@ -383,7 +379,6 @@ SET
         /BOXSTRING=@{'xxx','xxxxxxxxxxx'@}
         /CASE=@{UPPER,UPLOW@}
         /CPI=cpi_value
-        /DISK=@{ON,OFF@}
         /HIGHRES=@{ON,OFF@}
         /HISTOGRAM='c'
         /LOWRES=@{AUTO,ON,OFF@}
@@ -524,10 +519,6 @@ The command continuation prompt.  The default is @samp{    > }.
 Prompt used when expecting data input within @cmd{BEGIN DATA} (@pxref{BEGIN
 DATA}).  The default is @samp{data> }.
 
-@item ERRORBREAK
-Whether an error causes PSPP to stop processing the current command
-file after finishing the current command.  The default is OFF.
-
 @item MXERRS
 The maximum number of errors before PSPP halts processing of the current
 command file.  The default is 50.
@@ -615,30 +606,55 @@ RB format (@pxref{Binary and Hexadecimal Numeric Formats}).  The choices
 are the same as SET RIB.  The default is NATIVE.
 @end table
 
-Output routing subcommands affect where the output of transformations
-and procedures is sent.  These subcommands are
+In the PSPP text-based interface, the output routing subcommands
+affect where output is sent.  The following values are allowed for
+each of these subcommands:
 
 @table @asis
-@item ECHO
+@item OFF
+@item NONE
+Discard this kind of output.
+
+@item TERMINAL
+Write this output to the terminal, but not to listing files and other
+output devices.
+
+@item LISTING
+Write this output to listing files and other output devices, but not
+to the terminal.
 
-If turned on, commands are written to the listing file as they are read
-from command files.  The default is OFF.
+@item ON
+@itemx BOTH
+Write this type of output to all output devices.
+@end table
+
+These output routing subcommands are:
+
+@table @asis
+@item ERRORS
+Applies to error and warning messages.  The default is BOTH.
 
-@itemx ERRORS
-@itemx INCLUDE
 @itemx MESSAGES
-@item PRINTBACK
-@item RESULTS
-Currently not used.
+Applies to notes.  The default is BOTH.
+
+@itemx PRINTBACK
+Determines whether the syntax used for input is printed back as part
+of the output.  The default is NONE.
+
+@itemx RESULTS
+Applies to everything not in one of the above categories, such as the
+results of statistical procedures.  The default is BOTH.
 @end table
 
+These subcommands have no effect on output in the PSPP GUI
+environment.
+
 Output driver option subcommands affect output drivers' settings.  These
 subcommands are
 
 @table @asis
 @item HEADERS
 @itemx LENGTH
-@itemx LISTING
 @itemx MORE
 @itemx PAGER 
 @itemx WIDTH
@@ -646,7 +662,6 @@ subcommands are
 
 @cindex headers
 @cindex length
-@cindex listing
 @cindex more
 @cindex pager 
 @cindex width
index 6b20c67478909fe6232730b58d7b4056de720490..9bde4afcf26d77b9950e960cdfd29063b7cbbbeb 100644 (file)
@@ -2,7 +2,7 @@
 
 include $(top_srcdir)/lib/linreg/automake.mk
 
-if WITHGUI
+if HAVE_GUI
 include $(top_srcdir)/lib/gtk-contrib/automake.mk
 endif
 
index 045b4e767710e0ba7b2d43b21c03c0a07316cb6b..56b8a930ce77ea4229cce6e6211bc9b27d58ac57 100644 (file)
@@ -12,7 +12,7 @@ do 'pspp-module-config' || do {
 };
 
 WriteMakefile(
-    FULLPERL          => "PSPP_TEST_CMD=\"$Locations{BuildDir}/src/ui/terminal/pspp -B $Locations{SourceDir}/config\" \$(PERL)",
+    FULLPERL          => "PSPP_TEST_CMD=\"$Locations{BuildDir}/src/ui/terminal/pspp\" \$(PERL)",
     NAME              => 'PSPP',
     DISTNAME          => 'PSPP-Perl',
     VERSION_FROM      => "$Locations{BuildDir}/src/libpspp/version.c", 
index ef9acc3790c8bc93e13b44dc89c3fcecc46cf3b3..8eeb0a341ddd0c96a7a70bf6438c6167d391f09e 100644 (file)
@@ -34,6 +34,7 @@ PHONY += module-make
 module-make: perl-module/Makefile src/libpspp-core.la
        cd perl-module && $(MAKE) $(AM_MAKEFLAGS)
 
+ALL_LOCAL += perl_module_tarball
 perl_module_tarball:
        if test x"$(top_builddir)" != x"$(top_srcdir)" ; then \
         for f in $(module_sources); do \
@@ -47,22 +48,19 @@ perl_module_tarball:
        fi
        $(MAKE) $(AM_MAKEFLAGS) module-make perl-module/PSPP-Perl-$(VERSION_FOR_PERL).tar.gz
 
-ALL_LOCAL += perl_module_tarball
-
-check-local:
+CHECK_LOCAL += perl_module_check
+perl_module_check:
        loc=`pwd` ; cd $(top_builddir)/src/.libs ; llp=`pwd` ; cd $$loc ;  \
        LANG=C LD_LIBRARY_PATH=$$llp sh -c "cd perl-module && $(MAKE) $(AM_MAKEFLAGS) test"
 
-
-perl_module_CLEAN:
+CLEAN_LOCAL += perl_module_clean
+perl_module_clean:
        cd perl-module && $(MAKE) $(AM_MAKEFLAGS) clean || true
        if test x"$(top_builddir)" != x"$(top_srcdir)" ; then \
          rm -f $(module_sources) ; \
        fi
        rm -f perl-module/Makefile.old
 
-CLEAN_LOCAL += perl_module_CLEAN
-
 CLEANFILES += \
         perl-module/PSPP-Perl-$(VERSION_FOR_PERL).tar.gz \
        perl-module/pspp-module-config \
index 2dccd10a36973e560e8be7d267b92f9bdb918ac1..fd2f5a5f5d579ae20f933248af74088524d15c43 100644 (file)
@@ -21,7 +21,7 @@ None by default.
 
 =cut
 BEGIN {
-       $PSPP::VERSION='0.7.2';
+       $PSPP::VERSION='0.7.3';
        require XSLoader;
        XSLoader::load('PSPP', $PSPP::VERSION);
 }
index 92180aba9cde097c4409b2d71f6d78c66974504c..50be5df2a7dd0a29f86e88614bac657bb689d73e 100644 (file)
@@ -40,7 +40,7 @@ sub run_pspp_syntax
     print FH "$syntax";
     close (FH);
 
-    system ("cd $tempdir; $pspp_cmd -o raw-ascii $syntaxfile");
+    system ("cd $tempdir; $pspp_cmd -o pspp.csv $syntaxfile");
 }
 
 sub run_pspp_syntax_cmp
@@ -52,7 +52,7 @@ sub run_pspp_syntax_cmp
 
     run_pspp_syntax ($tempdir, $syntax);
 
-    my $diff =  diff ("$tempdir/pspp.list", \$result);
+    my $diff =  diff ("$tempdir/pspp.csv", \$result);
 
     if ( ! ($diff eq ""))
     {
@@ -175,32 +175,27 @@ sub run_pspp_syntax_cmp
        DISPLAY DOCUMENTS.
        LIST.
 SYNTAX
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|id      |Format: F2.0                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|name    |Format: A20                                |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 20                          |        |
-+--------+-------------------------------------------+--------+
+Variable,Description,,Position
+id,Format: F2.0,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+name,Format: A20,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 20,,
 
 File label:
+
 This is the file label
 
 Documents in the active file:
 
 This is a document line
 
-id                 name
--- --------------------
-21 wheelbarrow          
-
+Table: Data List
+id,name
+21,wheelbarrow         
 RESULT
 
 
@@ -256,40 +251,30 @@ RESULT
 GET FILE='$tempfile'.
 DISPLAY DICTIONARY.
 SYNTAX
-1.1 DISPLAY.  
-+----------+---------------------------------------------+--------+
-|Variable  |Description                                  |Position|
-#==========#=============================================#========#
-|integer   |My Integer                                   |       1|
-|          |Format: F8.0                                 |        |
-|          |Measure: Scale                               |        |
-|          |Display Alignment: Right                     |        |
-|          |Display Width: 8                             |        |
-|          |Missing Values: 9; 99                        |        |
-|          +---------+-----------------------------------+        |
-|          |        0|Zero                               |        |
-|          |        1|Unity                              |        |
-|          |        2|Duality                            |        |
-+----------+---------+-----------------------------------+--------+
-|string    |My String                                    |       2|
-|          |Format: A8                                   |        |
-|          |Measure: Nominal                             |        |
-|          |Display Alignment: Left                      |        |
-|          |Display Width: 8                             |        |
-|          |Missing Values: "this    "; "that    "       |        |
-|          +---------+-----------------------------------+        |
-|          | xx      |foo                                |        |
-|          | yy      |bar                                |        |
-+----------+---------+-----------------------------------+--------+
-|longstring|My Long String                               |       3|
-|          |Format: A9                                   |        |
-|          |Measure: Nominal                             |        |
-|          |Display Alignment: Left                      |        |
-|          |Display Width: 9                             |        |
-|          +---------+-----------------------------------+        |
-|          |xxx      |xfoo                               |        |
-+----------+---------+-----------------------------------+--------+
-
+Variable,Description,,Position
+integer,My Integer,,1
+,Format: F8.0,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,Missing Values: 9; 99,,
+,0,Zero,
+,1,Unity,
+,2,Duality,
+string,My String,,2
+,Format: A8,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+,"Missing Values: ""this    ""; ""that    """,,
+,xx      ,foo,
+,yy      ,bar,
+longstring,My Long String,,3
+,Format: A9,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 9,,
+,xxx      ,xfoo,
 RESULT
 
   }
@@ -493,7 +478,7 @@ EOF
 
 SYNTAX
 
- system ("cp $tempdir/pspp.list $tempdir/in.txt");
+ system ("cp $tempdir/pspp.csv $tempdir/in.txt");
 
  run_pspp_syntax ($tempdir, <<SYNTAX);
  get file='$tempdir/out.sav'.
@@ -502,7 +487,7 @@ SYNTAX
 
 SYNTAX
  
- ok (! diff ("$tempdir/pspp.list", "$tempdir/in.txt"), "Streaming of files");
+ ok (! diff ("$tempdir/pspp.csv", "$tempdir/in.txt"), "Streaming of files");
 }
 
 
index a249f5ad4e9557a8c0f5a6e28366dcc322182c1d..ebfb680a09316b0a0fa486067616d77153cf5fcb 100644 (file)
@@ -25,7 +25,9 @@ src_data_libdata_la_SOURCES = \
        src/data/caseinit.c \
        src/data/caseinit.h \
        src/data/casereader-filter.c \
+       src/data/casereader-project.c \
        src/data/casereader-provider.h \
+       src/data/casereader-select.c \
        src/data/casereader-translator.c \
        src/data/casereader.c \
        src/data/casereader.h \
index 1a40213a537d295f78241a0c35a0594ba3a6262a..9837013acb8bee86cb6d30bf0876a706a05dbc71 100644 (file)
@@ -320,7 +320,7 @@ caseproto_free__ (struct caseproto *proto)
 void
 caseproto_refresh_long_string_cache__ (const struct caseproto *proto_)
 {
-  struct caseproto *proto = (struct caseproto *) proto_;
+  struct caseproto *proto = CONST_CAST (struct caseproto *, proto_);
   size_t n, i;
 
   assert (proto->long_strings == NULL);
index b85a9f32d9260f02d6339b8f0852caca8518722f..b0f45c418c47aae8017b0469a5307cff6b9cd7f6 100644 (file)
@@ -22,6 +22,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <data/value.h>
+#include <libpspp/cast.h>
 #include <libpspp/compiler.h>
 
 /* Case prototype.
@@ -144,7 +145,7 @@ void caseproto_free__ (struct caseproto *);
 static inline struct caseproto *
 caseproto_ref (const struct caseproto *proto_)
 {
-  struct caseproto *proto = (struct caseproto *) proto_;
+  struct caseproto *proto = CONST_CAST (struct caseproto *, proto_);
   proto->ref_cnt++;
   return proto;
 }
diff --git a/src/data/casereader-project.c b/src/data/casereader-project.c
new file mode 100644 (file)
index 0000000..116a335
--- /dev/null
@@ -0,0 +1,106 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <data/casereader-provider.h>
+#include <data/subcase.h>
+
+#include "gl/xalloc.h"
+
+static bool
+projection_is_no_op (const struct casereader *reader, const struct subcase *sc)
+{
+  size_t n = subcase_get_n_fields (sc);
+  size_t i;
+
+  if (n != caseproto_get_n_widths (casereader_get_proto (reader)))
+    return false;
+
+  for (i = 0; i < n; i++)
+    if (subcase_get_case_index (sc, i) != i)
+      return false;
+
+  return true;
+}
+
+struct casereader_project
+  {
+    struct subcase old_sc;
+    struct subcase new_sc;
+  };
+
+static struct ccase *
+project_case (struct ccase *old, casenumber idx UNUSED, const void *project_)
+{
+  const struct casereader_project *project = project_;
+  struct ccase *new = case_create (subcase_get_proto (&project->new_sc));
+  subcase_copy (&project->old_sc, old, &project->new_sc, new);
+  case_unref (old);
+  return new;
+}
+
+static bool
+destroy_projection (void *project_)
+{
+  struct casereader_project *project = project_;
+  subcase_destroy (&project->old_sc);
+  subcase_destroy (&project->new_sc);
+  free (project);
+  return true;
+}
+
+/* Returns a casereader in which each row is obtained by extracting the subcase
+   SC from the corresponding row of SUBREADER. */
+struct casereader *
+casereader_project (struct casereader *subreader, const struct subcase *sc)
+{
+  if (projection_is_no_op (subreader, sc))
+    return casereader_rename (subreader);
+  else
+    {
+      struct casereader_project *project = xmalloc (sizeof *project);
+      const struct caseproto *proto;
+
+      subcase_clone (&project->old_sc, sc);
+      proto = subcase_get_proto (&project->old_sc);
+
+      subcase_init_empty (&project->new_sc);
+      subcase_add_proto_always (&project->new_sc, proto);
+
+      return casereader_translate_stateless (subreader, proto,
+                                             project_case, destroy_projection,
+                                             project);
+    }
+}
+
+/* Returns a casereader in which each row is obtained by extracting the value
+   with index COLUMN from the corresponding row of SUBREADER. */
+struct casereader *
+casereader_project_1 (struct casereader *subreader, int column)
+{
+  const struct caseproto *subproto = casereader_get_proto (subreader);
+  struct casereader *reader;
+  struct subcase sc;
+
+  subcase_init (&sc, column, caseproto_get_width (subproto, column),
+                SC_ASCEND);
+  reader = casereader_project (subreader, &sc);
+  subcase_destroy (&sc);
+
+  return reader;
+}
+
diff --git a/src/data/casereader-select.c b/src/data/casereader-select.c
new file mode 100644 (file)
index 0000000..a26ef67
--- /dev/null
@@ -0,0 +1,81 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <data/casereader-provider.h>
+
+#include "gl/xalloc.h"
+
+struct casereader_select
+  {
+    casenumber by;
+    casenumber i;
+  };
+
+static bool
+casereader_select_include (const struct ccase *c UNUSED, void *cs_)
+{
+  struct casereader_select *cs = cs_;
+  if (++cs->i >= cs->by)
+    {
+      cs->i = 0;
+      return true;
+    }
+  else
+    return false;
+}
+
+static bool
+casereader_select_destroy (void *cs_)
+{
+  struct casereader_select *cs = cs_;
+  free (cs);
+  return true;
+}
+
+/* Returns a casereader that contains cases FIRST though LAST, exclusive, of
+   those within SUBREADER.  (The first case in SUBREADER is number 0.)  If BY
+   is greater than 1, then it specifies a step between cases, e.g.  a BY value
+   of 2 causes the cases numbered FIRST + 1, FIRST + 3, FIRST + 5, and so on
+   to be omitted.
+
+   The caller gives up ownership of SUBREADER, transferring it into this
+   function. */
+struct casereader *
+casereader_select (struct casereader *subreader,
+                   casenumber first, casenumber last, casenumber by)
+{
+  if (by == 0)
+    by = 1;
+
+  casereader_advance (subreader, first);
+  if (last >= first)
+    casereader_truncate (subreader, (last - first) / by * by);
+
+  if (by == 1)
+    return casereader_rename (subreader);
+  else
+    {
+      struct casereader_select *cs = xmalloc (sizeof *cs);
+      cs->by = by;
+      cs->i = 0;
+      return casereader_create_filter_func (subreader,
+                                            casereader_select_include,
+                                            casereader_select_destroy,
+                                            cs, NULL);
+    }
+}
index feffa15c4510ba97e57cd95705cd9afd290c1e04..27ea413460aa501a61d4d81ae97a9c9c8f1d50df 100644 (file)
@@ -46,6 +46,11 @@ static const struct casereader_class casereader_translator_class;
    INPUT and auxiliary data AUX.  TRANSLATE must destroy its
    input case.
 
+   TRANSLATE may be stateful, that is, the output for a given
+   case may depend on previous cases.  If TRANSLATE is stateless,
+   then you may want to use casereader_translate_stateless
+   instead, since it sometimes performs better.
+
    The cases returned by TRANSLATE must match OUTPUT_PROTO.
 
    When the translating casereader is destroyed, DESTROY will be
@@ -106,7 +111,110 @@ static const struct casereader_class casereader_translator_class =
     NULL,
     NULL,
   };
+\f
+/* Casereader that applies a user-supplied function to translate
+   each case into another in a stateless fashion. */
+
+/* A statelessly translating casereader. */
+struct casereader_stateless_translator
+  {
+    struct casereader *subreader; /* Source of input cases. */
+
+    casenumber case_offset;
+    struct ccase *(*translate) (struct ccase *input, casenumber,
+                                const void *aux);
+    bool (*destroy) (void *aux);
+    void *aux;
+  };
+
+static const struct casereader_random_class
+casereader_stateless_translator_class;
+
+/* Creates and returns a new casereader whose cases are produced by reading
+   from SUBREADER and passing through the TRANSLATE function.  TRANSLATE must
+   takes ownership of its input case and returns a translated case, populating
+   the translated case based on INPUT and auxiliary data AUX.
+
+   TRANSLATE must be stateless, that is, the output for a given case must not
+   depend on previous cases.  This is because cases may be retrieved in
+   arbitrary order, and some cases may be retrieved multiple times, and some
+   cases may be skipped and never retrieved at all.  If TRANSLATE is stateful,
+   use casereader_create_translator instead.
+
+   The casenumber argument to the TRANSLATE function is the absolute case
+   number in SUBREADER, that is, 0 when the first case in SUBREADER is being
+   translated, 1 when the second case is being translated, and so on.
+
+   The cases returned by TRANSLATE must match OUTPUT_PROTO.
+
+   When the stateless translating casereader is destroyed, DESTROY will be
+   called to allow any auxiliary data maintained by TRANSLATE to be freed.
+
+   After this function is called, SUBREADER must not ever again be referenced
+   directly.  It will be destroyed automatically when the translating
+   casereader is destroyed. */
+struct casereader *
+casereader_translate_stateless (
+  struct casereader *subreader,
+  const struct caseproto *output_proto,
+  struct ccase *(*translate) (struct ccase *input, casenumber,
+                              const void *aux),
+  bool (*destroy) (void *aux),
+  void *aux)
+{
+  struct casereader_stateless_translator *cst = xmalloc (sizeof *cst);
+  struct casereader *reader;
+  cst->subreader = casereader_rename (subreader);
+  cst->translate = translate;
+  cst->destroy = destroy;
+  cst->aux = aux;
+  reader = casereader_create_random (
+    output_proto, casereader_get_case_cnt (cst->subreader),
+    &casereader_stateless_translator_class, cst);
+  taint_propagate (casereader_get_taint (cst->subreader),
+                   casereader_get_taint (reader));
+  return reader;
+}
+
+/* Internal read function for stateless translating casereader. */
+static struct ccase *
+casereader_stateless_translator_read (struct casereader *reader UNUSED,
+                                      void *cst_, casenumber idx)
+{
+  struct casereader_stateless_translator *cst = cst_;
+  struct ccase *tmp = casereader_peek (cst->subreader, idx);
+  if (tmp != NULL)
+    tmp = cst->translate (tmp, cst->case_offset + idx, cst->aux);
+  return tmp;
+}
+
+/* Internal destroy function for translating casereader. */
+static void
+casereader_stateless_translator_destroy (struct casereader *reader UNUSED,
+                                         void *cst_)
+{
+  struct casereader_stateless_translator *cst = cst_;
+  casereader_destroy (cst->subreader);
+  cst->destroy (cst->aux);
+  free (cst);
+}
+
+static void
+casereader_stateless_translator_advance (struct casereader *reader UNUSED,
+                                         void *cst_, casenumber cnt)
+{
+  struct casereader_stateless_translator *cst = cst_;
+  cst->case_offset += casereader_advance (cst->subreader, cnt);
+}
 
+/* Casereader class for stateless translating casereader. */
+static const struct casereader_random_class
+casereader_stateless_translator_class =
+  {
+    casereader_stateless_translator_read,
+    casereader_stateless_translator_destroy,
+    casereader_stateless_translator_advance,
+  };
 \f
 
 struct casereader_append_numeric
index a1550ac57560e5fb623d12ede14b7e1a65ca661b..97b7ceff3d1b7eb19e8ac6243aef08eb961a0f6b 100644 (file)
@@ -108,7 +108,7 @@ casereader_destroy (struct casereader *reader)
 struct casereader *
 casereader_clone (const struct casereader *reader_)
 {
-  struct casereader *reader = (struct casereader *) reader_;
+  struct casereader *reader = CONST_CAST (struct casereader *, reader_);
   struct casereader *clone;
   if ( reader == NULL ) 
     return NULL;
@@ -257,6 +257,20 @@ casereader_get_case_cnt (struct casereader *reader)
   return reader->case_cnt;
 }
 
+static casenumber
+casereader_count_cases__ (const struct casereader *reader,
+                          casenumber max_cases)
+{
+  struct casereader *clone;
+  casenumber n_cases;
+
+  clone = casereader_clone (reader);
+  n_cases = casereader_advance (clone, max_cases);
+  casereader_destroy (clone);
+
+  return n_cases;
+}
+
 /* Returns the number of cases that will be read by successive
    calls to casereader_read for READER, assuming that no errors
    occur.  Upon an error condition, the case count drops to 0, so
@@ -267,25 +281,30 @@ casereader_get_case_cnt (struct casereader *reader)
    of the contents of a clone of READER.  Thus, the return value
    is always correct in the absence of I/O errors. */
 casenumber
-casereader_count_cases (struct casereader *reader)
+casereader_count_cases (const struct casereader *reader)
 {
   if (reader->case_cnt == CASENUMBER_MAX)
     {
-      casenumber n_cases = 0;
-      struct ccase *c;
-
-      struct casereader *clone = casereader_clone (reader);
-
-      for (; (c = casereader_read (clone)) != NULL; case_unref (c))
-        n_cases++;
-
-      casereader_destroy (clone);
-      reader->case_cnt = n_cases;
+      struct casereader *reader_rw = CONST_CAST (struct casereader *, reader);
+      reader_rw->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX);
     }
-
   return reader->case_cnt;
 }
 
+/* Truncates READER to at most N cases. */
+void
+casereader_truncate (struct casereader *reader, casenumber n)
+{
+  /* This could be optimized, if it ever becomes too expensive, by adding a
+     "max_cases" member to struct casereader.  We could also add a "truncate"
+     function to the casereader implementation, to allow the casereader to
+     throw away data that cannot ever be read. */
+  if (reader->case_cnt == CASENUMBER_MAX)
+    reader->case_cnt = casereader_count_cases__ (reader, n);
+  if (reader->case_cnt > n)
+    reader->case_cnt = n;
+}
+
 /* Returns the prototype for the cases in READER.  The caller
    must not unref the returned prototype. */
 const struct caseproto *
@@ -294,6 +313,26 @@ casereader_get_proto (const struct casereader *reader)
   return reader->proto;
 }
 
+/* Skips past N cases in READER, stopping when the last case in
+   READER has been read or on an input error.  Returns the number
+   of cases successfully skipped. */
+casenumber
+casereader_advance (struct casereader *reader, casenumber n)
+{
+  casenumber i;
+
+  for (i = 0; i < n; i++)
+    {
+      struct ccase *c = casereader_read (reader);
+      if (c == NULL)
+        break;
+      case_unref (c);
+    }
+
+  return i;
+}
+
+
 /* Copies all the cases in READER to WRITER, propagating errors
    appropriately. */
 void
@@ -664,3 +703,42 @@ static const struct casereader_random_class shim_class =
     shim_destroy,
     shim_advance,
   };
+\f
+static const struct casereader_class casereader_null_class;
+
+/* Returns a casereader with no cases.  The casereader has the prototype
+   specified by PROTO.  PROTO may be specified as a null pointer, in which case
+   the casereader has no variables. */
+struct casereader *
+casereader_create_empty (const struct caseproto *proto_)
+{
+  struct casereader *reader;
+  struct caseproto *proto;
+
+  proto = proto_ != NULL ? caseproto_ref (proto_) : caseproto_create ();
+  reader = casereader_create_sequential (NULL, proto, 0,
+                                         &casereader_null_class, NULL);
+  caseproto_unref (proto);
+
+  return reader;
+}
+
+static struct ccase *
+casereader_null_read (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+  return NULL;
+}
+
+static void
+casereader_null_destroy (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+  /* Nothing to do. */
+}
+
+static const struct casereader_class casereader_null_class =
+  {
+    casereader_null_read,
+    casereader_null_destroy,
+    NULL,                       /* clone */
+    NULL,                       /* peek */
+  };
index 3b903bbfd52d66cdba8ffe0e960fa7f0d1ef2474..f2231e2d88984576e39e712427d3dfa4e530f889 100644 (file)
@@ -58,6 +58,7 @@
 struct dictionary;
 struct casereader;
 struct casewriter;
+struct subcase;
 
 struct ccase *casereader_read (struct casereader *);
 bool casereader_destroy (struct casereader *);
@@ -76,11 +77,15 @@ void casereader_force_error (struct casereader *);
 const struct taint *casereader_get_taint (const struct casereader *);
 
 casenumber casereader_get_case_cnt (struct casereader *);
-casenumber casereader_count_cases (struct casereader *);
+casenumber casereader_count_cases (const struct casereader *);
+void casereader_truncate (struct casereader *, casenumber);
 const struct caseproto *casereader_get_proto (const struct casereader *);
 
+casenumber casereader_advance (struct casereader *, casenumber);
 void casereader_transfer (struct casereader *, struct casewriter *);
 \f
+struct casereader *casereader_create_empty (const struct caseproto *);
+
 struct casereader *
 casereader_create_filter_func (struct casereader *,
                                bool (*include) (const struct ccase *,
@@ -112,6 +117,22 @@ casereader_create_translator (struct casereader *,
                               bool (*destroy) (void *aux),
                               void *aux);
 
+struct casereader *
+casereader_translate_stateless (struct casereader *,
+                                const struct caseproto *output_proto,
+                                struct ccase *(*translate) (struct ccase *,
+                                                            casenumber idx,
+                                                            const void *aux),
+                                bool (*destroy) (void *aux),
+                                void *aux);
+
+struct casereader *casereader_project (struct casereader *,
+                                       const struct subcase *);
+struct casereader *casereader_project_1 (struct casereader *, int column);
+struct casereader *casereader_select (struct casereader *,
+                                      casenumber first, casenumber last,
+                                      casenumber by);
+
 /* A function which creates a numberic value from an existing case */
 typedef double new_value_func (const struct ccase *, casenumber, void *);
 
index 9b04b9413c61bbace1e5b189d68e65eebe152482..936b6aa940051be14a422fde8a8773f22388eeb7 100644 (file)
@@ -168,7 +168,7 @@ casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt)
 struct ccase *
 casewindow_get_case (const struct casewindow *cw_, casenumber case_idx)
 {
-  struct casewindow *cw = (struct casewindow *) cw_;
+  struct casewindow *cw = CONST_CAST (struct casewindow *, cw_);
 
   assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
   if (casewindow_error (cw))
index 33e369f971da8751f78e29e76f23d230e6e0227d..63e644c186bf565168a7f6e199c4bc707f7ae7cf 100644 (file)
@@ -1199,9 +1199,11 @@ vdata_warning (const struct data_in *i, const char *format, va_list args)
   ds_put_format (&text, _("%s field) "), fmt_name (i->format));
   ds_put_vformat (&text, format, args);
 
-  m.category = MSG_DATA;
-  m.severity = MSG_WARNING;
+  m.category = MSG_C_DATA;
+  m.severity = MSG_S_WARNING;
   m.text = ds_cstr (&text);
+  m.where.file_name = NULL;
+  m.where.line_number = -1;
 
   msg_emit (&m);
 }
index fa24d8ce77014e980cb79e4700ffc63832c5d061..4abc526f0cb2a720cb8e3023eb7d732effdb5da4 100644 (file)
@@ -275,7 +275,7 @@ datasheet_destroy (struct datasheet *ds)
 const struct caseproto *
 datasheet_get_proto (const struct datasheet *ds_)
 {
-  struct datasheet *ds = (struct datasheet *) ds_;
+  struct datasheet *ds = CONST_CAST (struct datasheet *, ds_);
   if (ds->proto == NULL)
     {
       size_t i;
@@ -548,7 +548,7 @@ datasheet_get_row (const struct datasheet *ds, casenumber row)
 {
   size_t n_columns = datasheet_get_n_columns (ds);
   struct ccase *c = case_create (datasheet_get_proto (ds));
-  if (rw_case ((struct datasheet *) ds, OP_READ,
+  if (rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
                row, 0, n_columns, case_data_all_rw (c)))
     return c;
   else
@@ -582,7 +582,8 @@ datasheet_get_value (const struct datasheet *ds, casenumber row,
                      size_t column, union value *value)
 {
   assert (row >= 0);
-  return rw_case ((struct datasheet *) ds, OP_READ, row, column, 1, value);
+  return rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
+                  row, column, 1, value);
 }
 
 /* Stores VALUE into DS in the given ROW and COLUMN.  VALUE must
index ab653d874193a46d1f9a83a03f1e15ac4e09e7a6..1ddf5575aa68c4877f77fea845d3b4e6ea567ccc 100644 (file)
@@ -1016,7 +1016,7 @@ dict_set_case_limit (struct dictionary *d, casenumber case_limit)
 const struct caseproto *
 dict_get_proto (const struct dictionary *d_)
 {
-  struct dictionary *d = (struct dictionary *) d_;
+  struct dictionary *d = CONST_CAST (struct dictionary *, d_);
   if (d->proto == NULL)
     {
       size_t i;
@@ -1375,7 +1375,7 @@ dict_clear_vectors (struct dictionary *d)
 struct attrset *
 dict_get_attributes (const struct dictionary *d) 
 {
-  return (struct attrset *) &d->attributes;
+  return CONST_CAST (struct attrset *, &d->attributes);
 }
 
 /* Replaces D's attributes set by a copy of ATTRS. */
index 91229595924c7bfe7fe11d1486970ae598950f5c..e3047a3354cd3506917cefcb3e0a23587138981c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 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
 
 #include <config.h>
 
-#include <data/file-name.h>
+#include "data/file-name.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
-#include "intprops.h"
-#include "minmax.h"
-#include "dirname.h"
-#include "xmalloca.h"
-
-#include <data/settings.h>
-#include <libpspp/hash.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/verbose-msg.h>
-#include <libpspp/version.h>
+#include "data/settings.h"
+#include "libpspp/hash.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
 
-#include "xalloc.h"
+#include "gl/dirname.h"
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/relocatable.h"
+#include "gl/xalloc.h"
+#include "gl/xmalloca.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include <unistd.h>
-#include <sys/stat.h>
-
 #if defined _WIN32 || defined __WIN32__
 #define WIN32_LEAN_AND_MEAN  /* avoid including junk */
 #include <windows.h>
 #endif
 \f
-/* Initialization. */
-
-const char *config_path;
-
-void
-fn_init (void)
-{
-  config_path = fn_getenv_default ("STAT_CONFIG_PATH", default_config_path);
-}
-\f
 /* Functions for performing operations on file names. */
 
-
-/* Substitutes $variables in SRC, putting the result in DST,
-   properly handling the case where SRC is a substring of DST.
-   Variables are as defined by GETENV. Supports $var and ${var}
-   syntaxes; $$ substitutes as $. */
-void
-fn_interp_vars (struct substring src, const char *(*getenv) (const char *),
-                struct string *dst_)
-{
-  struct string dst = DS_EMPTY_INITIALIZER;
-  int c;
-
-  while ((c = ss_get_char (&src)) != EOF)
-    if (c != '$')
-      ds_put_char (&dst, c);
-    else
-      {
-        if (ss_match_char (&src, '$') || ss_is_empty (src))
-          ds_put_char (&dst, '$');
-        else
-          {
-            struct substring var_name;
-            size_t start;
-            const char *value;
-
-            if (ss_match_char (&src, '('))
-              ss_get_until (&src, ')', &var_name);
-            else if (ss_match_char (&src, '{'))
-              ss_get_until (&src, '}', &var_name);
-            else
-              ss_get_chars (&src, MAX (1, ss_span (src, ss_cstr (CC_ALNUM))),
-                            &var_name);
-
-            start = ds_length (&dst);
-            ds_put_substring (&dst, var_name);
-            value = getenv (ds_cstr (&dst) + start);
-            ds_truncate (&dst, start);
-
-            ds_put_cstr (&dst, value);
-          }
-      }
-
-  ds_swap (&dst, dst_);
-  ds_destroy (&dst);
-}
-
-/* Searches for a configuration file with name NAME in the path
-   given by PATH, which is environment-interpolated.
-   Directories in PATH are delimited by ':'.  Returns the
-   malloc'd full name of the first file found, or NULL if none is
-   found. */
+/* Searches for a configuration file with name NAME in the directories given in
+   PATH, which is terminated by a null pointer.  Returns the full name of the
+   first file found, which the caller is responsible for freeing with free(),
+   or NULL if none is found. */
 char *
-fn_search_path (const char *base_name, const char *path_)
+fn_search_path (const char *base_name, char **path)
 {
-  struct string path;
-  struct substring dir;
-  struct string file = DS_EMPTY_INITIALIZER;
-  size_t save_idx = 0;
+  size_t i;
 
   if (fn_is_absolute (base_name))
     return xstrdup (base_name);
 
-  /* Interpolate environment variables. */
-  ds_init_cstr (&path, path_);
-  fn_interp_vars (ds_ss (&path), fn_getenv, &path);
-
-  verbose_msg (2, _("searching for \"%s\" in path \"%s\""),
-               base_name, ds_cstr (&path));
-  while (ds_separate (&path, ss_cstr (":"), &save_idx, &dir))
+  for (i = 0; path[i] != NULL; i++)
     {
-      /* Construct file name. */
-      ds_clear (&file);
-      ds_put_substring (&file, dir);
-      if (!ds_is_empty (&file) && !ISSLASH (ds_last (&file)))
-       ds_put_char (&file, '/');
-      ds_put_cstr (&file, base_name);
-      ds_relocate (&file);
-
-      /* Check whether file exists. */
-      if (fn_exists (ds_cstr (&file)))
-       {
-         verbose_msg (2, _("...found \"%s\""), ds_cstr (&file));
-          ds_destroy (&path);
-         return ds_cstr (&file);
-       }
+      const char *dir = path[i];
+      char *file;
+
+      if (!strcmp (dir, "") || !strcmp (dir, "."))
+        file = xstrdup (base_name);
+      else if (ISSLASH (dir[strlen (dir) - 1]))
+        file = xasprintf ("%s%s", dir, base_name);
+      else
+        file = xasprintf ("%s/%s", dir, base_name);
+
+      if (fn_exists (file))
+        return file;
+      free (file);
     }
 
-  /* Failure. */
-  verbose_msg (2, _("...not found"));
-  ds_destroy (&path);
-  ds_destroy (&file);
   return NULL;
 }
 
@@ -246,11 +171,6 @@ safety_violation (const char *fn)
 }
 #endif
 
-/* As a general comment on the following routines, a `sensible value'
-   for errno includes 0 if there is no associated system error.  The
-   routines will only set errno to 0 if there is an error in a
-   callback that sets errno to 0; they themselves won't. */
-
 /* File open routine that understands `-' as stdin/stdout and `|cmd'
    as a pipe to command `cmd'.  Returns resultant FILE on success,
    NULL on failure.  If NULL is returned then errno is set to a
@@ -260,12 +180,18 @@ fn_open (const char *fn, const char *mode)
 {
   assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a');
 
-  if (mode[0] == 'r' && (!strcmp (fn, "stdin") || !strcmp (fn, "-")))
-    return stdin;
-  else if (mode[0] == 'w' && (!strcmp (fn, "stdout") || !strcmp (fn, "-")))
-    return stdout;
-  else if (mode[0] == 'w' && !strcmp (fn, "stderr"))
-    return stderr;
+  if (mode[0] == 'r')
+    {
+      if (!strcmp (fn, "stdin") || !strcmp (fn, "-"))
+        return stdin;
+    }
+  else
+    {
+      if (!strcmp (fn, "stdout") || !strcmp (fn, "-"))
+        return stdout;
+      if (!strcmp (fn, "stderr"))
+        return stderr;
+    }
 
 #if HAVE_POPEN
   if (fn[0] == '|')
@@ -298,7 +224,7 @@ fn_open (const char *fn, const char *mode)
     {
       FILE *f = fopen (fn, mode);
 
-      if (f && mode[0] == 'w')
+      if (f && mode[0] != 'r')
        setvbuf (f, NULL, _IOLBF, 0);
 
       return f;
index d34bd4196fea046db722197aa403db964a423deb..8e04d36a926dffb80618b236f60cf7e4309d802b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010 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
 
 #include <stdio.h>
 #include <stdbool.h>
-#include <libpspp/str.h>
 #include <sys/types.h>
 
-/* Search path for configuration files. */
-extern const char *config_path;
+struct string_set;
 
-void fn_init (void);
-
-void fn_interp_vars (struct substring src,
-                     const char *(*getenv) (const char *),
-                     struct string *dst);
-char *fn_search_path (const char *base_name, const char *path);
+char *fn_search_path (const char *base_name, char **path);
 char *fn_dir_name (const char *fn);
 char *fn_extension (const char *fn);
 
index e4c9234044a687a078d198c2ec85f5385cd4f7dd..f163d5e7737c0b6cf8e591b385d3cbd128edd36e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2010 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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+
+#include "data/make-file.h"
+
 #include <assert.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
-#include <stdio.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
-#include <data/file-name.h>
-#include <data/make-file.h>
-#include <libpspp/ll.h>
-#include <libpspp/message.h>
+#include "data/file-name.h"
+#include "libpspp/ll.h"
+#include "libpspp/message.h"
 
-#include "fatal-signal.h"
-#include "tempname.h"
-#include "xalloc.h"
+#include "gl/fatal-signal.h"
+#include "gl/tempname.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 19d33ebe76bfc070b0f28aed4c11bc61c89b7111..31795bebe58db8d4b66d187c2ba9f3978369d7e2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2010 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
    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 MKFILE_H
-#define MKFILE_H
+#ifndef MAKE_FILE_H
+#define MAKE_FILE_H
 
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
 
 /* Creates a temporary file and stores its name in *FILE_NAME and
    a file descriptor for it in *FD.  Returns success.  Caller is
index a463124274a20c6cd62e1071f15c51cd95edcb3a..55f616ec76502eef0533353c3619be7fd069fd95 100644 (file)
@@ -102,8 +102,8 @@ error (struct pfm_reader *r, const char *msg, ...)
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  m.category = MSG_GENERAL;
-  m.severity = MSG_ERROR;
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_ERROR;
   m.where.file_name = NULL;
   m.where.line_number = 0;
   m.text = ds_cstr (&text);
@@ -131,8 +131,8 @@ warning (struct pfm_reader *r, const char *msg, ...)
   ds_put_vformat (&text, msg, args);
   va_end (args);
 
-  m.category = MSG_GENERAL;
-  m.severity = MSG_WARNING;
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_WARNING;
   m.where.file_name = NULL;
   m.where.line_number = 0;
   m.text = ds_cstr (&text);
index b762214d10e20a33d6bbdf89ac52253a67589453..5e013a14af767d80a097a4c46f577ed77c4c3210 100644 (file)
@@ -682,7 +682,7 @@ dataset_end_of_command (struct dataset *ds)
       else
         {
           const struct taint *taint = casereader_get_taint (ds->source);
-          taint_reset_successor_taint ((struct taint *) taint);
+          taint_reset_successor_taint (CONST_CAST (struct taint *, taint));
           assert (!taint_has_tainted_successor (taint));
         }
     }
index c86ac9cc7e2c856ee685d271cf0995e5a9bbafd1..d95e3a14076a140d848d8ccad45c73e767592d47 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 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
@@ -52,17 +52,14 @@ struct settings
   int *viewlength;
   int *viewwidth;
   bool safer_mode;
-  bool do_echo;
   bool include;
   int epoch;
-  bool errorbreak;
   bool route_errors_to_terminal;
   bool route_errors_to_listing;
   bool scompress;
   bool undefined;
   double blanks;
-  int mxwarns;
-  int mxerrs;
+  int max_messages[MSG_N_SEVERITIES];
   bool printback;
   bool mprint;
   int mxloops;
@@ -77,6 +74,8 @@ struct settings
   int syntax;
 
   struct fmt_number_style *styles;
+
+  enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
 };
 
 static struct settings the_settings = {
@@ -93,15 +92,11 @@ static struct settings the_settings = {
     /* viewwidth */
   NULL,
     /* safer_mode */
-  false,
-    /* do_echo */
   false,
     /* include */
   true,
     /* epoch */
   -1,
-    /* errorbreak */
-  false,
     /* route_errors_to_terminal */
   true,
     /* route_errors_to_listing */
@@ -112,10 +107,12 @@ static struct settings the_settings = {
   true,
     /* blanks */
   SYSMIS,
-    /* mxwarns */
-  100,
-    /* mxerrs */
-  100,
+    /* max_messages */
+  {
+    100,                        /* MSG_S_ERROR */
+    100,                        /* MSG_S_WARNING */
+    100                         /* MSG_S_NOTE */
+  },
     /* printback */
   true,
     /* mprint */
@@ -139,7 +136,12 @@ static struct settings the_settings = {
     /* syntax */
   ENHANCED,
     /* styles */
-  NULL
+  NULL,
+    /* output devices */
+  {SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
+   SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
+   0,
+   SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL}
 };
 
 static void init_viewport ( int *, int *);
@@ -269,20 +271,6 @@ settings_set_safer_mode (void)
   the_settings.safer_mode = true;
 }
 
-/* Echo commands to the listing file/printer? */
-bool
-settings_get_echo (void)
-{
-  return the_settings.do_echo;
-}
-
-/* Set echo. */
-void
-settings_set_echo ( bool echo)
-{
-  the_settings.do_echo = echo;
-}
-
 /* If echo is on, whether commands from include files are echoed. */
 bool
 settings_get_include (void)
@@ -321,50 +309,6 @@ settings_set_epoch ( int epoch)
   assert (the_settings.epoch >= 0);
 }
 
-/* Does an error stop execution? */
-bool
-settings_get_errorbreak (void)
-{
-  return the_settings.errorbreak;
-}
-
-/* Sets whether an error stops execution. */
-void
-settings_set_errorbreak ( bool errorbreak)
-{
-  the_settings.errorbreak = errorbreak;
-}
-
-/* Route error messages to terminal? */
-bool
-settings_get_error_routing_to_terminal (void)
-{
-  return the_settings.route_errors_to_terminal;
-}
-
-/* Sets whether error messages should be routed to the
-   terminal. */
-void
-settings_set_error_routing_to_terminal ( bool route_to_terminal)
-{
-  the_settings.route_errors_to_terminal = route_to_terminal;
-}
-
-/* Route error messages to listing file? */
-bool
-settings_get_error_routing_to_listing (void)
-{
-  return the_settings.route_errors_to_listing;
-}
-
-/* Sets whether error messages should be routed to the
-   listing file. */
-void
-settings_set_error_routing_to_listing ( bool route_to_listing)
-{
-  the_settings.route_errors_to_listing = route_to_listing;
-}
-
 /* Compress system files by default? */
 bool
 settings_get_scompression (void)
@@ -408,46 +352,24 @@ settings_set_blanks ( double blanks)
   the_settings.blanks = blanks;
 }
 
-/* Maximum number of warnings + errors. */
+/* Returns the maximum number of messages to show of the given SEVERITY before
+   aborting.  (The value for MSG_S_WARNING is interpreted as maximum number of
+   warnings and errors combined.) */
 int
-settings_get_mxwarns (void)
+settings_get_max_messages (enum msg_severity severity)
 {
-  return the_settings.mxwarns;
+  assert (severity < MSG_N_SEVERITIES);
+  return the_settings.max_messages[severity];
 }
 
-/* Sets maximum number of warnings + errors. */
+/* Sets the maximum number of messages to show of the given SEVERITY before
+   aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
+   number of warnings and errors combined.) */
 void
-settings_set_mxwarns ( int mxwarns)
+settings_set_max_messages (enum msg_severity severity, int max)
 {
-  the_settings.mxwarns = mxwarns;
-}
-
-/* Maximum number of errors. */
-int
-settings_get_mxerrs (void)
-{
-  return the_settings.mxerrs;
-}
-
-/* Sets maximum number of errors. */
-void
-settings_set_mxerrs ( int mxerrs)
-{
-  the_settings.mxerrs = mxerrs;
-}
-
-/* Whether commands are written to the display. */
-bool
-settings_get_printback (void)
-{
-  return the_settings.printback;
-}
-
-/* Sets whether commands are written to the display. */
-void
-settings_set_printback ( bool printback)
-{
-  the_settings.printback = printback;
+  assert (severity < MSG_N_SEVERITIES);
+  the_settings.max_messages[severity] = max;
 }
 
 /* Independent of get_printback, controls whether the commands
@@ -757,3 +679,18 @@ settings_dollar_template (const struct fmt_spec *fmt)
 
   return ds_cstr (&str);
 }
+
+void
+settings_set_output_routing (enum settings_output_type type,
+                             enum settings_output_devices devices)
+{
+  assert (type < SETTINGS_N_OUTPUT_TYPES);
+  the_settings.output_routing[type] = devices;
+}
+
+enum settings_output_devices
+settings_get_output_routing (enum settings_output_type type)
+{
+  assert (type < SETTINGS_N_OUTPUT_TYPES);
+  return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
+}
index 3de1715f0738595dc7fd53a4df82b34a96dc98f0..7dcb0e34a479c2d5bf18cd431cd810e626decc6f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <data/format.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
+
+#include "data/format.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
 
 struct caseproto;
 struct settings;
@@ -63,22 +65,12 @@ void settings_set_viewwidth ( int);
 bool settings_get_safer_mode (void);
 void settings_set_safer_mode (void);
 
-bool settings_get_echo (void);
-void settings_set_echo ( bool);
 bool settings_get_include (void);
 void settings_set_include ( bool);
 
 int settings_get_epoch (void);
 void settings_set_epoch ( int);
 
-bool settings_get_errorbreak (void);
-void settings_set_errorbreak ( bool);
-
-bool settings_get_error_routing_to_terminal (void);
-void settings_set_error_routing_to_terminal (bool);
-bool settings_get_error_routing_to_listing (void);
-void settings_set_error_routing_to_listing (bool);
-
 bool settings_get_scompression (void);
 void settings_set_scompression (bool);
 
@@ -87,13 +79,9 @@ void settings_set_undefined (bool);
 double settings_get_blanks (void);
 void settings_set_blanks (double);
 
-int settings_get_mxwarns (void);
-void settings_set_mxwarns ( int);
-int settings_get_mxerrs (void);
-void settings_set_mxerrs ( int);
+int settings_get_max_messages (enum msg_severity);
+void settings_set_max_messages (enum msg_severity, int max);
 
-bool settings_get_printback (void);
-void settings_set_printback (bool);
 bool settings_get_mprint (void);
 void settings_set_mprint (bool);
 
@@ -140,4 +128,26 @@ const struct fmt_number_style * settings_get_style (enum fmt_type type);
 
 char * settings_dollar_template (const struct fmt_spec *fmt);
 
+/* Routing of different kinds of output. */
+enum settings_output_devices
+  {
+    SETTINGS_DEVICE_LISTING = 1 << 0,  /* File or device. */
+    SETTINGS_DEVICE_TERMINAL = 1 << 1, /* Screen. */
+    SETTINGS_DEVICE_UNFILTERED = 1 << 2 /* Gets all output, no filtering. */
+  };
+
+enum settings_output_type
+  {
+    SETTINGS_OUTPUT_ERROR,      /* Errors and warnings. */
+    SETTINGS_OUTPUT_NOTE,       /* Notes. */
+    SETTINGS_OUTPUT_SYNTAX,     /* Syntax. */
+    SETTINGS_OUTPUT_RESULT,     /* Everything else. */
+    SETTINGS_N_OUTPUT_TYPES
+  };
+
+void settings_set_output_routing (enum settings_output_type,
+                                  enum settings_output_devices);
+enum settings_output_devices settings_get_output_routing (
+  enum settings_output_type);
+
 #endif /* !settings_h */
index 6ffaa4c2bed24a603e3ce0aa267c16661e82f471..32056215e4ace37d4fcd9b544c3e48c493d82dec 100644 (file)
@@ -99,6 +99,27 @@ subcase_destroy (struct subcase *sc)
   caseproto_unref (sc->proto);
 }
 
+/* Returns true if VAR already has a field in SC,
+   false otherwise. */
+bool
+subcase_contains_var (const struct subcase *sc, const struct variable *var)
+{
+  return subcase_contains (sc, var_get_case_index (var));
+}
+
+/* Returns true if CASE_INDEX already has a field in SC,
+   false otherwise. */
+bool
+subcase_contains (const struct subcase *sc, int case_index)
+{
+  size_t i;
+
+  for (i = 0; i < sc->n_fields; i++)
+    if (sc->fields[i].case_index == case_index)
+      return true;
+
+  return false;
+}
 
 /* Add a field for VAR to SC, with DIRECTION as the sort order.
    Returns true if successful, false if VAR already has a field
@@ -107,8 +128,13 @@ bool
 subcase_add_var (struct subcase *sc, const struct variable *var,
                  enum subcase_direction direction)
 {
-  return subcase_add (sc, var_get_case_index (var),
-                     var_get_width (var), direction);
+  if (!subcase_contains_var (sc, var))
+    {
+      subcase_add_var_always (sc, var, direction);
+      return true;
+    }
+  else
+    return false;
 }
 
 /* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
@@ -116,14 +142,35 @@ subcase_add_var (struct subcase *sc, const struct variable *var,
    in SC. */
 bool
 subcase_add (struct subcase *sc, int case_index, int width,
-                 enum subcase_direction direction)
+             enum subcase_direction direction)
 {
-  struct subcase_field *field;
-  size_t i;
+  if (!subcase_contains (sc, case_index))
+    {
+      subcase_add_always (sc, case_index, width, direction);
+      return true;
+    }
+  else
+    return false;
+}
 
-  for (i = 0; i < sc->n_fields; i++)
-    if (sc->fields[i].case_index == case_index)
-      return false;
+/* Add a field for VAR to SC, with DIRECTION as the sort order,
+   regardless of whether VAR already has a field in SC. */
+void
+subcase_add_var_always (struct subcase *sc, const struct variable *var,
+                        enum subcase_direction direction)
+{
+  return subcase_add_always (sc, var_get_case_index (var),
+                             var_get_width (var), direction);
+}
+
+/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the
+   sort order, regardless of whether CASE_INDEX already has a
+   field in SC. */
+void
+subcase_add_always (struct subcase *sc, int case_index, int width,
+                    enum subcase_direction direction)
+{
+  struct subcase_field *field;
 
   sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
   field = &sc->fields[sc->n_fields++];
@@ -131,7 +178,27 @@ subcase_add (struct subcase *sc, int case_index, int width,
   field->width = width;
   field->direction = direction;
   invalidate_proto (sc);
-  return true;
+}
+
+/* Adds a field to SC for each column in PROTO, so that SC
+   contains all of the columns in PROTO in the same order as a
+   case conforming to PROTO.  The fields are added with
+   ascending direction. */
+void
+subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
+{
+  size_t n = caseproto_get_n_widths (proto);
+  size_t i;
+
+  sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
+  for (i = 0; i < n; i++)
+    {
+      struct subcase_field *field = &sc->fields[sc->n_fields++];
+      field->case_index = i;
+      field->width = caseproto_get_width (proto, i);
+      field->direction = SC_ASCEND;
+    }
+  invalidate_proto (sc);
 }
 
 /* Obtains a caseproto for a case described by SC.  The caller
@@ -139,7 +206,7 @@ subcase_add (struct subcase *sc, int case_index, int width,
 const struct caseproto *
 subcase_get_proto (const struct subcase *sc_)
 {
-  struct subcase *sc = (struct subcase *) sc_;
+  struct subcase *sc = CONST_CAST (struct subcase *, sc_);
 
   if (sc->proto == NULL)
     {
index 6e59da1d3679ac5b4c89f8a1b6a6ca6bc910627c..71bf6fd7cc33d4227a4e3c4380f6773a1bfc599a 100644 (file)
@@ -60,17 +60,27 @@ void subcase_clone (struct subcase *, const struct subcase *);
 void subcase_clear (struct subcase *);
 void subcase_destroy (struct subcase *);
 
-bool subcase_add (struct subcase *sc, int index, int width,
-                 enum subcase_direction direction);
+bool subcase_contains (const struct subcase *, int case_index);
+bool subcase_contains_var (const struct subcase *, const struct variable *);
 
+bool subcase_add (struct subcase *, int case_index, int width,
+                 enum subcase_direction direction);
 bool subcase_add_var (struct subcase *, const struct variable *,
                       enum subcase_direction);
 
+void subcase_add_always (struct subcase *sc, int case_index, int width,
+                         enum subcase_direction direction);
+void subcase_add_var_always (struct subcase *, const struct variable *,
+                             enum subcase_direction);
+void subcase_add_proto_always (struct subcase *, const struct caseproto *);
+
 const struct caseproto *subcase_get_proto (const struct subcase *);
 
 static inline bool subcase_is_empty (const struct subcase *);
 static inline size_t subcase_get_n_fields (const struct subcase *);
 
+static inline size_t subcase_get_case_index (const struct subcase *,
+                                             size_t idx);
 static inline enum subcase_direction subcase_get_direction (
   const struct subcase *, size_t idx);
 
@@ -100,6 +110,12 @@ bool subcase_equal_cx (const struct subcase *,
 bool subcase_equal_xx (const struct subcase *,
                        const union value *a, const union value *b);
 
+static inline size_t
+subcase_get_case_index (const struct subcase *sc, size_t idx)
+{
+  return sc->fields[idx].case_index;
+}
+
 static inline enum subcase_direction
 subcase_get_direction (const struct subcase *sc, size_t idx)
 {
index c8061f7bd5d7fee54c47f5e65aa739b442f10dce..6d6b57a6181b7c156bea52804418cd8771276a53 100644 (file)
 #include <data/value.h>
 #include <data/variable.h>
 #include <libpspp/array.h>
+#include <libpspp/cast.h>
 #include <libpspp/compiler.h>
 #include <libpspp/hash-functions.h>
 #include <libpspp/hmap.h>
+#include <libpspp/intern.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
 
 #include "xalloc.h"
 
-static struct atom *atom_create (const char *string);
-static void atom_destroy (struct atom *);
-static const char *atom_to_string (const struct atom *);
-
-/* Returns the label in VL.  The caller must not modify or free
-   the returned value. */
-const char *
-val_lab_get_label (const struct val_lab *vl)
-{
-  return atom_to_string (vl->label);
-}
-
 /* Creates and returns a new, empty set of value labels with the
    given WIDTH. */
 struct val_labs *
@@ -68,7 +58,7 @@ val_labs_clone (const struct val_labs *vls)
 
   copy = val_labs_create (vls->width);
   HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
-    val_labs_add (copy, &label->value, atom_to_string (label->label));
+    val_labs_add (copy, &label->value, label->label);
   return copy;
 }
 
@@ -123,7 +113,7 @@ val_labs_clear (struct val_labs *vls)
     {
       hmap_delete (&vls->labels, &label->node);
       value_destroy (&label->value, vls->width);
-      atom_destroy (label->label);
+      intern_unref (label->label);
       free (label);
     }
 }
@@ -143,7 +133,7 @@ do_add_val_lab (struct val_labs *vls, const union value *value,
   struct val_lab *lab = xmalloc (sizeof *lab);
   value_init (&lab->value, vls->width);
   value_copy (&lab->value, value, vls->width);
-  lab->label = atom_create (label);
+  lab->label = intern_new (label);
   hmap_insert (&vls->labels, &lab->node, value_hash (value, vls->width, 0));
 }
 
@@ -169,11 +159,11 @@ void
 val_labs_replace (struct val_labs *vls, const union value *value,
                   const char *label)
 {
-  struct val_lab *vl = (struct val_lab *) val_labs_lookup (vls, value);
+  struct val_lab *vl = val_labs_lookup (vls, value);
   if (vl != NULL)
     {
-      atom_destroy (vl->label);
-      vl->label = atom_create (label);
+      intern_unref (vl->label);
+      vl->label = intern_new (label);
     }
   else
     do_add_val_lab (vls, value, label);
@@ -181,12 +171,11 @@ val_labs_replace (struct val_labs *vls, const union value *value,
 
 /* Removes LABEL from VLS. */
 void
-val_labs_remove (struct val_labs *vls, const struct val_lab *label_)
+val_labs_remove (struct val_labs *vls, struct val_lab *label)
 {
-  struct val_lab *label = (struct val_lab *) label_;
   hmap_delete (&vls->labels, &label->node);
   value_destroy (&label->value, vls->width);
-  atom_destroy (label->label);
+  intern_unref (label->label);
   free (label);
 }
 
@@ -197,13 +186,13 @@ const char *
 val_labs_find (const struct val_labs *vls, const union value *value)
 {
   const struct val_lab *label = val_labs_lookup (vls, value);
-  return label ? atom_to_string (label->label) : NULL;
+  return label ? label->label : NULL;
 }
 
 /* Searches VLS for a value label for VALUE.  If successful,
    returns the value label; otherwise, returns a null pointer.
    Returns a null pointer if VLS is null. */
-const struct val_lab *
+struct val_lab *
 val_labs_lookup (const struct val_labs *vls, const union value *value)
 {
   if (vls != NULL)
@@ -270,89 +259,3 @@ val_labs_sorted (const struct val_labs *vls)
   else
     return NULL;
 }
-\f
-/* Atoms: reference-counted constant strings. */
-
-/* An atom. */
-struct atom
-  {
-    struct hmap_node node;      /* Hash map node. */
-    char *string;               /* String value. */
-    unsigned ref_count;         /* Number of references. */
-  };
-
-/* Hash table of atoms. */
-static struct hmap atoms = HMAP_INITIALIZER (atoms);
-
-static void free_atom (struct atom *atom);
-static void free_all_atoms (void);
-
-/* Creates and returns an atom for STRING. */
-static struct atom *
-atom_create (const char *string)
-{
-  static bool initialized;
-  struct atom *atom;
-  size_t hash;
-
-  assert (string != NULL);
-
-  if (!initialized)
-    {
-      initialized = true;
-      atexit (free_all_atoms);
-    }
-
-  hash = hash_string (string, 0);
-  HMAP_FOR_EACH_WITH_HASH (atom, struct atom, node, hash, &atoms)
-    if (!strcmp (atom->string, string))
-      {
-        atom->ref_count++;
-        return atom;
-      }
-
-  atom = xmalloc (sizeof *atom);
-  atom->string = xstrdup (string);
-  atom->ref_count = 1;
-  hmap_insert (&atoms, &atom->node, hash);
-  return atom;
-}
-
-/* Destroys ATOM. */
-static void
-atom_destroy (struct atom *atom)
-{
-  if (atom != NULL)
-    {
-      assert (atom->ref_count > 0);
-      atom->ref_count--;
-      if (atom->ref_count == 0)
-        {
-          hmap_delete (&atoms, &atom->node);
-          free_atom (atom);
-        }
-    }
-}
-
-/* Returns the string associated with ATOM. */
-static const char *
-atom_to_string (const struct atom *atom)
-{
-  return atom->string;
-}
-
-static void
-free_atom (struct atom *atom)
-{
-  free (atom->string);
-  free (atom);
-}
-
-static void
-free_all_atoms (void)
-{
-  struct atom *atom, *next;
-
-  HMAP_FOR_EACH_SAFE (atom, next, struct atom, node, &atoms)
-    free_atom (atom);
-}
index 53d13a389700eb586af6aaf14bd82bd540311235..d6f65d43c334d3b8657993af922cc26673cfe4a6 100644 (file)
@@ -38,7 +38,7 @@ struct val_lab
   {
     struct hmap_node node;      /* Node in hash map. */
     union value value;          /* The value being labeled. */
-    struct atom *label;         /* A ref-counted string. */
+    const char *label;          /* An interned string. */
   };
 
 /* Returns the value in VL.  The caller must not modify or free
@@ -52,7 +52,13 @@ static inline const union value *val_lab_get_value (const struct val_lab *vl)
   return &vl->value;
 }
 
-const char *val_lab_get_label (const struct val_lab *);
+/* Returns the label in VL.  The caller must not modify or free the returned
+   value. */
+static inline const char *
+val_lab_get_label (const struct val_lab *vl)
+{
+  return vl->label;
+}
 \f
 /* A set of value labels. */
 struct val_labs
@@ -70,7 +76,7 @@ size_t val_labs_count (const struct val_labs *);
 
 /* Looking up value labels. */
 const char *val_labs_find (const struct val_labs *, const union value *);
-const struct val_lab *val_labs_lookup (const struct val_labs *,
+struct val_lab *val_labs_lookup (const struct val_labs *,
                                        const union value *);
 
 /* Basic properties. */
@@ -82,7 +88,7 @@ void val_labs_set_width (struct val_labs *, int new_width);
 /* Adding value labels. */
 bool val_labs_add (struct val_labs *, const union value *, const char *);
 void val_labs_replace (struct val_labs *, const union value *, const char *);
-void val_labs_remove (struct val_labs *, const struct val_lab *);
+void val_labs_remove (struct val_labs *, struct val_lab *);
 
 /* Iterating through value labels. */
 const struct val_lab *val_labs_first (const struct val_labs *);
index d1e308640d05268df79f8639848cef04c618ba23..05edc57e2db85a3c02df4fbe3a16a6747d92c4bc 100644 (file)
@@ -957,7 +957,7 @@ void *
 var_attach_aux (const struct variable *v_,
                 void *aux, void (*aux_dtor) (struct variable *))
 {
-  struct variable *v = (struct variable *) v_ ; /* cast away const  */
+  struct variable *v = CONST_CAST (struct variable *, v_);
   assert (v->aux == NULL);
   assert (aux != NULL);
   v->aux = aux;
@@ -1015,7 +1015,7 @@ var_get_obs_vals (const struct variable *v)
 void
 var_set_obs_vals (const struct variable *v_, struct cat_vals *cat_vals)
 {
-  struct variable *v = (struct variable *) v_ ; /* cast away const */
+  struct variable *v = CONST_CAST (struct variable *, v_ );
   cat_stored_values_destroy (v->obs_vals);
   v->obs_vals = cat_vals;
 }
@@ -1035,7 +1035,7 @@ var_has_obs_vals (const struct variable *v)
 struct attrset *
 var_get_attributes (const struct variable *v) 
 {
-  return (struct attrset *) &v->attributes;
+  return CONST_CAST (struct attrset *, &v->attributes);
 }
 
 /* Replaces variable V's attributes set by a copy of ATTRS. */
index 4210b7fce45f8f05153f9fd4bd2cd28881255b01..3052b52353ca54416ffbb53f66c4354787bf6924 100644 (file)
@@ -13,9 +13,6 @@ include $(top_srcdir)/src/language/expressions/automake.mk
 noinst_LTLIBRARIES +=  src/language/liblanguage.la
 
 
-src_language_liblanguage_la_LIBADD = \
-       src/output/charts/libcharts.la
-
 src_language_liblanguage_la_SOURCES = \
        src/language/syntax-file.c \
        src/language/syntax-file.h \
index 32dba0b4f7cd0ca7760f18315e13ae0b845069a0..448fae7ea803463f11a54edbec50a23c816875a4 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <unistd.h>
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if HAVE_READLINE
+#include <readline/readline.h>
+#endif
 
 #include <data/casereader.h>
 #include <data/dictionary.h>
 #include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/table.h>
 #include <libpspp/getl.h>
-
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#if HAVE_READLINE
-#include <readline/readline.h>
-#endif
+#include <output/text-item.h>
 
 #include "xalloc.h"
 #include "xmalloca.h"
@@ -143,11 +140,7 @@ cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
 {
   int result;
 
-  som_new_series ();
-
   result = do_parse_command (lexer, ds, state);
-  if (cmd_result_is_failure (result))
-    lex_discard_rest_of_command (lexer);
 
   assert (!proc_is_open (ds));
   unset_cmd_algorithm ();
@@ -175,8 +168,9 @@ static enum cmd_result
 do_parse_command (struct lexer *lexer,
                  struct dataset *ds, enum cmd_state state)
 {
-  const struct command *command;
+  const struct command *command = NULL;
   enum cmd_result result;
+  bool opened = false;
 
   /* Read the command's first token. */
   prompt_set_style (PROMPT_FIRST);
@@ -203,53 +197,54 @@ do_parse_command (struct lexer *lexer,
       result = CMD_FAILURE;
       goto finish;
     }
-  else if (command->function == NULL)
+  text_item_submit (text_item_create (TEXT_ITEM_COMMAND_OPEN, command->name));
+  opened = true;
+
+  if (command->function == NULL)
     {
       msg (SE, _("%s is not yet implemented."), command->name);
       result = CMD_NOT_IMPLEMENTED;
-      goto finish;
     }
   else if ((command->flags & F_TESTING) && !settings_get_testing_mode ())
     {
       msg (SE, _("%s may be used only in testing mode."), command->name);
       result = CMD_FAILURE;
-      goto finish;
     }
   else if ((command->flags & F_ENHANCED) && settings_get_syntax () != ENHANCED)
     {
       msg (SE, _("%s may be used only in enhanced syntax mode."),
            command->name);
       result = CMD_FAILURE;
-      goto finish;
     }
   else if (!in_correct_state (command, state))
     {
       report_state_mismatch (command, state);
       result = CMD_FAILURE;
-      goto finish;
     }
-
-  /* Execute command. */
-  msg_set_command_name (command->name);
-  tab_set_command_name (command->name);
-  result = command->function (lexer, ds);
-  tab_set_command_name (NULL);
-  msg_set_command_name (NULL);
+  else
+    {
+      /* Execute command. */
+      result = command->function (lexer, ds);
+    }
 
   assert (cmd_result_is_valid (result));
 
  finish:
-  if ( cmd_result_is_failure (result))
+  if (cmd_result_is_failure (result))
     {
-      const struct source_stream *cs = lex_get_source_stream (lexer);
-
-      if ( source_stream_current_error_mode (cs) == ERRMODE_STOP )
+      lex_discard_rest_of_command (lexer);
+      if (source_stream_current_error_mode (
+            lex_get_source_stream (lexer)) == ERRMODE_STOP )
        {
          msg (MW, _("Error encountered while ERROR=STOP is effective."));
          result = CMD_CASCADING_FAILURE;
        }
     }
 
+  if (opened)
+    text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
+                                        command->name));
+
   return result;
 }
 
index 32847bb4a9298bd100f0cb80e8489097adc7d8ca..cb608f769d5d4b91adbb5c21fa5ae3d4403a2c08 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009 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
@@ -29,6 +29,7 @@
 #include <language/command.h>
 #include <language/lexer/lexer.h>
 #include <language/lexer/variable-parser.h>
+#include <libpspp/cast.h>
 #include <libpspp/ll.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
@@ -512,10 +513,10 @@ find_substitution (struct repeat_block *block, struct substring name)
 /* Makes appropriate DO REPEAT macro substitutions within the
    repeated lines. */
 static void
-do_repeat_filter (struct getl_interface *block_,
-                  struct string *line)
+do_repeat_filter (struct getl_interface *interface, struct string *line)
 {
-  struct repeat_block *block = (struct repeat_block *) block_;
+  struct repeat_block *block
+    = UP_CAST (interface, struct repeat_block, parent);
   bool in_apos, in_quote, dot;
   struct substring input;
   struct string output;
@@ -557,7 +558,8 @@ do_repeat_filter (struct getl_interface *block_,
 static struct repeat_line *
 current_line (const struct getl_interface *interface)
 {
-  struct repeat_block *block = (struct repeat_block *) interface;
+  struct repeat_block *block
+    = UP_CAST (interface, struct repeat_block, parent);
   return (block->cur_line != ll_null (&block->lines)
           ? ll_data (block->cur_line, struct repeat_line, ll)
           : NULL);
@@ -570,7 +572,8 @@ static bool
 do_repeat_read  (struct getl_interface *interface,
                  struct string *output)
 {
-  struct repeat_block *block = (struct repeat_block *) interface;
+  struct repeat_block *block
+    = UP_CAST (interface, struct repeat_block, parent);
   struct repeat_line *line;
 
   block->cur_line = ll_next (block->cur_line);
@@ -591,9 +594,10 @@ do_repeat_read  (struct getl_interface *interface,
 /* Frees a DO REPEAT block.
    Called by getl to close out the DO REPEAT block. */
 static void
-do_repeat_close (struct getl_interface *block_)
+do_repeat_close (struct getl_interface *interface)
 {
-  struct repeat_block *block = (struct repeat_block *) block_;
+  struct repeat_block *block
+    = UP_CAST (interface, struct repeat_block, parent);
   pool_destroy (block->pool);
 }
 
index 020f8e4c7e5a20a0caabc4add9f228f98937d1b6..eb578e270d3e9fee03e5b9c50e3fb688abad7b2f 100644 (file)
@@ -31,7 +31,7 @@
 #include <language/data-io/data-reader.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -644,8 +644,7 @@ dump_fixed_table (const struct data_parser *parser,
   struct tab_table *t;
   size_t i;
 
-  t = tab_create (4, parser->field_cnt + 1, 0);
-  tab_columns (t, TAB_COL_DOWN, 1);
+  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"));
@@ -653,7 +652,6 @@ dump_fixed_table (const struct data_parser *parser,
   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);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   for (i = 0; i < parser->field_cnt; i++)
     {
@@ -685,14 +683,12 @@ dump_delimited_table (const struct data_parser *parser,
   struct tab_table *t;
   size_t i;
 
-  t = tab_create (2, parser->field_cnt + 1, 0);
-  tab_columns (t, TAB_COL_DOWN, 1);
+  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);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   for (i = 0; i < parser->field_cnt; i++)
     {
index 6f620a6a948341a0dfa5db150763d20f51e92284..74e4c5692b1b83a95987bc1e16e7b92aaeebc500 100644 (file)
@@ -34,6 +34,7 @@
 #include <language/lexer/lexer.h>
 #include <language/prompt.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
@@ -140,7 +141,7 @@ dfm_open_reader (struct file_handle *fh, struct lexer *lexer)
   if (fh_get_referent (fh) != FH_REF_INLINE)
     {
       struct stat s;
-      r->where.file_name = fh_get_file_name (fh);
+      r->where.file_name = CONST_CAST (char *, fh_get_file_name (fh));
       r->where.line_number = 0;
       r->file = fn_open (fh_get_file_name (fh),
                          fh_get_mode (fh) == FH_MODE_TEXT ? "r" : "rb");
index c3f9b0881b959fac98a3cffac628662ffe143299..60f51b523b0c0250abbe4ae43753880be464ff4b 100644 (file)
 #include <data/data-out.h>
 #include <data/format.h>
 #include <data/procedure.h>
-#include <data/short-names.h>
+#include <data/subcase.h>
 #include <data/variable.h>
 #include <language/command.h>
 #include <language/dictionary/split-file.h>
 #include <language/lexer/lexer.h>
 #include <libpspp/compiler.h>
-#include <libpspp/message.h>
+#include <libpspp/ll.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include <output/htmlP.h>
-#include <output/manager.h>
-#include <output/output.h>
-#include <output/table.h>
+#include <output/tab.h>
+#include <output/table-item.h>
 
 #include "minmax.h"
 #include "xalloc.h"
      *variables=varlist("PV_NO_SCRATCH");
      cases=:from n:first,"%s>0"/by n:step,"%s>0"/ *to n:last,"%s>0";
      +format=numbering:numbered/!unnumbered,
-             wrap:!wrap/single,
-             weight:weight/!noweight.
+             wrap:!wrap/single.
 */
 /* (declarations) */
 /* (functions) */
 
-/* Layout for one output driver. */
-struct list_ext
-  {
-    int type;          /* 0=Values and labels fit across the page. */
-    size_t n_vertical; /* Number of labels to list vertically. */
-    size_t header_rows;        /* Number of header rows. */
-    char **header;     /* The header itself. */
-  };
-
 /* Parsed command. */
 static struct cmd_list cmd;
 
-/* Line buffer. */
-static struct string line_buffer;
-
-/* TTY-style output functions. */
-static unsigned n_lines_remaining (struct outp_driver *d);
-static unsigned n_chars_width (struct outp_driver *d);
-static void write_line (struct outp_driver *d, const char *s);
-
-/* Other functions. */
-static void list_case (const struct ccase *, casenumber case_idx,
-                       const struct dataset *);
-static void determine_layout (void);
-static void clean_up (void);
-static void write_header (struct outp_driver *);
-static void write_all_headers (struct casereader *, const struct dataset*);
-
-/* Returns the number of text lines that can fit on the remainder of
-   the page. */
-static inline unsigned
-n_lines_remaining (struct outp_driver *d)
-{
-  int diff;
-
-  diff = d->length - d->cp_y;
-  return (diff > 0) ? (diff / d->font_height) : 0;
-}
-
-/* Returns the number of fixed-width character that can fit across the
-   page. */
-static inline unsigned
-n_chars_width (struct outp_driver *d)
-{
-  return d->width / d->fixed_width;
-}
-
-/* Writes the line S at the current position and advances to the next
-   line.  */
-static void
-write_line (struct outp_driver *d, const char *s)
-{
-  struct outp_text text;
-
-  assert (d->cp_y + d->font_height <= d->length);
-  text.font = OUTP_FIXED;
-  text.justification = OUTP_LEFT;
-  text.string = ss_cstr (s);
-  text.x = d->cp_x;
-  text.y = d->cp_y;
-  text.h = text.v = INT_MAX;
-  d->class->text_draw (d, &text);
-  d->cp_x = 0;
-  d->cp_y += d->font_height;
-}
-
 /* Parses and executes the LIST procedure. */
 int
 cmd_list (struct lexer *lexer, struct dataset *ds)
 {
   struct dictionary *dict = dataset_dict (ds);
-  struct variable *casenum_var = NULL;
   struct casegrouper *grouper;
   struct casereader *group;
-  casenumber case_idx;
+  struct subcase sc;
+  size_t i;
   bool ok;
 
   if (!parse_list (lexer, ds, &cmd, NULL))
@@ -187,584 +121,65 @@ cmd_list (struct lexer *lexer, struct dataset *ds)
       cmd.step = 1;
     }
 
-  /* Weighting variable. */
-  if (cmd.weight == LST_WEIGHT)
-    {
-      if (dict_get_weight (dict) != NULL)
-       {
-         size_t i;
+  subcase_init_empty (&sc);
+  for (i = 0; i < cmd.n_variables; i++)
+    subcase_add_var (&sc, cmd.v_variables[i], SC_ASCEND);
 
-         for (i = 0; i < cmd.n_variables; i++)
-           if (cmd.v_variables[i] == dict_get_weight (dict))
-             break;
-         if (i >= cmd.n_variables)
-           {
-             /* Add the weight variable to the end of the variable list. */
-             cmd.n_variables++;
-             cmd.v_variables = xnrealloc (cmd.v_variables, cmd.n_variables,
-                                           sizeof *cmd.v_variables);
-             cmd.v_variables[cmd.n_variables - 1]
-                = dict_get_weight (dict);
-           }
-       }
-      else
-       msg (SW, _("`/FORMAT WEIGHT' specified, but weighting is not on."));
-    }
-
-  /* Case number. */
-  if (cmd.numbering == LST_NUMBERED)
+  grouper = casegrouper_create_splits (proc_open (ds), dict);
+  while (casegrouper_get_next_group (grouper, &group))
     {
-      /* Initialize the case-number variable. */
-      int width = cmd.last == LONG_MAX ? 5 : intlog10 (cmd.last);
-      struct fmt_spec format = fmt_for_output (FMT_F, width, 0);
-      casenum_var = var_create ("Case#", 0);
-      var_set_both_formats (casenum_var, &format);
-
-      /* Add the weight variable at the beginning of the variable list. */
-      cmd.n_variables++;
-      cmd.v_variables = xnrealloc (cmd.v_variables,
-                                   cmd.n_variables, sizeof *cmd.v_variables);
-      memmove (&cmd.v_variables[1], &cmd.v_variables[0],
-              (cmd.n_variables - 1) * sizeof *cmd.v_variables);
-      cmd.v_variables[0] = casenum_var;
-    }
-
-  determine_layout ();
-
-  case_idx = 0;
-  for (grouper = casegrouper_create_splits (proc_open (ds), dict);
-       casegrouper_get_next_group (grouper, &group);
-       casereader_destroy (group))
-    {
-      struct ccase *c;
-
-      write_all_headers (group, ds);
-      for (; (c = casereader_read (group)) != NULL; case_unref (c))
+      struct ccase *ccase;
+      struct table *t;
+
+      group = casereader_project (group, &sc);
+      if (cmd.numbering == LST_NUMBERED)
+        group = casereader_create_arithmetic_sequence (group, 1, 1);
+      group = casereader_select (group, cmd.first - 1,
+                                 (cmd.last != LONG_MAX ? cmd.last
+                                  : CASENUMBER_MAX), cmd.step);
+
+      ccase = casereader_peek (group, 0);
+      if (ccase != NULL)
         {
-          case_idx++;
-          if (case_idx >= cmd.first && case_idx <= cmd.last
-              && (case_idx - cmd.first) % cmd.step == 0)
-            list_case (c, case_idx, ds);
+          output_split_file_values (ds, ccase);
+          case_unref (ccase);
         }
-    }
-  ok = casegrouper_destroy (grouper);
-  ok = proc_commit (ds) && ok;
-
-  ds_destroy(&line_buffer);
-
-  clean_up ();
-
-  var_destroy (casenum_var);
-
-  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
-}
 
-/* Writes headers to all devices.  This is done at the beginning of
-   each SPLIT FILE group. */
-static void
-write_all_headers (struct casereader *input, const struct dataset *ds)
-{
-  struct outp_driver *d;
-  struct ccase *c;
-
-  c = casereader_peek (input, 0);
-  if (c == NULL)
-    return;
-  output_split_file_values (ds, c);
-  case_unref (c);
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    {
-      if (!d->class->special)
-       {
-         d->cp_y += d->font_height;            /* Blank line. */
-         write_header (d);
-       }
-      else if (d->class == &html_class)
-       {
-         struct html_driver_ext *x = d->ext;
-
-         fputs ("<TABLE BORDER=1>\n  <TR>\n", x->file);
-
-         {
-           size_t i;
+      if (cmd.numbering == LST_NUMBERED)
+        {
+          struct fmt_spec fmt;
+          size_t col;
+          int width;
 
-           for (i = 0; i < cmd.n_variables; i++)
-             fprintf (x->file, "    <TH><EM>%s</EM></TH>\n",
-                      var_get_name (cmd.v_variables[i]));
-         }
+          width = cmd.last == LONG_MAX ? 5 : intlog10 (cmd.last);
+          fmt = fmt_for_output (FMT_F, width, 0);
+          col = caseproto_get_n_widths (casereader_get_proto (group)) - 1;
 
-         fputs ("  </TR>\n", x->file);
-       }
+          t = table_from_casereader (group, col, _("Case Number"), &fmt);
+        }
       else
-       NOT_REACHED ();
-    }
-}
-
-/* Writes the headers.  Some of them might be vertical; most are
-   probably horizontal. */
-static void
-write_header (struct outp_driver *d)
-{
-  struct list_ext *prc = d->prc;
-
-  if (!prc->header_rows)
-    return;
-
-  if (n_lines_remaining (d) < prc->header_rows + 1)
-    {
-      outp_eject_page (d);
-      assert (n_lines_remaining (d) >= prc->header_rows + 1);
-    }
-
-  /* Design the header. */
-  if (!prc->header)
-    {
-      size_t i;
-      size_t x;
-
-      /* Allocate, initialize header. */
-      prc->header = xnmalloc (prc->header_rows, sizeof *prc->header);
-      {
-       int w = n_chars_width (d);
-       for (i = 0; i < prc->header_rows; i++)
-         {
-           prc->header[i] = xmalloc (w + 1);
-           memset (prc->header[i], ' ', w);
-         }
-      }
-
-      /* Put in vertical names. */
-      for (i = x = 0; i < prc->n_vertical; i++)
-       {
-         const struct variable *v = cmd.v_variables[i];
-          const char *name = var_get_name (v);
-          size_t name_len = strlen (name);
-          const struct fmt_spec *print = var_get_print_format (v);
-         size_t j;
-
-         memset (&prc->header[prc->header_rows - 1][x], '-', print->w);
-         x += print->w - 1;
-         for (j = 0; j < name_len; j++)
-           prc->header[name_len - j - 1][x] = name[j];
-         x += 2;
-       }
-
-      /* Put in horizontal names. */
-      for (; i < cmd.n_variables; i++)
-       {
-         const struct variable *v = cmd.v_variables[i];
-          const char *name = var_get_name (v);
-          size_t name_len = strlen (name);
-          const struct fmt_spec *print = var_get_print_format (v);
-
-         memset (&prc->header[prc->header_rows - 1][x], '-',
-                 MAX (print->w, (int) name_len));
-         if ((int) name_len < print->w)
-           x += print->w - name_len;
-         memcpy (&prc->header[0][x], name, name_len);
-         x += name_len + 1;
-       }
-
-      /* Add null bytes. */
-      for (i = 0; i < prc->header_rows; i++)
-       {
-         for (x = n_chars_width (d); x >= 1; x--)
-           if (prc->header[i][x - 1] != ' ')
-             {
-               prc->header[i][x] = 0;
-               break;
-             }
-         assert (x);
-       }
-    }
-
-  /* Write out the header, in back-to-front order except for the last line. */
-  if (prc->header_rows >= 2)
-    {
-      size_t i;
-
-      for (i = prc->header_rows - 1; i-- != 0; )
-        write_line (d, prc->header[i]);
-    }
-  write_line (d, prc->header[prc->header_rows - 1]);
-}
-
-
-/* Frees up all the memory we've allocated. */
-static void
-clean_up (void)
-{
-  struct outp_driver *d;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    if (d->class->special == 0)
-      {
-       struct list_ext *prc = d->prc;
-       size_t i;
+        t = NULL;
 
-       if (prc->header)
-         {
-           for (i = 0; i < prc->header_rows; i++)
-             free (prc->header[i]);
-           free (prc->header);
-         }
-       free (prc);
-      }
-    else if (d->class == &html_class)
-      {
-       if (d->page_open)
-         {
-           struct html_driver_ext *x = d->ext;
-
-           fputs ("</TABLE>\n", x->file);
-         }
-      }
-    else
-      NOT_REACHED ();
-
-  free (cmd.v_variables);
-}
-
-/* Writes string STRING at the current position.  If the text would
-   fall off the side of the page, then advance to the next line,
-   indenting by amount INDENT. */
-static void
-write_varname (struct outp_driver *d, char *string, int indent)
-{
-  struct outp_text text;
-  int width;
-
-  if (d->cp_x + outp_string_width (d, string, OUTP_FIXED) > d->width)
-    {
-      d->cp_y += d->font_height;
-      if (d->cp_y + d->font_height > d->length)
-       outp_eject_page (d);
-      d->cp_x = indent;
-    }
-
-  text.font = OUTP_FIXED;
-  text.justification = OUTP_LEFT;
-  text.string = ss_cstr (string);
-  text.x = d->cp_x;
-  text.y = d->cp_y;
-  text.h = text.v = INT_MAX;
-  d->class->text_draw (d, &text);
-  d->class->text_metrics (d, &text, &width, NULL);
-  d->cp_x += width;
-}
-
-/* When we can't fit all the values across the page, we write out all
-   the variable names just once.  This is where we do it. */
-static void
-write_fallback_headers (struct outp_driver *d)
-{
-  const int max_width = n_chars_width(d) - 10;
-
-  int index = 0;
-  int width = 0;
-  int line_number = 0;
-
-  const char *Line = _("Line");
-  char *leader = xmalloca (strlen (Line)
-                           + INT_STRLEN_BOUND (line_number) + 1 + 1);
-
-  while (index < cmd.n_variables)
-    {
-      struct outp_text text;
-      int leader_width;
-
-      /* Ensure that there is enough room for a line of text. */
-      if (d->cp_y + d->font_height > d->length)
-       outp_eject_page (d);
-
-      /* The leader is a string like `Line 1: '.  Write the leader. */
-      sprintf (leader, "%s %d:", Line, ++line_number);
-      text.font = OUTP_FIXED;
-      text.justification = OUTP_LEFT;
-      text.string = ss_cstr (leader);
-      text.x = 0;
-      text.y = d->cp_y;
-      text.h = text.v = INT_MAX;
-      d->class->text_draw (d, &text);
-      d->class->text_metrics (d, &text, &leader_width, NULL);
-      d->cp_x = leader_width;
-
-      goto entry;
-      do
-       {
-         width++;
-
-       entry:
-         {
-           int var_width = var_get_print_format (cmd.v_variables[index])->w;
-           if (width + var_width > max_width && width != 0)
-             {
-               width = 0;
-               d->cp_x = 0;
-               d->cp_y += d->font_height;
-               break;
-             }
-           width += var_width;
-         }
-
-         {
-           char varname[VAR_NAME_LEN + 2];
-           snprintf (varname, sizeof varname,
-                      " %s", var_get_name (cmd.v_variables[index]));
-           write_varname (d, varname, leader_width);
-         }
-       }
-      while (++index < cmd.n_variables);
-
-    }
-  d->cp_x = 0;
-  d->cp_y += d->font_height;
-
-  freea (leader);
-}
-
-/* There are three possible layouts for the LIST procedure:
-
-   1. If the values and their variables' name fit across the page,
-   then they are listed across the page in that way.
-
-   2. If the values can fit across the page, but not the variable
-   names, then as many variable names as necessary are printed
-   vertically to compensate.
-
-   3. If not even the values can fit across the page, the variable
-   names are listed just once, at the beginning, in a compact format,
-   and the values are listed with a variable name label at the
-   beginning of each line for easier reference.
-
-   This is complicated by the fact that we have to do all this for
-   every output driver, not just once.  */
-static void
-determine_layout (void)
-{
-  struct outp_driver *d;
-
-  /* This is the largest page width of any driver, so we can tell what
-     size buffer to allocate. */
-  int largest_page_width = 0;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    {
-      size_t column;   /* Current column. */
-      int width;       /* Accumulated width. */
-      int height;       /* Height of vertical names. */
-      int max_width;   /* Page width. */
-
-      struct list_ext *prc;
-
-      if (d->class == &html_class)
-       continue;
-
-      assert (d->class->special == 0);
-
-      outp_open_page (d);
-
-      max_width = n_chars_width (d);
-      largest_page_width = MAX (largest_page_width, max_width);
-
-      prc = d->prc = xmalloc (sizeof *prc);
-      prc->type = 0;
-      prc->n_vertical = 0;
-      prc->header = NULL;
-
-      /* Try layout #1. */
-      for (width = cmd.n_variables - 1, column = 0; column < cmd.n_variables; column++)
-       {
-         const struct variable *v = cmd.v_variables[column];
-          int fmt_width = var_get_print_format (v)->w;
-          int name_len = strlen (var_get_name (v));
-         width += MAX (fmt_width, name_len);
-       }
-      if (width <= max_width)
-       {
-         prc->header_rows = 2;
-         continue;
-       }
-
-      /* Try layout #2. */
-      for (width = cmd.n_variables - 1, height = 0, column = 0;
-          column < cmd.n_variables && width <= max_width;
-          column++)
+      for (i = 0; i < cmd.n_variables; i++)
         {
-          const struct variable *v = cmd.v_variables[column];
-          int fmt_width = var_get_print_format (v)->w;
-          size_t name_len = strlen (var_get_name (v));
-          width += fmt_width;
-          if (name_len > height)
-            height = name_len;
-        }
-
-      /* If it fit then we need to determine how many labels can be
-         written horizontally. */
-      if (width <= max_width && height <= SHORT_NAME_LEN)
-       {
-#ifndef NDEBUG
-         prc->n_vertical = SIZE_MAX;
-#endif
-         for (column = cmd.n_variables; column-- != 0; )
-           {
-             const struct variable *v = cmd.v_variables[column];
-              int name_len = strlen (var_get_name (v));
-              int fmt_width = var_get_print_format (v)->w;
-             int trial_width = width - fmt_width + MAX (fmt_width, name_len);
-             if (trial_width > max_width)
-               {
-                 prc->n_vertical = column + 1;
-                 break;
-               }
-             width = trial_width;
-           }
-         assert (prc->n_vertical != SIZE_MAX);
+          const struct variable *var = cmd.v_variables[i];
+          struct table *c;
 
-         prc->n_vertical = cmd.n_variables;
-         /* Finally determine the length of the headers. */
-         for (prc->header_rows = 0, column = 0;
-              column < prc->n_vertical;
-              column++)
-            {
-              const struct variable *var = cmd.v_variables[column];
-              size_t name_len = strlen (var_get_name (var));
-              prc->header_rows = MAX (prc->header_rows, name_len);
-            }
-         prc->header_rows++;
-         continue;
-       }
+          c = table_from_casereader (group, i, var_get_name (var),
+                                     var_get_print_format (var));
+          t = table_hpaste (t, c);
+        }
 
-      /* Otherwise use the ugly fallback listing format. */
-      prc->type = 1;
-      prc->header_rows = 0;
+      casereader_destroy (group);
 
-      d->cp_y += d->font_height;
-      write_fallback_headers (d);
-      d->cp_y += d->font_height;
+      table_item_submit (table_item_create (t, "Data List"));
     }
+  ok = casegrouper_destroy (grouper);
+  ok = proc_commit (ds) && ok;
 
-  ds_init_empty (&line_buffer);
-}
-
-/* Writes case C to output. */
-static void
-list_case (const struct ccase *c, casenumber case_idx,
-           const struct dataset *ds)
-{
-  struct dictionary *dict = dataset_dict (ds);
-  struct outp_driver *d;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    if (d->class->special == 0)
-      {
-       const struct list_ext *prc = d->prc;
-       const int max_width = n_chars_width (d);
-       int column;
-
-       if (!prc->header_rows)
-         {
-           ds_put_format(&line_buffer, "%8s: ",
-                          var_get_name (cmd.v_variables[0]));
-         }
-
-
-       for (column = 0; column < cmd.n_variables; column++)
-         {
-           const struct variable *v = cmd.v_variables[column];
-            const struct fmt_spec *print = var_get_print_format (v);
-           int width;
-
-           if (prc->type == 0 && column >= prc->n_vertical)
-              {
-                int name_len = strlen (var_get_name (v));
-                width = MAX (name_len, print->w);
-              }
-           else
-             width = print->w;
-
-           if (width + ds_length(&line_buffer) > max_width &&
-               ds_length(&line_buffer) != 0)
-             {
-               if (!n_lines_remaining (d))
-                 {
-                   outp_eject_page (d);
-                   write_header (d);
-                 }
-
-               write_line (d, ds_cstr (&line_buffer));
-               ds_clear(&line_buffer);
-
-               if (!prc->header_rows)
-                  ds_put_format (&line_buffer, "%8s: ", var_get_name (v));
-             }
-
-           if (width > print->w)
-              ds_put_char_multiple(&line_buffer, ' ', width - print->w);
-
-            if (fmt_is_string (print->type)
-                || dict_contains_var (dict, v))
-             {
-               char *s = data_out (case_data (c, v), dict_get_encoding (dict), print);
-               ds_put_cstr (&line_buffer, s);
-               free (s);
-             }
-            else
-              {
-               char *s;
-                union value case_idx_value;
-                case_idx_value.f = case_idx;
-                s = data_out (&case_idx_value, dict_get_encoding (dict), print);
-               ds_put_cstr (&line_buffer, s);
-               free (s);
-              }
-
-           ds_put_char (&line_buffer, ' ');
-         }
-
-       if (!n_lines_remaining (d))
-         {
-           outp_eject_page (d);
-           write_header (d);
-         }
-
-       write_line (d, ds_cstr (&line_buffer));
-       ds_clear(&line_buffer);
-      }
-    else if (d->class == &html_class)
-      {
-       struct html_driver_ext *x = d->ext;
-       int column;
-
-       fputs ("  <TR>\n", x->file);
-
-       for (column = 0; column < cmd.n_variables; column++)
-         {
-           const struct variable *v = cmd.v_variables[column];
-            const struct fmt_spec *print = var_get_print_format (v);
-           char *s = NULL;
-
-            if (fmt_is_string (print->type)
-                || dict_contains_var (dict, v))
-             s = data_out (case_data (c, v), dict_get_encoding (dict), print);
-            else
-              {
-                union value case_idx_value;
-                case_idx_value.f = case_idx;
-                s = data_out (&case_idx_value, dict_get_encoding (dict), print);
-              }
-
-            fputs ("    <TD>", x->file);
-            html_put_cell_contents (d, TAB_FIX, ss_buffer (s, print->w));
-           free (s);
-            fputs ("</TD>\n", x->file);
-         }
+  subcase_destroy (&sc);
 
-       fputs ("  </TR>\n", x->file);
-      }
-    else
-      NOT_REACHED ();
+  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
 /*
index 3f73ee25a8de16fb1f1883608e2c6fa8cf25fdba..25bcc750516964264f5bf99e9fd15fed251ed405 100644 (file)
@@ -26,8 +26,8 @@
 #include <language/data-io/file-handle.h>
 #include <language/expressions/public.h>
 #include <language/lexer/lexer.h>
-#include <output/manager.h>
 #include <libpspp/message.h>
+#include <output/text-item.h>
 
 #include "xalloc.h"
 
@@ -123,7 +123,7 @@ print_space_trns_proc (void *t_, struct ccase **c,
 
   while (n--)
     if (trns->writer == NULL)
-      som_blank_line ();
+      text_item_submit (text_item_create (TEXT_ITEM_BLANK_LINE, ""));
     else
       dfm_put_record (trns->writer, " ", 1);
 
index 2cfa0177c77950f26495aa9a5bd421ab8df73488..fd98eaedcc319fe5b44faf0294aa7dce6265a020 100644 (file)
@@ -38,8 +38,8 @@
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/text-item.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -396,8 +396,7 @@ dump_table (struct print_trns *trns, const struct file_handle *fh)
   int row;
 
   spec_cnt = ll_count (&trns->specs);
-  t = tab_create (4, spec_cnt + 1, 0);
-  tab_columns (t, TAB_COL_DOWN, 1);
+  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);
@@ -405,7 +404,6 @@ dump_table (struct print_trns *trns, const struct file_handle *fh)
   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_dim (t, tab_natural_dimensions, NULL);
   row = 1;
   ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
     {
@@ -516,14 +514,14 @@ flush_records (struct print_trns *trns, int target_record,
         {
           *eject = false;
           if (trns->writer == NULL)
-            som_eject_page ();
+            text_item_submit (text_item_create (TEXT_ITEM_EJECT_PAGE, ""));
           else
             leader = '1';
         }
       line[0] = legacy_from_native (trns->encoding, leader);
 
       if (trns->writer == NULL)
-        tab_output_text (TAB_FIX | TAT_NOWRAP, &line[1]);
+        tab_output_text (TAB_FIX, &line[1]);
       else
         {
           if (!trns->include_prefix)
index 5d2b42d758eed2d1e305d05046d59cf0aa290877..d27ab3a65b3ab1b34c6c74b9a8cb1b011287a7a2 100644 (file)
@@ -31,8 +31,7 @@
 #include <language/lexer/variable-parser.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -77,8 +76,7 @@ output_split_file_values (const struct dataset *ds, const struct ccase *c)
   if (split_cnt == 0)
     return;
 
-  t = tab_create (3, split_cnt + 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
+  t = tab_create (3, split_cnt + 1);
   tab_vline (t, TAL_GAP, 1, 0, split_cnt);
   tab_vline (t, TAL_GAP, 2, 0, split_cnt);
   tab_text (t, 0, 0, TAB_NONE, _("Variable"));
@@ -95,6 +93,7 @@ output_split_file_values (const struct dataset *ds, const struct ccase *c)
       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);
+
       tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, s);
 
       free (s);
@@ -103,6 +102,5 @@ output_split_file_values (const struct dataset *ds, const struct ccase *c)
       if (val_lab)
        tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
     }
-  tab_flags (t, SOMF_NO_TITLE);
   tab_submit (t);
 }
index f68a830b83810ba6eec7d4e73b42ab40b041ca91..1f47e1af104ba5281f1634eda67f81b9f49c3412 100644 (file)
@@ -39,9 +39,7 @@
 #include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
-#include <output/manager.h>
-#include <output/output.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "minmax.h"
 #include "xalloc.h"
@@ -66,22 +64,6 @@ enum
 static int describe_variable (const struct variable *v, struct tab_table *t,
                               int r, int pc, int flags);
 
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-sysfile_info_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  static const int max[] = {20, 5, 35, 3, 0};
-  const int *p;
-  int i;
-
-  for (p = max; *p; p++)
-    t->w[p - max] = MIN (tab_natural_width (t, d, p - max),
-                        *p * d->prop_em_width);
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = tab_natural_height (t, d, i);
-}
-
 /* SYSFILE INFO utility. */
 int
 cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
@@ -108,7 +90,7 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
     }
   casereader_destroy (reader);
 
-  t = tab_create (2, 11, 0);
+  t = tab_create (2, 11);
   tab_vline (t, TAL_GAP, 1, 0, 8);
   tab_text (t, 0, 0, TAB_LEFT, _("File:"));
   tab_text (t, 1, 0, TAB_LEFT, fh_get_file_name (h));
@@ -160,11 +142,9 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
                    dict_get_encoding(d) ? dict_get_encoding(d) : _("Unknown"));
 
 
-  tab_dim (t, tab_natural_dimensions, NULL);
   tab_submit (t);
 
-  t = tab_create (4, 1 + 2 * dict_get_var_cnt (d), 1);
-  tab_dim (t, sysfile_info_dim, NULL);
+  t = tab_create (4, 1 + 2 * dict_get_var_cnt (d));
   tab_headers (t, 0, 0, 1, 0);
   tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
   tab_joint_text (t, 1, 0, 2, 0, TAB_LEFT | TAT_TITLE, _("Description"));
@@ -179,7 +159,6 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   tab_vline (t, TAL_1, 3, 0, r);
 
   tab_resize (t, -1, r);
-  tab_flags (t, SOMF_NO_TITLE);
   tab_submit (t);
 
   dict_destroy (d);
@@ -212,7 +191,6 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
     display_documents (dataset_dict (ds));
   else if (lex_match_id (lexer, "FILE"))
     {
-      som_blank_line ();
       if (!lex_force_match_id (lexer, "LABEL"))
        return CMD_FAILURE;
       if (dict_get_label (dataset_dict (ds)) == NULL)
@@ -309,7 +287,6 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
 static void
 display_macros (void)
 {
-  som_blank_line ();
   tab_output_text (TAB_LEFT, _("Macros not supported."));
 }
 
@@ -318,7 +295,6 @@ display_documents (const struct dictionary *dict)
 {
   const char *documents = dict_get_documents (dict);
 
-  som_blank_line ();
   if (documents == NULL)
     tab_output_text (TAB_LEFT, _("The active file dictionary does not "
                                  "contain any documents."));
@@ -329,43 +305,15 @@ display_documents (const struct dictionary *dict)
 
       tab_output_text (TAB_LEFT | TAT_TITLE,
                       _("Documents in the active file:"));
-      som_blank_line ();
       for (i = 0; i < dict_get_document_line_cnt (dict); i++)
         {
           dict_get_document_line (dict, i, &line);
-          tab_output_text (TAB_LEFT | TAB_FIX | TAT_NOWRAP, ds_cstr (&line));
+          tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (&line));
         }
       ds_destroy (&line);
     }
 }
 
-static int _flags;
-
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-variables_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  int pc;
-  int i;
-
-  t->w[0] = tab_natural_width (t, d, 0);
-  if (_flags & (DF_VALUE_LABELS | DF_VARIABLE_LABELS | DF_MISSING_VALUES
-                | DF_AT_ATTRIBUTES | DF_ATTRIBUTES))
-    {
-      t->w[1] = MAX (tab_natural_width (t, d, 1), d->prop_em_width * 5);
-      t->w[2] = MAX (tab_natural_width (t, d, 2), d->prop_em_width * 35);
-      pc = 3;
-    }
-  else
-    pc = 1;
-  if (_flags & DF_DICT_INDEX)
-    t->w[pc] = tab_natural_width (t, d, pc);
-
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = tab_natural_height (t, d, i);
-}
-
 static void
 display_variables (const struct variable **vl, size_t n, int flags)
 {
@@ -375,8 +323,6 @@ display_variables (const struct variable **vl, size_t n, int flags)
   int r;                       /* Current row. */
   size_t i;
 
-  _flags = flags;
-
   /* One column for the name,
      two columns for general description,
      one column for dictionary index. */
@@ -387,7 +333,7 @@ display_variables (const struct variable **vl, size_t n, int flags)
   if (flags & DF_DICT_INDEX)
     nc++;
 
-  t = tab_create (nc, n + 5, 1);
+  t = tab_create (nc, n + 5);
   tab_headers (t, 0, 0, 1, 0);
   tab_hline (t, TAL_2, 0, nc - 1, 1);
   tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
@@ -397,7 +343,6 @@ display_variables (const struct variable **vl, size_t n, int flags)
                      ? _("Description") : _("Label")));
   if (flags & DF_DICT_INDEX)
     tab_text (t, pc, 0, TAB_LEFT | TAT_TITLE, _("Position"));
-  tab_dim (t, variables_dim, NULL);
 
   r = 1;
   for (i = 0; i < n; i++)
@@ -408,12 +353,9 @@ display_variables (const struct variable **vl, size_t n, int flags)
       tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, nc - 1, r - 1);
       tab_vline (t, TAL_1, 1, 0, r - 1);
     }
-  else
-    tab_flags (t, SOMF_NO_TITLE);
   if (flags & ~DF_DICT_INDEX)
     tab_vline (t, TAL_1, nc - 1, 0, r - 1);
   tab_resize (t, -1, r);
-  tab_columns (t, TAB_COL_DOWN, 1);
   tab_submit (t);
 }
 \f
@@ -478,15 +420,13 @@ display_data_file_attributes (struct attrset *set, int flags)
   if (!n_attrs)
     return;
 
-  t = tab_create (2, n_attrs + 1, 0);
+  t = tab_create (2, n_attrs + 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, 1, 1); 
   tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Attribute"));
   tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value"));
   display_attributes (t, set, flags, 0, 1);
-  tab_columns (t, TAB_COL_DOWN, 1);
-  tab_dim (t, tab_natural_dimensions, NULL);
   tab_title (t, "Custom data file attributes.");
   tab_submit (t);
 }
@@ -713,10 +653,8 @@ display_vectors (const struct dictionary *dict, int sorted)
   if (sorted)
     qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name);
 
-  t = tab_create (4, nrow + 1, 0);
+  t = tab_create (4, nrow + 1);
   tab_headers (t, 0, 0, 1, 0);
-  tab_columns (t, TAB_COL_DOWN, 1);
-  tab_dim (t, tab_natural_dimensions, NULL);
   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);
@@ -724,7 +662,6 @@ display_vectors (const struct dictionary *dict, int sorted)
   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"));
-  tab_flags (t, SOMF_NO_TITLE);
 
   row = 1;
   for (i = 0; i < nvec; i++)
index 85705098a2df44e2ad0e39da0764f75684bc9407..7e9e1d6cb542f8b15216c31fe8d9e90788609259 100644 (file)
@@ -30,8 +30,8 @@ expr_error (void *aux UNUSED, const char *format, ...)
   struct msg m;
   va_list args;
 
-  m.category = MSG_SYNTAX;
-  m.severity = MSG_ERROR;
+  m.category = MSG_C_SYNTAX;
+  m.severity = MSG_S_ERROR;
   va_start (args, format);
   m.text = xvasprintf (format, args);
   va_end (args);
index 8b3f2a48d00474811a09c090f8a82d1b75ed7546..1c35642f874daa9ef8447522af7428a34f89d023 100644 (file)
@@ -32,6 +32,7 @@
 #include <libpspp/getl.h>
 #include <libpspp/str.h>
 #include <output/journal.h>
+#include <output/text-item.h>
 
 #include "xalloc.h"
 
@@ -873,16 +874,16 @@ lex_preprocess_line (struct string *line,
     }
 }
 
-/* Reads a line, without performing any preprocessing.
-   Sets *SYNTAX, if SYNTAX is non-null, to the line's syntax
-   mode. */
+/* Reads a line, without performing any preprocessing. */
 bool
 lex_get_line_raw (struct lexer *lexer)
 {
   bool ok = getl_read_line (lexer->ss, &lexer->line_buffer);
-  enum syntax_mode mode = lex_current_syntax_mode (lexer);
-  journal_write (mode == GETL_BATCH, ds_cstr (&lexer->line_buffer));
-
+  if (ok)
+    {
+      const char *line = ds_cstr (&lexer->line_buffer);
+      text_item_submit (text_item_create (TEXT_ITEM_SYNTAX, line));
+    }
   return ok;
 }
 
index 1194110efa3ac850ed1584451e2782ec12870b83..8a39dbf0b2d2d6b6684766d8352d4cbf02cfdd59 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009 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
@@ -757,7 +757,7 @@ array_var_set_get_var (const struct var_set *vs, size_t idx)
 {
   struct array_var_set *avs = vs->aux;
 
-  return (struct variable *) avs->var[idx];
+  return CONST_CAST (struct variable *, avs->var[idx]);
 }
 
 /* If VS contains a variable named NAME, sets *IDX to its index
index 5ecd42fb34fa6b91a2322aecbecc3f400af43f7d..ede6a5e3b9c8c76d5b5d249113bc2537e3cff82d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010 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
@@ -31,9 +31,8 @@
 #include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <libpspp/verbose-msg.h>
 #include <libpspp/version.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
index ac7a2080bf02cc373e2f3ba53a0c9b444f2d9ffa..b3d02e141346ba2bb2bf8eccd60fa1665c3015cf 100644 (file)
@@ -966,20 +966,20 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
          case MEDIAN:
            {
              struct casereader *sorted_reader;
-             struct order_stats *median = percentile_create (0.5, i->cc);
+             struct percentile *median = percentile_create (0.5, i->cc);
+              struct order_stats *os = &median->parent;
 
              sorted_reader = casewriter_make_reader (i->writer);
 
-             order_stats_accumulate (&median, 1,
+             order_stats_accumulate (&os, 1,
                                      sorted_reader,
                                      i->weight,
                                      i->subject,
                                      i->exclude);
 
-             v->f = percentile_calculate ((struct percentile *) median,
-                                          PC_HAVERAGE);
+             v->f = percentile_calculate (median, PC_HAVERAGE);
 
-             statistic_destroy ((struct statistic *) median);
+             statistic_destroy (&median->parent.parent);
            }
            break;
          case SD:
index 21e3f0ae4e9419a420a2c0f6cf5d6d5acfd63f24..e3f0b1c1ed279efe91512c64890d79d3f75d2e3f 100644 (file)
@@ -35,6 +35,7 @@ language_stats_sources = \
        src/language/stats/npar-summary.c \
        src/language/stats/npar-summary.h \
        src/language/stats/roc.c \
+       src/language/stats/roc.h \
        src/language/stats/sign.c \
        src/language/stats/sign.h \
        src/language/stats/wilcoxon.c \
index 26e0257ca14030ca3d58a2ae10acd8f960b45d2c..3c8925803bfd5741623120e21c412ab8caa35d2e 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <config.h>
 #include <libpspp/compiler.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include <data/format.h>
 #include <data/case.h>
@@ -187,16 +187,14 @@ binomial_execute (const struct dataset *ds,
       const struct fmt_spec *wfmt = wvar ?
        var_get_print_format (wvar) : & F_8_0;
 
-      struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1, 0);
-
-      tab_dim (table, tab_natural_dimensions, NULL);
+      struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1);
 
       tab_title (table, _("Binomial Test"));
 
       tab_headers (table, 2, 0, 1, 0);
 
       tab_box (table, TAL_1, TAL_1, -1, TAL_1,
-               0, 0, table->nc - 1, tab_nr(table) - 1 );
+               0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
 
       for (v = 0 ; v < ost->n_vars; ++v)
         {
index 4593df4116eda81be5230a64ee2eee6c5f9fa15f..1f2df8d29a2417395836e4f9b81a9f84e722a959 100644 (file)
 #include <language/stats/freq.h>
 #include <language/stats/npar.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/compiler.h>
 #include <libpspp/hash.h>
 #include <libpspp/message.h>
 #include <libpspp/taint.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include <gsl/gsl_cdf.h>
 
@@ -179,8 +180,7 @@ create_variable_frequency_table (const struct dictionary *dict,
       return NULL;
     }
 
-  table = tab_create(4, n_cells + 2, 0);
-  tab_dim (table, tab_natural_dimensions, NULL);
+  table = tab_create(4, n_cells + 2);
 
   tab_title (table, var_to_string(var));
   tab_text (table, 1, 0, TAB_LEFT, _("Observed N"));
@@ -190,7 +190,7 @@ create_variable_frequency_table (const struct dictionary *dict,
   tab_headers (table, 1, 0, 1, 0);
 
   tab_box (table, TAL_1, TAL_1, -1, -1,
-          0, 0, table->nc - 1, tab_nr(table) - 1 );
+          0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
 
   tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 1);
 
@@ -199,7 +199,7 @@ create_variable_frequency_table (const struct dictionary *dict,
     tab_vline (table, TAL_1, i, 0, tab_nr(table) - 1);
 
 
-  tab_text (table, 0, table->nr - 1, TAB_LEFT, _("Total"));
+  tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
 
   return table;
 }
@@ -215,8 +215,7 @@ create_combo_frequency_table (const struct chisquare_test *test)
 
   int n_cells = test->hi - test->lo + 1;
 
-  table = tab_create(1 + ost->n_vars * 4, n_cells + 3, 0);
-  tab_dim (table, tab_natural_dimensions, NULL);
+  table = tab_create(1 + ost->n_vars * 4, n_cells + 3);
 
   tab_title (table, _("Frequencies"));
   for ( i = 0 ; i < ost->n_vars ; ++i )
@@ -254,12 +253,12 @@ create_combo_frequency_table (const struct chisquare_test *test)
   tab_headers (table, 1, 0, 2, 0);
 
   tab_box (table, TAL_1, TAL_1, -1, -1,
-          0, 0, table->nc - 1, tab_nr(table) - 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, table->nr - 1, TAB_LEFT, _("Total"));
+  tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
 
   return table;
 }
@@ -271,8 +270,7 @@ 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, 0);
-  tab_dim (table, tab_natural_dimensions, NULL);
+  table = tab_create (1 + ost->n_vars, 4);
   tab_title (table, _("Test Statistics"));
   tab_headers (table, 1, 0, 1, 0);
 
@@ -305,8 +303,9 @@ chisquare_execute (const struct dataset *ds,
 {
   const struct dictionary *dict = dataset_dict (ds);
   int v, i;
-  struct one_sample_test *ost = (struct one_sample_test *) test;
-  struct chisquare_test *cst = (struct chisquare_test *) test;
+  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;
   const struct variable *wvar = dict_get_weight (dict);
index 605609a7d68cc559e42cc605cf2543f49e9a441d..7fcca77cc7a883acbd05c8cdac604eb7bcc66544 100644 (file)
@@ -30,8 +30,7 @@
 #include <language/dictionary/split-file.h>
 #include <language/lexer/lexer.h>
 #include <language/lexer/variable-parser.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include <libpspp/message.h>
 #include <data/format.h>
 #include <math/moments.h>
@@ -94,9 +93,8 @@ output_descriptives (const struct corr *corr, const gsl_matrix *means,
   const int heading_columns = 1;
   const int heading_rows = 1;
 
-  struct tab_table *t = tab_create (nc, nr, 0);
+  struct tab_table *t = tab_create (nc, nr);
   tab_title (t, _("Descriptive Statistics"));
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
@@ -189,9 +187,8 @@ output_correlation (const struct corr *corr, const struct corr_opts *opts,
   /* One header row */
   nr += heading_rows;
 
-  t = tab_create (nc, nr, 0);
+  t = tab_create (nc, nr);
   tab_title (t, _("Correlations"));
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
index 99fa41d9c056a039ef9d92fdc9090758539c9d15..bb4acafa62c6cd279bb7622dc4ff18206bd415e3 100644 (file)
@@ -56,8 +56,7 @@
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
 #include <libpspp/str.h>
-#include <output/output.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "minmax.h"
 #include "xalloc.h"
@@ -230,8 +229,8 @@ free_proc (struct crosstabs_proc *proc)
 
          The rest of the data was allocated and destroyed at a
          lower level already. */
-      free (pt);
     }
+  free (proc->pivots);
 }
 
 static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds,
@@ -243,8 +242,7 @@ static void tabulate_general_case (struct pivot_table *, const struct ccase *,
 static void tabulate_integer_case (struct pivot_table *, const struct ccase *,
                                    double weight);
 static void postcalc (struct crosstabs_proc *);
-static void submit (struct crosstabs_proc *, struct pivot_table *,
-                    struct tab_table *);
+static void submit (struct pivot_table *, struct tab_table *);
 
 /* Parse and execute CROSSTABS, then clean up. */
 int
@@ -836,7 +834,7 @@ make_summary_table (struct crosstabs_proc *proc)
   struct string name;
   int i;
 
-  summary = tab_create (7, 3 + proc->n_pivots, 1);
+  summary = tab_create (7, 3 + proc->n_pivots);
   tab_title (summary, _("Summary."));
   tab_headers (summary, 1, 0, 3, 0);
   tab_joint_text (summary, 1, 0, 6, 0, TAB_CENTER, _("Cases"));
@@ -891,7 +889,7 @@ make_summary_table (struct crosstabs_proc *proc)
     }
   ds_destroy (&name);
 
-  submit (proc, NULL, summary);
+  submit (NULL, summary);
 }
 \f
 /* Output. */
@@ -914,8 +912,6 @@ static void display_symmetric (struct crosstabs_proc *, struct pivot_table *,
 static void display_risk (struct pivot_table *, struct tab_table *);
 static void display_directional (struct crosstabs_proc *, struct pivot_table *,
                                  struct tab_table *);
-static void crosstabs_dim (struct tab_table *, struct outp_driver *,
-                           void *proc);
 static void table_value_missing (struct crosstabs_proc *proc,
                                  struct tab_table *table, int c, int r,
                                 unsigned char opt, const union value *v,
@@ -1023,18 +1019,18 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
       free (x.col_tot);
     }
 
-  submit (proc, NULL, table);
+  submit (NULL, table);
 
   if (chisq)
     {
       if (!showed_fisher)
        tab_resize (chisq, 4 + (pt->n_vars - 2), -1);
-      submit (proc, pt, chisq);
+      submit (pt, chisq);
     }
 
-  submit (proc, pt, sym);
-  submit (proc, pt, risk);
-  submit (proc, pt, direct);
+  submit (pt, sym);
+  submit (pt, risk);
+  submit (pt, direct);
 
   free (pt->cols);
 }
@@ -1147,8 +1143,7 @@ create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
   int i;
 
   table = tab_create (pt->n_consts + 1 + pt->n_cols + 1,
-                      (pt->n_entries / pt->n_cols) * 3 / 2 * proc->n_cells + 10,
-                      true);
+                      (pt->n_entries / pt->n_cols) * 3 / 2 * proc->n_cells + 10);
   tab_headers (table, pt->n_consts + 1, 0, 2, 0);
 
   /* First header line. */
@@ -1224,8 +1219,7 @@ create_chisq_table (struct pivot_table *pt)
   struct tab_table *chisq;
 
   chisq = tab_create (6 + (pt->n_vars - 2),
-                      pt->n_entries / pt->n_cols * 3 / 2 * N_CHISQ + 10,
-                      1);
+                      pt->n_entries / pt->n_cols * 3 / 2 * N_CHISQ + 10);
   tab_headers (chisq, 1 + (pt->n_vars - 2), 0, 1, 0);
 
   tab_title (chisq, _("Chi-square tests."));
@@ -1252,7 +1246,7 @@ create_sym_table (struct pivot_table *pt)
   struct tab_table *sym;
 
   sym = tab_create (6 + (pt->n_vars - 2),
-                    pt->n_entries / pt->n_cols * 7 + 10, 1);
+                    pt->n_entries / pt->n_cols * 7 + 10);
   tab_headers (sym, 2 + (pt->n_vars - 2), 0, 1, 0);
   tab_title (sym, _("Symmetric measures."));
 
@@ -1274,8 +1268,7 @@ create_risk_table (struct pivot_table *pt)
 {
   struct tab_table *risk;
 
-  risk = tab_create (4 + (pt->n_vars - 2), pt->n_entries / pt->n_cols * 4 + 10,
-                     1);
+  risk = tab_create (4 + (pt->n_vars - 2), pt->n_entries / pt->n_cols * 4 + 10);
   tab_headers (risk, 1 + pt->n_vars - 2, 0, 2, 0);
   tab_title (risk, _("Risk estimate."));
 
@@ -1300,7 +1293,7 @@ create_direct_table (struct pivot_table *pt)
   struct tab_table *direct;
 
   direct = tab_create (7 + (pt->n_vars - 2),
-                       pt->n_entries / pt->n_cols * 7 + 10, 1);
+                       pt->n_entries / pt->n_cols * 7 + 10);
   tab_headers (direct, 3 + (pt->n_vars - 2), 0, 1, 0);
   tab_title (direct, _("Directional measures."));
 
@@ -1345,8 +1338,7 @@ delete_missing (struct pivot_table *pt)
 
 /* Prepare table T for submission, and submit it. */
 static void
-submit (struct crosstabs_proc *proc, struct pivot_table *pt,
-        struct tab_table *t)
+submit (struct pivot_table *pt, struct tab_table *t)
 {
   int i;
 
@@ -1356,7 +1348,7 @@ submit (struct crosstabs_proc *proc, struct pivot_table *pt,
   tab_resize (t, -1, 0);
   if (tab_nr (t) == tab_t (t))
     {
-      tab_destroy (t);
+      table_unref (&t->table);
       return;
     }
   tab_offset (t, 0, 0);
@@ -1370,49 +1362,8 @@ submit (struct crosstabs_proc *proc, struct pivot_table *pt,
   tab_box (t, -1, -1, -1, TAL_GAP, 0, tab_t (t), tab_l (t) - 1,
           tab_nr (t) - 1);
   tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1);
-  tab_dim (t, crosstabs_dim, proc);
-  tab_submit (t);
-}
-
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-crosstabs_dim (struct tab_table *t, struct outp_driver *d, void *proc_)
-{
-  struct crosstabs_proc *proc = proc_;
-  int i;
-
-  /* Width of a numerical column. */
-  int c = outp_string_width (d, "0.000000", OUTP_PROPORTIONAL);
-  if (proc->exclude == MV_NEVER)
-    c += outp_string_width (d, "M", OUTP_PROPORTIONAL);
 
-  /* Set width for header columns. */
-  if (t->l != 0)
-    {
-      size_t i;
-      int w;
-
-      w = d->width - c * (t->nc - t->l);
-      for (i = 0; i <= t->nc; i++)
-        w -= t->wrv[i];
-      w /= t->l;
-
-      if (w < d->prop_em_width * 8)
-       w = d->prop_em_width * 8;
-
-      if (w > d->prop_em_width * 15)
-       w = d->prop_em_width * 15;
-
-      for (i = 0; i < t->l; i++)
-       t->w[i] = w;
-    }
-
-  for (i = t->l; i < t->nc; i++)
-    t->w[i] = c;
-
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = tab_natural_height (t, d, i);
+  tab_submit (t);
 }
 
 static bool
@@ -1513,26 +1464,21 @@ 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 substring s;
-  const struct fmt_spec *print = var_get_print_format (var);
-
   const char *label = var_lookup_value_label (var, v);
-  if (label)
-    {
-      tab_text (table, c, r, TAB_LEFT, label);
-      return;
-    }
-
-  s = ss_cstr (data_out_pool (v, dict_get_encoding (proc->dict), print,
-                            table->container));
-  if (proc->exclude == MV_NEVER && var_is_num_missing (var, v->f, MV_USER))
-    s.string[s.length++] = 'M';
-  while (s.length && *s.string == ' ')
+  if (label != NULL)
+    tab_text (table, c, r, TAB_LEFT, label);
+  else
     {
-      s.length--;
-      s.string++;
+      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, proc->dict, print);
     }
-  tab_raw (table, c, r, opt, &s);
 }
 
 /* Draws a line across TABLE at the current row to indicate the most
@@ -1561,22 +1507,22 @@ format_cell_entry (struct tab_table *table, int c, int r, double value,
 {
   const struct fmt_spec f = {FMT_F, 10, 1};
   union value v;
-  struct substring s;
+  char suffixes[3];
+  int suffix_len;
+  char *s;
 
   v.f = value;
-  s = ss_cstr (data_out_pool (&v, dict_get_encoding (dict), &f, table->container));
+  s = data_out (&v, dict_get_encoding (dict), &f);
 
-  while (*s.string == ' ')
-    {
-      s.length--;
-      s.string++;
-    }
+  suffix_len = 0;
   if (suffix != 0)
-    s.string[s.length++] = suffix;
+    suffixes[suffix_len++] = suffix;
   if (mark_missing)
-    s.string[s.length++] = 'M';
+    suffixes[suffix_len++] = 'M';
+  suffixes[suffix_len] = '\0';
 
-  tab_raw (table, c, r, TAB_RIGHT, &s);
+  tab_text_format (table, c, r, TAB_RIGHT, "%s%s",
+                   s + strspn (s, " "), suffixes);
 }
 
 /* Displays the crosstabulation table. */
index 6b57fd297d8475ad63bcecc320a8c0c1b2d9201f..eb04bfa663889649855c771a944f98057e7381d8 100644 (file)
@@ -35,8 +35,7 @@
 #include <libpspp/message.h>
 #include <libpspp/assertion.h>
 #include <math/moments.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -552,15 +551,13 @@ dump_z_table (struct dsc_proc *dsc)
        cnt++;
   }
 
-  t = tab_create (2, cnt + 1, 0);
+  t = tab_create (2, cnt + 1);
   tab_title (t, _("Mapping of variables to corresponding Z-scores."));
-  tab_columns (t, SOM_COL_DOWN, 1);
   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"));
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   {
     size_t i, y;
@@ -873,13 +870,12 @@ display (struct dsc_proc *dsc)
     sort (dsc->vars, dsc->var_cnt, sizeof *dsc->vars,
           descriptives_compare_dsc_vars, dsc);
 
-  t = tab_create (nc, dsc->var_cnt + 1, 0);
+  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);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   nc = 0;
   tab_text (t, nc++, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
index 08077942340234031939cded549e87886d5119ee..d06f98ef9d79692cc6ad98cd1372dcfa79d571b4 100644 (file)
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
 #include <math/moments.h>
-#include <output/charts/box-whisker.h>
-#include <output/charts/cartesian.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/chart-item.h>
+#include <output/charts/boxplot.h>
+#include <output/charts/np-plot.h>
+#include <output/tab.h>
 
 #include "minmax.h"
 #include "xalloc.h"
@@ -61,9 +61,7 @@
 #define N_(msgid) msgid
 
 /* (headers) */
-#include <output/chart.h>
 #include <output/charts/plot-hist.h>
-#include <output/charts/plot-chart.h>
 #include <math/histogram.h>
 
 /* (specification)
@@ -104,11 +102,11 @@ struct factor_metrics
   struct percentile **ptl;
   size_t n_ptiles;
 
-  struct statistic *tukey_hinges;
-  struct statistic *box_whisker;
-  struct statistic *trimmed_mean;
-  struct statistic *histogram;
-  struct order_stats *np;
+  struct tukey_hinges *tukey_hinges;
+  struct box_whisker *box_whisker;
+  struct trimmed_mean *trimmed_mean;
+  struct histogram *histogram;
+  struct np *np;
 
   /* Three quartiles indexing into PTL */
   struct percentile **quartiles;
@@ -179,12 +177,12 @@ factor_destroy (struct xfactor *fctr)
          moments1_destroy (result->metrics[v].moments);
          extrema_destroy (result->metrics[v].minima);
          extrema_destroy (result->metrics[v].maxima);
-         statistic_destroy (result->metrics[v].trimmed_mean);
-         statistic_destroy (result->metrics[v].tukey_hinges);
-         statistic_destroy (result->metrics[v].box_whisker);
-         statistic_destroy (result->metrics[v].histogram);
+         statistic_destroy (&result->metrics[v].trimmed_mean->parent.parent);
+         statistic_destroy (&result->metrics[v].tukey_hinges->parent.parent);
+         statistic_destroy (&result->metrics[v].box_whisker->parent.parent);
+         statistic_destroy (&result->metrics[v].histogram->parent);
          for (i = 0 ; i < result->metrics[v].n_ptiles; ++i)
-           statistic_destroy ((struct statistic *) result->metrics[v].ptl[i]);
+           statistic_destroy (&result->metrics[v].ptl[i]->parent.parent);
          free (result->metrics[v].ptl);
          free (result->metrics[v].quartiles);
          casereader_destroy (result->metrics[v].up_reader);
@@ -320,82 +318,6 @@ cmd_examine (struct lexer *lexer, struct dataset *ds)
 };
 
 
-/* Plot the normal and detrended normal plots for RESULT.
-   Label the plots with LABEL */
-static void
-np_plot (struct np *np, const char *label)
-{
-  double yfirst = 0, ylast = 0;
-
-  double x_lower;
-  double x_upper;
-  double slack;
-
-  /* Normal Plot */
-  struct chart *np_chart;
-
-  /* Detrended Normal Plot */
-  struct chart *dnp_chart;
-
-  /* The slope and intercept of the ideal normal probability line */
-  const double slope = 1.0 / np->stddev;
-  const double intercept = -np->mean / np->stddev;
-
-  if ( np->n < 1.0 )
-    {
-      msg (MW, _("Not creating plot because data set is empty."));
-      return ;
-    }
-
-  np_chart = chart_create ();
-  dnp_chart = chart_create ();
-
-  if ( !np_chart || ! dnp_chart )
-    return ;
-
-  chart_write_title (np_chart, _("Normal Q-Q Plot of %s"), label);
-  chart_write_xlabel (np_chart, _("Observed Value"));
-  chart_write_ylabel (np_chart, _("Expected Normal"));
-
-  chart_write_title (dnp_chart, _("Detrended Normal Q-Q Plot of %s"),
-                    label);
-  chart_write_xlabel (dnp_chart, _("Observed Value"));
-  chart_write_ylabel (dnp_chart, _("Dev from Normal"));
-
-  yfirst = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
-  ylast = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
-
-  /* Need to make sure that both the scatter plot and the ideal fit into the
-     plot */
-  x_lower = MIN (np->y_min, (yfirst - intercept) / slope) ;
-  x_upper = MAX (np->y_max, (ylast  - intercept) / slope) ;
-  slack = (x_upper - x_lower)  * 0.05 ;
-
-  chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
-  chart_write_xscale (dnp_chart, np->y_min, np->y_max, 5);
-
-  chart_write_yscale (np_chart, yfirst, ylast, 5);
-  chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5);
-
-  {
-    struct casereader *reader = casewriter_make_reader (np->writer);
-    struct ccase *c;
-    while ((c = casereader_read (reader)) != NULL)
-      {
-       chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f);
-       chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f);
-
-       case_unref (c);
-      }
-    casereader_destroy (reader);
-  }
-
-  chart_line (dnp_chart, 0, 0, np->y_min, np->y_max , CHART_DIM_X);
-  chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
-
-  chart_submit (np_chart);
-  chart_submit (dnp_chart);
-}
 
 
 static void
@@ -412,20 +334,37 @@ show_npplot (const struct variable **dependent_var,
           ll != ll_null (&fctr->result_list);
           ll = ll_next (ll))
        {
-         struct string str;
+         struct string label;
          const struct factor_result *result =
            ll_data (ll, struct factor_result, ll);
-
-         ds_init_empty (&str);
-         ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
-
-         factor_to_string (fctr, result, &str);
-
-         np_plot ((struct np*) result->metrics[v].np, ds_cstr(&str));
-
-         statistic_destroy ((struct statistic *)result->metrics[v].np);
-
-         ds_destroy (&str);
+          struct chart_item *npp, *dnpp;
+          struct casereader *reader;
+          struct np *np;
+
+         ds_init_empty (&label);
+         ds_put_format (&label, "%s ", var_get_name (dependent_var[v]));
+         factor_to_string (fctr, result, &label);
+
+          np = result->metrics[v].np;
+          reader = casewriter_make_reader (np->writer);
+          npp = np_plot_create (np, reader, ds_cstr (&label));
+          dnpp = np_plot_create (np, reader, ds_cstr (&label));
+
+         ds_destroy (&label);
+
+          if (npp == NULL || dnpp == NULL)
+            {
+              msg (MW, _("Not creating NP plot because data set is empty."));
+              chart_item_unref (npp);
+              chart_item_unref (dnpp);
+            }
+          else
+            {
+              chart_item_submit (npp);
+              chart_item_submit (dnpp);
+            }
+
+         statistic_destroy (&np->parent.parent);
        }
     }
 }
@@ -448,15 +387,26 @@ show_histogram (const struct variable **dependent_var,
          struct string str;
          const struct factor_result *result =
            ll_data (ll, struct factor_result, ll);
+          struct histogram *histogram;
+          double mean, var, n;
+
+          histogram = result->metrics[v].histogram;
+          if (histogram == NULL)
+            {
+              /* Probably all values are SYSMIS. */
+              continue;
+            }
 
          ds_init_empty (&str);
          ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
 
          factor_to_string (fctr, result, &str);
 
-         histogram_plot ((struct histogram *) result->metrics[v].histogram,
-                         ds_cstr (&str),
-                         (struct moments1 *) result->metrics[v].moments);
+          moments1_calculate (result->metrics[v].moments,
+                              &n, &mean, &var, NULL,  NULL);
+          chart_item_submit (histogram_chart_create (histogram->gsl_hist,
+                                                     ds_cstr (&str), n, mean,
+                                                     sqrt (var), false));
 
          ds_destroy (&str);
        }
@@ -474,25 +424,18 @@ show_boxplot_groups (const struct variable **dependent_var,
 
   for (v = 0; v < n_dep_var; ++v)
     {
-      struct ll *ll;
-      int f = 0;
-      struct chart *ch = chart_create ();
+      const struct factor_result *result;
+      struct boxplot *boxplot;
       double y_min = DBL_MAX;
       double y_max = -DBL_MAX;
+      char *title;
 
-      for (ll = ll_head (&fctr->result_list);
-          ll != ll_null (&fctr->result_list);
-          ll = ll_next (ll))
+      ll_for_each (result, struct factor_result, ll, &fctr->result_list)
        {
+          struct factor_metrics *metrics = &result->metrics[v];
+         const struct ll_list *max_list = extrema_list (metrics->maxima);
+         const struct ll_list *min_list = extrema_list (metrics->minima);
          const struct extremum  *max, *min;
-         const struct factor_result *result =
-           ll_data (ll, struct factor_result, ll);
-
-         const struct ll_list *max_list =
-           extrema_list (result->metrics[v].maxima);
-
-         const struct ll_list *min_list =
-           extrema_list (result->metrics[v].minima);
 
          if ( ll_is_empty (max_list))
            {
@@ -500,52 +443,34 @@ show_boxplot_groups (const struct variable **dependent_var,
              continue;
            }
 
-         max = (const struct extremum *)
-           ll_data (ll_head(max_list), struct extremum, ll);
-
-          min = (const struct extremum *)
-           ll_data (ll_head (min_list), struct extremum, ll);
+         max = ll_data (ll_head(max_list), struct extremum, ll);
+          min = ll_data (ll_head (min_list), struct extremum, ll);
 
          y_max = MAX (y_max, max->value);
          y_min = MIN (y_min, min->value);
        }
 
-      boxplot_draw_yscale (ch, y_max, y_min);
-
-      if ( fctr->indep_var[0])
-       chart_write_title (ch, _("Boxplot of %s vs. %s"),
+      if (fctr->indep_var[0])
+       title = xasprintf (_("Boxplot of %s vs. %s"),
                           var_to_string (dependent_var[v]),
-                          var_to_string (fctr->indep_var[0]) );
+                          var_to_string (fctr->indep_var[0]));
       else
-       chart_write_title (ch, _("Boxplot of %s"),
-                          var_to_string (dependent_var[v]));
+       title = xasprintf (_("Boxplot of %s"),
+                           var_to_string (dependent_var[v]));
+      boxplot = boxplot_create (y_min, y_max, title);
+      free (title);
 
-      for (ll = ll_head (&fctr->result_list);
-          ll != ll_null (&fctr->result_list);
-          ll = ll_next (ll))
+      ll_for_each (result, struct factor_result, ll, &fctr->result_list)
        {
-         const struct factor_result *result =
-           ll_data (ll, struct factor_result, ll);
-
-         struct string str;
-         const double box_width = (ch->data_right - ch->data_left)
-           / (ll_count (&fctr->result_list) * 2.0 ) ;
-
-         const double box_centre = (f++ * 2 + 1) * box_width + ch->data_left;
-
-         ds_init_empty (&str);
+          struct factor_metrics *metrics = &result->metrics[v];
+         struct string str = DS_EMPTY_INITIALIZER;
          factor_to_string_concise (fctr, result, &str);
-
-         boxplot_draw_boxplot (ch,
-                               box_centre, box_width,
-                               (const struct box_whisker *)
-                                result->metrics[v].box_whisker,
-                               ds_cstr (&str));
-
+          boxplot_add_box (boxplot, metrics->box_whisker, ds_cstr (&str));
+          metrics->box_whisker = NULL;
          ds_destroy (&str);
        }
 
-      chart_submit (ch);
+      boxplot_submit (boxplot);
     }
 }
 
@@ -558,74 +483,42 @@ show_boxplot_variables (const struct variable **dependent_var,
                        )
 
 {
+  const struct factor_result *result;
   int v;
-  struct ll *ll;
-  const struct ll_list *result_list = &fctr->result_list;
-
-  for (ll = ll_head (result_list);
-       ll != ll_null (result_list);
-       ll = ll_next (ll))
 
+  ll_for_each (result, struct factor_result, ll, &fctr->result_list)
     {
       struct string title;
-      struct chart *ch = chart_create ();
       double y_min = DBL_MAX;
       double y_max = -DBL_MAX;
-
-      const struct factor_result *result =
-       ll_data (ll, struct factor_result, ll);
-
-      const double box_width = (ch->data_right - ch->data_left)
-       / (n_dep_var * 2.0 ) ;
+      struct boxplot *boxplot;
 
       for (v = 0; v < n_dep_var; ++v)
        {
-         const struct ll *max_ll =
-           ll_head (extrema_list (result->metrics[v].maxima));
-         const struct ll *min_ll =
-           ll_head (extrema_list (result->metrics[v].minima));
-
-         const struct extremum  *max =
-           (const struct extremum *) ll_data (max_ll, struct extremum, ll);
-
-          const struct extremum  *min =
-           (const struct extremum *) ll_data (min_ll, struct extremum, ll);
+          const struct factor_metrics *metrics = &result->metrics[v];
+         const struct ll *max_ll = ll_head (extrema_list (metrics->maxima));
+         const struct ll *min_ll = ll_head (extrema_list (metrics->minima));
+         const struct extremum *max = ll_data (max_ll, struct extremum, ll);
+          const struct extremum *min = ll_data (min_ll, struct extremum, ll);
 
          y_max = MAX (y_max, max->value);
          y_min = MIN (y_min, min->value);
        }
 
-
-      boxplot_draw_yscale (ch, y_max, y_min);
-
       ds_init_empty (&title);
       factor_to_string (fctr, result, &title);
-
-#if 0
-      ds_put_format (&title, "%s = ", var_get_name (fctr->indep_var[0]));
-      var_append_value_name (fctr->indep_var[0], &result->value[0], &title);
-#endif
-
-      chart_write_title (ch, ds_cstr (&title));
+      boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
       ds_destroy (&title);
 
       for (v = 0; v < n_dep_var; ++v)
        {
-         struct string str;
-         const double box_centre = (v * 2 + 1) * box_width + ch->data_left;
-
-         ds_init_empty (&str);
-         ds_init_cstr (&str, var_get_name (dependent_var[v]));
-
-         boxplot_draw_boxplot (ch,
-                               box_centre, box_width,
-                               (const struct box_whisker *) result->metrics[v].box_whisker,
-                               ds_cstr (&str));
-
-         ds_destroy (&str);
+          struct factor_metrics *metrics = &result->metrics[v];
+          boxplot_add_box (boxplot, metrics->box_whisker,
+                           var_get_name (dependent_var[v]));
+          metrics->box_whisker = NULL;
        }
 
-      chart_submit (ch);
+      boxplot_submit (boxplot);
     }
 }
 
@@ -674,16 +567,14 @@ output_examine (const struct dictionary *dict)
       if ( cmd.sbc_percentiles)
        show_percentiles (dependent_vars, n_dependent_vars, factor);
 
-      if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
-         cmd.cmp == XMN_GROUPS)
-       show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
-
-
-      if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
-         cmd.cmp == XMN_VARIABLES)
-       show_boxplot_variables (dependent_vars, n_dependent_vars,
-                               factor);
-
+      if (cmd.a_plot[XMN_PLT_BOXPLOT])
+        {
+          if (cmd.cmp == XMN_GROUPS)
+            show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
+          else if (cmd.cmp == XMN_VARIABLES)
+            show_boxplot_variables (dependent_vars, n_dependent_vars, factor);
+        }
+      
       if (cmd.a_plot[XMN_PLT_HISTOGRAM])
        show_histogram (dependent_vars, n_dependent_vars, factor);
 
@@ -989,15 +880,13 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
 
          metric->n_ptiles = percentile_list.n_data;
 
-         metric->ptl = xcalloc (metric->n_ptiles,
-                                sizeof (struct percentile *));
+         metric->ptl = xcalloc (metric->n_ptiles, sizeof *metric->ptl);
 
          metric->quartiles = xcalloc (3, sizeof (*metric->quartiles));
 
          for (i = 0 ; i < metric->n_ptiles; ++i)
            {
-             metric->ptl[i] = (struct percentile *)
-               percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
+             metric->ptl[i] = percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
 
              if ( percentile_list.data[i] == 25)
                metric->quartiles[0] = metric->ptl[i];
@@ -1018,18 +907,18 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
              n_os ++;
            }
 
-         os = xcalloc (sizeof (struct order_stats *), n_os);
+          os = xcalloc (n_os, sizeof *os);
 
          for (i = 0 ; i < metric->n_ptiles ; ++i )
            {
-             os[i] = (struct order_stats *) metric->ptl[i];
+             os[i] = &metric->ptl[i]->parent;
            }
 
-         os[i] = (struct order_stats *) metric->tukey_hinges;
-         os[i+1] = (struct order_stats *) metric->trimmed_mean;
+         os[i] = &metric->tukey_hinges->parent;
+         os[i+1] = &metric->trimmed_mean->parent;
 
          if (cmd->a_plot[XMN_PLT_NPPLOT])
-           os[i+2] = metric->np;
+           os[i+2] = &metric->np->parent;
 
          order_stats_accumulate (os, n_os,
                                  casereader_clone (metric->up_reader),
@@ -1080,7 +969,7 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
            {
              struct factor_metrics *metric = &result->metrics[v];
              if ( metric->histogram)
-               histogram_add ((struct histogram *) metric->histogram,
+               histogram_add (metric->histogram,
                               case_data (c, dependent_vars[v])->f, weight);
            }
          case_unref (c);
@@ -1096,13 +985,13 @@ examine_group (struct cmd_examine *cmd, struct casereader *reader, int level,
          struct factor_metrics *metric = &result->metrics[v];
           int n_vals = caseproto_get_n_widths (casereader_get_proto (
                                                  metric->up_reader));
+          struct order_stats *os;
 
          metric->box_whisker =
-           box_whisker_create ((struct tukey_hinges *) metric->tukey_hinges,
-                               cmd->v_id, n_vals - 1);
+           box_whisker_create ( metric->tukey_hinges, cmd->v_id, n_vals - 1);
 
-         order_stats_accumulate ((struct order_stats **) &metric->box_whisker,
-                                 1,
+          os = &metric->box_whisker->parent;
+         order_stats_accumulate ( &os, 1,
                                  casereader_clone (metric->up_reader),
                                  wv, dependent_vars[v], MV_ANY);
        }
@@ -1242,11 +1131,9 @@ show_summary (const struct variable **dependent_var, int n_dep_var,
 
   n_cols = heading_columns + 6;
 
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   /* Outline the box */
   tab_box (tbl,
           TAL_2, TAL_2,
@@ -1479,11 +1366,9 @@ show_descriptives (const struct variable **dependent_var,
 
   n_cols = heading_columns + 2;
 
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   /* Outline the box */
   tab_box (tbl,
           TAL_2, TAL_2,
@@ -1658,7 +1543,7 @@ show_descriptives (const struct variable **dependent_var,
          tab_double (tbl, n_cols - 2,
                     heading_rows + row_var_start + 3 + i * DESCRIPTIVE_ROWS,
                     TAB_CENTER,
-                    trimmed_mean_calculate ((struct trimmed_mean *) result->metrics[v].trimmed_mean),
+                    trimmed_mean_calculate (result->metrics[v].trimmed_mean),
                     NULL);
 
 
@@ -1791,11 +1676,9 @@ show_extremes (const struct variable **dependent_var,
 
   n_cols = heading_columns + 2;
 
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   /* Outline the box */
   tab_box (tbl,
           TAL_2, TAL_2,
@@ -1995,11 +1878,9 @@ show_percentiles (const struct variable **dependent_var,
 
   n_cols = heading_columns + n_percentiles;
 
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   /* Outline the box */
   tab_box (tbl,
           TAL_2, TAL_2,
@@ -2078,8 +1959,7 @@ show_percentiles (const struct variable **dependent_var,
 
          tab_vline (tbl, TAL_1, n_cols - n_percentiles -1, heading_rows, n_rows - 1);
 
-         tukey_hinges_calculate ((struct tukey_hinges *) result->metrics[v].tukey_hinges,
-                                 hinges);
+         tukey_hinges_calculate (result->metrics[v].tukey_hinges, hinges);
 
          for (j = 0; j < n_percentiles; ++j)
            {
index cfec4a9a40890d7eb09a4c6bbdcc05c98d810bcd..58d5b868eb5be5d5d2fc685ed1466b4ae40dd52e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010 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
 #include <libpspp/misc.h>
 #include <libpspp/message.h>
 
-#include <output/table.h>
+#include <output/tab.h>
 
+#include <output/charts/scree.h>
+#include <output/chart-item.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -70,6 +72,12 @@ enum extraction_method
     EXTRACTION_PAF,
   };
 
+enum plot_opts
+  {
+    PLOT_SCREE = 0x0001,
+    PLOT_ROTATION = 0x0002
+  };
+
 enum print_opts
   {
     PRINT_UNIVARIATE  = 0x0001,
@@ -100,6 +108,7 @@ struct cmd_factor
   enum mv_class exclude;
   enum print_opts print;
   enum extraction_method extraction;
+  enum plot_opts plot;
 
   /* Extraction Criteria */
   int n_factors;
@@ -526,6 +535,7 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
   factor.econverge = 0.001;
   factor.blank = 0;
   factor.sort = false;
+  factor.plot = 0;
 
   factor.wv = dict_get_weight (dict);
 
@@ -549,7 +559,6 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
     {
       lex_match (lexer, '/');
 
-
       if (lex_match_id (lexer, "PLOT"))
        {
           lex_match (lexer, '=');
@@ -557,6 +566,7 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
            {
              if (lex_match_id (lexer, "EIGEN"))
                {
+                 factor.plot |= PLOT_SCREE;
                }
 #if FACTOR_FULLY_IMPLEMENTED
              else if (lex_match_id (lexer, "ROTATION"))
@@ -914,6 +924,22 @@ communality (struct idata *idata, int n, int n_factors)
 }
 
 
+static void
+show_scree (const struct cmd_factor *f, struct idata *idata)
+{
+  struct scree *s;
+  const char *label ;
+
+  if ( !(f->plot & PLOT_SCREE) )
+    return;
+
+
+  label = f->extraction == EXTRACTION_PC ? _("Component Number") : _("Factor Number");
+
+  s = scree_create (idata->eval, label);
+
+  scree_submit (s);
+}
 
 static void
 show_communalities (const struct cmd_factor * factor,
@@ -937,12 +963,10 @@ show_communalities (const struct cmd_factor * factor,
   if (nc <= 1)
     return;
 
-  t = tab_create (nc, nr, 0);
+  t = tab_create (nc, nr);
 
   tab_title (t, _("Communalities"));
 
-  tab_dim (t, tab_natural_dimensions, NULL);
-
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
   c = 1;
@@ -997,15 +1021,13 @@ show_factor_matrix (const struct cmd_factor *factor, struct idata *idata, const
   const int nc = heading_columns + n_factors;
   gsl_permutation *perm;
 
-  struct tab_table *t = tab_create (nc, nr, 0);
+  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_dim (t, tab_natural_dimensions, NULL);
-
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
   if ( factor->extraction == EXTRACTION_PC )
@@ -1109,12 +1131,10 @@ show_explained_variance (const struct cmd_factor * factor, struct idata *idata,
   if ( nc <= heading_columns)
     return;
 
-  t = tab_create (nc, nr, 0);
+  t = tab_create (nc, nr);
 
   tab_title (t, _("Total Variance Explained"));
 
-  tab_dim (t, tab_natural_dimensions, NULL);
-
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
   /* Outline the box */
@@ -1261,12 +1281,10 @@ show_correlation_matrix (const struct cmd_factor *factor, const struct idata *id
   if (nr <= heading_rows && suffix_rows == 0)
     return;
 
-  t = tab_create (nc, nr + suffix_rows, 0);
+  t = tab_create (nc, nr + suffix_rows);
 
   tab_title (t, _("Correlation Matrix"));
 
-  tab_dim (t, tab_natural_dimensions, NULL);
-
   tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
 
   if (nr > heading_rows)
@@ -1406,9 +1424,8 @@ do_factor (const struct cmd_factor *factor, struct casereader *r)
 
       const int nr = heading_rows + factor->n_vars;
 
-      struct tab_table *t = tab_create (nc, nr, 0);
+      struct tab_table *t = tab_create (nc, nr);
       tab_title (t, _("Descriptive Statistics"));
-      tab_dim (t, tab_natural_dimensions, NULL);
 
       tab_headers (t, heading_columns, 0, heading_rows, 0);
 
@@ -1533,6 +1550,8 @@ do_factor (const struct cmd_factor *factor, struct casereader *r)
 
     factor_matrix_workspace_free (fmw);
 
+    show_scree (factor, idata);
+
     show_factor_matrix (factor, idata, factor_matrix);
 
     gsl_vector_free (initial_communalities);
index 5a704d0d019f1f0d723aac1c8b81b455f02c0f7a..e52aaf0f9ae3f50d7b40880050e18b6d06170c34 100644 (file)
 #include <libpspp/str.h>
 #include <math/histogram.h>
 #include <math/moments.h>
-#include <output/chart.h>
+#include <output/chart-item.h>
 #include <output/charts/piechart.h>
 #include <output/charts/plot-hist.h>
-#include <output/manager.h>
-#include <output/output.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "freq.h"
 
@@ -612,13 +610,14 @@ postcalc (const struct dataset *ds)
 
          hist = freq_tab_to_hist (ft,v);
 
-         histogram_plot_n (hist, var_to_string(v),
-                         vf->tab.valid_cases,
-                         d[frq_mean],
-                         d[frq_stddev],
-                         normal);
+          chart_item_submit (histogram_chart_create (
+                               hist->gsl_hist, var_to_string(v),
+                               vf->tab.valid_cases,
+                               d[frq_mean],
+                               d[frq_stddev],
+                               normal));
 
-         statistic_destroy ((struct statistic *)hist);
+         statistic_destroy (&hist->parent);
        }
 
       if ( chart == GFT_PIE)
@@ -1000,28 +999,6 @@ compare_freq_alpha_d (const void *a_, const void *b_, const void *v_)
 \f
 /* Frequency table display. */
 
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-full_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  int i = 0;
-  int columns = 5;
-
-  if (cmd.labels == FRQ_LABELS)
-    {
-    t->w[0] = MIN (tab_natural_width (t, d, 0), d->prop_em_width * 15);
-      i = 1;
-      columns ++;
-    }
-
-  for (;i < columns; i++)
-    t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
-
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = d->font_height;
-}
-
 /* Displays a full frequency table for variable V. */
 static void
 dump_full (const struct variable *v, const struct variable *wv)
@@ -1049,9 +1026,8 @@ dump_full (const struct variable *v, const struct variable *wv)
   vf = get_var_freqs (v);
   ft = &vf->tab;
   n_categories = ft->n_valid + ft->n_missing;
-  t = tab_create (5 + lab, n_categories + 2, 0);
+  t = tab_create (5 + lab, n_categories + 2);
   tab_headers (t, 0, 0, 1, 0);
-  tab_dim (t, full_dim, NULL);
 
   if (lab)
     tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Value Label"));
@@ -1118,25 +1094,6 @@ dump_full (const struct variable *v, const struct variable *wv)
   tab_submit (t);
 }
 
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-condensed_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  int cum_w = MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
-                  MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
-                       outp_string_width (d, "000", OUTP_PROPORTIONAL)));
-
-  int i;
-
-  for (i = 0; i < 2; i++)
-    t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
-  for (i = 2; i < 4; i++)
-    t->w[i] = cum_w;
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = d->font_height;
-}
-
 /* Display condensed frequency table for variable V. */
 static void
 dump_condensed (const struct variable *v, const struct variable *wv)
@@ -1153,7 +1110,7 @@ dump_condensed (const struct variable *v, const struct variable *wv)
   vf = get_var_freqs (v);
   ft = &vf->tab;
   n_categories = ft->n_valid + ft->n_missing;
-  t = tab_create (4, n_categories + 2, 0);
+  t = tab_create (4, n_categories + 2);
 
   tab_headers (t, 0, 0, 2, 0);
   tab_text (t, 0, 1, TAB_CENTER | TAT_TITLE, _("Value"));
@@ -1161,7 +1118,6 @@ dump_condensed (const struct variable *v, const struct variable *wv)
   tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
   tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Cum"));
   tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
-  tab_dim (t, condensed_dim, NULL);
 
   r = 2;
   for (f = ft->valid; f < ft->missing; f++)
@@ -1191,7 +1147,6 @@ dump_condensed (const struct variable *v, const struct variable *wv)
           0, 0, 3, r - 1);
   tab_hline (t, TAL_2, 0, 3, 2);
   tab_title (t, "%s", var_to_string (v));
-  tab_columns (t, SOM_COL_DOWN, 1);
   tab_submit (t);
 }
 \f
@@ -1359,8 +1314,7 @@ dump_statistics (const struct variable *v, bool show_varname,
     }
   calc_stats (v, stat_value);
 
-  t = tab_create (3, n_stats + n_percentiles + 2, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
+  t = tab_create (3, n_stats + n_percentiles + 2);
 
   tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ;
 
@@ -1401,11 +1355,8 @@ dump_statistics (const struct variable *v, bool show_varname,
                  var_get_print_format (v));
     }
 
-  tab_columns (t, SOM_COL_DOWN, 1);
   if (show_varname)
     tab_title (t, "%s", var_to_string (v));
-  else
-    tab_flags (t, SOMF_NO_TITLE);
 
 
   tab_submit (t);
@@ -1420,7 +1371,7 @@ freq_tab_to_hist (const struct freq_tab *ft, const struct variable *var)
   double x_min = DBL_MAX;
   double x_max = -DBL_MAX;
 
-  struct statistic *hist;
+  struct histogram *hist;
   const double bins = 11;
 
   struct hsh_iterator hi;
@@ -1442,10 +1393,10 @@ freq_tab_to_hist (const struct freq_tab *ft, const struct variable *var)
   for( i = 0 ; i < ft->n_valid ; ++i )
     {
       frq = &ft->valid[i];
-      histogram_add ((struct histogram *)hist, frq->value.f, frq->count);
+      histogram_add (hist, frq->value.f, frq->count);
     }
 
-  return (struct histogram *)hist;
+  return hist;
 }
 
 
@@ -1477,7 +1428,7 @@ freq_tab_to_slice_array(const struct freq_tab *frq_tab,
 
       ds_init_empty (&slices[i].label);
       var_append_value_name (var, &frq->value, &slices[i].label);
-      slices[i].magnetude = frq->count;
+      slices[i].magnitude = frq->count;
     }
 
   return slices;
@@ -1494,14 +1445,12 @@ do_piechart(const struct variable *var, const struct freq_tab *frq_tab)
 
   slices = freq_tab_to_slice_array(frq_tab, var, &n_slices);
 
-  piechart_plot(var_to_string(var), slices, n_slices);
+  chart_item_submit (piechart_create (var_to_string(var), slices, n_slices));
 
   for (i = 0 ; i < n_slices ; ++i )
-    {
-      ds_destroy (&slices[i].label);
-    }
+    ds_destroy (&slices[i].label);
 
-  free(slices);
+  free (slices);
 }
 
 
index fd36041636e5ad25d619ceffee2ea42824b7aa8f..0804945fabaa1504eff3779906b77dce6d3b9bda 100644 (file)
@@ -43,7 +43,7 @@
 #include <math/coefficient.h>
 #include <math/linreg.h>
 #include <math/moments.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 #include "gettext.h"
index d626dffac5f72075a582c370cb5940ec3845e2d1..05fa1d02527951bf7ecbf26a724ee76cfe2e8ffe 100644 (file)
@@ -17,7 +17,7 @@
 #include <config.h>
 
 #include <data/format.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include <data/casereader.h>
 #include <libpspp/hash.h>
 #include <data/variable.h>
@@ -102,16 +102,15 @@ do_summary_box (const struct descriptives *desc,
   if ( desc ) columns += 5;
   if ( quartiles ) columns += 3;
 
-  table = tab_create (columns, 2 + n_vars, 0);
+  table = tab_create (columns, 2 + n_vars);
 
-  tab_dim (table, tab_natural_dimensions, NULL);
 
   tab_title (table, _("Descriptive Statistics"));
 
   tab_headers (table, 1, 0, 1, 0);
 
   tab_box (table, TAL_1, TAL_1, -1, TAL_1,
-          0, 0, table->nc - 1, tab_nr(table) - 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);
@@ -159,13 +158,13 @@ do_summary_box (const struct descriptives *desc,
       const struct variable *var = vv[v];
       const struct fmt_spec *fmt = var_get_print_format (var);
 
-      tab_text (table, 0, 2 + v, TAT_NONE, var_to_string (var));
+      tab_text (table, 0, 2 + v, 0, var_to_string (var));
 
-      tab_double (table, 1, 2 + v, TAT_NONE, desc[v].n, fmt);
-      tab_double (table, 2, 2 + v, TAT_NONE, desc[v].mean, fmt);
-      tab_double (table, 3, 2 + v, TAT_NONE, desc[v].std_dev, fmt);
-      tab_double (table, 4, 2 + v, TAT_NONE, desc[v].min, fmt);
-      tab_double (table, 5, 2 + v, TAT_NONE, desc[v].max, fmt);
+      tab_double (table, 1, 2 + v, 0, desc[v].n, fmt);
+      tab_double (table, 2, 2 + v, 0, desc[v].mean, fmt);
+      tab_double (table, 3, 2 + v, 0, desc[v].std_dev, fmt);
+      tab_double (table, 4, 2 + v, 0, desc[v].min, fmt);
+      tab_double (table, 5, 2 + v, 0, desc[v].max, fmt);
     }
 
 
index bbccce671f075b161b1e95170d07197c6a3ac69d..8c6f98f82cf669275376313a03650b9ba5de0ff8 100644 (file)
@@ -32,6 +32,7 @@
 #include <language/stats/chisquare.h>
 #include <language/stats/wilcoxon.h>
 #include <language/stats/sign.h>
+#include <libpspp/cast.h>
 #include <libpspp/hash.h>
 #include <libpspp/pool.h>
 #include <libpspp/taint.h>
@@ -223,10 +224,11 @@ npar_custom_chisquare (struct lexer *lexer, struct dataset *ds,
   struct npar_specs *specs = aux;
 
   struct chisquare_test *cstp = pool_alloc(specs->pool, sizeof(*cstp));
-  struct one_sample_test *tp = (struct one_sample_test *) cstp;
+  struct one_sample_test *tp = &cstp->parent;
+  struct npar_test *nt = &tp->parent;
 
-  ((struct npar_test *)tp)->execute = chisquare_execute;
-  ((struct npar_test *)tp)->insert_variables = one_sample_insert_variables;
+  nt->execute = chisquare_execute;
+  nt->insert_variables = one_sample_insert_variables;
 
   if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
                                   &tp->vars, &tp->n_vars,
@@ -316,7 +318,7 @@ npar_custom_chisquare (struct lexer *lexer, struct dataset *ds,
                              specs->test,
                              sizeof(*specs->test) * specs->n_tests);
 
-  specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+  specs->test[specs->n_tests - 1] = nt;
 
   return 1;
 }
@@ -328,10 +330,11 @@ npar_custom_binomial (struct lexer *lexer, struct dataset *ds,
 {
   struct npar_specs *specs = aux;
   struct binomial_test *btp = pool_alloc(specs->pool, sizeof(*btp));
-  struct one_sample_test *tp = (struct one_sample_test *) btp;
+  struct one_sample_test *tp = &btp->parent;
+  struct npar_test *nt = &tp->parent;
 
-  ((struct npar_test *)tp)->execute = binomial_execute;
-  ((struct npar_test *)tp)->insert_variables = one_sample_insert_variables;
+  nt->execute = binomial_execute;
+  nt->insert_variables = one_sample_insert_variables;
 
   btp->category1 = btp->category2 = btp->cutpoint = SYSMIS;
 
@@ -381,7 +384,7 @@ npar_custom_binomial (struct lexer *lexer, struct dataset *ds,
                              specs->test,
                              sizeof(*specs->test) * specs->n_tests);
 
-  specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+  specs->test[specs->n_tests - 1] = nt;
 
   return 1;
 }
@@ -412,7 +415,7 @@ parse_two_sample_related_test (struct lexer *lexer,
   const struct variable **vlist2;
   size_t n_vlist2;
 
-  ((struct npar_test *)test_parameters)->insert_variables = two_sample_insert_variables;
+  test_parameters->parent.insert_variables = two_sample_insert_variables;
 
   if (!parse_variables_const_pool (lexer, pool,
                                   dict,
@@ -512,7 +515,8 @@ npar_custom_wilcoxon (struct lexer *lexer,
   struct npar_specs *specs = aux;
 
   struct two_sample_test *tp = pool_alloc (specs->pool, sizeof(*tp));
-  ((struct npar_test *)tp)->execute = wilcoxon_execute;
+  struct npar_test *nt = &tp->parent;
+  nt->execute = wilcoxon_execute;
 
   if (!parse_two_sample_related_test (lexer, dataset_dict (ds), cmd,
                                      tp, specs->pool) )
@@ -522,7 +526,7 @@ npar_custom_wilcoxon (struct lexer *lexer,
   specs->test = pool_realloc (specs->pool,
                              specs->test,
                              sizeof(*specs->test) * specs->n_tests);
-  specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+  specs->test[specs->n_tests - 1] = nt;
 
   return 1;
 }
@@ -535,7 +539,8 @@ npar_custom_mcnemar (struct lexer *lexer,
   struct npar_specs *specs = aux;
 
   struct two_sample_test *tp = pool_alloc(specs->pool, sizeof(*tp));
-  ((struct npar_test *)tp)->execute = NULL;
+  struct npar_test *nt = &tp->parent;
+  nt->execute = NULL;
 
 
   if (!parse_two_sample_related_test (lexer, dataset_dict (ds),
@@ -546,7 +551,7 @@ npar_custom_mcnemar (struct lexer *lexer,
   specs->test = pool_realloc (specs->pool,
                              specs->test,
                              sizeof(*specs->test) * specs->n_tests);
-  specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+  specs->test[specs->n_tests - 1] = nt;
 
   return 1;
 }
@@ -558,7 +563,9 @@ npar_custom_sign (struct lexer *lexer, struct dataset *ds,
   struct npar_specs *specs = aux;
 
   struct two_sample_test *tp = pool_alloc(specs->pool, sizeof(*tp));
-  ((struct npar_test *) tp)->execute = sign_execute;
+  struct npar_test *nt = &tp->parent;
+
+  nt->execute = sign_execute;
 
   if (!parse_two_sample_related_test (lexer, dataset_dict (ds), cmd,
                                      tp, specs->pool) )
@@ -568,7 +575,7 @@ npar_custom_sign (struct lexer *lexer, struct dataset *ds,
   specs->test = pool_realloc (specs->pool,
                              specs->test,
                              sizeof(*specs->test) * specs->n_tests);
-  specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+  specs->test[specs->n_tests - 1] = nt;
 
   return 1;
 }
@@ -579,7 +586,7 @@ one_sample_insert_variables (const struct npar_test *test,
                             struct const_hsh_table *var_hash)
 {
   int i;
-  struct one_sample_test *ost = (struct one_sample_test *) test;
+  struct one_sample_test *ost = UP_CAST (test, struct one_sample_test, parent);
 
   for ( i = 0 ; i < ost->n_vars ; ++i )
     const_hsh_insert (var_hash, ost->vars[i]);
index 0f6b20a1db04cdf9503e4a21cd67cb2f22ecf6bf..2d55edff73fb286597a7be6771b467a9c4b6422c 100644 (file)
@@ -40,8 +40,7 @@
 #include <math/group-proc.h>
 #include <math/group.h>
 #include <math/levene.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include "sort-criteria.h"
 #include <data/format.h>
 
@@ -259,10 +258,8 @@ show_anova_table (void)
   struct tab_table *t;
 
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
-
 
   tab_box (t,
           TAL_2, TAL_2,
@@ -370,9 +367,8 @@ show_descriptives (const struct dictionary *dict)
   for ( v = 0; v < n_vars; ++v )
     n_rows += group_proc_get (vars[v])->n_groups + 1;
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 2, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
 
   /* Put a frame around the entire box, and vertical lines inside */
@@ -517,9 +513,9 @@ show_homogeneity (void)
   struct tab_table *t;
 
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 1, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
+
 
   /* Put a frame around the entire box, and vertical lines inside */
   tab_box (t,
@@ -577,9 +573,8 @@ show_contrast_coeffs (short *bad_contrast)
 
   struct tab_table *t;
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 2, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   /* Put a frame around the entire box, and vertical lines inside */
   tab_box (t,
@@ -661,9 +656,8 @@ show_contrast_tests (short *bad_contrast)
 
   struct tab_table *t;
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 3, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   /* Put a frame around the entire box, and vertical lines inside */
   tab_box (t,
index c225370e459269cc572430f87e533f7a591662c4..ec3052c0acee616def219464aa7bf19edfec4550 100644 (file)
@@ -35,8 +35,7 @@
 #include <libpspp/compiler.h>
 #include <libpspp/taint.h>
 #include <math/sort.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include <gsl/gsl_cdf.h>
 
@@ -692,7 +691,7 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
       int v;
 
       tab_output_text (0, _("Variables Created By RANK"));
-      tab_output_text (0, "\n");
+      tab_output_text (0, "");
 
       for (i = 0 ; i <  n_rank_specs ; ++i )
        {
index 41a23f3e2580ebd9a9aac6ff289b89803c6f8da2..2487b9021d08bb14d86a14ed84e3b99dd6f5bad6 100644 (file)
@@ -43,7 +43,7 @@
 #include <math/coefficient.h>
 #include <math/linreg.h>
 #include <math/moments.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -149,8 +149,7 @@ reg_stats_r (pspp_linreg_cache * c)
   rsq = c->ssm / c->sst;
   adjrsq = 1.0 - (1.0 - rsq) * (c->n_obs - 1.0) / (c->n_obs - c->n_indeps);
   std_error = sqrt (pspp_linreg_mse (c));
-  t = tab_create (n_cols, n_rows, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
+  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);
@@ -191,9 +190,8 @@ reg_stats_coeff (pspp_linreg_cache * c)
   assert (c != NULL);
   n_rows = c->n_coeffs + 3;
 
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
   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);
@@ -288,9 +286,8 @@ reg_stats_anova (pspp_linreg_cache * c)
   struct tab_table *t;
 
   assert (c != NULL);
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
 
   tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
 
@@ -379,9 +376,8 @@ reg_stats_bcov (pspp_linreg_cache * c)
   assert (c != NULL);
   n_cols = c->n_indeps + 1 + 2;
   n_rows = 2 * (c->n_indeps + 1);
-  t = tab_create (n_cols, n_rows, 0);
+  t = tab_create (n_cols, n_rows);
   tab_headers (t, 2, 0, 1, 0);
-  tab_dim (t, tab_natural_dimensions, NULL);
   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);
index 681669d18999fdac3c5516c9815b9079aae99dfb..478f5c5bc1baa06c967f980e6d2704587fe131bc 100644 (file)
@@ -27,8 +27,8 @@
 #include <language/command.h>
 #include <libpspp/misc.h>
 #include <math/moments.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
+#include <output/text-item.h>
 
 #include "xalloc.h"
 #include "xmalloca.h"
@@ -379,18 +379,8 @@ run_reliability (struct casereader *input, struct dataset *ds,
        alpha (s->n_items, s->sum_of_variances, s->variance_of_sums);
     }
 
-
-  {
-    struct tab_table *tab = tab_create(1, 1, 0);
-
-    tab_dim (tab, tab_natural_dimensions, NULL);
-    tab_flags (tab, SOMF_NO_TITLE );
-
-    tab_text_format (tab, 0, 0, 0, "Scale: %s", ds_cstr (&rel->scale_name));
-
-    tab_submit(tab);
-  }
-
+  text_item_submit (text_item_create_format (TEXT_ITEM_PARAGRAPH, "Scale: %s",
+                                             ds_cstr (&rel->scale_name)));
 
   case_processing_summary (n_valid, n_missing, dataset_dict (ds));
 }
@@ -425,11 +415,9 @@ reliability_statistics (const struct reliability *rel)
   int heading_columns = rol[rel->model].heading_cols;
   int heading_rows = rol[rel->model].heading_rows;
 
-  struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   tab_title (tbl, _("Reliability Statistics"));
 
   /* Vertical lines for the data only */
@@ -468,11 +456,9 @@ reliability_summary_total (const struct reliability *rel)
   const int heading_rows = 1;
   const int n_rows = rel->sc[0].n_items + heading_rows ;
 
-  struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   tab_title (tbl, _("Item-Total Statistics"));
 
   /* Vertical lines for the data only */
@@ -678,11 +664,9 @@ case_processing_summary (casenumber n_valid, casenumber n_missing,
   int heading_columns = 2;
   int heading_rows = 1;
   struct tab_table *tbl;
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   tab_title (tbl, _("Case Processing Summary"));
 
   /* Vertical lines for the data only */
index 86aee1f9d1f5e6a9662f1a605ebf560db52b19b7..724bc523a3beef42df39ca5b801da5918f88d398 100644 (file)
 
 #include <config.h>
 
-#include <data/procedure.h>
-#include <language/lexer/variable-parser.h>
-#include <language/lexer/value-parser.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
+#include <language/stats/roc.h>
 
 #include <data/casegrouper.h>
 #include <data/casereader.h>
 #include <data/casewriter.h>
 #include <data/dictionary.h>
 #include <data/format.h>
-#include <math/sort.h>
+#include <data/procedure.h>
 #include <data/subcase.h>
-
-
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <language/lexer/value-parser.h>
+#include <language/lexer/variable-parser.h>
 #include <libpspp/misc.h>
+#include <math/sort.h>
+#include <output/chart-item.h>
+#include <output/charts/roc-chart.h>
+#include <output/tab.h>
 
 #include <gsl/gsl_cdf.h>
-#include <output/table.h>
-
-#include <output/charts/plot-chart.h>
-#include <output/charts/cartesian.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -386,13 +384,6 @@ struct roc_state
   double max;
 };
 
-#define CUTPOINT 0
-#define TP 1
-#define FN 2
-#define TN 3
-#define FP 4
-
-
 /* 
    Return a new casereader based upon CUTPOINT_RDR.
    The number of "positive" cases are placed into
@@ -418,7 +409,7 @@ accumulate_counts (struct casereader *cutpoint_rdr,
   for ( ; (cpc = casereader_read (r) ); case_unref (cpc))
     {
       struct ccase *new_case;
-      const double cp = case_data_idx (cpc, CUTPOINT)->f;
+      const double cp = case_data_idx (cpc, ROC_CUTPOINT)->f;
 
       assert (cp != SYSMIS);
 
@@ -582,7 +573,7 @@ process_positive_group (const struct variable *var, struct casereader *reader,
   return process_group (var, reader, gt, dict, &rs->n1,
                        &rs->cutpoint_rdr,
                        ge,
-                       TP, FN);
+                       ROC_TP, ROC_FN);
 }
 
 /*
@@ -600,7 +591,7 @@ process_negative_group (const struct variable *var, struct casereader *reader,
   return process_group (var, reader, lt, dict, &rs->n2,
                        &rs->cutpoint_rdr,
                        lt,
-                       TN, FP);
+                       ROC_TN, ROC_FP);
 }
 
 
@@ -611,11 +602,11 @@ append_cutpoint (struct casewriter *writer, double cutpoint)
 {
   struct ccase *cc = case_create (casewriter_get_proto (writer));
 
-  case_data_rw_idx (cc, CUTPOINT)->f = cutpoint;
-  case_data_rw_idx (cc, TP)->f = 0;
-  case_data_rw_idx (cc, FN)->f = 0;
-  case_data_rw_idx (cc, TN)->f = 0;
-  case_data_rw_idx (cc, FP)->f = 0;
+  case_data_rw_idx (cc, ROC_CUTPOINT)->f = cutpoint;
+  case_data_rw_idx (cc, ROC_TP)->f = 0;
+  case_data_rw_idx (cc, ROC_FN)->f = 0;
+  case_data_rw_idx (cc, ROC_TN)->f = 0;
+  case_data_rw_idx (cc, ROC_FP)->f = 0;
 
   casewriter_write (writer, cc);
 }
@@ -623,9 +614,9 @@ append_cutpoint (struct casewriter *writer, double cutpoint)
 
 /* 
    Create and initialise the rs[x].cutpoint_rdr casereaders.  That is, the readers will
-   be created with width 5, ready to take the values (cutpoint, TP, FN, TN, FP), and the
+   be created with width 5, ready to take the values (cutpoint, ROC_TP, ROC_FN, ROC_TN, ROC_FP), and the
    reader will be populated with its final number of cases.
-   However on exit from this function, only CUTPOINT entries will be set to their final
+   However on exit from this function, only ROC_CUTPOINT entries will be set to their final
    value.  The other entries will be initialised to zero.
 */
 static void
@@ -637,13 +628,13 @@ prepare_cutpoints (struct cmd_roc *roc, struct roc_state *rs, struct casereader
   struct caseproto *proto = caseproto_create ();
 
   struct subcase ordering;
-  subcase_init (&ordering, CUTPOINT, 0, SC_ASCEND);
+  subcase_init (&ordering, ROC_CUTPOINT, 0, SC_ASCEND);
 
   proto = caseproto_add_width (proto, 0); /* cutpoint */
-  proto = caseproto_add_width (proto, 0); /* TP */
-  proto = caseproto_add_width (proto, 0); /* FN */
-  proto = caseproto_add_width (proto, 0); /* TN */
-  proto = caseproto_add_width (proto, 0); /* FP */
+  proto = caseproto_add_width (proto, 0); /* ROC_TP */
+  proto = caseproto_add_width (proto, 0); /* ROC_FN */
+  proto = caseproto_add_width (proto, 0); /* ROC_TN */
+  proto = caseproto_add_width (proto, 0); /* ROC_FP */
 
   for (i = 0 ; i < roc->n_vars; ++i)
     {
@@ -935,7 +926,7 @@ show_auc  (struct roc_state *rs, const struct cmd_roc *roc)
   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, 0);
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
 
   if ( roc->n_vars > 1)
     tab_title (tbl, _("Area Under the Curve"));
@@ -944,7 +935,6 @@ show_auc  (struct roc_state *rs, const struct cmd_roc *roc)
 
   tab_headers (tbl, n_cols - n_fields, 0, 1, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
 
   tab_text (tbl, n_cols - n_fields, 1, TAT_TITLE, _("Area"));
 
@@ -1030,14 +1020,12 @@ 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, 0);
+  struct tab_table *tbl = tab_create (n_cols, n_rows);
 
   tab_title (tbl, _("Case Summary"));
 
   tab_headers (tbl, 1, 0, 2, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   tab_box (tbl,
           TAL_2, TAL_2,
           -1, -1,
@@ -1088,7 +1076,7 @@ show_coords (struct roc_state *rs, const struct cmd_roc *roc)
   for (i = 0; i < roc->n_vars; ++i)
     n_rows += casereader_count_cases (rs[i].cutpoint_rdr);
 
-  tbl = tab_create (n_cols, n_rows, 0);
+  tbl = tab_create (n_cols, n_rows);
 
   if ( roc->n_vars > 1)
     tab_title (tbl, _("Coordinates of the Curve"));
@@ -1098,8 +1086,6 @@ show_coords (struct roc_state *rs, const struct cmd_roc *roc)
 
   tab_headers (tbl, 1, 0, 1, 0);
 
-  tab_dim (tbl, tab_natural_dimensions, NULL);
-
   tab_hline (tbl, TAL_2, 0, n_cols - 1, 1);
 
   if ( roc->n_vars > 1)
@@ -1134,21 +1120,21 @@ show_coords (struct roc_state *rs, const struct cmd_roc *roc)
       for (; (cc = casereader_read (r)) != NULL;
           case_unref (cc), x++)
        {
-         const double se = case_data_idx (cc, TP)->f /
+         const double se = case_data_idx (cc, ROC_TP)->f /
            (
-            case_data_idx (cc, TP)->f
+            case_data_idx (cc, ROC_TP)->f
             +
-            case_data_idx (cc, FN)->f
+            case_data_idx (cc, ROC_FN)->f
             );
 
-         const double sp = case_data_idx (cc, TN)->f /
+         const double sp = case_data_idx (cc, ROC_TN)->f /
            (
-            case_data_idx (cc, TN)->f
+            case_data_idx (cc, ROC_TN)->f
             +
-            case_data_idx (cc, FP)->f
+            case_data_idx (cc, ROC_FP)->f
             );
 
-         tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, CUTPOINT)->f,
+         tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, ROC_CUTPOINT)->f,
                      var_get_print_format (roc->vars[i]));
 
          tab_double (tbl, n_cols - 2, x, 0, se, NULL);
@@ -1162,68 +1148,25 @@ show_coords (struct roc_state *rs, const struct cmd_roc *roc)
 }
 
 
-static void
-draw_roc (struct roc_state *rs, const struct cmd_roc *roc)
-{
-  int i;
-
-  struct chart *roc_chart = chart_create ();
-
-  chart_write_title (roc_chart, _("ROC Curve"));
-  chart_write_xlabel (roc_chart, _("1 - Specificity"));
-  chart_write_ylabel (roc_chart, _("Sensitivity"));
-
-  chart_write_xscale (roc_chart, 0, 1, 5);
-  chart_write_yscale (roc_chart, 0, 1, 5);
-
-  if ( roc->reference )
-    {
-      chart_line (roc_chart, 1.0, 0,
-                 0.0, 1.0,
-                 CHART_DIM_X);
-    }
-
-  for (i = 0; i < roc->n_vars; ++i)
-    {
-      struct ccase *cc;
-      struct casereader *r = casereader_clone (rs[i].cutpoint_rdr);
-
-      chart_vector_start (roc_chart, var_get_name (roc->vars[i]));
-      for (; (cc = casereader_read (r)) != NULL;
-          case_unref (cc))
-       {
-         double se = case_data_idx (cc, TP)->f;
-         double sp = case_data_idx (cc, TN)->f;
-
-         se /= case_data_idx (cc, FN)->f +
-           case_data_idx (cc, TP)->f ;
-
-         sp /= case_data_idx (cc, TN)->f +
-           case_data_idx (cc, FP)->f ;
-
-         chart_vector (roc_chart, 1 - sp, se);
-       }
-      chart_vector_end (roc_chart);
-      casereader_destroy (r);
-    }
-
-  chart_write_legend (roc_chart);
-
-  chart_submit (roc_chart);
-}
-
-
 static void
 output_roc (struct roc_state *rs, const struct cmd_roc *roc)
 {
   show_summary (roc);
 
   if ( roc->curve )
-    draw_roc (rs, roc);
+    {
+      struct roc_chart *rc;
+      size_t i;
+
+      rc = roc_chart_create (roc->reference);
+      for (i = 0; i < roc->n_vars; i++)
+        roc_chart_add_var (rc, var_get_name (roc->vars[i]),
+                           rs[i].cutpoint_rdr);
+      roc_chart_submit (rc);
+    }
 
   show_auc (rs, roc);
 
-
   if ( roc->print_coords )
     show_coords (rs, roc);
 }
diff --git a/src/language/stats/roc.h b/src/language/stats/roc.h
new file mode 100644 (file)
index 0000000..5d63c96
--- /dev/null
@@ -0,0 +1,28 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 LANGUAGE_STATS_ROC_H
+#define LANGUAGE_STATS_ROC_H 1
+
+/* These are case indexes into the cutpoint case readers for ROC
+   output, used by roc.c and roc-chart.c. */
+#define ROC_CUTPOINT 0
+#define ROC_TP 1
+#define ROC_FN 2
+#define ROC_TN 3
+#define ROC_FP 4
+
+#endif /* language/stats/roc.h */
index a5a272126007c557a2c006b652d73cf7e9fe4436..754b0d7dfcd6b47c08d62f6f4db05ab8a6e90812 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <data/variable.h>
 #include <libpspp/str.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include <gsl/gsl_cdf.h>
 #include <gsl/gsl_randist.h>
 #include "npar.h"
@@ -52,24 +52,22 @@ output_frequency_table (const struct two_sample_test *t2s,
                        const struct dictionary *dict)
 {
   int i;
-  struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs, 0);
+  struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs);
 
   const struct variable *wv = dict_get_weight (dict);
   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
 
-  tab_dim (table, tab_natural_dimensions, NULL);
-
   tab_title (table, _("Frequencies"));
 
   tab_headers (table, 2, 0, 1, 0);
 
   /* Vertical lines inside the box */
   tab_box (table, 0, 0, -1, TAL_1,
-          1, 0, table->nc - 1, tab_nr (table) - 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, table->nc - 1, tab_nr (table) - 1 );
+          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
 
   tab_text (table,  2, 0,  TAB_CENTER, _("N"));
 
@@ -86,7 +84,7 @@ output_frequency_table (const struct two_sample_test *t2s,
 
       ds_destroy (&pair_name);
 
-      tab_hline (table, TAL_1, 0, table->nc - 1, 1 + i * 4);
+      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"));
@@ -108,26 +106,24 @@ 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, 0);
-
-  tab_dim (table, tab_natural_dimensions, NULL);
+  struct tab_table *table = tab_create (1 + t2s->n_pairs, 4);
 
   tab_title (table, _("Test Statistics"));
 
   tab_headers (table, 0, 1,  0, 1);
 
-  tab_hline (table, TAL_2, 0, table->nc - 1, 1);
-  tab_vline (table, TAL_2, 1, 0, table->nr - 1);
+  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,
-          table->nc - 1, tab_nr (table) - 1);
+          tab_nc (table) - 1, tab_nr (table) - 1);
 
   /* Box around entire table */
   tab_box (table, TAL_2, TAL_2, -1, -1,
-          0, 0, table->nc - 1,
+          0, 0, tab_nc (table) - 1,
           tab_nr (table) - 1);
 
   tab_text (table,  0, 1, TAT_TITLE | TAB_LEFT,
index 8f23cefd4afa54c8be6cfebe7031128a913e3616..8aee3b157992827fa9021c876b39822809ab43b2 100644 (file)
@@ -44,8 +44,7 @@
 #include <math/group-proc.h>
 #include <math/levene.h>
 #include <math/correlation.h>
-#include <output/manager.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include <data/format.h>
 
 #include "minmax.h"
@@ -477,13 +476,11 @@ static void
 ssbox_base_init (struct ssbox *this, int cols, int rows)
 {
   this->finalize = ssbox_base_finalize;
-  this->t = tab_create (cols, rows, 0);
+  this->t = tab_create (cols, rows);
 
-  tab_columns (this->t, SOM_COL_DOWN, 1);
   tab_headers (this->t, 0, 0, 1, 0);
   tab_box (this->t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
   tab_hline (this->t, TAL_2, 0, cols- 1, 1);
-  tab_dim (this->t, tab_natural_dimensions, NULL);
 }
 \f
 /* ssbox implementations. */
@@ -1069,11 +1066,10 @@ trbox_base_init (struct trbox *self, size_t data_rows, int cols)
   const size_t rows = 3 + data_rows;
 
   self->finalize = trbox_base_finalize;
-  self->t = tab_create (cols, rows, 0);
+  self->t = tab_create (cols, rows);
   tab_headers (self->t, 0, 0, 3, 0);
   tab_box (self->t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
   tab_hline (self->t, TAL_2, 0, cols- 1, 3);
-  tab_dim (self->t, tab_natural_dimensions, NULL);
 }
 
 /* Base finalizer for the trbox */
@@ -1093,14 +1089,12 @@ pscbox (struct t_test_proc *proc)
 
   struct tab_table *table;
 
-  table = tab_create (cols, rows, 0);
+  table = tab_create (cols, rows);
 
-  tab_columns (table, SOM_COL_DOWN, 1);
   tab_headers (table, 0, 0, 1, 0);
   tab_box (table, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
   tab_hline (table, TAL_2, 0, cols - 1, 1);
   tab_vline (table, TAL_2, 2, 0, rows - 1);
-  tab_dim (table, tab_natural_dimensions, NULL);
   tab_title (table, _("Paired Samples Correlations"));
 
   /* column headings */
index 310206c0e7bf88961e820c05f97831f8568da5a6..e1dab91c9ff661cbf3d64618e9f5edb7a7b703d8 100644 (file)
@@ -38,7 +38,7 @@
 #include <libpspp/misc.h>
 #include <math/sort.h>
 #include <math/wilcoxon-sig.h>
-#include <output/table.h>
+#include <output/tab.h>
 #include <signal.h>
 #include <unistd.h>
 
@@ -225,9 +225,7 @@ show_ranks_box (const struct wilcoxon_state *ws,
   const struct variable *wv = dict_get_weight (dict);
   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
 
-  struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs, 0);
-
-  tab_dim (table, tab_natural_dimensions, NULL);
+  struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs);
 
   tab_title (table, _("Ranks"));
 
@@ -235,11 +233,11 @@ show_ranks_box (const struct wilcoxon_state *ws,
 
   /* Vertical lines inside the box */
   tab_box (table, 0, 0, -1, TAL_1,
-          1, 0, table->nc - 1, tab_nr (table) - 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, table->nc - 1, tab_nr (table) - 1 );
+          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
 
 
   tab_text (table,  2, 0,  TAB_CENTER, _("N"));
@@ -261,7 +259,7 @@ show_ranks_box (const struct wilcoxon_state *ws,
       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, table->nc - 1, 1 + i * 4);
+      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));
@@ -290,8 +288,8 @@ show_ranks_box (const struct wilcoxon_state *ws,
 
     }
 
-  tab_hline (table, TAL_2, 0, table->nc - 1, 1);
-  tab_vline (table, TAL_2, 2, 0, table->nr - 1);
+  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);
@@ -306,9 +304,7 @@ show_tests_box (const struct wilcoxon_state *ws,
                )
 {
   size_t i;
-  struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3, 0);
-
-  tab_dim (table, tab_natural_dimensions, NULL);
+  struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3);
 
   tab_title (table, _("Test Statistics"));
 
@@ -316,11 +312,11 @@ show_tests_box (const struct wilcoxon_state *ws,
 
   /* Vertical lines inside the box */
   tab_box (table, 0, 0, -1, TAL_1,
-          0, 0, table->nc - 1, tab_nr (table) - 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, table->nc - 1, tab_nr (table) - 1 );
+          0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
 
 
   tab_text (table,  0, 1,  TAB_LEFT, _("Z"));
@@ -377,8 +373,8 @@ show_tests_box (const struct wilcoxon_state *ws,
        }
     }
 
-  tab_hline (table, TAL_2, 0, table->nc - 1, 1);
-  tab_vline (table, TAL_2, 1, 0, table->nr - 1);
+  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);
index 0771ade3a9e92dccc0c3063a7c14d13014c010e3..5521972477f270a1a046b9a99f5b0b3e5a117f69 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010 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
 #include <language/command.h>
 #include <language/lexer/lexer.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <libpspp/verbose-msg.h>
 #include <libpspp/version.h>
-#include <output/table.h>
+#include <output/tab.h>
 
 #include <libpspp/ll.h>
 
@@ -62,14 +62,16 @@ struct syntax_file_source
 static const char *
 name (const struct getl_interface *s)
 {
-  const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+  const struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+                                                  parent);
   return sfs->fn;
 }
 
 static int
 line_number (const struct getl_interface *s)
 {
-  const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+  const struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+                                                  parent);
   return sfs->ln;
 }
 
@@ -80,12 +82,12 @@ static bool
 read_syntax_file (struct getl_interface *s,
                   struct string *line)
 {
-  struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+  struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+                                            parent);
 
   /* Open file, if not yet opened. */
   if (sfs->syntax_file == NULL)
     {
-      verbose_msg (1, _("opening \"%s\" as syntax file"), sfs->fn);
       sfs->syntax_file = fn_open (sfs->fn, "r");
 
       if (sfs->syntax_file == NULL)
@@ -111,17 +113,14 @@ read_syntax_file (struct getl_interface *s,
     }
   while (sfs->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
 
-  /* Echo to listing file, if configured to do so. */
-  if (settings_get_echo ())
-    tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
-
   return true;
 }
 
 static void
 syntax_close (struct getl_interface *s)
 {
-  struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+  struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+                                            parent);
 
   if (sfs->syntax_file && EOF == fn_close (sfs->fn, sfs->syntax_file))
     msg (MW, _("Closing `%s': %s."), sfs->fn, strerror (errno));
@@ -151,6 +150,6 @@ create_syntax_file_source (const char *fn)
   ss->parent.name = name ;
   ss->parent.location = line_number;
 
-  return (struct getl_interface *) ss;
+  return &ss->parent;
 }
 
index 94a56f97aacb55ae642b3eac0290cd8531f2b2c3..405141cd50a7fd1734f387281b5b344d5a7e74f9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical interface for PSPP.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -17,6 +17,7 @@
 
 #include <config.h>
 
+#include <libpspp/cast.h>
 #include <libpspp/getl.h>
 #include <libpspp/compiler.h>
 #include <libpspp/str.h>
@@ -60,7 +61,8 @@ location (const struct getl_interface *i UNUSED)
 static void
 do_close (struct getl_interface *i )
 {
-  struct syntax_string_source *sss = (struct syntax_string_source *) i;
+  struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
+                                              parent);
 
   ds_destroy (&sss->buffer);
 
@@ -73,7 +75,8 @@ static bool
 read_single_line (struct getl_interface *i,
                  struct string *line)
 {
-  struct syntax_string_source *sss = (struct syntax_string_source *) i;
+  struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
+                                              parent);
 
   size_t next;
 
@@ -120,7 +123,7 @@ create_syntax_string_source (const char *format, ...)
   sss->parent.location = location;
 
 
-  return (struct getl_interface *) sss;
+  return &sss->parent;
 }
 
 /* Return the syntax currently contained in S.
index d8c49a595c0250a30155080a5372c629a2da598f..5aea2c334f34f5157a7dbcd77d4fa0f4a478f6b7 100644 (file)
 #include <language/command.h>
 #include <language/lexer/lexer.h>
 #include <libpspp/assertion.h>
-#include <output/output.h>
+#include <libpspp/string-map.h>
+#include <output/measure.h>
 
 /* Executes the DEBUG PAPER SIZE command. */
 int
 cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
 {
+  const char *paper_size;
   int h, v;
 
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
+  paper_size = ds_cstr (lex_tokstr (lexer));
 
-  printf ("\"%s\" => ", ds_cstr (lex_tokstr (lexer)));
-  if (outp_get_paper_size (ds_cstr (lex_tokstr (lexer)), &h, &v))
+  printf ("\"%s\" => ", paper_size);
+  if (measure_paper (paper_size, &h, &v))
     printf ("%.1f x %.1f in, %.0f x %.0f mm\n",
             h / 72000., v / 72000.,
             h / (72000 / 25.4), v / (72000 / 25.4));
index 19e9f9e54bf36b860b46f8d4681ce61660931b10..ebd6a990fc88e1c1c02a48a7562fd91d4fccdc32 100644 (file)
@@ -19,8 +19,7 @@
 #include <libpspp/str.h>
 #include <language/lexer/lexer.h>
 #include <language/command.h>
-#include <output/table.h>
-#include <output/manager.h>
+#include <output/tab.h>
 
 #include "xalloc.h"
 
@@ -33,10 +32,7 @@ cmd_echo (struct lexer *lexer, struct dataset *ds UNUSED)
   if (lex_token (lexer) != T_STRING)
     return CMD_FAILURE;
 
-  tab = tab_create(1, 1, 0);
-
-  tab_dim (tab, tab_natural_dimensions, NULL);
-  tab_flags (tab, SOMF_NO_TITLE );
+  tab = tab_create(1, 1);
 
   tab_text(tab, 0, 0, 0, ds_cstr (lex_tokstr (lexer)));
 
index fe98aeb87f3347b82b61853adc70360cee87f132..ceb78771d748fb6f18bb8cb79274a23421720eab 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+
+#include <data/file-name.h>
 #include <language/command.h>
-#include <libpspp/message.h>
-#include <libpspp/getl.h>
-#include <language/syntax-file.h>
 #include <language/lexer/lexer.h>
+#include <language/syntax-file.h>
+#include <libpspp/getl.h>
+#include <libpspp/message.h>
 #include <libpspp/str.h>
-#include <data/file-name.h>
 
 #include "dirname.h"
 #include "xalloc.h"
index 5c2b571ec57a7df2a7f9203abe2d23d244e083c9..6a1d184f600f88d28723a409b5237ad1b30a3c7e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
@@ -40,8 +40,8 @@
 #include <libpspp/message.h>
 #include <libpspp/i18n.h>
 #include <math/random.h>
+#include <output/driver.h>
 #include <output/journal.h>
-#include <output/output.h>
 
 #if HAVE_LIBTERMCAP
 #if HAVE_TERMCAP_H
@@ -72,13 +72,10 @@ int tgetnum (const char *);
      cpi=integer "x>0" "%s must be greater than 0";
      cprompt=string;
      decimal=dec:dot/comma;
-     disk=custom;
      dprompt=string;
-     echo=echo:on/off;
      endcmd=string "x==1" "one character long";
      epoch=custom;
-     errorbreak=errbrk:on/off;
-     errors=errors:terminal/listing/both/on/none/off;
+     errors=custom;
      format=custom;
      headers=headers:no/yes/blank;
      highres=hires:on/off;
@@ -88,11 +85,10 @@ int tgetnum (const char *);
      log=custom;
      length=custom;
      locale=custom;
-     listing=custom;
      lowres=lores:auto/on/off;
      lpi=integer "x>0" "%s must be greater than 0";
      menus=menus:standard/extended;
-     messages=messages:on/off/terminal/listing/both/on/none/off;
+     messages=custom;
      mexpand=mexp:on/off;
      miterate=integer "x>0" "%s must be greater than 0";
      mnest=integer "x>0" "%s must be greater than 0";
@@ -102,9 +98,9 @@ int tgetnum (const char *);
      mxmemory=integer;
      mxwarns=integer;
      nulline=null:on/off;
-     printback=prtbck:on/off;
+     printback=custom;
      prompt=string;
-     results=res:on/off/terminal/listing/both/on/none/off;
+     results=custom;
      rib=rib:msbfirst/lsbfirst/vax/native;
      rrb=rrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
      safer=safe:on;
@@ -162,24 +158,14 @@ cmd_set (struct lexer *lexer, struct dataset *ds)
   if (cmd.sbc_decimal)
     settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ',');
 
-  if (cmd.sbc_echo)
-    settings_set_echo (cmd.echo == STC_ON);
   if (cmd.sbc_endcmd)
     settings_set_endcmd (cmd.s_endcmd[0]);
-  if (cmd.sbc_errorbreak)
-    settings_set_errorbreak (cmd.errbrk == STC_ON);
-  if (cmd.sbc_errors)
-    {
-      bool both = cmd.errors == STC_BOTH || cmd.errors == STC_ON;
-      settings_set_error_routing_to_terminal (cmd.errors == STC_TERMINAL || both);
-      settings_set_error_routing_to_listing (cmd.errors == STC_LISTING || both);
-    }
   if (cmd.sbc_include)
     settings_set_include (cmd.inc == STC_ON);
   if (cmd.sbc_mxerrs)
-    settings_set_mxerrs (cmd.n_mxerrs[0]);
+    settings_set_max_messages (MSG_S_ERROR, cmd.n_mxerrs[0]);
   if (cmd.sbc_mxwarns)
-    settings_set_mxwarns (cmd.n_mxwarns[0]);
+    settings_set_max_messages (MSG_S_WARNING, cmd.n_mxwarns[0]);
   if (cmd.sbc_nulline)
     settings_set_nulline (cmd.null == STC_ON);
   if (cmd.sbc_rib)
@@ -280,7 +266,30 @@ stc_to_float_format (int stc)
   NOT_REACHED ();
 }
 
+static int
+set_output_routing (struct lexer *lexer, enum settings_output_type type)
+{
+  enum settings_output_devices devices;
+
+  lex_match (lexer, '=');
+  if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "BOTH"))
+    devices = SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL;
+  else if (lex_match_id (lexer, "TERMINAL"))
+    devices = SETTINGS_DEVICE_TERMINAL;
+  else if (lex_match_id (lexer, "LISTING"))
+    devices = SETTINGS_DEVICE_LISTING;
+  else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NONE"))
+    devices = 0;
+  else
+    {
+      lex_error (lexer, NULL);
+      return 0;
+    }
+
+  settings_set_output_routing (type, devices);
 
+  return 1;
+}
 
 /* Parses the BLANKS subcommand, which controls the value that
    completely blank fields in numeric data imply.  X, Wnd: Syntax is
@@ -336,6 +345,13 @@ stc_custom_epoch (struct lexer *lexer,
   return 1;
 }
 
+static int
+stc_custom_errors (struct lexer *lexer, struct dataset *ds UNUSED,
+                   struct cmd_set *cmd UNUSED, void *aux UNUSED)
+{
+  return set_output_routing (lexer, SETTINGS_OUTPUT_ERROR);
+}
+
 static int
 stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
@@ -396,7 +412,26 @@ stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED,
   return 1;
 }
 
+static int
+stc_custom_messages (struct lexer *lexer, struct dataset *ds UNUSED,
+                   struct cmd_set *cmd UNUSED, void *aux UNUSED)
+{
+  return set_output_routing (lexer, SETTINGS_OUTPUT_NOTE);
+}
+
+static int
+stc_custom_printback (struct lexer *lexer, struct dataset *ds UNUSED,
+                      struct cmd_set *cmd UNUSED, void *aux UNUSED)
+{
+  return set_output_routing (lexer, SETTINGS_OUTPUT_SYNTAX);
+}
 
+static int
+stc_custom_results (struct lexer *lexer, struct dataset *ds UNUSED,
+                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
+{
+  return set_output_routing (lexer, SETTINGS_OUTPUT_RESULT);
+}
 
 static int
 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
@@ -488,33 +523,24 @@ stc_custom_log (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *
 {
   return stc_custom_journal (lexer, ds, cmd, aux);
 }
-
-static int
-stc_custom_listing (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
+\f
+static char *
+show_output_routing (enum settings_output_type type)
 {
-  bool listing;
+  enum settings_output_devices devices;
+  const char *s;
 
-  lex_match (lexer, '=');
-  if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES"))
-    listing = true;
-  else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO"))
-    listing = false;
+  devices = settings_get_output_routing (type);
+  if (devices & SETTINGS_DEVICE_LISTING)
+    s = devices & SETTINGS_DEVICE_TERMINAL ? "BOTH" : "LISTING";
+  else if (devices & SETTINGS_DEVICE_TERMINAL)
+    s = "TERMINAL";
   else
-    {
-      /* FIXME */
-      return 0;
-    }
-  outp_enable_device (listing, OUTP_DEV_LISTING);
+    s = "NONE";
 
-  return 1;
+  return xstrdup (s);
 }
 
-static int
-stc_custom_disk (struct lexer *lexer, struct dataset *ds, struct cmd_set *cmd UNUSED, void *aux)
-{
-  return stc_custom_listing (lexer, ds, cmd, aux);
-}
-\f
 static char *
 show_blanks (const struct dataset *ds UNUSED)
 {
@@ -600,12 +626,7 @@ show_endcmd (const struct dataset *ds UNUSED)
 static char *
 show_errors (const struct dataset *ds UNUSED)
 {
-  bool terminal = settings_get_error_routing_to_terminal ();
-  bool listing = settings_get_error_routing_to_listing ();
-  return xstrdup (terminal && listing ? "BOTH"
-                  : terminal ? "TERMINAL"
-                  : listing ? "LISTING"
-                  : "NONE");
+  return show_output_routing (SETTINGS_OUTPUT_ERROR);
 }
 
 static char *
@@ -627,10 +648,28 @@ show_locale (const struct dataset *ds UNUSED)
   return xstrdup (get_default_encoding ());
 }
 
+static char *
+show_messages (const struct dataset *ds UNUSED)
+{
+  return show_output_routing (SETTINGS_OUTPUT_NOTE);
+}
+
+static char *
+show_printback (const struct dataset *ds UNUSED)
+{
+  return show_output_routing (SETTINGS_OUTPUT_SYNTAX);
+}
+
+static char *
+show_results (const struct dataset *ds UNUSED)
+{
+  return show_output_routing (SETTINGS_OUTPUT_RESULT);
+}
+
 static char *
 show_mxerrs (const struct dataset *ds UNUSED)
 {
-  return xasprintf ("%d", settings_get_mxerrs ());
+  return xasprintf ("%d", settings_get_max_messages (MSG_S_ERROR));
 }
 
 static char *
@@ -642,7 +681,7 @@ show_mxloops (const struct dataset *ds UNUSED)
 static char *
 show_mxwarns (const struct dataset *ds UNUSED)
 {
-  return xasprintf ("%d", settings_get_mxwarns ());
+  return xasprintf ("%d", settings_get_max_messages (MSG_S_WARNING));
 }
 
 /* Returns a name for the given INTEGER_FORMAT value. */
@@ -773,9 +812,12 @@ const struct show_sbc show_table[] =
     {"FORMAT", show_format},
     {"LENGTH", show_length},
     {"LOCALE", show_locale},
+    {"MESSAGES", show_messages},
     {"MXERRS", show_mxerrs},
     {"MXLOOPS", show_mxloops},
     {"MXWARNS", show_mxwarns},
+    {"PRINTBACk", show_printback},
+    {"RESULTS", show_results},
     {"RIB", show_rib},
     {"RRB", show_rrb},
     {"SCOMPRESSION", show_scompression},
index 1bdb0e9a0db6487467d51aa958452cf91ef13637..fe826db155dadb8ad1b5cd97d2df7709399171ba 100644 (file)
 #include <libpspp/message.h>
 #include <libpspp/start-date.h>
 #include <libpspp/version.h>
-#include <output/output.h>
+#include <output/text-item.h>
 
 #include "xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static int get_title (struct lexer *, const char *cmd, char **title);
+static int parse_title (struct lexer *, enum text_item_type);
+static void set_title (const char *title, enum text_item_type);
 
 int
 cmd_title (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  return get_title (lexer, "TITLE", &outp_title);
+  return parse_title (lexer, TEXT_ITEM_TITLE);
 }
 
 int
 cmd_subtitle (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  return get_title (lexer, "SUBTITLE", &outp_subtitle);
+  return parse_title (lexer, TEXT_ITEM_SUBTITLE);
 }
 
 static int
-get_title (struct lexer *lexer, const char *cmd, char **title)
+parse_title (struct lexer *lexer, enum text_item_type type)
 {
   int c;
 
@@ -59,30 +60,24 @@ get_title (struct lexer *lexer, const char *cmd, char **title)
       lex_get (lexer);
       if (!lex_force_string (lexer))
        return CMD_FAILURE;
-      if (*title)
-       free (*title);
-      *title = ds_xstrdup (lex_tokstr (lexer));
+      set_title (ds_cstr (lex_tokstr (lexer)), type);
       lex_get (lexer);
-      if (lex_token (lexer) != '.')
-       {
-         msg (SE, _("%s: `.' expected after string."), cmd);
-         return CMD_FAILURE;
-       }
+      return lex_end_of_command (lexer);
     }
   else
     {
-      char *cp;
-
-      if (*title)
-       free (*title);
-      *title = xstrdup (lex_rest_of_line (lexer));
+      set_title (lex_rest_of_line (lexer), type);
       lex_discard_line (lexer);
-      for (cp = *title; *cp; cp++)
-       *cp = toupper ((unsigned char) (*cp));
     }
   return CMD_SUCCESS;
 }
 
+static void
+set_title (const char *title, enum text_item_type type)
+{
+  text_item_submit (text_item_create (type, title));
+}
+
 /* Performs the FILE LABEL command. */
 int
 cmd_file_label (struct lexer *lexer, struct dataset *ds)
index 8ce2d12576697beb5562fc65fc4a03522ce2a9a0..4fb889b17717ae3a0dec8bc98ee5a81ea6e219b9 100644 (file)
@@ -352,7 +352,7 @@ count_trns_proc (void *trns_, struct ccase **c,
 static bool
 count_trns_free (void *trns_)
 {
-  struct count_trns *trns = (struct count_trns *) trns_;
+  struct count_trns *trns = trns_;
   pool_destroy (trns->pool);
   return true;
 }
index 74b2ceb387f54d04e669cfbadb7eb4e7589c89a3..b776612922f2579b290f3a3657f12adb8efee0fe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -29,6 +29,7 @@
 #endif
 
 #include <libpspp/abt.h>
+#include <libpspp/cast.h>
 
 #include <stdbool.h>
 
@@ -145,8 +146,8 @@ insert_relative (struct abt *abt, const struct abt_node *p, bool after,
           p = p->down[dir];
           dir = !after;
         }
-      ((struct abt_node *) p)->down[dir] = node;
-      node->up = (struct abt_node *) p;
+      CONST_CAST (struct abt_node *, p)->down[dir] = node;
+      node->up = CONST_CAST (struct abt_node *, p);
       abt_reaugmented (abt, node);
     }
 
@@ -280,7 +281,7 @@ abt_find (const struct abt *abt, const struct abt_node *target)
     {
       cmp = abt->compare (target, p, abt->aux);
       if (cmp == 0)
-        return (struct abt_node *) p;
+        return CONST_CAST (struct abt_node *, p);
     }
 
   return NULL;
@@ -307,7 +308,7 @@ abt_next (const struct abt *abt, const struct abt_node *p)
       p = p->down[1];
       while (p->down[0] != NULL)
         p = p->down[0];
-      return (struct abt_node *) p;
+      return CONST_CAST (struct abt_node *, p);
     }
 }
 
@@ -332,7 +333,7 @@ abt_prev (const struct abt *abt, const struct abt_node *p)
       p = p->down[0];
       while (p->down[1] != NULL)
         p = p->down[1];
-      return (struct abt_node *) p;
+      return CONST_CAST (struct abt_node *, p);
     }
 }
 
index 3801eb86636c14d2d4a73420329d7c568768d630..24d7268a2d6543a383361c50914d796e52e7b6c1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
    tree paper.  */
 
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define abt_data(NODE, STRUCT, MEMBER)                                  \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define abt_data(NODE, STRUCT, MEMBER)                          \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct abt_node *),      \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Node in an augmented binary tree. */
 struct abt_node
index 6df2a2d803995841b319a5398661a2f4024416d5..942974c8cf42114ef39cece0fb52ae0e3355904a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010 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
@@ -370,7 +370,7 @@ insert_range (void *array_, size_t count, size_t size,
 /* Makes room for a new element at IDX in ARRAY, which initially
    consists of COUNT elements of SIZE bytes each, by shifting
    elements IDX...COUNT (exclusive) to the right by one
-   positions. */
+   position. */
 void
 insert_element (void *array, size_t count, size_t size,
                 size_t idx)
index 109aee4c611832a4733c95bdbe70fccbaa7f1e08..dc17fbd7ef56fdd3f8b1a44c532fb9c964c28c90 100644 (file)
@@ -118,7 +118,7 @@ void insert_range (void *array, size_t count, size_t size,
 /* Makes room for a new element at IDX in ARRAY, which initially
    consists of COUNT elements of SIZE bytes each, by shifting
    elements IDX...COUNT (exclusive) to the right by one
-   positions. */
+   position. */
 void insert_element (void *array, size_t count, size_t size,
                      size_t idx);
 
index 746756d8900ba0207e45ae77718ed8dbab8dda91..0172d80fd07a83570b077f53b4900428c69a5d7a 100644 (file)
@@ -14,6 +14,7 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/bit-vector.h \
        src/libpspp/bt.c \
        src/libpspp/bt.h \
+       src/libpspp/cast.h \
        src/libpspp/compiler.h \
        src/libpspp/copyleft.c \
        src/libpspp/copyleft.h \
@@ -39,6 +40,8 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/i18n.h \
        src/libpspp/integer-format.c \
        src/libpspp/integer-format.h \
+       src/libpspp/intern.c \
+       src/libpspp/intern.h \
        src/libpspp/legacy-encoding.c \
        src/libpspp/legacy-encoding.h \
        src/libpspp/ll.c \
@@ -65,6 +68,12 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/sparse-xarray.h \
        src/libpspp/start-date.c \
        src/libpspp/start-date.h \
+       src/libpspp/string-array.c \
+       src/libpspp/string-array.h \
+       src/libpspp/string-map.c \
+       src/libpspp/string-map.h \
+       src/libpspp/string-set.c \
+       src/libpspp/string-set.h \
        src/libpspp/str.c \
        src/libpspp/str.h \
        src/libpspp/taint.c \
@@ -73,8 +82,6 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/tmpfile.h \
        src/libpspp/tower.c \
        src/libpspp/tower.h \
-       src/libpspp/verbose-msg.c \
-       src/libpspp/verbose-msg.h \
        src/libpspp/version.h 
 
 DISTCLEANFILES+=src/libpspp/version.c
@@ -98,10 +105,6 @@ src/libpspp/version.c: $(top_srcdir)/AUTHORS Makefile
 (`date`).\";" >> $@
        echo "const char host_system[] = \"$(host_triplet)\";" >> $@
        echo "const char build_system[] = \"$(build_triplet)\";" >> $@
-       echo "const char default_config_path[] =\
-\"\$$HOME/.pspp:$(pkgsysconfdir)\";" >> $@
-       echo "const char include_path[] =\
-\"./:\$$HOME/.pspp/include:$(pkgdatadir)\";" >> $@
        echo "const char locale_dir[] = \"$(datadir)/locale\";" >> $@
        echo "const char *const authors[] = {" >> $@
        sed -e 's/^/  \"/' -e 's/$$/\",/' $(top_srcdir)/AUTHORS >> $@
index 26eb982b25d47c26c9699c24018a0910cb2dbcd5..751c8fe764cd6f71aeec94be3550855f8dd3ce6e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -67,6 +67,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include <libpspp/cast.h>
+
 static void rebalance_subtree (struct bt *, struct bt_node *, size_t);
 
 static struct bt_node **down_link (struct bt *, struct bt_node *);
@@ -250,7 +252,7 @@ bt_find (const struct bt *bt, const struct bt_node *target)
     {
       cmp = bt->compare (target, p, bt->aux);
       if (cmp == 0)
-        return (struct bt_node *) p;
+        return CONST_CAST (struct bt_node *, p);
     }
 
   return NULL;
@@ -283,7 +285,7 @@ bt_find_ge (const struct bt *bt, const struct bt_node *target)
             break;
         }
     }
-  return (struct bt_node *) q;
+  return CONST_CAST (struct bt_node *, q);
 }
 
 /* Searches BT for, and returns, the last node in in-order whose
@@ -314,7 +316,7 @@ bt_find_le (const struct bt *bt, const struct bt_node *target)
             break;
         }
     }
-  return (struct bt_node *) q;
+  return CONST_CAST (struct bt_node *, q);
 }
 
 /* Returns the node in BT following P in in-order.
@@ -338,7 +340,7 @@ bt_next (const struct bt *bt, const struct bt_node *p)
       p = p->down[1];
       while (p->down[0] != NULL)
         p = p->down[0];
-      return (struct bt_node *) p;
+      return CONST_CAST (struct bt_node *, p);
     }
 }
 
@@ -363,7 +365,7 @@ bt_prev (const struct bt *bt, const struct bt_node *p)
       p = p->down[0];
       while (p->down[1] != NULL)
         p = p->down[1];
-      return (struct bt_node *) p;
+      return CONST_CAST (struct bt_node *, p);
     }
 }
 
index 340b8760166c31fec29ea42ae8ecc50c24911806..7045632ef204e2edd228dc4dd8473174318212be 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
    fully encapsulated. */
 
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define bt_data(NODE, STRUCT, MEMBER)                                  \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define bt_data(NODE, STRUCT, MEMBER)                           \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct bt_node *),       \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Node in a balanced binary tree. */
 struct bt_node
diff --git a/src/libpspp/cast.h b/src/libpspp/cast.h
new file mode 100644 (file)
index 0000000..1e33857
--- /dev/null
@@ -0,0 +1,92 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 LIBPSPP_CAST_H
+#define LIBPSPP_CAST_H 1
+
+#include <stddef.h>
+
+/* Expands to a void expression that checks that POINTER is an
+   expression whose type is a qualified or unqualified version of
+   a type compatible with TYPE (a pointer type) and, if not,
+   causes a compiler warning to be issued (on typical compilers).
+
+   Examples:
+
+   int *ip;
+   const int *cip;
+   const int **cipp;
+   int ***ippp;
+   double *dp;
+
+   // None of these causes a warning:
+   CHECK_POINTER_HAS_TYPE (ip, int *);
+   CHECK_POINTER_HAS_TYPE (ip, const int *);
+   CHECK_POINTER_HAS_TYPE (cip, int *);
+   CHECK_POINTER_HAS_TYPE (cip, const int *);
+   CHECK_POINTER_HAS_TYPE (dp, double *);
+   CHECK_POINTER_HAS_TYPE (dp, const double *);
+   CHECK_POINTER_HAS_TYPE (cipp, const int **);
+   CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
+   CHECK_POINTER_HAS_TYPE (ippp, int ***);
+   CHECK_POINTER_HAS_TYPE (ippp, int **const *);
+
+   // None of these causes a warning either, although it is unusual to
+   // const-qualify a pointer like this (it's like declaring a "const int",
+   // for example).
+   CHECK_POINTER_HAS_TYPE (ip, int *const);
+   CHECK_POINTER_HAS_TYPE (ip, const int *const);
+   CHECK_POINTER_HAS_TYPE (cip, int *const);
+   CHECK_POINTER_HAS_TYPE (cip, const int *const);
+   CHECK_POINTER_HAS_TYPE (cipp, const int **const);
+   CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
+   CHECK_POINTER_HAS_TYPE (ippp, int ***const);
+   CHECK_POINTER_HAS_TYPE (ippp, int **const *const);
+
+   // Provokes a warning because "int" is not compatible with "double":
+   CHECK_POINTER_HAS_TYPE (dp, int *);
+
+   // Provoke warnings because C's type compatibility rules only allow
+   // adding a "const" qualifier to the outermost pointer:
+   CHECK_POINTER_HAS_TYPE (ippp, const int ***);
+   CHECK_POINTER_HAS_TYPE (ippp, int *const**);
+*/
+#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE)           \
+        ((void) sizeof ((TYPE) (POINTER) == (POINTER)))
+
+/* Given expressions A and B, both of which have pointer type,
+   expands to a void expression that causes a compiler warning if
+   A and B are not pointers to qualified or unqualified versions
+   of compatible types.
+
+   Examples similar to those given for CHECK_POINTER_HAS_TYPE,
+   above, can easily be devised. */
+#define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))
+
+/* Equivalent to casting POINTER to TYPE, but also issues a
+   warning if the cast changes anything other than an outermost
+   "const" or "volatile" qualifier. */
+#define CONST_CAST(TYPE, POINTER)                       \
+        (CHECK_POINTER_HAS_TYPE (POINTER, TYPE),        \
+         (TYPE) (POINTER))
+
+/* Given POINTER, a pointer to the given MEMBER within structure
+   STRUCT, returns the address of the STRUCT. */
+#define UP_CAST(POINTER, STRUCT, MEMBER)                                \
+        (CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \
+         (STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER)))
+
+#endif /* libpspp/cast.h */
index d22819446f5e5ee7a5eececf9c4f0e3ef261e758..d8b29e968965eaa4c96744928f1b92640cb32cf8 100644 (file)
 #define PURE_FUNCTION
 #endif
 
+/* This attribute indicates that the argument with the given
+   IDX must be a null pointer.  IDX counts backward in the
+   argument list, so that 0 is the last argument, 1 is the
+   second-from-last argument, and so on. */
+#if __GNUC__ > 3
+#define SENTINEL(IDX) ATTRIBUTE ((sentinel(IDX)))
+#else
+#define SENTINEL
+#endif
+
 #endif /* compiler.h */
index 302cd9137ddbc7b748ae07c9c4c34103ffecbf86..dc69f11a12a2b45e9ecf77c5dd89a00e5c69e18e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
 
 #include <config.h>
 
-#include <stdlib.h>
+#include "libpspp/getl.h"
 
-#include "getl.h"
+#include <stdlib.h>
 
-#include <libpspp/str.h>
-#include <libpspp/ll.h>
-#include <libpspp/version.h>
+#include "libpspp/ll.h"
+#include "libpspp/str.h"
+#include "libpspp/string-array.h"
 
-#include "xalloc.h"
+#include "gl/relocatable.h"
+#include "gl/xalloc.h"
 
 struct getl_source
   {
@@ -41,14 +42,15 @@ struct getl_source
 struct source_stream
   {
     struct ll_list sources ;  /* List of source files. */
-
-    struct string the_include_path;
+    struct string_array include_path;
   };
 
-const char *
-getl_include_path (const struct source_stream *ss)
+char **
+getl_include_path (const struct source_stream *ss_)
 {
-  return ds_cstr (&ss->the_include_path);
+  struct source_stream *ss = CONST_CAST (struct source_stream *, ss_);
+  string_array_terminate_null (&ss->include_path);
+  return ss->include_path.strings;
 }
 
 static struct getl_source *
@@ -80,15 +82,19 @@ source_stream_current_error_mode (const struct source_stream *ss)
 
 /* Initialize getl. */
 struct source_stream *
-create_source_stream (const char *initial_include_path)
+create_source_stream (void)
 {
-  struct source_stream *ss = xzalloc (sizeof (*ss));
+  struct source_stream *ss;
+
+  ss = xzalloc (sizeof (*ss));
   ll_init (&ss->sources);
-#if 0
-  ds_init_cstr (&ss->the_include_path,
-                fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
-#endif
-  ds_init_cstr (&ss->the_include_path, initial_include_path);
+
+  string_array_init (&ss->include_path);
+  string_array_append (&ss->include_path, ".");
+  if (getenv ("HOME") != NULL)
+    string_array_append_nocopy (&ss->include_path,
+                                xasprintf ("%s/.pspp", getenv ("HOME")));
+  string_array_append (&ss->include_path, relocate (PKGDATADIR));
 
   return ss;
 }
@@ -97,17 +103,14 @@ create_source_stream (const char *initial_include_path)
 void
 getl_clear_include_path (struct source_stream *ss)
 {
-  ds_clear (&ss->the_include_path);
+  string_array_clear (&ss->include_path);
 }
 
 /* Add to the include path. */
 void
 getl_add_include_dir (struct source_stream *ss, const char *path)
 {
-  if (ds_length (&ss->the_include_path))
-    ds_put_char (&ss->the_include_path, ':');
-
-  ds_put_cstr (&ss->the_include_path, path);
+  string_array_append (&ss->include_path, path);
 }
 
 /* Appends source S to the list of source files. */
@@ -231,7 +234,7 @@ destroy_source_stream (struct source_stream *ss)
 {
   while ( !ll_is_empty (&ss->sources))
     close_source (ss);
-  ds_destroy (&ss->the_include_path);
+  string_array_destroy (&ss->include_path);
 
   free (ss);
 }
index c0399377982bf556ce588cabfcdf0b4cdd1e571e..47dea27e4285be8e1d13e85a934d3e2424427b2f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010 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
@@ -80,7 +80,7 @@ struct getl_interface
 
 struct source_stream;
 
-struct source_stream * create_source_stream (const char *);
+struct source_stream *create_source_stream (void);
 
 enum syntax_mode source_stream_current_syntax_mode
    (const struct source_stream *);
@@ -94,7 +94,7 @@ void destroy_source_stream (struct source_stream *);
 
 void getl_clear_include_path (struct source_stream *);
 void getl_add_include_dir (struct source_stream *, const char *);
-const char * getl_include_path (const struct source_stream *);
+char **getl_include_path (const struct source_stream *);
 
 void getl_abort_noninteractive (struct source_stream *);
 bool getl_is_interactive (const struct source_stream *);
index 57fc2678d09548ad50922b9130298afb6cf80cac..e586bcc0c18d1ae79242dc5a6ba42068db5b1f63 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009 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
index 134224373d2ec2dbf6536b4d7909799df59b06d6..3a3c516a03485ab7e4a5ecac923719c3425c4ee0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -70,6 +70,7 @@
 #ifndef LIBPSPP_HEAP_H
 #define LIBPSPP_HEAP_H 1
 
+#include <libpspp/cast.h>
 #include <stdbool.h>
 #include <stddef.h>
 
@@ -78,8 +79,9 @@ struct pool;
 /* Returns the data structure corresponding to the given heap
    NODE, assuming that NODE is embedded as the given MEMBER name
    in data type STRUCT. */
-#define heap_data(NODE, STRUCT, MEMBER)                                 \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define heap_data(NODE, STRUCT, MEMBER)                         \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct heap_node *),     \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A node in a heap.  Opaque.
    One of these structures must be embedded in your heap node. */
index e73d84fd153764ec96935c6242dc2388820c5757..1592f803bedb17bd9c1ca4dc285f5bd6e72fd1c4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
        }
    */
 
+#include <stdbool.h>
 #include <stddef.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT.  NODE must not be a null pointer. */
 #define HMAP_DATA(NODE, STRUCT, MEMBER)                         \
-  ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+        (CHECK_POINTER_HAS_TYPE (NODE, struct hmap_node *),     \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* Like HMAP_DATA, except that a null NODE yields a null pointer
    result. */
@@ -180,6 +183,7 @@ static inline struct hmap_node *hmap_next (const struct hmap *,
                                            const struct hmap_node *);
 
 /* Counting. */
+static bool hmap_is_empty (const struct hmap *);
 static inline size_t hmap_count (const struct hmap *);
 static inline size_t hmap_capacity (const struct hmap *);
 
@@ -440,6 +444,14 @@ hmap_next (const struct hmap *map, const struct hmap_node *node)
           : hmap_first_nonempty_bucket__ (map, (node->hash & map->mask) + 1));
 }
 
+/* Returns true if MAP currently contains no data items, false
+   otherwise. */
+static inline bool
+hmap_is_empty (const struct hmap *map)
+{
+  return map->count == 0;
+}
+
 /* Returns the number of data items currently in MAP. */
 static inline size_t
 hmap_count (const struct hmap *map) 
index d73245084178025d2f550c47af66487590310b7a..437b2bdba5a7aad4ad301f672fc3681b5f2010fd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -32,7 +32,7 @@ hmapx_destroy (struct hmapx *map)
 {
   if (map != NULL) 
     {
-      if (hmapx_count (map) > 0) 
+      if (!(hmapx_is_empty (map)))
         {
           struct hmapx_node *node, *next;
           for (node = hmapx_first (map); node != NULL; node = next)
index 32a4452fe2417d58157ca8da27e079f2052fcc88..d463504a52de33ca1a1cc45bde187dfaaadd71f7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -165,6 +165,7 @@ static inline struct hmapx_node *hmapx_next (const struct hmapx *,
                                              const struct hmapx_node *);
 
 /* Counting. */
+static inline bool hmapx_is_empty (const struct hmapx *);
 static inline size_t hmapx_count (const struct hmapx *);
 static inline size_t hmapx_capacity (const struct hmapx *);
 
@@ -404,6 +405,14 @@ hmapx_next (const struct hmapx *map, const struct hmapx_node *node)
   return HMAP_NEXT (node, struct hmapx_node, hmap_node, &map->hmap);
 }
 
+/* Returns true if MAP currently contains no data items, false
+   otherwise. */
+static inline bool
+hmapx_is_empty (const struct hmapx *map)
+{
+  return hmap_is_empty (&map->hmap);
+}
+
 /* Returns the number of data items currently in MAP. */
 static inline size_t
 hmapx_count (const struct hmapx *map) 
diff --git a/src/libpspp/intern.c b/src/libpspp/intern.c
new file mode 100644 (file)
index 0000000..0bb9277
--- /dev/null
@@ -0,0 +1,121 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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 "libpspp/intern.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmap.h"
+
+#include "gl/xalloc.h"
+
+/* A single interned string. */
+struct interned_string
+  {
+    struct hmap_node node;      /* Node in hash table. */
+    size_t ref_cnt;             /* Reference count. */
+    char string[1];             /* Null-terminated string. */
+  };
+
+/* All interned strings. */
+static struct hmap interns = HMAP_INITIALIZER (interns);
+
+/* Searches the table of interned string for  */
+static struct interned_string *
+intern_lookup__ (const char *s, size_t length, unsigned int hash)
+{
+  struct interned_string *is;
+
+  HMAP_FOR_EACH_WITH_HASH (is, struct interned_string, node, hash, &interns)
+    if (!memcmp (s, is->string, length + 1))
+      return is;
+
+  return NULL;
+}
+
+/* Returns an interned version of string S.  Pass the returned string to
+   intern_unref() to release it. */
+const char *
+intern_new (const char *s)
+{
+  size_t length = strlen (s);
+  unsigned int hash = hash_bytes (s, length, 0);
+  struct interned_string *is;
+
+  is = intern_lookup__ (s, length, hash);
+  if (is != NULL)
+    is->ref_cnt++;
+  else
+    {
+      is = xmalloc (length + sizeof *is);
+      hmap_insert (&interns, &is->node, hash);
+      is->ref_cnt = 1;
+      memcpy (is->string, s, length + 1);
+    }
+  return is->string;
+}
+
+static struct interned_string *
+interned_string_from_string (const char *s)
+{
+  const size_t ofs = offsetof (struct interned_string, string);
+  struct interned_string *is = (struct interned_string *) (s - ofs);
+  assert (is->ref_cnt > 0);
+  return is;
+}
+
+/* Increases the reference count on S, which must be an interned string
+   returned by intern_new(). */
+const char *
+intern_ref (const char *s)
+{
+  struct interned_string *is = interned_string_from_string (s);
+  is->ref_cnt++;
+  return s;
+}
+
+/* Decreases the reference count on S, which must be an interned string
+   returned by intern_new().  If the reference count reaches 0, frees the
+   interned string. */
+void
+intern_unref (const char *s)
+{
+  struct interned_string *is = interned_string_from_string (s);
+  if (--is->ref_cnt == 0)
+    {
+      hmap_delete (&interns, &is->node);
+      free (is);
+    }
+}
+
+/* Given null-terminated string S, returns true if S is an interned string
+   returned by intern_string_new(), false otherwise.
+
+   This is appropriate for use in debug assertions, e.g.:
+       assert (is_interned_string (s));
+*/
+bool
+is_interned_string (const char *s)
+{
+  size_t length = strlen (s);
+  unsigned int hash = hash_bytes (s, length, 0);
+  return intern_lookup__ (s, length, hash) != NULL;
+}
diff --git a/src/libpspp/intern.h b/src/libpspp/intern.h
new file mode 100644 (file)
index 0000000..147a69a
--- /dev/null
@@ -0,0 +1,41 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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 LIBPSPP_INTERN_H
+#define LIBPSPP_INTERN_H 1
+
+/* Interned strings.
+
+   An "interned" string is stored in a global hash table.  Only one copy of any
+   given string is kept in the hash table, which reduces memory usage in cases
+   where there might otherwise be many duplicates of a given string.
+
+   Interned strings can be compared for equality by comparing pointers, which
+   can also be a significant advantage in some cases.
+
+   Interned strings are immutable.
+
+   See http://en.wikipedia.org/wiki/String_interning for more information. */
+
+#include <stdbool.h>
+
+const char *intern_new (const char *);
+const char *intern_ref (const char *);
+void intern_unref (const char *);
+
+bool is_interned_string (const char *);
+
+#endif /* libpspp/intern.h */
index b9d595bc97a00212e9ebc1c156a1a01f75ed1556..e6533f2cd25fccf5beb2cbf9a4da31c279022027 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009 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
@@ -169,7 +169,7 @@ ll_find_equal (const struct ll *r0, const struct ll *r1,
   for (x = r0; x != r1; x = ll_next (x))
     if (compare (x, target, aux) == 0)
       break;
-  return (struct ll *) x;
+  return CONST_CAST (struct ll *, x);
 }
 
 /* Returns the first node in R0...R1 for which PREDICATE returns
@@ -185,7 +185,7 @@ ll_find_if (const struct ll *r0, const struct ll *r1,
   for (x = r0; x != r1; x = ll_next (x))
     if (predicate (x, aux))
       break;
-  return (struct ll *) x;
+  return CONST_CAST (struct ll *, x);
 }
 
 /* Compares each pair of adjacent nodes in R0...R1
@@ -203,10 +203,10 @@ ll_find_adjacent_equal (const struct ll *r0, const struct ll *r1,
 
       for (x = r0, y = ll_next (x); y != r1; x = y, y = ll_next (y))
         if (compare (x, y, aux) == 0)
-          return (struct ll *) x;
+          return CONST_CAST (struct ll *, x);
     }
 
-  return (struct ll *) r1;
+  return CONST_CAST (struct ll *, r1);
 }
 
 /* Returns the number of nodes in R0...R1.
@@ -272,7 +272,7 @@ ll_max (const struct ll *r0, const struct ll *r1,
         if (compare (x, max, aux) > 0)
           max = x;
     }
-  return (struct ll *) max;
+  return CONST_CAST (struct ll *, max);
 }
 
 /* Returns the least node in R0...R1 according to COMPARE given
@@ -291,7 +291,7 @@ ll_min (const struct ll *r0, const struct ll *r1,
         if (compare (x, min, aux) < 0)
           min = x;
     }
-  return (struct ll *) min;
+  return CONST_CAST (struct ll *, min);
 }
 
 /* Lexicographically compares A0...A1 to B0...B1.
@@ -474,7 +474,7 @@ ll_find_run (const struct ll *r0, const struct ll *r1,
       while (r0 != r1 && compare (ll_prev (r0), r0, aux) <= 0);
     }
 
-  return (struct ll *) r0;
+  return CONST_CAST (struct ll *, r0);
 }
 
 /* Merges B0...B1 into A0...A1 according to COMPARE given
@@ -681,6 +681,6 @@ ll_find_partition (const struct ll *r0, const struct ll *r1,
     if (predicate (x, aux))
       return NULL;
 
-  return (struct ll *) partition;
+  return CONST_CAST (struct ll *, partition);
 }
 \f
index 65ecf55f2cad759a50085a85e90f1e3c79cf7f02..bf871f6b0f842a0a42726de48364aad08ea4d3ea 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009 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
@@ -50,6 +50,9 @@
 #include <assert.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <libpspp/cast.h>
+
+#include <libpspp/cast.h>
 
 /* Embedded, circular doubly linked list.
 
 /* Returns the data structure corresponding to the given node LL,
    assuming that LL is embedded as the given MEMBER name in data
    type STRUCT. */
-#define ll_data(LL, STRUCT, MEMBER)                                    \
-        ((STRUCT *) ((char *) (LL) - offsetof (STRUCT, MEMBER)))
+#define ll_data(LL, STRUCT, MEMBER)                     \
+        (CHECK_POINTER_HAS_TYPE(LL, struct ll *),       \
+         UP_CAST(LL, STRUCT, MEMBER))
 
 /* Linked list node. */
 struct ll
@@ -378,7 +382,7 @@ ll_tail (const struct ll_list *list)
 static inline struct ll *
 ll_null (const struct ll_list *list)
 {
-  return (struct ll *) &list->null;
+  return CONST_CAST (struct ll *, &list->null);
 }
 
 /* Returns the node following LL in its list,
index 4dc82bffeb66219bf37d12f7cff7131a0c73cccc..905850bc41c13ec74be83289e0571c0972f464dc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009 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
@@ -219,6 +219,20 @@ llx_remove_if (struct llx *r0, struct llx *r1,
   return count;
 }
 
+/* Returns the first node in R0...R1 that has data TARGET.
+   Returns NULL if no node in R0...R1 equals TARGET. */
+struct llx *
+llx_find (const struct llx *r0, const struct llx *r1, const void *target)
+{
+  const struct llx *x;
+
+  for (x = r0; x != r1; x = llx_next (x))
+    if (llx_data (x) == target)
+      return CONST_CAST (struct llx *, x);
+
+  return NULL;
+}
+
 /* Returns the first node in R0...R1 that equals TARGET
    according to COMPARE given auxiliary data AUX.
    Returns R1 if no node in R0...R1 equals TARGET. */
@@ -232,7 +246,7 @@ llx_find_equal (const struct llx *r0, const struct llx *r1,
   for (x = r0; x != r1; x = llx_next (x))
     if (compare (llx_data (x), target, aux) == 0)
       break;
-  return (struct llx *) x;
+  return CONST_CAST (struct llx *, x);
 }
 
 /* Returns the first node in R0...R1 for which PREDICATE returns
@@ -248,7 +262,7 @@ llx_find_if (const struct llx *r0, const struct llx *r1,
   for (x = r0; x != r1; x = llx_next (x))
     if (predicate (llx_data (x), aux))
       break;
-  return (struct llx *) x;
+  return CONST_CAST (struct llx *, x);
 }
 
 /* Compares each pair of adjacent nodes in R0...R1
@@ -266,10 +280,10 @@ llx_find_adjacent_equal (const struct llx *r0, const struct llx *r1,
 
       for (x = r0, y = llx_next (x); y != r1; x = y, y = llx_next (y))
         if (compare (llx_data (x), llx_data (y), aux) == 0)
-          return (struct llx *) x;
+          return CONST_CAST (struct llx *, x);
     }
 
-  return (struct llx *) r1;
+  return CONST_CAST (struct llx *, r1);
 }
 
 /* Returns the number of nodes in R0...R1.
@@ -329,7 +343,7 @@ llx_max (const struct llx *r0, const struct llx *r1,
         if (compare (llx_data (x), llx_data (max), aux) > 0)
           max = x;
     }
-  return (struct llx *) max;
+  return CONST_CAST (struct llx *, max);
 }
 
 /* Returns the least node in R0...R1 according to COMPARE given
@@ -348,7 +362,7 @@ llx_min (const struct llx *r0, const struct llx *r1,
         if (compare (llx_data (x), llx_data (min), aux) < 0)
           min = x;
     }
-  return (struct llx *) min;
+  return CONST_CAST (struct llx *, min);
 }
 
 /* Lexicographically compares A0...A1 to B0...B1.
@@ -521,7 +535,7 @@ llx_find_run (const struct llx *r0, const struct llx *r1,
                                   llx_data (r0), aux) <= 0);
     }
 
-  return (struct llx *) r0;
+  return CONST_CAST (struct llx *, r0);
 }
 
 /* Merges B0...B1 into A0...A1 according to COMPARE given
@@ -734,7 +748,7 @@ llx_find_partition (const struct llx *r0, const struct llx *r1,
     if (predicate (llx_data (x), aux))
       return NULL;
 
-  return (struct llx *) partition;
+  return CONST_CAST (struct llx *, partition);
 }
 \f
 /* Allocates and returns a node using malloc. */
index 6232f3967ce3bdd9b9495bbf0cf0fc3a34934a6f..2aa18e7ba5694bced71cbe32a3feb69700e23f9b 100644 (file)
@@ -110,6 +110,12 @@ struct llx_list
     struct ll_list ll_list;     /* The list. */
   };
 
+/* Suitable for use as the initializer for a `struct llx_list'
+   named LIST.  Typical usage:
+       struct llx_list list = LLX_INITIALIZER (list);
+   LLX_INITIALIZER() is an alternative to llx_init(). */
+#define LLX_INITIALIZER(LIST) { LL_INITIALIZER ((LIST).ll_list) }
+
 /* Memory manager. */
 struct llx_manager
   {
@@ -180,6 +186,8 @@ size_t llx_remove_if (struct llx *r0, struct llx *r1,
                       const struct llx_manager *);
 
 /* Non-mutating algorithms. */
+struct llx *llx_find (const struct llx *r0, const struct llx *r1,
+                      const void *target);
 struct llx *llx_find_equal (const struct llx *r0, const struct llx *r1,
                             const void *target,
                             llx_compare_func *, void *aux);
index 5faee1f1d6c8dc33279e36acc9b3188b56b1f218..c227a60368a0ff725dacc9baba4e00bf916cf37d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
 #include <string.h>
 #include <unistd.h>
 
+#include <libpspp/str.h>
 #include <libpspp/version.h>
 
-#include "progname.h"
-#include "xalloc.h"
-#include "xvasprintf.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
-/* Current command name as set by msg_set_command_name(). */
-static char *command_name;
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 /* Message handler as set by msg_init(). */
 static void (*msg_handler)  (const struct msg *);
@@ -73,27 +74,77 @@ void
 msg_done (void)
 {
 }
-
+\f
+/* Working with messages. */
 
 /* Duplicate a message */
 struct msg *
-msg_dup(const struct msg *m)
+msg_dup (const struct msg *m)
 {
-  struct msg *new_msg = xmalloc (sizeof *m);
+  struct msg *new_msg;
 
-  *new_msg = *m;
-  new_msg->text = xstrdup(m->text);
+  new_msg = xmemdup (m, sizeof *m);
+  if (m->where.file_name != NULL)
+    new_msg->where.file_name = xstrdup (m->where.file_name);
+  new_msg->text = xstrdup (m->text);
 
   return new_msg;
 }
 
+/* Frees a message created by msg_dup().
+
+   (Messages not created by msg_dup(), as well as their where.file_name
+   members, are typically not dynamically allocated, so this function should
+   not be used to destroy them.) */
 void
-msg_destroy(struct msg *m)
+msg_destroy (struct msg *m)
 {
-  free(m->text);
-  free(m);
+  free (m->where.file_name);
+  free (m->text);
+  free (m);
 }
 
+char *
+msg_to_string (const struct msg *m, const char *command_name)
+{
+  const char *label;
+  struct string s;
+
+  ds_init_empty (&s);
+
+  if (m->category != MSG_C_GENERAL
+      && (m->where.file_name || m->where.line_number != -1))
+    {
+      if (m->where.file_name)
+        ds_put_format (&s, "%s:", m->where.file_name);
+      if (m->where.line_number != -1)
+        ds_put_format (&s, "%d:", m->where.line_number);
+      ds_put_char (&s, ' ');
+    }
+
+  switch (m->severity)
+    {
+    case MSG_S_ERROR:
+      label = _("error");
+      break;
+    case MSG_S_WARNING:
+      label = _("warning");
+      break;
+    case MSG_S_NOTE:
+    default:
+      label = _("note");
+      break;
+    }
+  ds_put_format (&s, "%s: ", label);
+
+  if (m->category == MSG_C_SYNTAX && command_name != NULL)
+    ds_put_format (&s, "%s: ", command_name);
+
+  ds_put_cstr (&s, m->text);
+
+  return ds_cstr (&s);
+}
+\f
 /* Emits M as an error message.
    Frees allocated data in M. */
 void
@@ -101,6 +152,11 @@ msg_emit (struct msg *m)
 {
   if ( s_stream )
     get_msg_location (s_stream, &m->where);
+  else
+    {
+      m->where.file_name = NULL;
+      m->where.line_number = -1;
+    }
 
   if (!messages_disabled)
      msg_handler (m);
@@ -127,22 +183,6 @@ msg_enable (void)
 \f
 /* Private functions. */
 
-/* Sets COMMAND_NAME as the command name included in some kinds
-   of error messages. */
-void
-msg_set_command_name (const char *command_name_)
-{
-  free (command_name);
-  command_name = command_name_ ? xstrdup (command_name_) : NULL;
-}
-
-/* Returns the current command name, or NULL if none. */
-const char *
-msg_get_command_name (void)
-{
-  return command_name;
-}
-
 void
 request_bug_report_and_abort (const char *msg)
 {
@@ -157,8 +197,6 @@ request_bug_report_and_abort (const char *msg)
   fprintf (stderr, "version:             %s\n", stat_version);
   fprintf (stderr, "host_system:         %s\n", host_system);
   fprintf (stderr, "build_system:        %s\n", build_system);
-  fprintf (stderr, "default_config_path: %s\n", default_config_path);
-  fprintf (stderr, "include_path:        %s\n", include_path);
   fprintf (stderr, "locale_dir:          %s\n", locale_dir);
   fprintf (stderr, "compiler version:    %s\n",
 #ifdef __VERSION__
index be4ba3e21dcba2f25e68aa98a3f1674d97dc13d9..e1fc4f5aab1235459b075ddf92e2c704c4561d62 100644 (file)
 /* What kind of message is this? */
 enum msg_category
   {
-    MSG_GENERAL,        /* General info. */
-    MSG_SYNTAX,         /* Messages that relate to syntax files. */
-    MSG_DATA            /* Messages that relate to data files. */
+    MSG_C_GENERAL,              /* General info. */
+    MSG_C_SYNTAX,               /* Messages that relate to syntax files. */
+    MSG_C_DATA,                 /* Messages that relate to data files. */
+    MSG_N_CATEGORIES
   };
 
 /* How important a condition is it? */
 enum msg_severity
   {
-    MSG_ERROR,
-    MSG_WARNING,
-    MSG_NOTE
+    MSG_S_ERROR,
+    MSG_S_WARNING,
+    MSG_S_NOTE,
+    MSG_N_SEVERITIES
   };
 
 /* Combination of a category and a severity for convenience. */
@@ -46,7 +48,6 @@ enum msg_class
     MSG_CLASS_CNT,
   };
 
-
 static inline enum msg_category
 msg_class_to_category (enum msg_class class)
 {
@@ -69,8 +70,8 @@ msg_class_from_category_and_severity (enum msg_category category,
 /* A file location.  */
 struct msg_locator
   {
-    const char *file_name;             /* File name. */
-    int line_number;                   /* Line number. */
+    char *file_name;           /* File name. */
+    int line_number;            /* Line number. */
   };
 
 /* A message. */
@@ -89,8 +90,10 @@ void msg_init (struct source_stream *, void (*handler) (const struct msg *) );
 
 void msg_done (void);
 
-struct msg * msg_dup(const struct msg *m);
-void msg_destroy(struct msg *m);
+/* Working with messages. */
+struct msg *msg_dup (const struct msg *);
+void msg_destroy(struct msg *);
+char *msg_to_string (const struct msg *, const char *command_name);
 
 /* Emitting messages. */
 void msg (enum msg_class, const char *format, ...)
@@ -102,8 +105,6 @@ void msg_enable (void);
 void msg_disable (void);
 
 /* Error context. */
-void msg_set_command_name (const char *);
-const char *msg_get_command_name (void);
 void msg_push_msg_locator (const struct msg_locator *);
 void msg_pop_msg_locator (const struct msg_locator *);
 
index 09550e29ac9c802def722eb8269d50efb9ab726d..fb8082e9217f6d7d4614b35e9a347761e8ad356a 100644 (file)
@@ -17,8 +17,9 @@
 #include <config.h>
 #include <stdlib.h>
 #include "msg-locator.h"
-#include <libpspp/message.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
+#include <libpspp/message.h>
 #include "getl.h"
 
 #include "xalloc.h"
@@ -77,7 +78,7 @@ get_msg_location (const struct source_stream *ss, struct msg_locator *loc)
     }
   else
     {
-      loc->file_name = getl_source_name (ss);
+      loc->file_name = CONST_CAST (char *, getl_source_name (ss));
       loc->line_number = getl_source_location (ss);
     }
 }
index 3dd77c9ffac30f2fb85429df8a35091ce108c7ef..024fe93790e507a052e14e4990152b9b17c7ea91 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
 #include <stdbool.h>
 
 #include <libpspp/bt.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
 #define range_map_data(NODE, STRUCT, MEMBER)                            \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+        (CHECK_POINTER_HAS_TYPE (NODE, struct range_map_node *),        \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A range map node, to be embedded in the data value. */
 struct range_map_node
index efa3b4d670e7e06c3c560ebc64ade1bf4d45ae21..cd17fe02a4e2130544d5d37687cf46210ff2de39 100644 (file)
@@ -287,7 +287,7 @@ range_set_allocate_fully (struct range_set *rs, unsigned long int request,
 bool
 range_set_contains (const struct range_set *rs_, unsigned long int position)
 {
-  struct range_set *rs = (struct range_set *) rs_;
+  struct range_set *rs = CONST_CAST (struct range_set *, rs_);
   if (position < rs->cache_end && position >= rs->cache_start)
     return rs->cache_value;
   else
@@ -328,7 +328,7 @@ range_set_contains (const struct range_set *rs_, unsigned long int position)
 unsigned long int
 range_set_scan (const struct range_set *rs_, unsigned long int start)
 {
-  struct range_set *rs = (struct range_set *) rs_;
+  struct range_set *rs = CONST_CAST (struct range_set *, rs_);
   unsigned long int retval = ULONG_MAX;
   struct bt_node *bt_node;
 
index 941692b40029098ea8224ea4d0a4f0e1b9026385..ee7dac23137d3c39b392b13cb11c7d560c71fc79 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <stdbool.h>
 #include <libpspp/bt.h>
+#include <libpspp/cast.h>
 
 /* A set of ranges. */
 struct range_set
@@ -122,7 +123,7 @@ static inline const struct range_set_node *
 range_set_next (const struct range_set *rs, const struct range_set_node *node)
 {
   return (node != NULL
-          ? range_set_next__ (rs, (struct range_set_node *) node)
+          ? range_set_next__ (rs, CONST_CAST (struct range_set_node *, node))
           : range_set_first__ (rs));
 }
 
@@ -147,7 +148,7 @@ static inline const struct range_set_node *
 range_set_prev (const struct range_set *rs, const struct range_set_node *node)
 {
   return (node != NULL
-          ? range_set_prev__ (rs, (struct range_set_node *) node)
+          ? range_set_prev__ (rs, CONST_CAST (struct range_set_node *, node))
           : range_set_last__ (rs));
 }
 
index 28398d5cc86321e9e648a9c0ac30c052c1d26641..298f2caf9eb9ae09108aa247fc6db7b000183de1 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
 
@@ -577,7 +578,7 @@ leaf_size (const struct sparse_array *spar)
 static struct leaf_node *
 find_leaf_node (const struct sparse_array *spar_, unsigned long int key)
 {
-  struct sparse_array *spar = (struct sparse_array *) spar_;
+  struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
   const union pointer *p;
   int level;
 
@@ -679,7 +680,7 @@ static void *
 scan_forward (const struct sparse_array *spar_, unsigned long int start,
               unsigned long int *found)
 {
-  struct sparse_array *spar = (struct sparse_array *) spar_;
+  struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
 
   /* Check the cache. */
   if (start >> BITS_PER_LEVEL == spar->cache_ofs)
@@ -761,7 +762,7 @@ static void *
 scan_reverse (const struct sparse_array *spar_, unsigned long int start,
               unsigned long int *found)
 {
-  struct sparse_array *spar = (struct sparse_array *) spar_;
+  struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
 
   /* Check the cache. */
   if (start >> BITS_PER_LEVEL == spar->cache_ofs)
index afe32de9f2049bfcc5a80ac7a95b36b348be4cb7..79f3c912e9b649cf39d3ab9a0b37510e25867bf5 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+#include <libpspp/cast.h>
 #include <libpspp/message.h>
 #include <libpspp/pool.h>
 
@@ -1214,13 +1215,24 @@ ds_capacity (const struct string *st)
 char *
 ds_cstr (const struct string *st_)
 {
-  struct string *st = (struct string *) st_;
+  struct string *st = CONST_CAST (struct string *, st_);
   if (st->ss.string == NULL)
     ds_extend (st, 1);
   st->ss.string[st->ss.length] = '\0';
   return st->ss.string;
 }
 
+/* Returns the value of ST as a null-terminated string and then
+   reinitialized ST as an empty string.  The caller must free the
+   returned string with free(). */
+char *
+ds_steal_cstr (struct string *st)
+{
+  char *s = ds_cstr (st);
+  ds_init_empty (st);
+  return s;
+}
+
 /* Reads characters from STREAM and appends them to ST, stopping
    after MAX_LENGTH characters, after appending a newline, or
    after an I/O error or end of file was encountered, whichever
index a134079f90dd52f7c359d7ad4fba3049c5c85203..0b57f7364e07816400b0d90f80e12376f219b821 100644 (file)
@@ -203,6 +203,7 @@ char *ds_xstrdup (const struct string *);
 
 size_t ds_capacity (const struct string *);
 char *ds_cstr (const struct string *);
+char *ds_steal_cstr (struct string *);
 
 /* File input. */
 bool ds_read_line (struct string *, FILE *, size_t max_length);
diff --git a/src/libpspp/string-array.c b/src/libpspp/string-array.c
new file mode 100644 (file)
index 0000000..b9067ab
--- /dev/null
@@ -0,0 +1,256 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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 "libpspp/string-array.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/array.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
+
+/* Initializes SA as an initially empty array of strings. */
+void
+string_array_init (struct string_array *sa)
+{
+  sa->strings = NULL;
+  sa->n = 0;
+  sa->allocated = 0;
+}
+
+/* Initializes DST as an array of strings whose contents are initially copies
+   of the strings in SRC. */
+void
+string_array_clone (struct string_array *dst, const struct string_array *src)
+{
+  size_t i;
+
+  dst->strings = xmalloc (sizeof *dst->strings * src->n);
+  for (i = 0; i < src->n; i++)
+    dst->strings[i] = xstrdup (src->strings[i]);
+  dst->n = src->n;
+  dst->allocated = src->n;
+}
+
+/* Exchanges the contents of A and B. */
+void
+string_array_swap (struct string_array *a, struct string_array *b)
+{
+  struct string_array tmp = *a;
+  *a = *b;
+  *b = tmp;
+}
+
+/* Frees the strings in SA.  SA must be reinitialized (with
+   string_array_init()) before it is used again. */
+void
+string_array_destroy (struct string_array *sa)
+{
+  if (sa != NULL)
+    {
+      string_array_clear (sa);
+      free (sa->strings);
+    }
+}
+
+/* Returns true if SA contains at least one copy of STRING, otherwise false.
+
+   This function runs in O(n) time in the number of strings in SA. */
+bool
+string_array_contains (const struct string_array *sa, const char *string)
+{
+  return string_array_find (sa, string) != SIZE_MAX;
+}
+
+/* If SA contains at least one copy of STRING, returns the smallest index of
+   any of those copies.  If SA does not contain STRING, returns SIZE_MAX.
+
+   This function runs in O(n) time in the number of strings in SA. */
+size_t
+string_array_find (const struct string_array *sa, const char *string)
+{
+  size_t i;
+
+  for (i = 0; i < sa->n; i++)
+    if (!strcmp (sa->strings[i], string))
+      return i;
+  return SIZE_MAX;
+}
+
+/* Appends a copy of STRING to SA.  The caller retains ownership of STRING. */
+void
+string_array_append (struct string_array *sa, const char *string)
+{
+  string_array_insert (sa, string, sa->n);
+}
+
+/* Appends STRING to SA.  Ownership of STRING transfers to SA. */
+void
+string_array_append_nocopy (struct string_array *sa, char *string)
+{
+  string_array_insert_nocopy (sa, string, sa->n);
+}
+
+/* Inserts a copy of STRING in SA just before the string with index BEFORE,
+   which must be less than or equal to the number of strings in SA.  The caller
+   retains ownership of STRING.
+
+   In general, this function runs in O(n) time in the number of strings that
+   must be shifted to higher indexes; if BEFORE is the number of strings in SA,
+   it runs in amortized constant time. */
+void
+string_array_insert (struct string_array *sa,
+                     const char *string, size_t before)
+{
+  string_array_insert_nocopy (sa, xstrdup (string), before);
+}
+
+static void
+string_array_expand__ (struct string_array *sa)
+{
+  if (sa->n >= sa->allocated)
+    sa->strings = x2nrealloc (sa->strings, &sa->allocated,
+                              sizeof *sa->strings);
+}
+
+/* Inserts STRING in SA just before the string with index BEFORE, which must be
+   less than or equal to the number of strings in SA.  Ownership of STRING
+   transfers to SA.
+
+   In general, this function runs in O(n) time in the number of strings that
+   must be shifted to higher indexes; if BEFORE is the number of strings in SA,
+   it runs in amortized constant time. */
+void
+string_array_insert_nocopy (struct string_array *sa, char *string,
+                            size_t before)
+{
+  string_array_expand__ (sa);
+  if (before < sa->n)
+    insert_element (sa->strings, sa->n, sizeof *sa->strings, before);
+
+  sa->strings[before] = string;
+  sa->n++;
+}
+
+/* Deletes from SA the string with index IDX, which must be less than the
+   number of strings in SA, and shifts down the strings with higher indexes.
+   Frees the string.
+
+   In general, this function runs in O(n) time in the number of strings that
+   must be shifted to lower indexes.  If IDX is the last string in SA, it runs
+   in amortized constant time. */
+void
+string_array_delete (struct string_array *sa, size_t idx)
+{
+  free (string_array_delete_nofree (sa, idx));
+}
+
+/* Deletes from SA the string with index IDX, which must be less than the
+   number of strings in SA.  Returns the string, which the caller is
+   responsible for freeing with free().
+
+   In general, this function runs in O(n) time in the number of strings that
+   must be shifted to lower indexes.  If IDX is the last string in SA, it runs
+   in amortized constant time. */
+char *
+string_array_delete_nofree (struct string_array *sa, size_t idx)
+{
+  char *s = sa->strings[idx];
+  if (idx != sa->n - 1)
+    remove_element (sa->strings, sa->n, sizeof *sa->strings, idx);
+  sa->n--;
+  return s;
+}
+
+/* Deletes all of the strings from SA and frees them. */
+void
+string_array_clear (struct string_array *sa)
+{
+  size_t i;
+
+  for (i = 0; i < sa->n; i++)
+    free (sa->strings[i]);
+  sa->n = 0;
+}
+
+/* Ensures that 'sa->strings[sa->n]' is a null pointer (until SA is modified
+   further). */
+void
+string_array_terminate_null (struct string_array *sa)
+{
+  string_array_expand__ (sa);
+  sa->strings[sa->n] = NULL;
+}
+
+/* Reduces the amount of memory allocated for SA's strings to the minimum
+   necessary. */
+void
+string_array_shrink (struct string_array *sa)
+{
+  if (sa->allocated > sa->n)
+    {
+      if (sa->n > 0)
+        sa->strings = xrealloc (sa->strings, sa->n * sizeof *sa->strings);
+      else
+        {
+          free (sa->strings);
+          sa->strings = NULL;
+        }
+      sa->allocated = sa->n;
+    }
+}
+
+static int
+compare_strings (const void *a_, const void *b_)
+{
+  const void *const *a = a_;
+  const void *const *b = b_;
+
+  return strcmp (*a, *b);
+}
+
+/* Sorts the strings in SA into order according to strcmp(). */
+void
+string_array_sort (struct string_array *sa)
+{
+  qsort (sa->strings, sa->n, sizeof *sa->strings, compare_strings);
+}
+
+/* Returns a single string that consists of each of the strings in SA
+   concatenated, separated from each other with SEPARATOR.
+
+   The caller is responsible for freeing the returned string with free(). */
+char *
+string_array_join (const struct string_array *sa, const char *separator)
+{
+  struct string dst;
+  const char *s;
+  size_t i;
+
+  ds_init_empty (&dst);
+  STRING_ARRAY_FOR_EACH (s, i, sa)
+    {
+      if (i > 0)
+        ds_put_cstr (&dst, separator);
+      ds_put_cstr (&dst, s);
+    }
+  return ds_steal_cstr (&dst);
+}
diff --git a/src/libpspp/string-array.h b/src/libpspp/string-array.h
new file mode 100644 (file)
index 0000000..f3ec042
--- /dev/null
@@ -0,0 +1,96 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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 LIBPSPP_STRING_ARRAY_H
+#define LIBPSPP_STRING_ARRAY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/* An unordered array of strings.
+
+   Not opaque by any means. */
+struct string_array
+  {
+    char **strings;
+    size_t n;
+    size_t allocated;
+  };
+
+/* Suitable for use as the initializer for a string_array named ARRAY.  Typical
+   usage:
+       struct string_array array = STRING_ARRAY_INITIALIZER (array);
+   STRING_ARRAY_INITIALIZER is an alternative to calling string_array_init. */
+#define STRING_ARRAY_INITIALIZER(ARRAY) { NULL, 0, 0 }
+
+void string_array_init (struct string_array *);
+void string_array_clone (struct string_array *, const struct string_array *);
+void string_array_swap (struct string_array *, struct string_array *);
+void string_array_destroy (struct string_array *);
+
+static inline size_t string_array_count (const struct string_array *);
+static inline bool string_array_is_empty (const struct string_array *);
+
+bool string_array_contains (const struct string_array *, const char *);
+size_t string_array_find (const struct string_array *, const char *);
+
+void string_array_append (struct string_array *, const char *);
+void string_array_append_nocopy (struct string_array *, char *);
+void string_array_insert (struct string_array *, const char *, size_t before);
+void string_array_insert_nocopy (struct string_array *, char *, size_t before);
+void string_array_delete (struct string_array *, size_t idx);
+char *string_array_delete_nofree (struct string_array *, size_t idx);
+
+void string_array_clear (struct string_array *);
+
+void string_array_terminate_null (struct string_array *);
+void string_array_shrink (struct string_array *);
+
+void string_array_sort (struct string_array *);
+
+char *string_array_join (const struct string_array *, const char *separator);
+
+/* Macros for conveniently iterating through a string_array, e.g. to print all
+   of the strings in "my_array":
+
+   const char *string;
+   size_t idx;
+
+   STRING_ARRAY_FOR_EACH (string, idx, &my_array)
+     puts (string);
+*/
+#define STRING_ARRAY_FOR_EACH(STRING, IDX, ARRAY)                  \
+  for ((IDX) = 0;                                                  \
+       ((IDX) < (ARRAY)->n                                         \
+        ? ((STRING) = (ARRAY)->strings[IDX], true)                 \
+        : false);                                                  \
+       (IDX)++)
+\f
+/* Returns the number of strings currently in ARRAY. */
+static inline size_t
+string_array_count (const struct string_array *array)
+{
+  return array->n;
+}
+
+/* Returns true if ARRAY currently contains no strings, false otherwise. */
+static inline bool
+string_array_is_empty (const struct string_array *array)
+{
+  return array->n == 0;
+}
+
+#endif /* libpspp/string-array.h */
diff --git a/src/libpspp/string-map.c b/src/libpspp/string-map.c
new file mode 100644 (file)
index 0000000..4812479
--- /dev/null
@@ -0,0 +1,366 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <libpspp/string-map.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+#include <libpspp/string-set.h>
+
+#include "gl/xalloc.h"
+
+static struct string_map_node *string_map_find_node__ (
+  const struct string_map *, const char *key, unsigned int hash);
+static bool string_map_delete__ (struct string_map *, const char *key,
+                                 unsigned int hash);
+static struct string_map_node *string_map_insert__ (struct string_map *,
+                                                    char *key, char *value,
+                                                    unsigned int hash);
+
+/* Sets NODE's value to a copy of NEW_VALUE and returns the node's previous
+   value.  The caller is responsible for freeing the returned string (with
+   free()). */
+char *
+string_map_node_swap_value (struct string_map_node *node,
+                            const char *new_value)
+{
+  return string_map_node_swap_value_nocopy (node, xstrdup (new_value));
+}
+
+/* Sets NODE's value to NEW_VALUE, which must be a malloc()'d string,
+   transferring ownership of NEW_VALUE to the node.  Returns the node's
+   previous value, which the caller is responsible for freeing (with
+   free()). */
+char *
+string_map_node_swap_value_nocopy (struct string_map_node *node,
+                                   char *new_value)
+{
+  char *old_value = node->value;
+  node->value = new_value;
+  return old_value;
+}
+
+/* Replaces NODE's value by a copy of VALUE. */
+void
+string_map_node_set_value (struct string_map_node *node, const char *value)
+{
+  string_map_node_set_value_nocopy (node, xstrdup (value));
+}
+
+/* Replaces NODE's value by VALUE, which must be a malloc()'d string,
+   transferring ownership of VALUE to the node.. */
+void
+string_map_node_set_value_nocopy (struct string_map_node *node, char *value)
+{
+  free (node->value);
+  node->value = value;
+}
+
+/* Frees NODE and and its key and value.  Ordinarily nodes are owned by
+   string_maps, but this function should only be used by a caller that owns
+   NODE, such as one that has called string_map_delete_nofree() for the
+   node. */
+void
+string_map_node_destroy (struct string_map_node *node)
+{
+  free (node->key);
+  free (node->value);
+  free (node);
+}
+\f
+/* Initializes MAP as an initially empty string map. */
+void
+string_map_init (struct string_map *map)
+{
+  hmap_init (&map->hmap);
+}
+
+/* Initializes MAP as a new string map that initially contains the same pairs
+   as OLD. */
+void
+string_map_clone (struct string_map *map, const struct string_map *old)
+{
+  const struct string_map_node *node;
+  const char *key, *value;
+
+  string_map_init (map);
+  hmap_reserve (&map->hmap, string_map_count (old));
+  STRING_MAP_FOR_EACH_KEY_VALUE (key, value, node, old)
+    string_map_insert__ (map, xstrdup (key), xstrdup (value),
+                         node->hmap_node.hash);
+}
+
+/* Exchanges the contents of string maps A and B. */
+void
+string_map_swap (struct string_map *a, struct string_map *b)
+{
+  hmap_swap (&a->hmap, &b->hmap);
+}
+
+/* Frees MAP and its nodes and key-value pairs. */
+void
+string_map_destroy (struct string_map *map)
+{
+  if (map != NULL)
+    {
+      string_map_clear (map);
+      hmap_destroy (&map->hmap);
+    }
+}
+
+/* Returns true if MAP contains KEY as a key, otherwise false. */
+bool
+string_map_contains (const struct string_map *map, const char *key)
+{
+  return string_map_find_node (map, key) != NULL;
+}
+
+/* If MAP contains KEY as a key, returns the corresponding value.  Otherwise,
+   returns a null pointer. */
+const char *
+string_map_find (const struct string_map *map, const char *key)
+{
+  const struct string_map_node *node = string_map_find_node (map, key);
+  return node != NULL ? node->value : NULL;
+}
+
+/* If MAP contains KEY as a key, returns the corresponding node.  Otherwise,
+   returns a null pointer. */
+struct string_map_node *
+string_map_find_node (const struct string_map *map, const char *key)
+{
+  return string_map_find_node__ (map, key, hash_string (key, 0));
+}
+
+/* If MAP contains KEY as a key, deletes that key's node and returns its value,
+   which the caller is responsible for freeing (using free()).  Otherwise,
+   returns a null pointer. */
+char *
+string_map_find_and_delete (struct string_map *map, const char *key)
+{
+  struct string_map_node *node = string_map_find_node (map, key);
+  char *value = NULL;
+  if (node != NULL)
+    {
+      value = node->value;
+      node->value = NULL;
+      string_map_delete_node (map, node);
+    }
+  return value;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing copies
+   of KEY and VALUE and returns the new node.  Otherwise, returns the existing
+   node that contains KEY. */
+struct string_map_node *
+string_map_insert (struct string_map *map, const char *key, const char *value)
+{
+  unsigned int hash = hash_string (key, 0);
+  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  if (node == NULL)
+    node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+  return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing KEY and
+   VALUE and returns the new node.  Otherwise, returns the existing node that
+   contains KEY.  Either way, ownership of KEY and VALUE is transferred to
+   MAP. */
+struct string_map_node *
+string_map_insert_nocopy (struct string_map *map, char *key, char *value)
+{
+  unsigned int hash = hash_string (key, 0);
+  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  if (node == NULL)
+    node = string_map_insert__ (map, key, value, hash);
+  else
+    {
+      free (key);
+      free (value);
+    }
+  return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing copies
+   of KEY and VALUE.  Otherwise, replaces the existing node's value by a copy
+   of VALUE.  Returns the node. */
+struct string_map_node *
+string_map_replace (struct string_map *map, const char *key, const char *value)
+{
+  unsigned int hash = hash_string (key, 0);
+  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  if (node == NULL)
+    node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+  else
+    string_map_node_set_value (node, value);
+  return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing KEY and
+   VALUE.  Otherwise, replaces the existing node's value by VALUE.  Either way,
+   ownership of KEY and VALUE is transferred to MAP.  Returns the node. */
+struct string_map_node *
+string_map_replace_nocopy (struct string_map *map, char *key, char *value)
+{
+  unsigned int hash = hash_string (key, 0);
+  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  if (node == NULL)
+    node = string_map_insert__ (map, key, value, hash);
+  else
+    {
+      free (key);
+      string_map_node_set_value_nocopy (node, value);
+    }
+  return node;
+}
+
+/* Searches MAP for a node with KEY as its key.  If found, deletes the node
+   and its key and value and returns true.  Otherwise, returns false without
+   modifying MAP. */
+bool
+string_map_delete (struct string_map *map, const char *key)
+{
+  return string_map_delete__ (map, key, hash_string (key, 0));
+}
+
+/* Deletes NODE from MAP and destroys the node and its key and value. */
+void
+string_map_delete_node (struct string_map *map, struct string_map_node *node)
+{
+  string_map_delete_nofree (map, node);
+  string_map_node_destroy (node);
+}
+
+/* Deletes NODE from MAP.  Transfers ownership of NODE to the caller, which
+   becomes responsible for destroying it. */
+void
+string_map_delete_nofree (struct string_map *map, struct string_map_node *node)
+{
+  hmap_delete (&map->hmap, &node->hmap_node);
+}
+
+/* Removes all nodes from MAP and frees them and their keys and values. */
+void
+string_map_clear (struct string_map *map)
+{
+  struct string_map_node *node, *next;
+
+  STRING_MAP_FOR_EACH_NODE_SAFE (node, next, map)
+    string_map_delete_node (map, node);
+}
+
+/* Inserts a copy of each of the nodes in SRC into DST.  When SRC and DST both
+   have a particular key, the value in DST's node is left unchanged. */
+void
+string_map_insert_map (struct string_map *dst, const struct string_map *src)
+{
+  const struct string_map_node *node;
+
+  STRING_MAP_FOR_EACH_NODE (node, src)
+    {
+      if (!string_map_find_node__ (dst, node->key, node->hmap_node.hash))
+        string_map_insert__ (dst, xstrdup (node->key), xstrdup (node->value),
+                             node->hmap_node.hash);
+    }
+}
+
+/* Inserts a copy of each of the nodes in SRC into DST.  When SRC and DST both
+   have a particular key, the value in DST's node is replaced by a copy of the
+   value in SRC's node. */
+void
+string_map_replace_map (struct string_map *dst, const struct string_map *src)
+{
+  const struct string_map_node *snode;
+
+  STRING_MAP_FOR_EACH_NODE (snode, src)
+    {
+      struct string_map_node *dnode;
+      dnode = string_map_find_node__ (dst, snode->key, snode->hmap_node.hash);
+      if (dnode != NULL)
+        string_map_node_set_value (dnode, snode->value);
+      else
+        string_map_insert__ (dst, xstrdup (snode->key), xstrdup (snode->value),
+                             snode->hmap_node.hash);
+    }
+}
+
+/* Inserts each of the keys in MAP into KEYS.  KEYS must already have been
+   initialized (using string_set_init()). */
+void
+string_map_get_keys (const struct string_map *map, struct string_set *keys)
+{
+  const struct string_map_node *node;
+  const char *key;
+
+  STRING_MAP_FOR_EACH_KEY (key, node, map)
+    string_set_insert (keys, key);
+}
+
+/* Inserts each of the values in MAP into VALUES.  VALUES must already have
+   been initialized (using string_set_init()). */
+void
+string_map_get_values (const struct string_map *map, struct string_set *values)
+{
+  const struct string_map_node *node;
+  const char *value;
+
+  STRING_MAP_FOR_EACH_VALUE (value, node, map)
+    string_set_insert (values, value);
+}
+\f
+static struct string_map_node *
+string_map_find_node__ (const struct string_map *map, const char *key,
+                        unsigned int hash)
+{
+  struct string_map_node *node;
+
+  HMAP_FOR_EACH_WITH_HASH (node, struct string_map_node, hmap_node,
+                           hash, &map->hmap)
+    if (!strcmp (key, node->key))
+      return node;
+
+  return NULL;
+}
+
+static bool
+string_map_delete__ (struct string_map *map, const char *key,
+                     unsigned int hash)
+{
+  struct string_map_node *node = string_map_find_node__ (map, key, hash);
+  if (node != NULL)
+    {
+      string_map_delete_node (map, node);
+      return true;
+    }
+  else
+    return false;
+}
+
+static struct string_map_node *
+string_map_insert__ (struct string_map *map, char *key, char *value,
+                     unsigned int hash)
+{
+  struct string_map_node *node = xmalloc (sizeof *node);
+  node->key = key;
+  node->value = value;
+  hmap_insert (&map->hmap, &node->hmap_node, hash);
+  return node;
+}
+
diff --git a/src/libpspp/string-map.h b/src/libpspp/string-map.h
new file mode 100644 (file)
index 0000000..f8ffabc
--- /dev/null
@@ -0,0 +1,213 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 LIBPSPP_STRING_MAP_H
+#define LIBPSPP_STRING_MAP_H
+
+/* Map from a unique string key to a string value.
+
+   This is a convenient wrapper around a "struct hmap" for storing string
+   key-value pairs. */
+
+#include <stdbool.h>
+#include <libpspp/hmap.h>
+
+struct string_set;
+
+/* A node within a string map. */
+struct string_map_node
+  {
+    struct hmap_node hmap_node;
+    char *key;
+    char *value;
+  };
+
+/* Returns the string key within NODE.  The caller must not modify or free the
+   returned string. */
+static inline const char *
+string_map_node_get_key (const struct string_map_node *node)
+{
+  return node->key;
+}
+
+/* Returns the string key within NODE.  The caller must not free the returned
+   string. */
+static inline const char *
+string_map_node_get_value (const struct string_map_node *node)
+{
+  return node->value;
+}
+
+/* Returns the string key within NODE.  The caller must not free the returned
+   string. */
+static inline char *
+string_map_node_get_value_rw (struct string_map_node *node)
+{
+  return node->value;
+}
+
+char *string_map_node_swap_value (struct string_map_node *,
+                                  const char *new_value);
+char *string_map_node_swap_value_nocopy (struct string_map_node *,
+                                         char *new_value);
+void string_map_node_set_value (struct string_map_node *, const char *value);
+void string_map_node_set_value_nocopy (struct string_map_node *, char *value);
+void string_map_node_destroy (struct string_map_node *);
+\f
+/* Unordered map from unique string keys to string values. */
+struct string_map
+  {
+    struct hmap hmap;
+  };
+
+/* Suitable for use as the initializer for a string_map named MAP.  Typical
+   usage:
+       struct string_map map = STRING_MAP_INITIALIZER (map);
+   STRING_MAP_INITIALIZER is an alternative to calling string_map_init. */
+#define STRING_MAP_INITIALIZER(MAP) { HMAP_INITIALIZER ((MAP).hmap) }
+
+void string_map_init (struct string_map *);
+void string_map_clone (struct string_map *, const struct string_map *);
+void string_map_swap (struct string_map *, struct string_map *);
+void string_map_destroy (struct string_map *);
+
+static inline size_t string_map_count (const struct string_map *);
+static inline bool string_map_is_empty (const struct string_map *);
+
+bool string_map_contains (const struct string_map *, const char *);
+const char *string_map_find (const struct string_map *, const char *);
+struct string_map_node *string_map_find_node (const struct string_map *,
+                                              const char *);
+char *string_map_find_and_delete (struct string_map *, const char *key);
+
+struct string_map_node *string_map_insert (struct string_map *,
+                                           const char *key, const char *value);
+struct string_map_node *string_map_insert_nocopy (struct string_map *,
+                                                  char *key, char *value);
+struct string_map_node *string_map_replace (struct string_map *,
+                                           const char *key, const char *value);
+struct string_map_node *string_map_replace_nocopy (struct string_map *,
+                                                   char *key, char *value);
+bool string_map_delete (struct string_map *, const char *);
+void string_map_delete_node (struct string_map *, struct string_map_node *);
+void string_map_delete_nofree (struct string_map *, struct string_map_node *);
+
+void string_map_clear (struct string_map *);
+void string_map_insert_map (struct string_map *, const struct string_map *);
+void string_map_replace_map (struct string_map *, const struct string_map *);
+
+void string_map_get_keys (const struct string_map *, struct string_set *);
+void string_map_get_values (const struct string_map *, struct string_set *);
+
+static inline struct string_map_node *string_map_first (
+  const struct string_map *);
+static inline struct string_map_node *string_map_next (
+  const struct string_map *, const struct string_map_node *);
+
+/* Macros for conveniently iterating through a string_map, e.g. to print all of
+   the key-value pairs in "my_map":
+
+   struct string_map_node *node;
+   const char *key, *value;
+
+   STRING_MAP_FOR_EACH_KEY_VALUE (key, value, node, &my_map)
+     printf ("%s=%s\n", key, value);
+   */
+#define STRING_MAP_FOR_EACH_NODE(NODE, MAP)                     \
+        for ((NODE) = string_map_first (MAP); (NODE) != NULL;   \
+             (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_NODE_SAFE(NODE, NEXT, MAP)          \
+        for ((NODE) = string_map_first (MAP);                   \
+             ((NODE) != NULL                                    \
+              && ((NEXT) = string_map_next (MAP, NODE), 1));    \
+             (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_KEY(KEY, NODE, MAP)                 \
+        for ((NODE) = string_map_first (MAP);                   \
+             ((NODE) != NULL                                    \
+              && ((KEY) = string_map_node_get_key (NODE), 1));  \
+             (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_KEY_SAFE(KEY, NODE, NEXT, MAP)      \
+        for ((NODE) = string_map_first (MAP);                   \
+             ((NODE) != NULL                                    \
+              && ((KEY) = string_map_node_get_key (NODE), 1)    \
+              && ((NEXT) = string_map_next (MAP, NODE), 1));    \
+             (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_VALUE(VALUE, NODE, MAP)     \
+        for ((NODE) = string_map_first (MAP);           \
+             ((NODE) != NULL                            \
+              && ((VALUE) = (NODE)->value, 1));         \
+             (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_VALUE_SAFE(VALUE, NODE, NEXT, MAP)  \
+        for ((NODE) = string_map_first (MAP);                   \
+             ((NODE) != NULL                                    \
+              && ((VALUE) = (NODE)->value, 1)                   \
+              && ((NEXT) = string_map_next (MAP, NODE), 1));    \
+             (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_KEY_VALUE(KEY, VALUE, NODE, MAP)    \
+        for ((NODE) = string_map_first (MAP);                   \
+             ((NODE) != NULL                                    \
+              && ((KEY) = string_map_node_get_key (NODE), 1)    \
+              && ((VALUE) = (NODE)->value, 1));                 \
+             (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_KEY_VALUE_SAFE(KEY, VALUE, NODE, NEXT, MAP) \
+        for ((NODE) = string_map_first (MAP);                           \
+             ((NODE) != NULL                                            \
+              && ((KEY) = string_map_node_get_key (NODE), 1)            \
+              && ((VALUE) = (NODE)->value, 1)                           \
+              && ((NEXT) = string_map_next (MAP, NODE), 1));            \
+             (NODE) = (NEXT))
+\f
+/* Returns the number of key-value pairs currently in MAP. */
+static inline size_t
+string_map_count (const struct string_map *map)
+{
+  return hmap_count (&map->hmap);
+}
+
+/* Returns true if MAP currently contains no key-value pairs, false
+   otherwise. */
+static inline bool
+string_map_is_empty (const struct string_map *map)
+{
+  return hmap_is_empty (&map->hmap);
+}
+
+/* Returns the first node in MAP, or a null pointer if MAP is empty.  See the
+   hmap_first function for information about complexity (O(1) amortized) and
+   ordering (arbitrary).
+
+   The STRING_MAP_FOR_EACH family of macros provide convenient ways to iterate
+   over all the nodes in a string map. */
+static inline struct string_map_node *
+string_map_first (const struct string_map *map)
+{
+  return HMAP_FIRST (struct string_map_node, hmap_node, &map->hmap);
+}
+
+/* Returns the next node in MAP following NODE, or a null pointer if NODE is
+   the last node in MAP.  See the hmap_next function for information about
+   complexity (O(1) amortized) and ordering (arbitrary).
+
+   The STRING_MAP_FOR_EACH family of macros provide convenient ways to iterate
+   over all the nodes in a string map. */
+static inline struct string_map_node *
+string_map_next (const struct string_map *map,
+                 const struct string_map_node *node)
+{
+  return HMAP_NEXT (node, struct string_map_node, hmap_node, &map->hmap);
+}
+
+#endif /* libpspp/string-map.h */
diff --git a/src/libpspp/string-set.c b/src/libpspp/string-set.c
new file mode 100644 (file)
index 0000000..3fd370d
--- /dev/null
@@ -0,0 +1,261 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/>. */
+
+/* If you add routines in this file, please add a corresponding test to
+   string-set-test.c. */
+
+#include <config.h>
+
+#include <libpspp/string-set.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+
+#include "gl/xalloc.h"
+
+static struct string_set_node *string_set_find_node__ (
+  const struct string_set *, const char *, unsigned int hash);
+static void string_set_insert__ (struct string_set *, char *,
+                                 unsigned int hash);
+static bool string_set_delete__ (struct string_set *, const char *,
+                                 unsigned int hash);
+
+/* Initializes SET as a new string set that is initially empty. */
+void
+string_set_init (struct string_set *set)
+{
+  hmap_init (&set->hmap);
+}
+
+/* Initializes SET as a new string set that initially contains the same strings
+   as OLD. */
+void
+string_set_clone (struct string_set *set, const struct string_set *old)
+{
+  const struct string_set_node *node;
+  const char *s;
+
+  string_set_init (set);
+  hmap_reserve (&set->hmap, string_set_count (old));
+  STRING_SET_FOR_EACH (s, node, old)
+    string_set_insert__ (set, xstrdup (s), node->hmap_node.hash);
+}
+
+/* Exchanges the contents of string sets A and B. */
+void
+string_set_swap (struct string_set *a, struct string_set *b)
+{
+  hmap_swap (&a->hmap, &b->hmap);
+}
+
+/* Frees SET and its nodes and strings. */
+void
+string_set_destroy (struct string_set *set)
+{
+  if (set != NULL)
+    {
+      string_set_clear (set);
+      hmap_destroy (&set->hmap);
+    }
+}
+
+/* Returns true if SET contains S, false otherwise. */
+bool
+string_set_contains (const struct string_set *set, const char *s)
+{
+  return string_set_find_node (set, s) != NULL;
+}
+
+/* Returns the node in SET that contains S, or a null pointer if SET does not
+   contain S. */
+struct string_set_node *
+string_set_find_node (const struct string_set *set, const char *s)
+{
+  return string_set_find_node__ (set, s, hash_string (s, 0));
+}
+
+/* Inserts a copy of S into SET.  Returns true if successful, false if SET
+   is unchanged because it already contained S. */
+bool
+string_set_insert (struct string_set *set, const char *s)
+{
+  unsigned int hash = hash_string (s, 0);
+  if (!string_set_find_node__ (set, s, hash))
+    {
+      string_set_insert__ (set, xstrdup (s), hash);
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Inserts S, which must be a malloc'd string, into SET, transferring ownership
+   of S to SET.  Returns true if successful, false if SET is unchanged because
+   it already contained a copy of S.  (In the latter case, S is freed.) */
+bool
+string_set_insert_nocopy (struct string_set *set, char *s)
+{
+  unsigned int hash = hash_string (s, 0);
+  if (!string_set_find_node__ (set, s, hash))
+    {
+      string_set_insert__ (set, s, hash);
+      return true;
+    }
+  else
+    {
+      free (s);
+      return false;
+    }
+}
+
+/* Deletes S from SET.  Returns true if successful, false if SET is unchanged
+   because it did not contain a copy of S. */
+bool
+string_set_delete (struct string_set *set, const char *s)
+{
+  return string_set_delete__ (set, s, hash_string (s, 0));
+}
+
+/* Deletes NODE from SET, and frees NODE and its string. */
+void
+string_set_delete_node (struct string_set *set, struct string_set_node *node)
+{
+  free (string_set_delete_nofree (set, node));
+}
+
+/* Deletes NODE from SET and frees NODE.  Returns the string that NODE
+   contained, transferring ownership to the caller. */
+char *
+string_set_delete_nofree (struct string_set *set, struct string_set_node *node)
+{
+  char *string = node->string;
+  hmap_delete (&set->hmap, &node->hmap_node);
+  free (node);
+  return string;
+}
+
+/* Removes all nodes from SET. */
+void
+string_set_clear (struct string_set *set)
+{
+  struct string_set_node *node, *next;
+
+  HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+                      &set->hmap)
+    string_set_delete_node (set, node);
+}
+
+/* Calculates A = union(A, B).
+
+   If B may be modified, string_set_union_and_intersection() is
+   faster than this function. */
+void
+string_set_union (struct string_set *a, const struct string_set *b)
+{
+  struct string_set_node *node;
+  HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
+    if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
+      string_set_insert__ (a, xstrdup (node->string), node->hmap_node.hash);
+}
+
+/* Calculates A = union(A, B) and B = intersect(A, B).
+
+   If only the intersection is needed, string_set_intersect() is
+   faster. */
+void
+string_set_union_and_intersection (struct string_set *a, struct string_set *b)
+{
+  struct string_set_node *node, *next;
+
+  HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+                      &b->hmap)
+    if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
+      {
+        hmap_delete (&b->hmap, &node->hmap_node);
+        hmap_insert (&a->hmap, &node->hmap_node, node->hmap_node.hash);
+      }
+}
+
+/* Calculates A = intersect(A, B). */
+void
+string_set_intersect (struct string_set *a, const struct string_set *b)
+{
+  struct string_set_node *node, *next;
+
+  HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+                      &a->hmap)
+    if (!string_set_find_node__ (b, node->string, node->hmap_node.hash))
+      string_set_delete_node (a, node);
+}
+
+/* Removes from A all of the strings in B. */
+void
+string_set_subtract (struct string_set *a, const struct string_set *b)
+{
+  struct string_set_node *node, *next;
+
+  if (string_set_count (a) < string_set_count (b))
+    {
+      HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+                          &a->hmap)
+        if (string_set_find_node__ (b, node->string, node->hmap_node.hash))
+          string_set_delete_node (a, node);
+    }
+  else
+    {
+      HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
+        string_set_delete__ (a, node->string, node->hmap_node.hash);
+    }
+}
+\f
+/* Internal functions. */
+
+static struct string_set_node *
+string_set_find_node__ (const struct string_set *set, const char *s,
+                        unsigned int hash)
+{
+  struct string_set_node *node;
+
+  HMAP_FOR_EACH_WITH_HASH (node, struct string_set_node, hmap_node,
+                           hash, &set->hmap)
+    if (!strcmp (s, node->string))
+      return node;
+
+  return NULL;
+}
+
+static void
+string_set_insert__ (struct string_set *set, char *s, unsigned int hash)
+{
+  struct string_set_node *node = xmalloc (sizeof *node);
+  node->string = s;
+  hmap_insert (&set->hmap, &node->hmap_node, hash);
+}
+
+static bool
+string_set_delete__ (struct string_set *set, const char *s, unsigned int hash)
+{
+  struct string_set_node *node = string_set_find_node__ (set, s, hash);
+  if (node != NULL)
+    {
+      string_set_delete_node (set, node);
+      return true;
+    }
+  else
+    return false;
+}
diff --git a/src/libpspp/string-set.h b/src/libpspp/string-set.h
new file mode 100644 (file)
index 0000000..a604e15
--- /dev/null
@@ -0,0 +1,148 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 LIBPSPP_STRING_SET_H
+#define LIBPSPP_STRING_SET_H
+
+/* Set of unique strings.
+
+   This is a convenient wrapper around a "struct hmap" for storing strings. */
+
+#include <stdbool.h>
+#include <libpspp/hmap.h>
+
+/* A node in the string set. */
+struct string_set_node
+  {
+    struct hmap_node hmap_node;
+    char *string;
+  };
+
+/* Returns the string within NODE.  The caller must not modify or free the
+   returned string. */
+static inline const char *
+string_set_node_get_string (const struct string_set_node *node)
+{
+  return node->string;
+}
+\f
+/* An unordered set of unique strings. */
+struct string_set
+  {
+    struct hmap hmap;
+  };
+
+/* Suitable for use as the initializer for a string_set named SET.  Typical
+   usage:
+       struct string_set set = STRING_SET_INITIALIZER (set);
+   STRING_SET_INITIALIZER is an alternative to calling string_set_init. */
+#define STRING_SET_INITIALIZER(SET) { HMAP_INITIALIZER ((SET).hmap) }
+
+void string_set_init (struct string_set *);
+void string_set_clone (struct string_set *, const struct string_set *);
+void string_set_swap (struct string_set *, struct string_set *);
+void string_set_destroy (struct string_set *);
+
+static inline size_t string_set_count (const struct string_set *);
+static inline bool string_set_is_empty (const struct string_set *);
+
+bool string_set_contains (const struct string_set *, const char *);
+struct string_set_node *string_set_find_node (const struct string_set *,
+                                              const char *);
+
+bool string_set_insert (struct string_set *, const char *);
+bool string_set_insert_nocopy (struct string_set *, char *);
+bool string_set_delete (struct string_set *, const char *);
+void string_set_delete_node (struct string_set *, struct string_set_node *);
+char *string_set_delete_nofree (struct string_set *, struct string_set_node *);
+
+void string_set_clear (struct string_set *);
+void string_set_union (struct string_set *, const struct string_set *);
+void string_set_union_and_intersection (struct string_set *,
+                                        struct string_set *);
+void string_set_intersect (struct string_set *, const struct string_set *);
+void string_set_subtract (struct string_set *, const struct string_set *);
+
+static inline const struct string_set_node *string_set_first (
+  const struct string_set *);
+static inline const struct string_set_node *string_set_next (
+  const struct string_set *, const struct string_set_node *);
+
+/* Macros for conveniently iterating through a string_set, e.g. to print all of
+   the strings in "my_set":
+
+   struct string_set_node *node;
+   const char *string;
+
+   STRING_SET_FOR_EACH (string, node, &my_set)
+     puts (string);
+   */
+#define STRING_SET_FOR_EACH(STRING, NODE, SET)                  \
+        for ((NODE) = string_set_first (SET);                   \
+             ((NODE) != NULL                                    \
+              ? ((STRING) = string_set_node_get_string (NODE),  \
+                 1)                                             \
+              : 0);                                             \
+             (NODE) = string_set_next (SET, NODE))
+#define STRING_SET_FOR_EACH_SAFE(STRING, NODE, NEXT, SET)       \
+        for ((NODE) = string_set_first (SET);                   \
+             ((NODE) != NULL                                    \
+              ? ((STRING) = string_set_node_get_string (NODE),  \
+                 (NEXT) = string_set_next (SET, NODE),          \
+                 1)                                             \
+              : 0);                                             \
+             (NODE) = (NEXT))
+\f
+/* Returns the number of strings currently in SET. */
+static inline size_t
+string_set_count (const struct string_set *set)
+{
+  return hmap_count (&set->hmap);
+}
+
+/* Returns true if SET currently contains no strings, false otherwise. */
+static inline bool
+string_set_is_empty (const struct string_set *set)
+{
+  return hmap_is_empty (&set->hmap);
+}
+
+/* Returns the first node in SET, or a null pointer if SET is empty.  See the
+   hmap_first function for information about complexity (O(1) amortized) and
+   ordering (arbitrary).
+
+   The STRING_SET_FOR_EACH and STRING_SET_FOR_EACH_SAFE macros provide
+   convenient ways to iterate over all the nodes in a string set. */
+static inline const struct string_set_node *
+string_set_first (const struct string_set *set)
+{
+  return HMAP_FIRST (struct string_set_node, hmap_node, &set->hmap);
+}
+
+/* Returns the next node in SET following NODE, or a null pointer if NODE is
+   the last node in SET.  See the hmap_next function for information about
+   complexity (O(1) amortized) and ordering (arbitrary).
+
+   The STRING_SET_FOR_EACH and STRING_SET_FOR_EACH_SAFE macros provide
+   convenient ways to iterate over all the nodes in a string set. */
+static inline const struct string_set_node *
+string_set_next (const struct string_set *set,
+                 const struct string_set_node *node)
+{
+  return HMAP_NEXT (node, struct string_set_node, hmap_node, &set->hmap);
+}
+
+#endif /* libpspp/string-set.h */
index 3a74587bb5918ae8cee61766619187b5ca758532..4c1cecb97cdbbdbcdd2302e91f2741e7a68a8bc2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -22,6 +22,7 @@
 
 #include <libpspp/array.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 
 #include "xalloc.h"
 
@@ -79,7 +80,7 @@ taint_create (void)
 struct taint *
 taint_clone (const struct taint *taint_)
 {
-  struct taint *taint = (struct taint *) taint_;
+  struct taint *taint = CONST_CAST (struct taint *, taint_);
 
   assert (taint->ref_cnt > 0);
   taint->ref_cnt++;
@@ -139,8 +140,8 @@ taint_destroy (struct taint *taint)
 void
 taint_propagate (const struct taint *from_, const struct taint *to_)
 {
-  struct taint *from = (struct taint *) from_;
-  struct taint *to = (struct taint *) to_;
+  struct taint *from = CONST_CAST (struct taint *, from_);
+  struct taint *to = CONST_CAST (struct taint *, to_);
 
   if (from != to)
     {
@@ -165,7 +166,7 @@ taint_is_tainted (const struct taint *taint)
 void
 taint_set_taint (const struct taint *taint_)
 {
-  struct taint *taint = (struct taint *) taint_;
+  struct taint *taint = CONST_CAST (struct taint *, taint_);
   if (!taint->tainted)
     recursively_set_taint (taint);
 }
@@ -186,7 +187,7 @@ taint_has_tainted_successor (const struct taint *taint)
 void
 taint_reset_successor_taint (const struct taint *taint_)
 {
-  struct taint *taint = (struct taint *) taint_;
+  struct taint *taint = CONST_CAST (struct taint *, taint_);
 
   if (taint->tainted_successor)
     {
index 0d3093646faa6a9d20a941048760f0d0d11d8be6..aff135d0cc0a1c27b0ea9af1d58dec6beb08d19a 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdlib.h>
 
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 
 #include "error.h"
 #include "xalloc.h"
@@ -81,7 +82,7 @@ tmpfile_destroy (struct tmpfile *tf)
 static bool
 do_seek (const struct tmpfile *tf_, off_t offset)
 {
-  struct tmpfile *tf = (struct tmpfile *) tf_;
+  struct tmpfile *tf = CONST_CAST (struct tmpfile *, tf_);
 
   if (!tmpfile_error (tf))
     {
@@ -106,7 +107,7 @@ do_seek (const struct tmpfile *tf_, off_t offset)
 static bool
 do_read (const struct tmpfile *tf_, void *buffer, size_t bytes)
 {
-  struct tmpfile *tf = (struct tmpfile *) tf_;
+  struct tmpfile *tf = CONST_CAST (struct tmpfile *, tf_);
 
   assert (!tmpfile_error (tf));
   if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1)
index e8d253d086731c61dd539962cbc79f9c2b3b0750..9157987774e555c625d63af41a9343dc4447c574 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -21,6 +21,7 @@
 #include <limits.h>
 
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/compiler.h>
 
 static struct tower_node *abt_to_tower_node (const struct abt_node *);
@@ -184,7 +185,7 @@ tower_lookup (const struct tower *t_,
               unsigned long height,
               unsigned long *node_start)
 {
-  struct tower *t = (struct tower *) t_;
+  struct tower *t = CONST_CAST (struct tower *, t_);
   struct abt_node *p;
 
   assert (height < tower_height (t));
@@ -237,7 +238,7 @@ tower_lookup (const struct tower *t_,
 struct tower_node *
 tower_get (const struct tower *t_, unsigned long int index) 
 {
-  struct tower *t = (struct tower *) t_;
+  struct tower *t = CONST_CAST (struct tower *, t_);
   struct abt_node *p;
 
   assert (index < tower_count (t));
index 246984a2c1bfd6cd1c46100fbe95f84140843a92..9be8231c98ad7c9b0c7fc217a14a513d2813aa92 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
 
 #include <stdbool.h>
 #include <libpspp/abt.h>
+#include <libpspp/cast.h>
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
    data type STRUCT. */
-#define tower_data(NODE, STRUCT, MEMBER)                            \
-        ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define tower_data(NODE, STRUCT, MEMBER)                        \
+        (CHECK_POINTER_HAS_TYPE (NODE, struct tower_node *),    \
+         UP_CAST (NODE, STRUCT, MEMBER))
 
 /* A node within a tower. */
 struct tower_node
diff --git a/src/libpspp/verbose-msg.c b/src/libpspp/verbose-msg.c
deleted file mode 100644 (file)
index a65db7d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 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 <libpspp/verbose-msg.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "progname.h"
-
-/* Level of verbosity.
-   Higher values cause more output. */
-static int verbosity;
-
-/* Increases the verbosity level. */
-void
-verbose_increment_level (void)
-{
-  verbosity++;
-}
-
-/* Writes MESSAGE formatted with printf, to stderr, if the
-   verbosity level is at least LEVEL. */
-void
-verbose_msg (int level, const char *format, ...)
-{
-  if (level <= verbosity)
-    {
-      va_list args;
-
-      va_start (args, format);
-      fprintf (stderr, "%s: ", program_name);
-      vfprintf (stderr, format, args);
-      putc ('\n', stderr);
-      va_end (args);
-    }
-}
-
diff --git a/src/libpspp/verbose-msg.h b/src/libpspp/verbose-msg.h
deleted file mode 100644 (file)
index 2a19331..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 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 VERBOSE_MSG_H
-#define VERBOSE_MSG_H 1
-
-#include <libpspp/compiler.h>
-
-void verbose_increment_level (void);
-void verbose_msg (int level, const char *format, ...)
-     PRINTF_FORMAT (2, 3);
-
-#endif /* verbose-msg.h */
index 88cd3ebe75352f17f1370695f119f7c7874548ca..e2125154a8ca20ccd57005012957bf7d4ae68fec 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010 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
@@ -33,12 +33,6 @@ extern const char host_system[];
 /* Canonical name of build system type. */
 extern const char build_system[];
 
-/* Configuration path at build time. */
-extern const char default_config_path[];
-
-/* Include path. */
-extern const char include_path[];
-
 /* Locale directory. */
 extern const char locale_dir[];
 
index 288fc072ef119ccb2c49b2001a015a34834378ad..de4124efe16c5beb799c7b5d0b2af42743ff79d7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -20,6 +20,7 @@
 #include "tukey-hinges.h"
 #include <gl/xalloc.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <math.h>
 #include <float.h>
 #include <data/val-type.h>
@@ -30,8 +31,8 @@
 static void
 destroy (struct statistic *s)
 {
-  struct order_stats *os = (struct order_stats *) s;
-  struct box_whisker *bw = (struct box_whisker *) s;
+  struct box_whisker *bw = UP_CAST (s, struct box_whisker, parent.parent);
+  struct order_stats *os = &bw->parent;
   struct ll *ll;
 
   for (ll = ll_head (&bw->outliers); ll != ll_null (&bw->outliers); )
@@ -53,7 +54,7 @@ static void
 acc (struct statistic *s, const struct ccase *cx,
      double c UNUSED, double cc UNUSED, double y)
 {
-  struct box_whisker *bw = (struct box_whisker *) s;
+  struct box_whisker *bw = UP_CAST (s, struct box_whisker, parent.parent);
   bool extreme;
   struct outlier *o;
 
@@ -110,13 +111,13 @@ box_whisker_outliers (const struct box_whisker *bw)
   return &bw->outliers;
 }
 
-struct statistic *
+struct box_whisker *
 box_whisker_create (const struct tukey_hinges *th,
                    const struct variable *id_var,  size_t casenumber_idx)
 {
   struct box_whisker *w = xzalloc (sizeof (*w));
-  struct order_stats *os = (struct order_stats *) w;
-  struct statistic *stat = (struct statistic *) w;
+  struct order_stats *os = &w->parent;
+  struct statistic *stat = &os->parent;
 
   os->n_k = 0;
 
@@ -135,5 +136,5 @@ box_whisker_create (const struct tukey_hinges *th,
 
   ll_init (&w->outliers);
 
-  return stat;
+  return w;
 }
index 5202b646727b184ccc22b3ffcfd7e14f3c32c8fd..bef091e83b448dafc5c601fab3d04eb0d60f19f6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -52,7 +52,7 @@ struct box_whisker
   const struct variable *id_var;
 };
 
-struct statistic * box_whisker_create (const struct tukey_hinges *,
+struct box_whisker * box_whisker_create (const struct tukey_hinges *,
                                         const struct variable *, size_t);
 
 void box_whisker_whiskers (const struct box_whisker *bw, double whiskers[2]);
index 67079398d169ec58737c6f3b94a7d243b9fc8516..3c88c3858f61c6b1c2230843a7b9151a47902956 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009 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
@@ -19,6 +19,7 @@
 
 #include <gl/xalloc.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 
 #include <gsl/gsl_histogram.h>
 #include "chart-geometry.h"
@@ -28,7 +29,8 @@
 void
 histogram_add (struct histogram *h, double y, double c)
 {
-  ((struct statistic *)h)->accumulate ((struct statistic *) h, NULL, c, 0, y);
+  struct statistic *stat = &h->parent;
+  stat->accumulate (stat, NULL, c, 0, y);
 }
 
 
@@ -36,7 +38,7 @@ histogram_add (struct histogram *h, double y, double c)
 static void
 acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc UNUSED, double y)
 {
-  struct histogram *hist = (struct histogram *) s;
+  struct histogram *hist = UP_CAST (s, struct histogram, parent);
 
   gsl_histogram_accumulate (hist->gsl_hist, y, c);
 }
@@ -45,17 +47,17 @@ acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc UNU
 static void
 destroy (struct statistic *s)
 {
-  struct histogram *h = (struct histogram *) s;
+  struct histogram *h = UP_CAST (s, struct histogram, parent);
   gsl_histogram_free (h->gsl_hist);
   free (s);
 }
 
 
-struct statistic *
+struct histogram *
 histogram_create (int bins, double min, double max)
 {
   struct histogram *h = xmalloc (sizeof *h);
-  struct statistic *stat = (struct statistic *) h;
+  struct statistic *stat = &h->parent;
   double upper_limit, lower_limit;
 
   double bin_width = chart_rounded_tick ((max - min) / (double) bins);
@@ -78,6 +80,6 @@ histogram_create (int bins, double min, double max)
   stat->accumulate = acc;
   stat->destroy = destroy;
 
-  return stat;
+  return h;
 }
 
index b2b204ee808098c2bf378ef99e8419c6d4223988..bc4a5ae6c1354d9711a467ceba8cf904a875a8fa 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -30,7 +30,7 @@ struct histogram
   gsl_histogram *gsl_hist;
 };
 
-struct statistic * histogram_create (int bins, double max, double min);
+struct histogram * histogram_create (int bins, double max, double min);
 
 void histogram_add (struct histogram *h, double y, double c);
 
index 7bd582105f940c28ffeb26506d4c5fe941ff728d..f7e269991346cd0c6cb076eacec04bcbbd62590c 100644 (file)
@@ -246,9 +246,7 @@ levene2_precalc (struct levene_info *l)
       struct hsh_table *hash = group_proc_get (var)->group_hash;
 
 
-      for(g = (struct group_statistics *) hsh_first(hash,&hi);
-         g != 0 ;
-         g = (struct group_statistics *) hsh_next(hash,&hi) )
+      for (g = hsh_first(hash,&hi); g != 0; g = hsh_next(hash, &hi))
        {
          g->lz_mean = g->lz_total / g->n ;
        }
@@ -308,9 +306,7 @@ levene2_postcalc (struct levene_info *l)
       struct group_proc *gp = group_proc_get (var);
       struct hsh_table *hash = gp->group_hash;
 
-      for(g = (struct group_statistics *) hsh_first(hash,&hi);
-         g != 0 ;
-         g = (struct group_statistics *) hsh_next(hash,&hi) )
+      for (g = hsh_first(hash, &hi); g != 0; g = hsh_next(hash, &hi))
        {
          lz_numerator += g->n * pow2(g->lz_mean - l->lz[v].grand_mean );
        }
index e61bf58e117aaf915d596bc26b8875152f0f0deb..b631820903e6ebf4e41a536ebe7ea964924af918 100644 (file)
@@ -24,6 +24,7 @@
 #include <data/case.h>
 #include <data/casewriter.h>
 #include <libpspp/compiler.h>
+#include <libpspp/cast.h>
 #include <libpspp/misc.h>
 #include <math/moments.h>
 
@@ -32,8 +33,8 @@
 static void
 destroy (struct statistic *stat)
 {
-  struct order_stats *os = (struct order_stats *) stat;
-  free (os);
+  struct np *np = UP_CAST (stat, struct np, parent.parent);
+  free (np);
 }
 
 
@@ -42,7 +43,7 @@ acc (struct statistic *s, const struct ccase *cx UNUSED,
      double c, double cc, double y)
 {
   struct ccase *cp;
-  struct np *np = (struct np *) s;
+  struct np *np = UP_CAST (s, struct np, parent.parent);
   double rank = np->prev_cc + (c + 1) / 2.0;
 
   double ns = gsl_cdf_ugaussian_Pinv (rank / ( np->n + 1 ));
@@ -69,13 +70,13 @@ acc (struct statistic *s, const struct ccase *cx UNUSED,
   np->prev_cc = cc;
 }
 
-struct order_stats *
+struct np *
 np_create (const struct moments1 *m)
 {
   double variance;
   struct np *np = xzalloc (sizeof (*np));
-  struct statistic *stat = (struct statistic *) np;
-  struct order_stats *os = (struct order_stats *) np;
+  struct order_stats *os = &np->parent;
+  struct statistic *stat = &os->parent;
   struct caseproto *proto;
   int i;
 
@@ -98,5 +99,5 @@ np_create (const struct moments1 *m)
   stat->destroy = destroy;
   stat->accumulate = acc;
 
-  return os;
+  return np;
 }
index 7db51f73b223fbcf7ade345afec06c45b5687fb9..b5265bd41f72c57d5b895a578a428971957fb61a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -54,6 +54,6 @@ struct np
 };
 
 
-struct order_stats * np_create (const struct moments1 *);
+struct np * np_create (const struct moments1 *);
 
 #endif
index 1b6aa131ea745ba6c0b55b33a54f3a6d39ceddbe..e550d2b2eb55f66fd4baea366e7a058abb849443 100644 (file)
@@ -90,7 +90,7 @@ update_k_values (const struct ccase *cx, double y_i, double c_i, double cc_i,
     {
       int k;
       struct order_stats *tos = os[j];
-      struct statistic  *stat = (struct statistic *) tos;
+      struct statistic  *stat = &tos->parent;
       for (k = 0 ; k < tos->n_k; ++k)
        {
          struct k *myk = &tos->k[k];
index bf99de163ffbaafe2af8711685e9a640a0256784..c76bb492ba767a90ffa2c03c8d35bf8a7d532ab6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -24,6 +24,7 @@
 #define N_(msgid) msgid
 
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <data/val-type.h>
 #include <gl/xalloc.h>
 #include <data/variable.h>
@@ -44,7 +45,7 @@ const char *const ptile_alg_desc[] = {
 double
 percentile_calculate (const struct percentile *ptl, enum pc_alg alg)
 {
-  struct percentile *mutable = (struct percentile *) ptl;
+  struct percentile *mutable = CONST_CAST (struct percentile *, ptl);
   const struct order_stats *os = &ptl->parent;
 
   assert (os->cc == ptl->w);
@@ -154,18 +155,19 @@ percentile_calculate (const struct percentile *ptl, enum pc_alg alg)
 static void
 destroy (struct statistic *stat)
 {
-  struct order_stats *os = (struct order_stats *) stat;
+  struct percentile *ptl = UP_CAST (stat, struct percentile, parent.parent);
+  struct order_stats *os = &ptl->parent;
   free (os->k);
-  free (os);
+  free (ptl);
 }
 
 
-struct order_stats *
+struct percentile *
 percentile_create (double p, double W)
 {
   struct percentile *ptl = xzalloc (sizeof (*ptl));
-  struct order_stats *os = (struct order_stats *) ptl;
-  struct statistic *stat = (struct statistic *) ptl;
+  struct order_stats *os = &ptl->parent;
+  struct statistic *stat = &os->parent;
 
   assert (p >= 0);
   assert (p <= 1.0);
@@ -186,6 +188,6 @@ percentile_create (double p, double W)
 
   stat->destroy = destroy;
 
-  return os;
+  return ptl;
 }
 
index 0dd09820945e1bafaee5a017ba3756cb4197783b..ff46bea6dce45611b88c621df4f7e86a30d97534 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009 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
@@ -52,7 +52,7 @@ struct percentile
 /* Create the Pth percentile.
    W is the total sum of weights in the data set
 */
-struct order_stats *percentile_create (double p, double W);
+struct percentile *percentile_create (double p, double W);
 
 /* Return the value of the percentile */
 double percentile_calculate (const struct percentile *ptl, enum pc_alg alg);
index da3d4240e5b232533de6c5c31073b53adda49f48..d1cc6b708279098ab8d263b95923d9b31c968ed6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -20,6 +20,7 @@
 
 #include <gl/xalloc.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <math.h>
 #include <data/val-type.h>
 
@@ -27,8 +28,8 @@
 static void
 acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc, double y)
 {
-  struct trimmed_mean *tm = (struct trimmed_mean *) s;
-  struct order_stats *os = (struct order_stats *) s;
+  struct trimmed_mean *tm = UP_CAST (s, struct trimmed_mean, parent.parent);
+  struct order_stats *os = &tm->parent;
 
   if ( cc > os->k[0].tc && cc < os->k[1].tc)
       tm->sum += c * y;
@@ -40,17 +41,18 @@ acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc, do
 static void
 destroy (struct statistic *s)
 {
-  struct order_stats *os = (struct order_stats *) s;
+  struct trimmed_mean *tm = UP_CAST (s, struct trimmed_mean, parent.parent);
+  struct order_stats *os = &tm->parent;
   free (os->k);
-  free (s);
+  free (tm);
 }
 
-struct statistic *
+struct trimmed_mean *
 trimmed_mean_create (double W, double tail)
 {
   struct trimmed_mean *tm = xzalloc (sizeof (*tm));
-  struct order_stats *os = (struct order_stats *) tm;
-  struct statistic *stat = (struct statistic *) tm;
+  struct order_stats *os = &tm->parent;
+  struct statistic *stat = &os->parent;
 
   os->n_k = 2;
   os->k = xcalloc (sizeof (*os->k), 2);
@@ -68,7 +70,7 @@ trimmed_mean_create (double W, double tail)
   tm->w = W;
   tm->tail = tail;
 
-  return stat;
+  return tm;
 }
 
 
index 9339cab983ff9fba971d2cd2703ee81f17be6f66..c667b1be7ffcd9f9486606022c521143f5f08e6e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -36,7 +36,7 @@ struct trimmed_mean
   double tail;
 };
 
-struct statistic * trimmed_mean_create (double W, double c_min);
+struct trimmed_mean * trimmed_mean_create (double W, double c_min);
 double trimmed_mean_calculate (const struct trimmed_mean *);
 
 #endif
index 95a79c1d30026da280cbc6fa2542518c0ff4ad1f..22ab45210c38c98066eb4bb654663114cb496ddd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -20,6 +20,7 @@
 
 #include <gl/xalloc.h>
 #include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <math.h>
 
 void
@@ -59,19 +60,20 @@ tukey_hinges_calculate (const struct tukey_hinges *th, double hinge[3])
 static void
 destroy (struct statistic *s)
 {
-  struct order_stats *os = (struct order_stats *) s;
+  struct tukey_hinges *th = UP_CAST (s, struct tukey_hinges, parent.parent);
+  struct order_stats *os = &th->parent;
 
   free (os->k);
   free (s);
 };
 
-struct statistic *
+struct tukey_hinges *
 tukey_hinges_create (double W, double c_min)
 {
   double d;
   struct tukey_hinges *th = xzalloc (sizeof (*th));
-  struct order_stats *os = (struct order_stats *) th;
-  struct statistic *stat = (struct statistic *) th;
+  struct order_stats *os = &th->parent;
+  struct statistic *stat = &os->parent;
 
   assert (c_min >= 0);
 
@@ -97,5 +99,5 @@ tukey_hinges_create (double W, double c_min)
 
   stat->destroy = destroy;
 
-  return stat;
+  return th;
 }
index d87691f8b01a4dceb78fddfc9294c17053e8690b..4b509da1d4321a8396510fd4c08b40d801214ffe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 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
@@ -27,7 +27,7 @@ struct tukey_hinges
   struct order_stats parent;
 };
 
-struct statistic * tukey_hinges_create (double W, double c_min);
+struct tukey_hinges * tukey_hinges_create (double W, double c_min);
 
 
 void tukey_hinges_calculate (const struct tukey_hinges *h, double hinge[3]);
diff --git a/src/output/afm.c b/src/output/afm.c
deleted file mode 100644 (file)
index 480aa15..0000000
+++ /dev/null
@@ -1,1156 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 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 "afm.h"
-#include "c-ctype.h"
-#include "c-strtod.h"
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include "error.h"
-#include "minmax.h"
-#include <libpspp/assertion.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* A kern pair entry. */
-struct afm_kern_pair
-  {
-    struct afm_character *successor; /* Second character. */
-    int adjust;                 /* Adjustment. */
-  };
-
-/* A ligature. */
-struct afm_ligature
-  {
-    struct afm_character *successor; /* Second character. */
-    struct afm_character *ligature;  /* Resulting ligature. */
-  };
-
-/* How to map between byte strings and character values. */
-enum mapping_scheme
-  {
-    MAP_UNKNOWN,                /* Not yet determined. */
-    MAP_ONE_BYTE,               /* 8-bit coding. */
-    MAP_TWO_BYTE,               /* 16-bit coding. */
-    MAP_ESCAPE,                 /* 8-bit coding with escape to change fonts. */
-    MAP_DOUBLE_ESCAPE,          /* 8-bit coding with multiple escapes. */
-    MAP_SHIFT                   /* 8-bit coding with 2 fonts that toggle. */
-  };
-
-/* AFM file data.  */
-struct afm
-  {
-    struct pool *pool;         /* Containing pool. */
-    char *findfont_name;        /* Name for PostScript /findfont operator. */
-    int ascent;                 /* Height above the baseline (non-negative). */
-    int descent;                /* Depth below the baseline (non-negative). */
-
-    /* Encoding characters into strings. */
-    enum mapping_scheme mapping; /* Basic mapping scheme. */
-    char escape_char;           /* MAP_ESCAPE only: escape character to use. */
-    char shift_out;             /* MAP_SHIFT only: selects font 0. */
-    char shift_in;              /* MAP_SHIFT only: selects font 1. */
-
-    /* Characters. */
-    struct afm_character *undefined_codes[256];
-    struct afm_character **codes[256];
-    struct afm_character **chars;
-    size_t char_cnt;
-  };
-
-/* AFM file parser. */
-struct parser
-  {
-    struct pool *pool;          /* Containing pool. */
-    struct afm *afm;            /* AFM being parsed. */
-    FILE *file;                 /* File being parsed. */
-    const char *file_name;      /* Name of file being parsed. */
-    int line_number;            /* Current line number in file. */
-    jmp_buf bail_out;           /* longjmp() target for error handling. */
-
-    size_t char_allocated;
-    int max_code;
-  };
-
-static struct afm *create_afm (void);
-static struct afm_character *create_character (struct afm *);
-
-static void afm_error (struct parser *, const char *, ...)
-     PRINTF_FORMAT (2, 3)
-     NO_RETURN;
-
-static void parse_afm (struct parser *);
-static void skip_section (struct parser *, const char *end_key);
-static bool parse_set_specific (struct parser *, const char *end_key);
-static void parse_direction (struct parser *);
-static void parse_char_metrics (struct parser *);
-static void parse_kern_pairs (struct parser *);
-static void add_kern_pair (struct parser *p,
-                           struct afm_character *, struct afm_character *,
-                           int adjust);
-
-static int skip_spaces (struct parser *);
-static char *parse_key (struct parser *);
-static void skip_line (struct parser *);
-static void force_eol (struct parser *);
-static bool get_integer (struct parser *, int *);
-static int force_get_integer (struct parser *);
-static bool get_number (struct parser *, int *);
-static int force_get_number (struct parser *);
-static bool get_hex_code (struct parser *, int *);
-static int force_get_hex_code (struct parser *);
-static bool get_word (struct parser *, char **);
-static char *force_get_word (struct parser *);
-static bool get_string (struct parser *, char **);
-static char *force_get_string (struct parser *);
-
-static struct afm_character *get_char_by_name (struct parser *, const char *);
-static struct afm_character *get_char_by_code (const struct afm *, int code);
-
-/* Reads FILE_NAME as an AFM file and returns the metrics data.
-   Returns a null pointer if the file cannot be parsed. */
-struct afm *
-afm_open (const char *file_name)
-{
-  struct afm *volatile afm;
-  struct parser *parser;
-
-  parser = pool_create_container (struct parser, pool);
-  afm = parser->afm = create_afm ();
-  parser->file = pool_fopen (parser->pool, file_name, "r");
-  parser->file_name = file_name;
-  parser->line_number = 0;
-  if (parser->file == NULL)
-    {
-      error (0, errno, _("opening font metrics file \"%s\""), file_name);
-      goto error;
-    }
-
-  if (setjmp (parser->bail_out))
-    goto error;
-
-  parse_afm (parser);
-  pool_destroy (parser->pool);
-  return afm;
-
- error:
-  pool_destroy (parser->pool);
-  pool_destroy (afm->pool);
-  return create_afm ();
-}
-
-/* Creates and returns an empty set of metrics. */
-static struct afm *
-create_afm (void)
-{
-  struct afm *afm;
-  struct afm_character *def_char;
-  size_t i;
-
-  afm = pool_create_container (struct afm, pool);
-  afm->findfont_name = NULL;
-  afm->ascent = 0;
-  afm->descent = 0;
-  afm->mapping = MAP_UNKNOWN;
-  afm->escape_char = 255;
-  afm->shift_out = 14;
-  afm->shift_in = 15;
-  def_char = create_character (afm);
-  for (i = 0; i < 256; i++)
-    afm->undefined_codes[i] = def_char;
-  for (i = 0; i < 256; i++)
-    afm->codes[i] = afm->undefined_codes;
-  afm->chars = NULL;
-  afm->char_cnt = 0;
-
-  return afm;
-}
-
-/* Creates and returns an initialized character within AFM. */
-static struct afm_character *
-create_character (struct afm *afm)
-{
-  struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
-  c->code = ' ';
-  c->name = NULL;
-  c->width = 12000;
-  c->ascent = 0;
-  c->descent = 0;
-  c->kern_pairs = NULL;
-  c->kern_pair_cnt = 0;
-  c->ligatures = NULL;
-  c->ligature_cnt = 0;
-  return c;
-}
-
-/* Reports the given MESSAGE at the current line in parser P
-   and bails out with longjmp(). */
-static void
-afm_error (struct parser *p, const char *message, ...)
-{
-  va_list args;
-  char *msg;
-
-  va_start (args, message);
-  msg = xasprintf (message, args);
-  va_end (args);
-
-  error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
-  free (msg);
-
-  longjmp (p->bail_out, 1);
-}
-
-/* Parses an AFM file with parser P. */
-static void
-parse_afm (struct parser *p)
-{
-  char *key;
-
-  p->char_allocated = 0;
-  p->max_code = 0;
-
-  key = force_get_word (p);
-  if (strcmp (key, "StartFontMetrics"))
-    afm_error (p, _("first line must be StartFontMetrics"));
-  skip_line (p);
-
-  do
-    {
-      key = parse_key (p);
-      if (!strcmp (key, "FontName"))
-        p->afm->findfont_name = pool_strdup (p->afm->pool,
-                                             force_get_string (p));
-      else if (!strcmp (key, "Ascender"))
-        p->afm->ascent = force_get_integer (p);
-      else if (!strcmp (key, "Descender"))
-        p->afm->descent = force_get_integer (p);
-      else if (!strcmp (key, "MappingScheme"))
-        {
-          int scheme = force_get_integer (p);
-          if (scheme == 4)
-            p->afm->mapping = MAP_ONE_BYTE;
-          else if (scheme == 2 || scheme == 5 || scheme == 6)
-            p->afm->mapping = MAP_TWO_BYTE;
-          else if (scheme == 3)
-            p->afm->mapping = MAP_ESCAPE;
-          else if (scheme == 7)
-            p->afm->mapping = MAP_DOUBLE_ESCAPE;
-          else if (scheme == 8)
-            p->afm->mapping = MAP_SHIFT;
-          else
-            afm_error (p, _("unsupported MappingScheme %d"), scheme);
-        }
-      else if (!strcmp (key, "EscChar"))
-        p->afm->escape_char = force_get_integer (p);
-      else if (!strcmp (key, "StartDirection"))
-        parse_direction (p);
-      else if (!strcmp (key, "StartCharMetrics"))
-        parse_char_metrics (p);
-      else if (!strcmp (key, "StartKernPairs")
-               || !strcmp (key, "StartKernPairs0"))
-        parse_kern_pairs (p);
-      else if (!strcmp (key, "StartTrackKern"))
-        skip_section (p, "EndTrackKern");
-      else if (!strcmp (key, "StartComposites"))
-        skip_section (p, "EndComposites");
-      else
-        skip_line (p);
-    }
-  while (strcmp (key, "EndFontMetrics"));
-
-  if (p->afm->findfont_name == NULL)
-    afm_error (p, _("required FontName is missing"));
-  if (p->afm->mapping == MAP_UNKNOWN)
-    {
-      /* There seem to be a number of fonts out there that use a
-         2-byte encoding but don't announce it with
-         MappingScheme. */
-      p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
-    }
-}
-
-/* Reads lines from parser P until one starts with END_KEY. */
-static void
-skip_section (struct parser *p, const char *end_key)
-{
-  const char *key;
-  skip_line (p);
-  do
-    {
-      key = parse_key (p);
-      skip_line (p);
-    }
-  while (strcmp (key, end_key));
-}
-
-/* Attempts to read an integer from parser P.
-   If one is found, and it is nonzero, skips lines until END_KEY
-   is encountered and returns false.
-   Otherwise, skips the rest of the line and returns true.
-   (This is useful because AFM files can have multiple sets of
-   metrics.  Set 0 is for normal text, other sets are for
-   vertical text, etc.  We only care about set 0.) */
-static bool
-parse_set_specific (struct parser *p, const char *end_key)
-{
-  int set;
-
-  if (get_integer (p, &set) && set != 0)
-    {
-      skip_section (p, end_key);
-      return false;
-    }
-  else
-    {
-      force_eol (p);
-      return true;
-    }
-}
-
-/* Parses a StartDirection...EndDirection section in parser P. */
-static void
-parse_direction (struct parser *p)
-{
-  const char *key;
-
-  if (!parse_set_specific (p, "EndDirection"))
-    return;
-
-  do
-    {
-      key = parse_key (p);
-      if (!strcmp (key, "CharWidth"))
-        p->afm->codes[0][0]->width = force_get_integer (p);
-      skip_line (p);
-    }
-  while (strcmp (key, "EndDirection"));
-}
-
-/* Parses a StartCharMetrics...EndCharMetrics section in parser
-   P. */
-static void
-parse_char_metrics (struct parser *p)
-{
-  struct parsing_ligature
-    {
-      struct afm_character *first;
-      char *successor;
-      char *ligature;
-    };
-
-  struct parsing_ligature *ligatures = NULL;
-  size_t ligature_cnt = 0;
-  size_t ligature_allocated = 0;
-
-  size_t i;
-
-  skip_line (p);
-
-  for (;;)
-    {
-      char *key;
-      struct afm_character *c;
-
-      key = parse_key (p);
-      if (!strcmp (key, "EndCharMetrics"))
-        break;
-
-      if (p->afm->char_cnt == p->char_allocated)
-        p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
-                                        &p->char_allocated,
-                                        sizeof *p->afm->chars);
-      c = create_character (p->afm);
-
-      if (!strcmp (key, "C"))
-        c->code = force_get_integer (p);
-      else if (!strcmp (key, "CH"))
-        c->code = force_get_hex_code (p);
-      else
-        afm_error (p, _("CharMetrics line must start with C or CH"));
-      if (c->code < 0 || c->code > 65535)
-        c->code = -1;
-
-      if (c->code > p->max_code)
-        p->max_code = c->code;
-
-      p->afm->chars[p->afm->char_cnt++] = c;
-      if (c->code != -1)
-        p->afm->codes[c->code >> 8][c->code & 0xff] = c;
-
-      key = force_get_word (p);
-      while (!strcmp (key, ";"))
-        {
-          if (!get_word (p, &key))
-            break;
-
-          if (!strcmp (key, "N"))
-            c->name = force_get_word (p);
-          else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
-            c->width = force_get_number (p);
-          else if (!strcmp (key, "W") || !strcmp (key, "W0"))
-            {
-              c->width = force_get_number (p);
-              force_get_number (p);
-            }
-          else if (!strcmp (key, "B"))
-            {
-              int llx, lly, urx, ury;
-              llx = force_get_number (p);
-              lly = force_get_number (p);
-              urx = force_get_number (p);
-              ury = force_get_number (p);
-              c->ascent = MAX (0, ury);
-              c->descent = MAX (0, -lly);
-            }
-          else if (!strcmp (key, "L"))
-            {
-              struct parsing_ligature *ligature;
-              if (ligature_cnt == ligature_allocated)
-                ligatures = pool_2nrealloc (p->pool, ligatures,
-                                            &ligature_allocated,
-                                            sizeof *ligatures);
-              ligature = &ligatures[ligature_cnt++];
-              ligature->first = c;
-              ligature->successor = force_get_word (p);
-              ligature->ligature = force_get_word (p);
-            }
-          else
-            {
-              while (strcmp (key, ";"))
-                key = force_get_word (p);
-              continue;
-            }
-          if (!get_word (p, &key))
-            break;
-        }
-    }
-  skip_line (p);
-
-  for (i = 0; i < ligature_cnt; i++)
-    {
-      struct parsing_ligature *src = &ligatures[i];
-      struct afm_ligature *dst;
-      src->first->ligatures = pool_nrealloc (p->afm->pool,
-                                             src->first->ligatures,
-                                             src->first->ligature_cnt + 1,
-                                             sizeof *src->first->ligatures);
-      dst = &src->first->ligatures[src->first->ligature_cnt++];
-      dst->successor = get_char_by_name (p, src->successor);
-      dst->ligature = get_char_by_name (p, src->ligature);
-    }
-}
-
-/* Parses a StartKernPairs...EndKernPairs section in parser P. */
-static void
-parse_kern_pairs (struct parser *p)
-{
-  char *key;
-
-  skip_line (p);
-
-  do
-    {
-      struct afm_character *c1, *c2;
-      int adjust;
-
-      key = parse_key (p);
-      if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
-        {
-          c1 = get_char_by_name (p, force_get_word (p));
-          c2 = get_char_by_name (p, force_get_word (p));
-          adjust = force_get_number (p);
-          if (!strcmp (key, "KP"))
-            force_get_number (p);
-          add_kern_pair (p, c1, c2, adjust);
-        }
-      else if (!strcmp (key, "KPH"))
-        {
-          c1 = get_char_by_code (p->afm, force_get_hex_code (p));
-          c2 = get_char_by_code (p->afm, force_get_hex_code (p));
-          adjust = force_get_number (p);
-          force_get_number (p);
-          add_kern_pair (p, c1, c2, adjust);
-        }
-      else
-        skip_line (p);
-    }
-  while (strcmp (key, "EndKernPairs"));
-}
-
-/* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
-   to the metrics within parser P. */
-static void
-add_kern_pair (struct parser *p, struct afm_character *first,
-               struct afm_character *second, int adjust)
-{
-  struct afm_kern_pair *kp;
-
-  first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
-                                     first->kern_pair_cnt + 1,
-                                     sizeof *first->kern_pairs);
-  kp = &first->kern_pairs[first->kern_pair_cnt++];
-  kp->successor = second;
-  kp->adjust = adjust;
-}
-
-/* Returns the character with the given NAME with the metrics for
-   parser P.  Reports an error if no character has the given
-   name. */
-static struct afm_character *
-get_char_by_name (struct parser *p, const char *name)
-{
-  size_t i;
-
-  for (i = 0; i < p->afm->char_cnt; i++)
-    {
-      struct afm_character *c = p->afm->chars[i];
-      if (c->name != NULL && !strcmp (c->name, name))
-        return c;
-    }
-  afm_error (p, _("reference to unknown character \"%s\""), name);
-}
-
-/* Returns the character with the given CODE within AFM.
-   Returns a default character if the font doesn't have a
-   character with that code. */
-static struct afm_character *
-get_char_by_code (const struct afm *afm, int code_)
-{
-  uint16_t code = code_;
-  return afm->codes[code >> 8][code & 0xff];
-}
-\f
-/* Skips white space, except for new-lines, within parser P. */
-static int
-skip_spaces (struct parser *p)
-{
-  int c;
-  while (isspace (c = getc (p->file)) && c != '\n')
-    continue;
-  ungetc (c, p->file);
-  return c;
-}
-
-/* Parses a word at the beginning of a line.
-   Skips comments.
-   Reports an error if not at the beginning of a line. */
-static char *
-parse_key (struct parser *p)
-{
-  force_eol (p);
-  for (;;)
-    {
-      char *key;
-
-      do
-        {
-          p->line_number++;
-          getc (p->file);
-        }
-      while (skip_spaces (p) == '\n');
-
-      key = force_get_word (p);
-      if (strcmp (key, "Comment"))
-        return key;
-
-      skip_line (p);
-    }
-}
-
-/* Skips to the next line within parser P. */
-static void
-skip_line (struct parser *p)
-{
-  for (;;)
-    {
-      int c = getc (p->file);
-      if (c == EOF)
-        afm_error (p, _("expected end of file"));
-      if (c == '\n')
-        break;
-    }
-  ungetc ('\n', p->file);
-}
-
-/* Ensures that parser P is at the end of a line. */
-static void
-force_eol (struct parser *p)
-{
-  if (skip_spaces (p) != '\n')
-    afm_error (p, _("syntax error expecting end of line"));
-}
-
-/* Tries to read an integer into *INTEGER at the current position
-   in parser P.
-   Returns success. */
-static bool
-get_integer (struct parser *p, int *integer)
-{
-  int c = skip_spaces (p);
-  if (isdigit (c) || c == '-')
-    {
-      char *tail;
-      long tmp;
-
-      errno = 0;
-      tmp = strtol (force_get_word (p), &tail, 10);
-      if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX)
-        afm_error (p, _("number out of valid range"));
-      if (*tail != '\0')
-        afm_error (p, _("invalid numeric syntax"));
-      *integer = tmp;
-
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Returns an integer read from the current position in P.
-   Reports an error if unsuccessful. */
-static int
-force_get_integer (struct parser *p)
-{
-  int integer;
-  if (!get_integer (p, &integer))
-    afm_error (p, _("syntax error expecting integer"));
-  return integer;
-}
-
-/* Tries to read a floating-point number at the current position
-   in parser P.  Stores the number's integer part into *INTEGER.
-   Returns success. */
-static bool
-get_number (struct parser *p, int *integer)
-{
-  int c = skip_spaces (p);
-  if (c == '-' || c == '.' || isdigit (c))
-    {
-      char *tail;
-      double number;
-
-      errno = 0;
-      number = c_strtod (force_get_word (p), &tail);
-      if (errno == ERANGE || number < INT_MIN || number > INT_MAX)
-        afm_error (p, _("number out of valid range"));
-      if (*tail != '\0')
-        afm_error (p, _("invalid numeric syntax"));
-      *integer = number;
-
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Returns the integer part of a floating-point number read from
-   the current position in P.
-   Reports an error if unsuccessful. */
-static int
-force_get_number (struct parser *p)
-{
-  int integer;
-  if (!get_number (p, &integer))
-    afm_error (p, _("syntax error expecting number"));
-  return integer;
-}
-
-/* Tries to read an integer expressed in hexadecimal into
-   *INTEGER from P.
-   Returns success. */
-static bool
-get_hex_code (struct parser *p, int *integer)
-{
-  if (skip_spaces (p) == '<')
-    {
-      if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
-        afm_error (p, _("syntax error in hex constant"));
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Reads an integer expressed in hexadecimal and returns its
-   value.
-   Reports an error if unsuccessful. */
-static int
-force_get_hex_code (struct parser *p)
-{
-  int integer;
-  if (!get_hex_code (p, &integer))
-    afm_error (p, _("syntax error expecting hex constant"));
-  return integer;
-}
-
-/* Tries to read a word from P into *WORD.
-   The word is allocated in P's pool.
-   Returns success. */
-static bool
-get_word (struct parser *p, char **word)
-{
-  if (skip_spaces (p) != '\n')
-    {
-      struct string s;
-      int c;
-
-      ds_init_empty (&s);
-      while (!isspace (c = getc (p->file)) && c != EOF)
-        ds_put_char (&s, c);
-      ungetc (c, p->file);
-      *word = ds_cstr (&s);
-      pool_register (p->pool, free, *word);
-      return true;
-    }
-  else
-    {
-      *word = NULL;
-      return false;
-    }
-}
-
-/* Reads a word from P and returns it.
-   The word is allocated in P's pool.
-   Reports an error if unsuccessful. */
-static char *
-force_get_word (struct parser *p)
-{
-  char *word;
-  if (!get_word (p, &word))
-    afm_error (p, _("unexpected end of line"));
-  return word;
-}
-
-/* Reads a string, consisting of the remainder of the current
-   line, from P, and stores it in *STRING.
-   Leading and trailing spaces are removed.
-   The word is allocated in P's pool.
-   Returns true if a non-empty string was successfully read,
-   false otherwise. */
-static bool
-get_string (struct parser *p, char **string)
-{
-  struct string s = DS_EMPTY_INITIALIZER;
-
-  skip_spaces (p);
-  for (;;)
-    {
-      int c = getc (p->file);
-      if (c == EOF || c == '\n')
-        break;
-      ds_put_char (&s, c);
-    }
-  ungetc ('\n', p->file);
-  ds_rtrim (&s, ss_cstr (CC_SPACES));
-
-  if (!ds_is_empty (&s))
-    {
-      *string = ds_cstr (&s);
-      pool_register (p->pool, free, *string);
-      return true;
-    }
-  else
-    {
-      *string = NULL;
-      ds_destroy (&s);
-      return false;
-    }
-}
-
-/* Reads a string, consisting of the remainder of the current
-   line, from P, and returns it.
-   Leading and trailing spaces are removed.
-   The word is allocated in P's pool.
-   Reports an error if the string is empty. */
-static char *
-force_get_string (struct parser *p)
-{
-  char *string;
-  if (!get_string (p, &string))
-    afm_error (p, _("unexpected end of line expecting string"));
-  return string;
-}
-\f
-/* Closes AFM and frees its storage. */
-void
-afm_close (struct afm *afm)
-{
-  if (afm != NULL)
-    pool_destroy (afm->pool);
-}
-
-/* Returns the string that must be passed to the PostScript
-   "findfont" operator to obtain AFM's font. */
-const char *
-afm_get_findfont_name (const struct afm *afm)
-{
-  return afm->findfont_name;
-}
-
-/* Returns the ascent for AFM, that is, the font's height above
-   the baseline, in units of 1/1000 of the nominal font size. */
-int
-afm_get_ascent (const struct afm *afm)
-{
-  return afm->ascent;
-}
-
-/* Returns the descent for AFM, that is, the font's depth below
-   the baseline, in units of 1/1000 of the nominal font size. */
-int
-afm_get_descent (const struct afm *afm)
-{
-  return afm->descent;
-}
-
-/* Returns the character numbered CODE within AFM,
-   or a default character if the font has none. */
-const struct afm_character *
-afm_get_character (const struct afm *afm, int code)
-{
-  return get_char_by_code (afm, code);
-}
-
-/* Returns the ligature formed when FIRST is followed by SECOND,
-   or a null pointer if there is no such ligature. */
-const struct afm_character *
-afm_get_ligature (const struct afm_character *first,
-                  const struct afm_character *second)
-{
-  size_t i;
-
-  for (i = 0; i < first->ligature_cnt; i++)
-    if (first->ligatures[i].successor == second)
-      return first->ligatures[i].ligature;
-  return NULL;
-}
-
-/* Returns the pair kerning x-adjustment when FIRST is followed
-   by SECOND, or 0 if no pair kerning should be done for the
-   given pair of characters. */
-int
-afm_get_kern_adjustment (const struct afm_character *first,
-                         const struct afm_character *second)
-{
-  size_t i;
-
-  for (i = 0; i < first->kern_pair_cnt; i++)
-    if (first->kern_pairs[i].successor == second)
-      return first->kern_pairs[i].adjust;
-  return 0;
-}
-\f
-/* Encodes the N characters in S as a PostScript string in OUT,
-   using a single-byte encoding.
-   Returns the number of characters remaining after all those
-   that could be successfully encoded were. */
-static size_t
-encode_one_byte (const struct afm_character **s, size_t n,
-                 struct string *out)
-{
-  ds_put_char (out, '(');
-  for (; n > 0; s++, n--)
-    {
-      uint8_t code = (*s)->code;
-      if (code != (*s)->code)
-        break;
-
-      if (code == '(' || code == ')' || code == '\\')
-        ds_put_format (out, "\\%c", code);
-      else if (!c_isprint (code))
-        ds_put_format (out, "\\%03o", code);
-      else
-        ds_put_char (out, code);
-    }
-  ds_put_char (out, ')');
-  return n;
-}
-
-/* State of binary encoder for PostScript. */
-struct binary_encoder
-  {
-    struct string *out;         /* Output string. */
-    uint32_t b;                 /* Accumulated bytes for base-85 encoding. */
-    size_t n;                   /* Number of bytes in b (0...3). */
-  };
-
-/* Initializes encoder E for output to OUT. */
-static void
-binary_init (struct binary_encoder *e, struct string *out)
-{
-  e->out = out;
-  e->b = e->n = 0;
-}
-
-/* Returns the character that represents VALUE in ASCII85
-   encoding. */
-static int
-value_to_ascii85 (int value)
-{
-  assert (value >= 0 && value < 85);
-#if C_CTYPE_ASCII
-  return value + 33;
-#else
-  return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
-          "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
-#endif
-}
-
-/* Appends the first N characters of the ASCII85 representation
-   of B to string OUT. */
-static void
-append_ascii85_block (unsigned b, size_t n, struct string *out)
-{
-  char c[5];
-  int i;
-
-  for (i = 4; i >= 0; i--)
-    {
-      c[i] = value_to_ascii85 (b % 85);
-      b /= 85;
-    }
-  ds_put_substring (out, ss_buffer (c, n));
-}
-
-/* Encodes BYTE with encoder E. */
-static void
-binary_put (struct binary_encoder *e, uint8_t byte)
-{
-  e->b = (e->b << 8) | byte;
-  e->n++;
-  if (e->n % 4 == 0)
-    {
-      if (e->n == 4)
-        ds_put_cstr (e->out, "<~");
-
-      if (e->b != 0)
-        append_ascii85_block (e->b, 5, e->out);
-      else
-        ds_put_char (e->out, 'z');
-    }
-}
-
-/* Finishes up encoding with E. */
-static void
-binary_finish (struct binary_encoder *e)
-{
-  if (e->n >= 4)
-    {
-      /* We output at least one complete ASCII85 block.
-         Finish up. */
-      size_t n = e->n % 4;
-      if (n > 0)
-        append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out);
-      ds_put_cstr (e->out, "~>");
-    }
-  else if (e->n > 0)
-    {
-      /* It's cheaper (or at least the same cost) to encode this
-         string in hexadecimal. */
-      uint32_t b;
-      size_t i;
-
-      ds_put_cstr (e->out, "<");
-      b = e->b << 8 * (4 - e->n);
-      for (i = 0; i < e->n; i++)
-        {
-          ds_put_format (e->out, "%02x", b >> 24);
-          b <<= 8;
-        }
-      ds_put_cstr (e->out, ">");
-    }
-  else
-    {
-      /* Empty string. */
-      ds_put_cstr (e->out, "()");
-    }
-}
-
-/* Encodes the N characters in S into encoder E,
-   using a two-byte encoding.
-   Returns the number of characters remaining after all those
-   that could be successfully encoded were. */
-static size_t
-encode_two_byte (const struct afm_character **s, size_t n,
-                 struct binary_encoder *e)
-{
-  for (; n > 0; s++, n--)
-    {
-      uint16_t code = (*s)->code;
-      if (code != (*s)->code)
-        break;
-
-      binary_put (e, code >> 8);
-      binary_put (e, code);
-    }
-  return n;
-}
-
-/* Encodes the N characters in S into encoder E,
-   using an escape-based encoding with ESCAPE_CHAR as escape.
-   Returns the number of characters remaining after all those
-   that could be successfully encoded were. */
-static size_t
-encode_escape (const struct afm_character **s, size_t n,
-               unsigned char escape_char,
-               struct binary_encoder *e)
-{
-  uint8_t cur_font = 0;
-
-  for (; n > 0; s++, n--)
-    {
-      uint16_t code = (*s)->code;
-      uint8_t font_num = code >> 8;
-      uint8_t char_num = code & 0xff;
-      if (code != (*s)->code)
-        break;
-
-      if (font_num != cur_font)
-        {
-          if (font_num == escape_char)
-            break;
-          binary_put (e, escape_char);
-          binary_put (e, font_num);
-          cur_font = font_num;
-        }
-      binary_put (e, char_num);
-    }
-  return n;
-}
-
-/* Encodes the N characters in S into encoder E,
-   using an double escape-based encoding with ESCAPE_CHAR as
-   escape.
-   Returns the number of characters remaining after all those
-   that could be successfully encoded were. */
-static size_t
-encode_double_escape (const struct afm_character **s, size_t n,
-                      unsigned char escape_char,
-                      struct binary_encoder *e)
-{
-  unsigned cur_font = 0;
-
-  for (; n > 0; s++, n--)
-    {
-      unsigned font_num = (*s)->code >> 8;
-      uint8_t char_num = (*s)->code & 0xff;
-      if ((*s)->code & ~0x1ffff)
-        break;
-
-      if (font_num != cur_font)
-        {
-          if (font_num == (escape_char & 0xff))
-            break;
-          if (font_num >= 256)
-            binary_put (e, escape_char);
-          binary_put (e, escape_char);
-          binary_put (e, font_num & 0xff);
-          cur_font = font_num;
-        }
-      binary_put (e, char_num);
-    }
-  return n;
-}
-
-/* Encodes the N characters in S into encoder E,
-   using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
-   shift characters.
-   Returns the number of characters remaining after all those
-   that could be successfully encoded were. */
-static size_t
-encode_shift (const struct afm_character **s, size_t n,
-              unsigned char shift_in, unsigned char shift_out,
-              struct binary_encoder *e)
-{
-  unsigned cur_font = 0;
-
-  for (; n > 0; s++, n--)
-    {
-      int font_num = ((*s)->code & 0x100) != 0;
-      uint8_t char_num = (*s)->code & 0xff;
-      if ((*s)->code & ~0x1ff)
-        break;
-
-      if (font_num != cur_font)
-        {
-          binary_put (e, font_num ? shift_out : shift_in);
-          cur_font = font_num;
-        }
-      binary_put (e, char_num);
-    }
-  return n;
-}
-
-/* Encodes the N characters in S into a PostScript string in OUT,
-   according to AFM's character encoding.
-   Returns the number of characters successfully encoded,
-   which may be less than N if an unencodable character was
-   encountered. */
-size_t
-afm_encode_string (const struct afm *afm,
-                   const struct afm_character **s, size_t n,
-                   struct string *out)
-{
-  size_t initial_length = ds_length (out);
-  size_t chars_left;
-
-  if (afm->mapping == MAP_ONE_BYTE)
-    chars_left = encode_one_byte (s, n, out);
-  else
-    {
-      struct binary_encoder e;
-
-      binary_init (&e, out);
-      switch (afm->mapping)
-        {
-        case MAP_TWO_BYTE:
-          chars_left = encode_two_byte (s, n, &e);
-          break;
-
-        case MAP_ESCAPE:
-          chars_left = encode_escape (s, n, afm->escape_char, &e);
-          break;
-
-        case MAP_DOUBLE_ESCAPE:
-          chars_left = encode_double_escape (s, n, afm->escape_char, &e);
-          break;
-
-        case MAP_SHIFT:
-          chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
-          break;
-
-        default:
-          NOT_REACHED ();
-        }
-      binary_finish (&e);
-    }
-
-  if (chars_left == n)
-    ds_truncate (out, initial_length);
-  return n - chars_left;
-}
diff --git a/src/output/afm.h b/src/output/afm.h
deleted file mode 100644 (file)
index 6525af6..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 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 AFM_H
-#define AFM_H 1
-
-#include <stddef.h>
-#include <libpspp/str.h>
-
-/* Metrics for a single character.  */
-struct afm_character
-  {
-    int code;                   /* Non-negative character code, -1 if none. */
-    const char *name;           /* Character name, if any. */
-    int width;                 /* Width. */
-    int ascent;                        /* Height above baseline, never negative. */
-    int descent;                /* Depth below baseline, never negative. */
-
-    /* Pairwise kerning data for this character in the first
-       position, other characters in the second position. */
-    struct afm_kern_pair *kern_pairs;
-    size_t kern_pair_cnt;
-
-    /* Ligature data for this character in the first position,
-       other characters in the second position. */
-    struct afm_ligature *ligatures;
-    size_t ligature_cnt;
-  };
-
-struct afm *afm_open (const char *file_name);
-void afm_close (struct afm *);
-
-int afm_get_ascent (const struct afm *);
-int afm_get_descent (const struct afm *);
-const char *afm_get_findfont_name (const struct afm *);
-
-const struct afm_character *afm_get_character (const struct afm *,
-                                               int code);
-const struct afm_character *afm_get_ligature (const struct afm_character *,
-                                              const struct afm_character *);
-int afm_get_kern_adjustment (const struct afm_character *,
-                             const struct afm_character *);
-
-size_t afm_encode_string (const struct afm *,
-                          const struct afm_character **, size_t,
-                          struct string *);
-
-#endif /* afm.h */
index 29d7b76b2940d76dbc0af108827922785f8e71ce..c5f30816fb12efefae8865ea43de35158b59d13c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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
 #include <data/settings.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
-#include <libpspp/pool.h>
+#include <libpspp/message.h>
 #include <libpspp/start-date.h>
+#include <libpspp/string-map.h>
 #include <libpspp/version.h>
+#include <output/cairo.h>
+#include <output/chart-item-provider.h>
+#include <output/message-item.h>
+#include <output/options.h>
+#include <output/tab.h>
+#include <output/text-item.h>
+#include <output/driver-provider.h>
+#include <output/render.h>
+#include <output/table-item.h>
 
-#include "chart.h"
 #include "error.h"
 #include "minmax.h"
-#include "output.h"
 #include "xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* ASCII driver options: (defaults listed first)
-
-   output-file="pspp.list"
-   append=no|yes                If output-file exists, append to it?
-   chart-files="pspp-#.png"     Name used for charts.
-   chart-type=png               Format of charts (use "none" to disable).
-
-   paginate=on|off              Formfeeds are desired?
-   tab-width=8                  Width of a tab; 0 to not use tabs.
-
-   headers=on|off               Put headers at top of page?
-   emphasis=bold|underline|none Style to use for emphasis.
-   length=66|auto
-   width=79|auto
-   squeeze=off|on               Squeeze multiple newlines into exactly one.
-
-   top-margin=2
-   bottom-margin=2
-
-   box[x]="strng"               Sets box character X (X in base 4: 0-3333).
-   init="string"                Set initialization string.
- */
-
-/* Disable messages by failed range checks. */
-/*#define SUPPRESS_WARNINGS 1 */
+/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
+#define H TABLE_HORZ
+#define V TABLE_VERT
 
 /* Line styles bit shifts. */
 enum
@@ -76,16 +62,23 @@ enum
     LNS_COUNT = 256
   };
 
+static inline int
+make_box_index (int left, int right, int top, int bottom)
+{
+  return ((left << LNS_LEFT) | (right << LNS_RIGHT)
+          | (top << LNS_TOP) | (bottom << LNS_BOTTOM));
+}
+
 /* Character attributes. */
 #define ATTR_EMPHASIS   0x100   /* Bold-face. */
 #define ATTR_BOX        0x200   /* Line drawing character. */
 
 /* A line of text. */
-struct line
+struct ascii_line
   {
     unsigned short *chars;      /* Characters and attributes. */
-    int char_cnt;               /* Length. */
-    int char_cap;               /* Allocated bytes. */
+    int n_chars;                /* Length. */
+    int allocated_chars;        /* Allocated "chars" elements. */
   };
 
 /* How to emphasize text. */
@@ -96,24 +89,24 @@ enum emphasis_style
     EMPH_NONE                   /* No emphasis. */
   };
 
-/* ASCII output driver extension record. */
-struct ascii_driver_ext
+/* ASCII output driver. */
+struct ascii_driver
   {
-    struct pool *pool;
+    struct output_driver driver;
 
     /* User parameters. */
-    bool append;                /* Append if output-file already exists? */
+    bool append;                /* Append if output file already exists? */
     bool headers;              /* Print headers at top of page? */
     bool paginate;             /* Insert formfeeds? */
     bool squeeze_blank_lines;   /* Squeeze multiple blank lines into one? */
     enum emphasis_style emphasis; /* How to emphasize text. */
-    int tab_width;             /* Width of a tab; 0 not to use tabs. */
-    const char *chart_type;     /* Type of charts to output; NULL for none. */
-    const char *chart_file_name; /* Name of files used for charts. */
+    char *chart_file_name;      /* Name of files used for charts. */
 
+    int width;                  /* Page width. */
+    int length;                 /* Page length minus margins and header. */
     bool auto_width;            /* Use viewwidth as page width? */
     bool auto_length;           /* Use viewlength as page width? */
-    int page_length;           /* Page length before subtracting margins. */
+
     int top_margin;            /* Top margin in lines. */
     int bottom_margin;         /* Bottom margin in lines. */
 
@@ -121,820 +114,835 @@ struct ascii_driver_ext
     char *init;                 /* Device initialization string. */
 
     /* Internal state. */
+    char *command_name;
+    char *title;
+    char *subtitle;
     char *file_name;            /* Output file name. */
     FILE *file;                 /* Output file. */
-    bool reported_error;        /* Reported file open error? */
+    bool error;                 /* Output error? */
     int page_number;           /* Current page number. */
-    struct line *lines;         /* Page content. */
-    int line_cap;               /* Number of lines allocated. */
+    struct ascii_line *lines;   /* Page content. */
+    int allocated_lines;        /* Number of lines allocated. */
     int chart_cnt;              /* Number of charts so far. */
+    int y;
   };
 
-static void ascii_flush (struct outp_driver *);
-static int get_default_box_char (size_t idx);
-static bool update_page_size (struct outp_driver *, bool issue_error);
-static bool handle_option (struct outp_driver *this, const char *key,
-                           const struct string *val);
+static const struct output_driver_class ascii_driver_class;
 
-static bool
-ascii_open_driver (struct outp_driver *this, struct substring options)
+static void ascii_submit (struct output_driver *, const struct output_item *);
+
+static int vertical_margins (const struct ascii_driver *);
+
+static const char *get_default_box (int right, int bottom, int left, int top);
+static bool update_page_size (struct ascii_driver *, bool issue_error);
+static int parse_page_size (struct driver_option *);
+
+static void ascii_close_page (struct ascii_driver *);
+static bool ascii_open_page (struct ascii_driver *);
+
+static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2],
+                             enum render_line_style styles[TABLE_N_AXES][2]);
+static void ascii_measure_cell_width (void *, const struct table_cell *,
+                                      int *min, int *max);
+static int ascii_measure_cell_height (void *, const struct table_cell *,
+                                      int width);
+static void ascii_draw_cell (void *, const struct table_cell *,
+                             int bb[TABLE_N_AXES][2],
+                             int clip[TABLE_N_AXES][2]);
+
+static struct ascii_driver *
+ascii_driver_cast (struct output_driver *driver)
 {
-  struct ascii_driver_ext *x;
-  int i;
+  assert (driver->class == &ascii_driver_class);
+  return UP_CAST (driver, struct ascii_driver, driver);
+}
 
-  this->width = 79;
-  this->font_height = 1;
-  this->prop_em_width = 1;
-  this->fixed_width = 1;
-  for (i = 0; i < OUTP_L_COUNT; i++)
-    this->horiz_line_width[i] = this->vert_line_width[i] = i != OUTP_L_NONE;
-
-  this->ext = x = pool_create_container (struct ascii_driver_ext, pool);
-  x->append = false;
-  x->headers = true;
-  x->paginate = true;
-  x->squeeze_blank_lines = false;
-  x->emphasis = EMPH_BOLD;
-  x->tab_width = 8;
-  x->chart_file_name = pool_strdup (x->pool, "pspp-#.png");
-  x->chart_type = pool_strdup (x->pool, "png");
-  x->auto_width = false;
-  x->auto_length = false;
-  x->page_length = 66;
-  x->top_margin = 2;
-  x->bottom_margin = 2;
-  for (i = 0; i < LNS_COUNT; i++)
-    x->box[i] = NULL;
-  x->init = NULL;
-  x->file_name = pool_strdup (x->pool, "pspp.list");
-  x->file = NULL;
-  x->reported_error = false;
-  x->page_number = 0;
-  x->lines = NULL;
-  x->line_cap = 0;
-  x->chart_cnt = 0;
-
-  if (!outp_parse_options (options, handle_option, this))
-    goto error;
+static struct driver_option *
+opt (struct output_driver *d, struct string_map *options, const char *key,
+     const char *default_value)
+{
+  return driver_option_get (d, options, key, default_value);
+}
 
-  if (!update_page_size (this, true))
-    goto error;
+static struct output_driver *
+ascii_create (const char *file_name, enum settings_output_devices device_type,
+              struct string_map *o)
+{
+  struct output_driver *d;
+  struct ascii_driver *a;
+  int paper_length;
+  int right, bottom, left, top;
+
+  a = xzalloc (sizeof *a);
+  d = &a->driver;
+  output_driver_init (&a->driver, &ascii_driver_class, file_name, device_type);
+  a->append = parse_boolean (opt (d, o, "append", "false"));
+  a->headers = parse_boolean (opt (d, o, "headers", "false"));
+  a->paginate = parse_boolean (opt (d, o, "paginate", "false"));
+  a->squeeze_blank_lines = parse_boolean (opt (d, o, "squeeze", "true"));
+  a->emphasis = parse_enum (opt (d, o, "emphasis", "none"),
+                            "bold", EMPH_BOLD,
+                            "underline", EMPH_UNDERLINE,
+                            "none", EMPH_NONE,
+                            (char *) NULL);
+
+  a->chart_file_name = parse_chart_file_name (opt (d, o, "charts", file_name));
+
+  a->top_margin = parse_int (opt (d, o, "top-margin", "0"), 0, INT_MAX);
+  a->bottom_margin = parse_int (opt (d, o, "bottom-margin", "0"), 0, INT_MAX);
+
+  a->width = parse_page_size (opt (d, o, "width", "79"));
+  paper_length = parse_page_size (opt (d, o, "length", "66"));
+  a->auto_width = a->width < 0;
+  a->auto_length = paper_length < 0;
+  a->length = paper_length - vertical_margins (a);
+
+  for (right = 0; right < 4; right++)
+    for (bottom = 0; bottom < 4; bottom++)
+      for (left = 0; left < 4; left++)
+        for (top = 0; top < 4; top++)
+          {
+            int indx = make_box_index (left, right, top, bottom);
+            const char *default_value;
+            char name[16];
 
-  for (i = 0; i < LNS_COUNT; i++)
-    if (x->box[i] == NULL)
-      {
-        char s[2];
-        s[0] = get_default_box_char (i);
-        s[1] = '\0';
-        x->box[i] = pool_strdup (x->pool, s);
-      }
+            sprintf (name, "box[%d%d%d%d]", right, bottom, left, top);
+            default_value = get_default_box (right, bottom, left, top);
+            a->box[indx] = parse_string (opt (d, o, name, default_value));
+          }
+  a->init = parse_string (opt (d, o, "init", ""));
+
+  a->command_name = NULL;
+  a->title = xstrdup ("");
+  a->subtitle = xstrdup ("");
+  a->file_name = xstrdup (file_name);
+  a->file = NULL;
+  a->error = false;
+  a->page_number = 0;
+  a->lines = NULL;
+  a->allocated_lines = 0;
+  a->chart_cnt = 1;
+
+  if (!update_page_size (a, true))
+    goto error;
 
-  return true;
+  return d;
 
- error:
-  pool_destroy (x->pool);
-  return false;
+error:
+  output_driver_destroy (d);
+  return NULL;
 }
 
-static int
-get_default_box_char (size_t idx)
+static const char *
+get_default_box (int right, int bottom, int left, int top)
 {
-  /* Disassemble IDX into components. */
-  unsigned top = (idx >> LNS_TOP) & 3;
-  unsigned left = (idx >> LNS_LEFT) & 3;
-  unsigned bottom = (idx >> LNS_BOTTOM) & 3;
-  unsigned right = (idx >> LNS_RIGHT) & 3;
-
-  /* Reassemble components into nibbles in the order TLBR.
-     This makes it easy to read the case labels. */
-  unsigned value = (top << 12) | (left << 8) | (bottom << 4) | (right << 0);
-  switch (value)
+  switch ((top << 12) | (left << 8) | (bottom << 4) | (right << 0))
     {
     case 0x0000:
-      return ' ';
+      return " ";
 
     case 0x0100: case 0x0101: case 0x0001:
-      return '-';
+      return "-";
 
     case 0x1000: case 0x1010: case 0x0010:
-      return '|';
+      return "|";
 
     case 0x0300: case 0x0303: case 0x0003:
     case 0x0200: case 0x0202: case 0x0002:
-      return '=';
+      return "=";
 
     default:
-      return left > 1 || top > 1 || right > 1 || bottom > 1 ? '#' : '+';
+      return left > 1 || top > 1 || right > 1 || bottom > 1 ? "#" : "+";
     }
 }
 
+static int
+parse_page_size (struct driver_option *option)
+{
+  int dim = atol (option->default_value);
+
+  if (option->value != NULL)
+    {
+      if (!strcmp (option->value, "auto"))
+        dim = -1;
+      else
+        {
+          int value;
+          char *tail;
+
+          errno = 0;
+          value = strtol (option->value, &tail, 0);
+          if (dim >= 1 && errno != ERANGE && *tail == '\0')
+            dim = value;
+          else
+            error (0, 0, _("%s: %s must be positive integer or `auto'"),
+                   option->driver_name, option->name);
+        }
+    }
+
+  driver_option_destroy (option);
+
+  return dim;
+}
+
+static int
+vertical_margins (const struct ascii_driver *a)
+{
+  return a->top_margin + a->bottom_margin + (a->headers ? 3 : 0);
+}
+
 /* Re-calculates the page width and length based on settings,
    margins, and, if "auto" is set, the size of the user's
    terminal window or GUI output window. */
 static bool
-update_page_size (struct outp_driver *this, bool issue_error)
+update_page_size (struct ascii_driver *a, bool issue_error)
 {
-  struct ascii_driver_ext *x = this->ext;
-  int margins = x->top_margin + x->bottom_margin + 1 + (x->headers ? 3 : 0);
-
-  if (x->auto_width)
-    this->width = settings_get_viewwidth ();
-  if (x->auto_length)
-    x->page_length = settings_get_viewlength ();
+  enum { MIN_WIDTH = 6, MIN_LENGTH = 6 };
 
-  this->length = x->page_length - margins;
+  if (a->auto_width)
+    a->width = settings_get_viewwidth ();
+  if (a->auto_length)
+    a->length = settings_get_viewlength () - vertical_margins (a);
 
-  if (this->width < 59 || this->length < 15)
+  if (a->width < MIN_WIDTH || a->length < MIN_LENGTH)
     {
       if (issue_error)
         error (0, 0,
                _("ascii: page excluding margins and headers "
-                 "must be at least 59 characters wide by 15 lines long, but "
+                 "must be at least %d characters wide by %d lines long, but "
                  "as configured is only %d characters by %d lines"),
-             this->width, this->length);
-      if (this->width < 59)
-        this->width = 59;
-      if (this->length < 15)
-        {
-          this->length = 15;
-          x->page_length = this->length + margins;
-        }
+               MIN_WIDTH, MIN_LENGTH,
+               a->width, a->length);
+      if (a->width < MIN_WIDTH)
+        a->width = MIN_WIDTH;
+      if (a->length < MIN_LENGTH)
+        a->length = MIN_LENGTH;
       return false;
     }
 
   return true;
 }
 
-static bool
-ascii_close_driver (struct outp_driver *this)
+static void
+ascii_destroy (struct output_driver *driver)
 {
-  struct ascii_driver_ext *x = this->ext;
+  struct ascii_driver *a = ascii_driver_cast (driver);
+  int i;
 
-  ascii_flush (this);
-  pool_detach_file (x->pool, x->file);
-  pool_destroy (x->pool);
+  if (a->y > 0)
+    ascii_close_page (a);
 
-  return true;
+  if (a->file != NULL)
+    fn_close (a->file_name, a->file);
+  free (a->command_name);
+  free (a->title);
+  free (a->subtitle);
+  free (a->file_name);
+  free (a->chart_file_name);
+  for (i = 0; i < LNS_COUNT; i++)
+    free (a->box[i]);
+  free (a->init);
+  for (i = 0; i < a->allocated_lines; i++)
+    free (a->lines[i].chars);
+  free (a->lines);
+  free (a);
 }
 
-/* Generic option types. */
-enum
-  {
-    boolean_arg,
-    emphasis_arg,
-    nonneg_int_arg,
-    page_size_arg,
-    string_arg
-  };
-
-static const struct outp_option option_tab[] =
-  {
-    {"headers", boolean_arg, 0},
-    {"paginate", boolean_arg, 1},
-    {"squeeze", boolean_arg, 2},
-    {"append", boolean_arg, 3},
-
-    {"emphasis", emphasis_arg, 0},
-
-    {"length", page_size_arg, 0},
-    {"width", page_size_arg, 1},
-
-    {"top-margin", nonneg_int_arg, 0},
-    {"bottom-margin", nonneg_int_arg, 1},
-    {"tab-width", nonneg_int_arg, 2},
+static void
+ascii_flush (struct output_driver *driver)
+{
+  struct ascii_driver *a = ascii_driver_cast (driver);
+  if (a->y > 0)
+    {
+      ascii_close_page (a);
 
-    {"output-file", string_arg, 0},
-    {"chart-files", string_arg, 1},
-    {"chart-type", string_arg, 2},
-    {"init", string_arg, 3},
+      if (fn_close (a->file_name, a->file) != 0)
+        error (0, errno, _("ascii: closing output file \"%s\""),
+               a->file_name);
+      a->file = NULL;
+    }
+}
 
-    {NULL, 0, 0},
-  };
+static void
+ascii_init_caption_cell (const char *caption, struct table_cell *cell)
+{
+  cell->contents = caption;
+  cell->options = TAB_LEFT;
+  cell->destructor = NULL;
+}
 
-static bool
-handle_option (struct outp_driver *this, const char *key,
-               const struct string *val)
+static void
+ascii_output_table_item (struct ascii_driver *a,
+                         const struct table_item *table_item)
 {
-  struct ascii_driver_ext *x = this->ext;
-  int subcat;
-  const char *value;
+  const char *caption = table_item_get_caption (table_item);
+  struct render_params params;
+  struct render_page *page;
+  struct render_break x_break;
+  int caption_height;
+  int i;
+
+  update_page_size (a, false);
 
-  value = ds_cstr (val);
-  if (!strncmp (key, "box[", 4))
+  if (caption != NULL)
+    {
+      /* XXX doesn't do well with very large captions */
+      struct table_cell cell;
+      ascii_init_caption_cell (caption, &cell);
+      caption_height = ascii_measure_cell_height (a, &cell, a->width);
+    }
+  else
+    caption_height = 0;
+
+  params.draw_line = ascii_draw_line;
+  params.measure_cell_width = ascii_measure_cell_width;
+  params.measure_cell_height = ascii_measure_cell_height;
+  params.draw_cell = ascii_draw_cell,
+    params.aux = a;
+  params.size[H] = a->width;
+  params.size[V] = a->length - caption_height;
+  params.font_size[H] = 1;
+  params.font_size[V] = 1;
+  for (i = 0; i < RENDER_N_LINES; i++)
     {
-      char *tail;
-      int indx = strtol (&key[4], &tail, 4);
-      if (*tail != ']' || indx < 0 || indx > LNS_COUNT)
-       {
-         error (0, 0, _("ascii: bad index value for `box' key: syntax "
-                         "is box[INDEX], 0 <= INDEX < %d decimal, with INDEX "
-                         "expressed in base 4"),
-                 LNS_COUNT);
-         return false;
-       }
-      if (x->box[indx] != NULL)
-       error (0, 0, _("ascii: multiple values for %s"), key);
-      x->box[indx] = pool_strdup (x->pool, value);
-      return true;
+      int width = i == RENDER_LINE_NONE ? 0 : 1;
+      params.line_widths[H][i] = width;
+      params.line_widths[V][i] = width;
     }
 
-  switch (outp_match_keyword (key, option_tab, &subcat))
+  if (a->file == NULL && !ascii_open_page (a))
+    return;
+
+  page = render_page_create (&params, table_item_get_table (table_item));
+  for (render_break_init (&x_break, page, H);
+       render_break_has_next (&x_break); )
     {
-    case -1:
-      error (0, 0, _("ascii: unknown parameter `%s'"), key);
-      break;
-    case page_size_arg:
-      {
-       char *tail;
-       int arg;
+      struct render_page *x_slice;
+      struct render_break y_break;
 
-        if (ss_equals_case (ds_ss (val), ss_cstr ("auto")))
-          {
-            if (!(this->device & OUTP_DEV_SCREEN))
-              {
-                /* We only let `screen' devices have `auto'
-                   length or width because output to such devices
-                   is flushed before each new command.  Resizing
-                   a device in the middle of output seems like a
-                   bad idea. */
-                error (0, 0, _("ascii: only screen devices may have `auto' "
-                               "length or width"));
-              }
-            else if (subcat == 0)
-              x->auto_length = true;
-            else
-              x->auto_width = true;
-          }
-        else
-          {
-            errno = 0;
-            arg = strtol (value, &tail, 0);
-            if (arg < 1 || errno == ERANGE || *tail)
-              {
-                error (0, 0, _("ascii: positive integer required as "
-                               "`%s' value"),
-                       key);
-                break;
-              }
-            switch (subcat)
-              {
-              case 0:
-                x->page_length = arg;
-                break;
-              case 1:
-                this->width = arg;
-                break;
-              default:
-                NOT_REACHED ();
-              }
-          }
-      }
-      break;
-    case emphasis_arg:
-      if (!strcmp (value, "bold"))
-        x->emphasis = EMPH_BOLD;
-      else if (!strcmp (value, "underline"))
-        x->emphasis = EMPH_UNDERLINE;
-      else if (!strcmp (value, "none"))
-        x->emphasis = EMPH_NONE;
-      else
-        error (0, 0,
-               _("ascii: `emphasis' value must be `bold', "
-                 "`underline', or `none'"));
-      break;
-    case nonneg_int_arg:
-      {
-       char *tail;
-       int arg;
-
-       errno = 0;
-       arg = strtol (value, &tail, 0);
-       if (arg < 0 || errno == ERANGE || *tail)
-         {
-           error (0, 0,
-                   _("ascii: zero or positive integer required as `%s' value"),
-                   key);
-           break;
-         }
-       switch (subcat)
-         {
-         case 0:
-           x->top_margin = arg;
-           break;
-         case 1:
-           x->bottom_margin = arg;
-           break;
-         case 2:
-           x->tab_width = arg;
-           break;
-         default:
-           NOT_REACHED ();
-         }
-      }
-      break;
-    case boolean_arg:
-      {
-       bool setting;
-       if (!strcmp (value, "on") || !strcmp (value, "true")
-           || !strcmp (value, "yes") || atoi (value))
-         setting = true;
-       else if (!strcmp (value, "off") || !strcmp (value, "false")
-                || !strcmp (value, "no") || !strcmp (value, "0"))
-         setting = false;
-       else
-         {
-           error (0, 0, _("ascii: boolean value expected for `%s'"), key);
-           return false;
-         }
-       switch (subcat)
-         {
-         case 0:
-           x->headers = setting;
-           break;
-         case 1:
-           x->paginate = setting;
-           break;
-          case 2:
-            x->squeeze_blank_lines = setting;
-            break;
-          case 3:
-            x->append = setting;
-            break;
-         default:
-           NOT_REACHED ();
-         }
-      }
-      break;
-    case string_arg:
-      switch (subcat)
+      x_slice = render_break_next (&x_break, a->width);
+      for (render_break_init (&y_break, x_slice, V);
+           render_break_has_next (&y_break); )
         {
-        case 0:
-          x->file_name = pool_strdup (x->pool, value);
-          break;
-        case 1:
-          if (ds_find_char (val, '#') != SIZE_MAX)
-            x->chart_file_name = pool_strdup (x->pool, value);
-          else
-            error (0, 0, _("`chart-files' value must contain `#'"));
-          break;
-        case 2:
-          if (value[0] != '\0')
-            x->chart_type = pool_strdup (x->pool, value);
-          else
-            x->chart_type = NULL;
-          break;
-        case 3:
-          x->init = pool_strdup (x->pool, value);
-          break;
+          struct render_page *y_slice;
+          int space;
+
+          if (a->y > 0)
+            a->y++;
+
+          space = a->length - a->y - caption_height;
+          if (render_break_next_size (&y_break) > space)
+            {
+              assert (a->y > 0);
+              ascii_close_page (a);
+              if (!ascii_open_page (a))
+                return;
+              continue;
+            }
+
+          y_slice = render_break_next (&y_break, space);
+          if (caption_height)
+            {
+              struct table_cell cell;
+              int bb[TABLE_N_AXES][2];
+
+              ascii_init_caption_cell (caption, &cell);
+              bb[H][0] = 0;
+              bb[H][1] = a->width;
+              bb[V][0] = 0;
+              bb[V][1] = caption_height;
+              ascii_draw_cell (a, &cell, bb, bb);
+              a->y += caption_height;
+              caption_height = 0;
+            }
+          render_page_draw (y_slice);
+          a->y += render_page_get_size (y_slice, V);
+          render_page_unref (y_slice);
         }
-      break;
-    default:
-      NOT_REACHED ();
+      render_break_destroy (&y_break);
     }
+  render_break_destroy (&x_break);
+}
 
-  return true;
+static void
+ascii_output_text (struct ascii_driver *a, const char *text)
+{
+  struct table_item *table_item;
+
+  table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+  ascii_output_table_item (a, table_item);
+  table_item_unref (table_item);
 }
 
 static void
-ascii_open_page (struct outp_driver *this)
+ascii_submit (struct output_driver *driver,
+              const struct output_item *output_item)
 {
-  struct ascii_driver_ext *x = this->ext;
-  int i;
+  struct ascii_driver *a = ascii_driver_cast (driver);
 
-  update_page_size (this, false);
+  output_driver_track_current_command (output_item, &a->command_name);
 
-  if (x->file == NULL)
+  if (a->error)
+    return;
+
+  if (is_table_item (output_item))
+    ascii_output_table_item (a, to_table_item (output_item));
+  else if (is_chart_item (output_item) && a->chart_file_name != NULL)
     {
-      x->file = fn_open (x->file_name, x->append ? "a" : "w");
-      if (x->file != NULL)
-        {
-          pool_attach_file (x->pool, x->file);
-          if (x->init != NULL)
-            fputs (x->init, x->file);
-        }
-      else
+      struct chart_item *chart_item = to_chart_item (output_item);
+      char *file_name;
+
+      file_name = xr_draw_png_chart (chart_item, a->chart_file_name,
+                                     a->chart_cnt++);
+      if (file_name != NULL)
         {
-          /* Report the error to the user and complete
-             initialization.  If we do not finish initialization,
-             then calls to other driver functions will segfault
-             later.  It would be better to simply drop the driver
-             entirely, but we do not have a convenient mechanism
-             for this (yet). */
-          if (!x->reported_error)
-            error (0, errno, _("ascii: opening output file \"%s\""),
-                   x->file_name);
-          x->reported_error = true;
-        }
-    }
+          struct text_item *text_item;
 
-  x->page_number++;
+          text_item = text_item_create_format (
+            TEXT_ITEM_PARAGRAPH, _("See %s for a chart."), file_name);
 
-  if (this->length > x->line_cap)
-    {
-      x->lines = pool_nrealloc (x->pool,
-                                x->lines, this->length, sizeof *x->lines);
-      for (i = x->line_cap; i < this->length; i++)
-        {
-          struct line *line = &x->lines[i];
-          line->chars = NULL;
-          line->char_cap = 0;
+          ascii_submit (driver, &text_item->output_item);
+          text_item_unref (text_item);
+          free (file_name);
         }
-      x->line_cap = this->length;
     }
-
-  for (i = 0; i < this->length; i++)
-    x->lines[i].char_cnt = 0;
-}
-
-/* Ensures that at least the first LENGTH characters of line Y in
-   THIS driver identified X have been cleared out. */
-static inline void
-expand_line (struct outp_driver *this, int y, int length)
-{
-  struct ascii_driver_ext *ext = this->ext;
-  struct line *line = &ext->lines[y];
-  if (line->char_cnt < length)
+  else if (is_text_item (output_item))
     {
-      int x;
-      if (line->char_cap < length)
+      const struct text_item *text_item = to_text_item (output_item);
+      enum text_item_type type = text_item_get_type (text_item);
+      const char *text = text_item_get_text (text_item);
+
+      switch (type)
         {
-          line->char_cap = MIN (length * 2, this->width);
-          line->chars = pool_nrealloc (ext->pool,
-                                       line->chars,
-                                       line->char_cap, sizeof *line->chars);
+        case TEXT_ITEM_TITLE:
+          free (a->title);
+          a->title = xstrdup (text);
+          break;
+
+        case TEXT_ITEM_SUBTITLE:
+          free (a->subtitle);
+          a->subtitle = xstrdup (text);
+          break;
+
+        case TEXT_ITEM_COMMAND_CLOSE:
+          break;
+
+        case TEXT_ITEM_BLANK_LINE:
+          if (a->y > 0)
+            a->y++;
+          break;
+
+        case TEXT_ITEM_EJECT_PAGE:
+          if (a->y > 0)
+            ascii_close_page (a);
+          break;
+
+        default:
+          ascii_output_text (a, text);
+          break;
         }
-      for (x = line->char_cnt; x < length; x++)
-        line->chars[x] = ' ';
-      line->char_cnt = length;
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, a->command_name);
+      ascii_output_text (a, s);
+      free (s);
     }
 }
 
+const struct output_driver_factory txt_driver_factory =
+  { "txt", ascii_create };
+const struct output_driver_factory list_driver_factory =
+  { "list", ascii_create };
+
+static const struct output_driver_class ascii_driver_class =
+  {
+    "text",
+    ascii_destroy,
+    ascii_submit,
+    ascii_flush,
+  };
+\f
+enum wrap_mode
+  {
+    WRAP_WORD,
+    WRAP_CHAR,
+    WRAP_WORD_CHAR
+  };
+
+static void ascii_expand_line (struct ascii_driver *, int y, int length);
+static void ascii_layout_cell (struct ascii_driver *,
+                               const struct table_cell *,
+                               int bb[TABLE_N_AXES][2],
+                               int clip[TABLE_N_AXES][2], enum wrap_mode wrap,
+                               int *width, int *height);
+
 static void
-ascii_line (struct outp_driver *this,
-            int x0, int y0, int x1, int y1,
-            enum outp_line_style top, enum outp_line_style left,
-            enum outp_line_style bottom, enum outp_line_style right)
+ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2],
+                 enum render_line_style styles[TABLE_N_AXES][2])
 {
-  struct ascii_driver_ext *ext = this->ext;
-  int y;
-  unsigned short value;
+  struct ascii_driver *a = a_;
+  unsigned short int value;
+  int x1, y1;
+  int x, y;
 
-  assert (this->page_open);
-#if DEBUGGING
-  if (x0 < 0 || x1 > this->width || y0 < 0 || y1 > this->length)
+  /* Clip to the page. */
+  if (bb[H][0] >= a->width || bb[V][0] + a->y >= a->length)
+    return;
+  x1 = MIN (bb[H][1], a->width);
+  y1 = MIN (bb[V][1] + a->y, a->length);
+
+  /* Draw. */
+  value = ATTR_BOX | make_box_index (styles[V][0], styles[V][1],
+                                     styles[H][0], styles[H][1]);
+  for (y = bb[V][0] + a->y; y < y1; y++)
     {
-#if !SUPPRESS_WARNINGS
-      printf (_("ascii: bad line (%d,%d)-(%d,%d) out of (%d,%d)\n"),
-             x0, y0, x1, y1, this->width, this->length);
-#endif
-      return;
+      ascii_expand_line (a, y, x1);
+      for (x = bb[H][0]; x < x1; x++)
+        a->lines[y].chars[x] = value;
     }
-#endif
+}
 
-  value = ((left << LNS_LEFT) | (right << LNS_RIGHT)
-           | (top << LNS_TOP) | (bottom << LNS_BOTTOM) | ATTR_BOX);
-  for (y = y0; y < y1; y++)
+static void
+ascii_measure_cell_width (void *a_, const struct table_cell *cell,
+                          int *min_width, int *max_width)
+{
+  struct ascii_driver *a = a_;
+  int bb[TABLE_N_AXES][2];
+  int clip[TABLE_N_AXES][2];
+  int h;
+
+  bb[H][0] = 0;
+  bb[H][1] = INT_MAX;
+  bb[V][0] = 0;
+  bb[V][1] = INT_MAX;
+  clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
+  ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, max_width, &h);
+
+  if (strchr (cell->contents, ' '))
     {
-      int x;
-
-      expand_line (this, y, x1);
-      for (x = x0; x < x1; x++)
-        ext->lines[y].chars[x] = value;
+      bb[H][1] = 1;
+      ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, min_width, &h);
     }
+  else
+    *min_width = *max_width;
+}
+
+static int
+ascii_measure_cell_height (void *a_, const struct table_cell *cell, int width)
+{
+  struct ascii_driver *a = a_;
+  int bb[TABLE_N_AXES][2];
+  int clip[TABLE_N_AXES][2];
+  int w, h;
+
+  bb[H][0] = 0;
+  bb[H][1] = width;
+  bb[V][0] = 0;
+  bb[V][1] = INT_MAX;
+  clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
+  ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, &w, &h);
+  return h;
 }
 
 static void
-ascii_submit (struct outp_driver *this UNUSED, struct som_entity *s)
+ascii_draw_cell (void *a_, const struct table_cell *cell,
+                 int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2])
 {
-  extern struct som_table_class tab_table_class;
+  struct ascii_driver *a = a_;
+  int w, h;
 
-  assert (s->class == &tab_table_class);
-  assert (s->type == SOM_CHART);
+  ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, &w, &h);
 }
 
+/* Ensures that at least the first LENGTH characters of line Y in
+   ascii driver A have been cleared out. */
 static void
-text_draw (struct outp_driver *this,
-           enum outp_font font,
-           int x, int y,
-           enum outp_justification justification, int width,
-           const char *string, size_t length)
+ascii_expand_line (struct ascii_driver *a, int y, int length)
 {
-  struct ascii_driver_ext *ext = this->ext;
-  unsigned short attr = font == OUTP_EMPHASIS ? ATTR_EMPHASIS : 0;
+  struct ascii_line *line = &a->lines[y];
+  if (line->n_chars < length)
+    {
+      int x;
+      if (line->allocated_chars < length)
+        {
+          line->allocated_chars = MAX (length, MIN (length * 2, a->width));
+          line->chars = xnrealloc (line->chars, line->allocated_chars,
+                                   sizeof *line->chars);
+        }
+      for (x = line->n_chars; x < length; x++)
+        line->chars[x] = ' ';
+      line->n_chars = length;
+    }
+}
 
-  int line_len;
+static void
+text_draw (struct ascii_driver *a, const struct table_cell *cell,
+           int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
+           int y, const char *string, int n)
+{
+  int x0 = MAX (0, clip[H][0]);
+  int y0 = MAX (0, clip[V][0] + a->y);
+  int x1 = clip[H][1];
+  int y1 = MIN (a->length, clip[V][1] + a->y);
+  int x;
+
+  y += a->y;
+  if (y < y0 || y >= y1)
+    return;
 
-  switch (justification)
+  switch (cell->options & TAB_ALIGNMENT)
     {
-    case OUTP_LEFT:
+    case TAB_LEFT:
+      x = bb[H][0];
       break;
-    case OUTP_CENTER:
-      x += (width - length + 1) / 2;
+    case TAB_CENTER:
+      x = (bb[H][0] + bb[H][1] - n + 1) / 2;
       break;
-    case OUTP_RIGHT:
-      x += width - length;
+    case TAB_RIGHT:
+      x = bb[H][1] - n;
       break;
     default:
       NOT_REACHED ();
     }
 
-  if (y >= this->length || x >= this->width)
-    return;
-
-  if (x + length > this->width)
-    length = this->width - x;
+  if (x0 > x)
+    {
+      n -= x0 - x;
+      if (n <= 0)
+        return;
+      string += x0 - x;
+      x = x0;
+    }
+  if (x + n >= x1)
+    n = x1 - x;
 
-  line_len = x + length;
+  if (n > 0)
+    {
+      int attr = cell->options & TAB_EMPH ? ATTR_EMPHASIS : 0;
+      size_t i;
 
-  expand_line (this, y, line_len);
-  while (length-- > 0)
-    ext->lines[y].chars[x++] = *string++ | attr;
+      ascii_expand_line (a, y, x + n);
+      for (i = 0; i < n; i++)
+        a->lines[y].chars[x + i] = string[i] | attr;
+    }
 }
 
-/* Divides the text T->S into lines of width T->H.  Sets *WIDTH
-   to the maximum width of a line and *HEIGHT to the number of
-   lines, if those arguments are non-null.  Actually draws the
-   text if DRAW is true. */
 static void
-delineate (struct outp_driver *this, const struct outp_text *text, bool draw,
-           int *width, int *height)
+ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell,
+                   int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
+                   enum wrap_mode wrap, int *width, int *height)
 {
-  int max_width;
-  int height_left;
-
-  const char *cp = ss_data (text->string);
+  size_t length = strlen (cell->contents);
+  int y, pos;
 
-  max_width = 0;
-  height_left = text->v;
-
-  while (height_left > 0)
+  *width = 0;
+  pos = 0;
+  for (y = bb[V][0]; y < bb[V][1] && pos < length; y++)
     {
-      size_t chars_left;
+      const char *line = &cell->contents[pos];
+      const char *new_line;
       size_t line_len;
-      const char *end;
-
-      /* Initially the line is up to text->h characters long. */
-      chars_left = ss_end (text->string) - cp;
-      if (chars_left == 0)
-        break;
-      line_len = MIN (chars_left, text->h);
 
-      /* A new-line terminates the line prematurely. */
-      end = memchr (cp, '\n', line_len);
-      if (end != NULL)
-        line_len = end - cp;
+      /* Find line length without considering word wrap. */
+      line_len = MIN (bb[H][1] - bb[H][0], length - pos);
+      new_line = memchr (line, '\n', line_len);
+      if (new_line != NULL)
+        line_len = new_line - line;
 
-      /* Don't cut off words if it can be avoided. */
-      if (cp + line_len < ss_end (text->string))
+      /* Word wrap. */
+      if (pos + line_len < length && wrap != WRAP_CHAR)
         {
           size_t space_len = line_len;
-          while (space_len > 0 && !isspace ((unsigned char) cp[space_len]))
+          while (space_len > 0 && !isspace ((unsigned char) line[space_len]))
             space_len--;
           if (space_len > 0)
             line_len = space_len;
+          else if (wrap == WRAP_WORD)
+            {
+              while (pos + line_len < length
+                     && !isspace ((unsigned char) line[line_len]))
+                line_len++;
+            }
         }
+      if (line_len > *width)
+        *width = line_len;
 
       /* Draw text. */
-      if (draw)
-        text_draw (this,
-                   text->font,
-                   text->x, text->y + (text->v - height_left),
-                   text->justification, text->h,
-                   cp, line_len);
-
-      /* Update. */
-      height_left--;
-      if (line_len > max_width)
-        max_width = line_len;
+      text_draw (a, cell, bb, clip, y, line, line_len);
 
       /* Next line. */
-      cp += line_len;
-      if (cp < ss_end (text->string) && isspace ((unsigned char) *cp))
-        cp++;
+      pos += line_len;
+      if (pos < length && isspace ((unsigned char) cell->contents[pos]))
+        pos++;
     }
-
-  if (width != NULL)
-    *width = max_width;
-  if (height != NULL)
-    *height = text->v - height_left;
+  *height = y - bb[V][0];
 }
+\f
+/* ascii_close_page () and support routines. */
 
-static void
-ascii_text_metrics (struct outp_driver *this, const struct outp_text *t,
-                    int *width, int *height)
+static bool
+ascii_open_page (struct ascii_driver *a)
 {
-  delineate (this, t, false, width, height);
-}
+  int i;
 
-static void
-ascii_text_draw (struct outp_driver *this, const struct outp_text *t)
-{
-  assert (this->page_open);
-  delineate (this, t, true, NULL, NULL);
+  if (a->error)
+    return false;
+
+  if (a->file == NULL)
+    {
+      a->file = fn_open (a->file_name, a->append ? "a" : "w");
+      if (a->file != NULL)
+        {
+          if (a->init != NULL)
+            fputs (a->init, a->file);
+        }
+      else
+        {
+          error (0, errno, _("ascii: opening output file \"%s\""),
+                 a->file_name);
+          a->error = true;
+          return false;
+        }
+    }
+
+  a->page_number++;
+
+  if (a->length > a->allocated_lines)
+    {
+      a->lines = xnrealloc (a->lines, a->length, sizeof *a->lines);
+      for (i = a->allocated_lines; i < a->length; i++)
+        {
+          struct ascii_line *line = &a->lines[i];
+          line->chars = NULL;
+          line->allocated_chars = 0;
+        }
+      a->allocated_lines = a->length;
+    }
+
+  for (i = 0; i < a->length; i++)
+    a->lines[i].n_chars = 0;
+
+  return true;
 }
-\f
-/* ascii_close_page () and support routines. */
 
-/* Writes the LENGTH characters in S to OUT.  */
+/* Writes LINE to A's output file.  */
 static void
-output_line (struct outp_driver *this, const struct line *line,
-             struct string *out)
+output_line (struct ascii_driver *a, const struct ascii_line *line)
 {
-  struct ascii_driver_ext *ext = this->ext;
-  const unsigned short *s = line->chars;
   size_t length;
+  size_t i;
 
-  for (length = line->char_cnt; length-- > 0; s++)
-    if (*s & ATTR_BOX)
-      ds_put_cstr (out, ext->box[*s & 0xff]);
-    else
-      {
-        if (*s & ATTR_EMPHASIS)
-          {
-            if (ext->emphasis == EMPH_BOLD)
-              {
-                ds_put_char (out, *s);
-                ds_put_char (out, '\b');
-              }
-            else if (ext->emphasis == EMPH_UNDERLINE)
-              ds_put_cstr (out, "_\b");
-          }
-        ds_put_char (out, *s);
-      }
+  length = line->n_chars;
+  while (length > 0 && line->chars[length - 1] == ' ')
+    length--;
+
+  for (i = 0; i < length; i++)
+    {
+      int attribute = line->chars[i] & (ATTR_BOX | ATTR_EMPHASIS);
+      int ch = line->chars[i] & ~(ATTR_BOX | ATTR_EMPHASIS);
+
+      switch (attribute)
+        {
+        case ATTR_BOX:
+          fputs (a->box[ch], a->file);
+          break;
+
+        case ATTR_EMPHASIS:
+          if (a->emphasis == EMPH_BOLD)
+            fprintf (a->file, "%c\b%c", ch, ch);
+          else if (a->emphasis == EMPH_UNDERLINE)
+            fprintf (a->file, "_\b%c", ch);
+          else
+            putc (ch, a->file);
+          break;
+
+        default:
+          putc (ch, a->file);
+          break;
+        }
+    }
+
+  putc ('\n', a->file);
 }
 
 static void
-append_lr_justified (struct string *out, int width,
-                     const char *left, const char *right)
+output_title_line (FILE *out, int width, const char *left, const char *right)
 {
-  ds_put_char_multiple (out, ' ', width);
+  struct string s = DS_EMPTY_INITIALIZER;
+  ds_put_char_multiple (&s, ' ', width);
   if (left != NULL)
     {
       size_t length = MIN (strlen (left), width);
-      memcpy (ds_end (out) - width, left, length);
+      memcpy (ds_end (&s) - width, left, length);
     }
   if (right != NULL)
     {
       size_t length = MIN (strlen (right), width);
-      memcpy (ds_end (out) - length, right, length);
+      memcpy (ds_end (&s) - length, right, length);
     }
-  ds_put_char (out, '\n');
-}
-
-static void
-dump_output (struct outp_driver *this, struct string *out)
-{
-  struct ascii_driver_ext *x = this->ext;
-  fwrite (ds_data (out), ds_length (out), 1, x->file);
-  ds_clear (out);
+  ds_put_char (&s, '\n');
+  fputs (ds_cstr (&s), out);
+  ds_destroy (&s);
 }
 
 static void
-ascii_close_page (struct outp_driver *this)
+ascii_close_page (struct ascii_driver *a)
 {
-  struct ascii_driver_ext *x = this->ext;
-  struct string out;
-  int line_num;
+  bool any_blank;
+  int i, y;
 
-  if (x->file == NULL)
+  a->y = 0;
+  if (a->file == NULL)
     return;
 
-  ds_init_empty (&out);
+  if (!a->top_margin && !a->bottom_margin && a->squeeze_blank_lines
+      && !a->paginate && a->page_number > 1)
+    putc ('\n', a->file);
 
-  ds_put_char_multiple (&out, '\n', x->top_margin);
-  if (x->headers)
+  for (i = 0; i < a->top_margin; i++)
+    putc ('\n', a->file);
+  if (a->headers)
     {
       char *r1, *r2;
 
-      r1 = xasprintf (_("%s - Page %d"), get_start_date (), x->page_number);
+      r1 = xasprintf (_("%s - Page %d"), get_start_date (), a->page_number);
       r2 = xasprintf ("%s - %s" , version, host_system);
 
-      append_lr_justified (&out, this->width, outp_title, r1);
-      append_lr_justified (&out, this->width, outp_subtitle, r2);
-      ds_put_char (&out, '\n');
+      output_title_line (a->file, a->width, a->title, r1);
+      output_title_line (a->file, a->width, a->subtitle, r2);
+      putc ('\n', a->file);
 
       free (r1);
       free (r2);
     }
-  dump_output (this, &out);
 
-  for (line_num = 0; line_num < this->length; line_num++)
+  any_blank = false;
+  for (y = 0; y < a->allocated_lines; y++)
     {
+      struct ascii_line *line = &a->lines[y];
 
-      /* Squeeze multiple blank lines into a single blank line if
-         requested. */
-      if (x->squeeze_blank_lines)
+      if (a->squeeze_blank_lines && y > 0 && line->n_chars == 0)
+        any_blank = true;
+      else
         {
-          if (line_num >= x->line_cap)
-            break;
-          if (line_num > 0
-              && x->lines[line_num].char_cnt == 0
-              && x->lines[line_num - 1].char_cnt == 0)
-            continue;
-        }
-
-      if (line_num < x->line_cap)
-        output_line (this, &x->lines[line_num], &out);
-      ds_put_char (&out, '\n');
-      dump_output (this, &out);
-    }
-
-  ds_put_char_multiple (&out, '\n', x->bottom_margin);
-  if (x->paginate)
-    ds_put_char (&out, '\f');
+          if (any_blank)
+            {
+              putc ('\n', a->file);
+              any_blank = false;
+            }
 
-  dump_output (this, &out);
-  ds_destroy (&out);
-}
-
-/* Flushes all output to the user and lets the user deal with it.
-   This is applied only to output drivers that are designated as
-   "screen" drivers that the user is interacting with in real
-   time. */
-static void
-ascii_flush (struct outp_driver *this)
-{
-  struct ascii_driver_ext *x = this->ext;
-  if (x->file != NULL)
-    {
-      if (fn_close (x->file_name, x->file) != 0)
-        error (0, errno, _("ascii: closing output file \"%s\""),
-               x->file_name);
-      pool_detach_file (x->pool, x->file);
-      x->file = NULL;
-    }
-}
-
-static void
-ascii_chart_initialise (struct outp_driver *this, struct chart *ch)
-{
-  struct ascii_driver_ext *x = this->ext;
-  struct outp_text t;
-  char *text;
-
-  if (x->chart_type == NULL)
-    return;
-
-  /* Initialize chart. */
-  chart_init_separate (ch, x->chart_type, x->chart_file_name, ++x->chart_cnt);
-  if (ch->file_name == NULL)
-    return;
-
-  /* Mention chart in output.
-     First advance current position. */
-  if (!this->page_open)
-    outp_open_page (this);
-  else
-    {
-      this->cp_y++;
-      if (this->cp_y >= this->length)
-        {
-          outp_close_page (this);
-          outp_open_page (this);
+          output_line (a, line);
         }
     }
-
-  /* Then write the text. */
-  text = xasprintf ("See %s for a chart.", ch->file_name);
-  t.font = OUTP_FIXED;
-  t.justification = OUTP_LEFT;
-  t.string = ss_cstr (text);
-  t.h = this->width;
-  t.v = 1;
-  t.x = 0;
-  t.y = this->cp_y;
-  ascii_text_draw (this, &t);
-  this->cp_y++;
-
-  free (text);
-}
-
-static void
-ascii_chart_finalise (struct outp_driver *this, struct chart *ch)
-{
-  struct ascii_driver_ext *x = this->ext;
-  if (x->chart_type != NULL)
-    chart_finalise_separate (ch);
+  if (!a->squeeze_blank_lines)
+    for (y = a->allocated_lines; y < a->length; y++)
+      putc ('\n', a->file);
+
+  for (i = 0; i < a->bottom_margin; i++)
+    putc ('\n', a->file);
+  if (a->paginate)
+    putc ('\f', a->file);
 }
-
-const struct outp_class ascii_class =
-{
-  "ascii",
-  0,
-
-  ascii_open_driver,
-  ascii_close_driver,
-
-  ascii_open_page,
-  ascii_close_page,
-  ascii_flush,
-
-  ascii_submit,
-
-  ascii_line,
-  ascii_text_metrics,
-  ascii_text_draw,
-
-  ascii_chart_initialise,
-  ascii_chart_finalise
-};
index ec92c559e044723180977db31ca43708c7f637bd..259f3b0e6a95afd8e8d04f3e9e6801b1ff1a477d 100644 (file)
@@ -1,35 +1,72 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-
-include $(top_srcdir)/src/output/charts/automake.mk
-
 noinst_LTLIBRARIES += src/output/liboutput.la 
 
-output_sources = \
-       src/output/afm.c \
-       src/output/afm.h \
+src_output_liboutput_la_CPPFLAGS = $(LIBXML2_CFLAGS) $(AM_CPPFLAGS) 
+
+src_output_liboutput_la_SOURCES = \
        src/output/ascii.c \
+       src/output/chart-item-provider.h \
+       src/output/chart-item.c \
+       src/output/chart-item.h \
+       src/output/charts/boxplot.c \
+       src/output/charts/boxplot.h \
+       src/output/charts/np-plot.c \
+       src/output/charts/np-plot.h \
+       src/output/charts/piechart.c \
+       src/output/charts/piechart.h \
+       src/output/charts/plot-hist.c \
+       src/output/charts/plot-hist.h \
+       src/output/charts/roc-chart.c \
+       src/output/charts/roc-chart.h \
+       src/output/charts/scree.c \
+       src/output/charts/scree.h \
+       src/output/csv.c \
+       src/output/driver-provider.h \
+       src/output/driver.c \
+       src/output/driver.h \
        src/output/html.c \
-       src/output/htmlP.h \
        src/output/journal.c \
        src/output/journal.h \
-       src/output/output.c \
-       src/output/output.h \
-       src/output/postscript.c \
-       src/output/manager.c \
-       src/output/manager.h \
-       src/output/chart.h \
-       src/output/table.c src/output/table.h
-
-
-if WITHCHARTS
-src_output_liboutput_la_SOURCES = $(output_sources) src/output/chart.c
-
-EXTRA_DIST += src/output/dummy-chart.c
-else
-src_output_liboutput_la_SOURCES = $(output_sources) src/output/dummy-chart.c
-
-EXTRA_DIST += src/output/chart.c
+       src/output/measure.c \
+       src/output/measure.h \
+       src/output/message-item.c \
+       src/output/message-item.h \
+       src/output/msglog.c \
+       src/output/msglog.h \
+       src/output/odt.c \
+       src/output/options.c \
+       src/output/options.h \
+       src/output/output-item-provider.h \
+       src/output/output-item.c \
+       src/output/output-item.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 \
+       src/output/table-provider.h \
+       src/output/table-select.c \
+       src/output/table-transpose.c \
+       src/output/table.c \
+       src/output/table.h \
+       src/output/text-item.c \
+       src/output/text-item.h
+if HAVE_CAIRO
+src_output_liboutput_la_SOURCES += \
+       src/output/cairo-chart.c \
+       src/output/cairo-chart.h \
+       src/output/cairo.c \
+       src/output/cairo.h \
+       src/output/charts/boxplot-cairo.c \
+       src/output/charts/np-plot-cairo.c \
+       src/output/charts/piechart-cairo.c \
+       src/output/charts/plot-hist-cairo.c \
+       src/output/charts/roc-chart-cairo.c \
+       src/output/charts/scree-cairo.c
 endif
 
 EXTRA_DIST += src/output/OChangeLog
diff --git a/src/output/cairo-chart.c b/src/output/cairo-chart.c
new file mode 100644 (file)
index 0000000..b5e17e0
--- /dev/null
@@ -0,0 +1,499 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2009 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/cairo-chart.h"
+
+#include <assert.h>
+#include <cairo/cairo.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "math/chart-geometry.h"
+#include "output/cairo.h"
+#include "output/chart-item.h"
+
+#include "error.h"
+#include "xalloc.h"
+#include "xvasprintf.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+void
+xrchart_geometry_init (cairo_t *cr, struct xrchart_geometry *geom,
+                       double width, double length)
+{
+  /* Set default chartetry. */
+  geom->data_top = 0.900 * length;
+  geom->data_right = 0.800 * width;
+  geom->data_bottom = 0.120 * length;
+  geom->data_left = 0.150 * width;
+  geom->abscissa_top = 0.070 * length;
+  geom->ordinate_right = 0.120 * width;
+  geom->title_bottom = 0.920 * length;
+  geom->legend_left = 0.810 * width;
+  geom->legend_right = width;
+  geom->font_size = 15.0;
+  geom->in_path = false;
+  geom->dataset = NULL;
+  geom->n_datasets = 0;
+
+  geom->fill_colour.red = 255;
+  geom->fill_colour.green = 0;
+  geom->fill_colour.blue = 0;
+
+  cairo_set_line_width (cr, 1.0);
+
+  cairo_rectangle (cr, geom->data_left, geom->data_bottom,
+                   geom->data_right - geom->data_left,
+                   geom->data_top - geom->data_bottom);
+  cairo_stroke (cr);
+}
+
+void
+xrchart_geometry_free (cairo_t *cr UNUSED, struct xrchart_geometry *geom)
+{
+  int i;
+
+  for (i = 0 ; i < geom->n_datasets; ++i)
+    free (geom->dataset[i]);
+  free (geom->dataset);
+}
+
+#if ! PANGO_VERSION_CHECK (2, 22, 0)
+int pango_layout_get_baseline (PangoLayout    *layout);
+
+/* Shamelessly copied from the pango source */
+int
+pango_layout_get_baseline (PangoLayout    *layout)
+{
+  int baseline;
+
+  /* XXX this is so inefficient */
+  PangoLayoutIter *iter = pango_layout_get_iter (layout);
+  baseline = pango_layout_iter_get_baseline (iter);
+  pango_layout_iter_free (iter);
+
+  return baseline;
+}
+#endif
+
+
+
+const struct xrchart_colour data_colour[XRCHART_N_COLOURS] =
+  {
+    { 165, 42, 42 },            /* brown */
+    { 255, 0, 0 },              /* red */
+    { 255, 165, 0 },            /* orange */
+    { 255, 255, 0 },            /* yellow */
+    { 0, 255, 0 },              /* green */
+    { 0, 0, 255 },              /* blue */
+    { 238, 130, 238 },          /* violet */
+    { 190, 190, 190 },          /* grey */
+    { 255, 192, 203 },          /* pink */
+  };
+
+void
+xrchart_draw_marker (cairo_t *cr, double x, double y,
+                     enum xrmarker_type marker, double size)
+{
+  cairo_save (cr);
+  cairo_translate (cr, x, y);
+  cairo_scale (cr, size / 2.0, size / 2.0);
+  cairo_set_line_width (cr, cairo_get_line_width (cr) / (size / 2.0));
+  switch (marker)
+    {
+    case XRMARKER_CIRCLE:
+      cairo_arc (cr, 0, 0, 1.0, 0, 2 * M_PI);
+      cairo_stroke (cr);
+      break;
+
+    case XRMARKER_ASTERISK:
+      cairo_move_to (cr, 0, -1.0); /* | */
+      cairo_line_to (cr, 0, 1.0);
+      cairo_move_to (cr, -M_SQRT1_2, -M_SQRT1_2); /* / */
+      cairo_line_to (cr, M_SQRT1_2, M_SQRT1_2);
+      cairo_move_to (cr, -M_SQRT1_2, M_SQRT1_2); /* \ */
+      cairo_line_to (cr, M_SQRT1_2, -M_SQRT1_2);
+      cairo_stroke (cr);
+      break;
+
+    case XRMARKER_SQUARE:
+      cairo_rectangle (cr, -1.0, -1.0, 2.0, 2.0);
+      cairo_stroke (cr);
+      break;
+    }
+  cairo_restore (cr);
+}
+
+void
+xrchart_label (cairo_t *cr, int horz_justify, int vert_justify,
+               double font_size, const char *string)
+{
+  PangoFontDescription *desc;
+  PangoLayout *layout;
+  double x, y;
+
+  desc = pango_font_description_from_string ("sans serif");
+  if (desc == NULL)
+    {
+      cairo_new_path (cr);
+      return;
+    }
+  pango_font_description_set_absolute_size (desc, font_size * PANGO_SCALE);
+
+  cairo_save (cr);
+  cairo_get_current_point (cr, &x, &y);
+  cairo_translate (cr, x, y);
+  cairo_move_to (cr, 0, 0);
+  cairo_scale (cr, 1.0, -1.0);
+
+  layout = pango_cairo_create_layout (cr);
+  pango_layout_set_font_description (layout, desc);
+  pango_layout_set_text (layout, string, -1);
+  if (horz_justify != 'l')
+    {
+      int width_pango;
+      double width;
+
+      pango_layout_get_size (layout, &width_pango, NULL);
+      width = (double) width_pango / PANGO_SCALE;
+      if (horz_justify == 'r')
+        cairo_rel_move_to (cr, -width, 0);
+      else
+        cairo_rel_move_to (cr, -width / 2.0, 0);
+    }
+  if (vert_justify == 'x')
+    {
+      int baseline_pango = pango_layout_get_baseline (layout);
+      double baseline = (double) baseline_pango / PANGO_SCALE;
+      cairo_rel_move_to (cr, 0, -baseline);
+    }
+  else if (vert_justify != 't')
+    {
+      int height_pango;
+      double height;
+
+      pango_layout_get_size (layout, NULL, &height_pango);
+      height = (double) height_pango / PANGO_SCALE;
+      if (vert_justify == 'b')
+        cairo_rel_move_to (cr, 0, -height);
+      else if (vert_justify == 'c')
+        cairo_rel_move_to (cr, 0, -height / 2.0);
+    }
+  pango_cairo_show_layout (cr, layout);
+  g_object_unref (layout);
+
+  cairo_restore (cr);
+
+  cairo_new_path (cr);
+
+  pango_font_description_free (desc);
+}
+
+/* Draw a tick mark at position
+   If label is non zero, then print it at the tick mark
+*/
+void
+draw_tick (cairo_t *cr, const struct xrchart_geometry *geom,
+           enum tick_orientation orientation,
+           double position,
+           const char *label, ...)
+{
+  const int tickSize = 10;
+  double x, y;
+
+  cairo_move_to (cr, geom->data_left, geom->data_bottom);
+
+  if (orientation == TICK_ABSCISSA)
+    {
+      cairo_rel_move_to (cr, position, 0);
+      cairo_rel_line_to (cr, 0, -tickSize);
+    }
+  else if (orientation == TICK_ORDINATE)
+    {
+      cairo_rel_move_to (cr, 0, position);
+      cairo_rel_line_to (cr, -tickSize, 0);
+    }
+  else
+    NOT_REACHED ();
+  cairo_get_current_point (cr, &x, &y);
+
+  cairo_stroke (cr);
+
+  if (label != NULL)
+    {
+      va_list ap;
+      char *s;
+
+      cairo_move_to (cr, x, y);
+
+      va_start (ap, label);
+      s = xvasprintf (label, ap);
+      if (orientation == TICK_ABSCISSA)
+        xrchart_label (cr, 'c', 't', geom->font_size, s);
+      else if (orientation == TICK_ORDINATE)
+        {
+          if (fabs (position) < DBL_EPSILON)
+           cairo_rel_move_to (cr, 0, 10);
+          xrchart_label (cr, 'r', 'c', geom->font_size, s);
+        }
+      free (s);
+      va_end (ap);
+    }
+}
+
+
+/* Write the title on a chart*/
+void
+xrchart_write_title (cairo_t *cr, const struct xrchart_geometry *geom,
+                   const char *title, ...)
+{
+  va_list ap;
+  char *s;
+
+  cairo_save (cr);
+  cairo_move_to (cr, geom->data_left, geom->title_bottom);
+
+  va_start(ap, title);
+  s = xvasprintf (title, ap);
+  xrchart_label (cr, 'l', 'x', geom->font_size * 1.5, s);
+  free (s);
+  va_end (ap);
+
+  cairo_restore (cr);
+}
+
+
+/* Set the scale for the abscissa */
+void
+xrchart_write_xscale (cairo_t *cr, struct xrchart_geometry *geom,
+                    double min, double max, int ticks)
+{
+  double x;
+
+  const double tick_interval =
+    chart_rounded_tick ((max - min) / (double) ticks);
+
+  geom->x_max = ceil (max / tick_interval) * tick_interval;
+  geom->x_min = floor (min / tick_interval) * tick_interval;
+  geom->abscissa_scale = fabs(geom->data_right - geom->data_left) /
+    fabs(geom->x_max - geom->x_min);
+
+  for (x = geom->x_min; x <= geom->x_max; x += tick_interval)
+    draw_tick (cr, geom, TICK_ABSCISSA,
+               (x - geom->x_min) * geom->abscissa_scale, "%g", x);
+}
+
+
+/* Set the scale for the ordinate */
+void
+xrchart_write_yscale (cairo_t *cr, struct xrchart_geometry *geom,
+                    double smin, double smax, int ticks)
+{
+  double y;
+
+  const double tick_interval =
+    chart_rounded_tick ((smax - smin) / (double) ticks);
+
+  geom->y_max = ceil (smax / tick_interval) * tick_interval;
+  geom->y_min = floor (smin / tick_interval) * tick_interval;
+
+  geom->ordinate_scale =
+    (fabs (geom->data_top - geom->data_bottom)
+     / fabs (geom->y_max - geom->y_min));
+
+  for (y = geom->y_min; y <= geom->y_max; y += tick_interval)
+    draw_tick (cr, geom, TICK_ORDINATE,
+              (y - geom->y_min) * geom->ordinate_scale, "%g", y);
+}
+
+/* Write the abscissa label */
+void
+xrchart_write_xlabel (cairo_t *cr, const struct xrchart_geometry *geom,
+                    const char *label)
+{
+  cairo_move_to (cr, geom->data_left, geom->abscissa_top);
+  xrchart_label (cr, 'l', 't', geom->font_size, label);
+}
+
+/* Write the ordinate label */
+void
+xrchart_write_ylabel (cairo_t *cr, const struct xrchart_geometry *geom,
+                    const char *label)
+{
+  cairo_save (cr);
+  cairo_translate (cr, -geom->data_bottom, -geom->ordinate_right);
+  cairo_move_to (cr, 0, 0);
+  cairo_rotate (cr, M_PI / 2.0);
+  xrchart_label (cr, 'l', 'x', geom->font_size, label);
+  cairo_restore (cr);
+}
+
+
+void
+xrchart_write_legend (cairo_t *cr, const struct xrchart_geometry *geom)
+{
+  int i;
+  const int vstep = geom->font_size * 2;
+  const int xpad = 10;
+  const int ypad = 10;
+  const int swatch = 20;
+  const int legend_top = geom->data_top;
+  const int legend_bottom = legend_top -
+    (vstep * geom->n_datasets + 2 * ypad );
+
+  cairo_save (cr);
+
+  cairo_rectangle (cr, geom->legend_left, legend_top,
+                   geom->legend_right - xpad - geom->legend_left,
+                   legend_bottom - legend_top);
+  cairo_stroke (cr);
+
+  for (i = 0 ; i < geom->n_datasets ; ++i )
+    {
+      const int ypos = legend_top - vstep * (i + 1);
+      const int xpos = geom->legend_left + xpad;
+      const struct xrchart_colour *colour;
+
+      cairo_move_to (cr, xpos, ypos);
+
+      cairo_save (cr);
+      colour = &data_colour [ i % XRCHART_N_COLOURS];
+      cairo_set_source_rgb (cr,
+                            colour->red / 255.0,
+                            colour->green / 255.0,
+                            colour->blue / 255.0);
+      cairo_rectangle (cr, xpos, ypos, swatch, swatch);
+      cairo_fill_preserve (cr);
+      cairo_stroke (cr);
+      cairo_restore (cr);
+
+      cairo_move_to (cr, xpos + swatch * 1.5, ypos);
+      xrchart_label (cr, 'l', 'x', geom->font_size, geom->dataset[i]);
+    }
+
+  cairo_restore (cr);
+}
+
+/* Start a new vector called NAME */
+void
+xrchart_vector_start (cairo_t *cr, struct xrchart_geometry *geom, const char *name)
+{
+  const struct xrchart_colour *colour;
+
+  cairo_save (cr);
+
+  colour = &data_colour[geom->n_datasets % XRCHART_N_COLOURS];
+  cairo_set_source_rgb (cr,
+                        colour->red / 255.0,
+                        colour->green / 255.0,
+                        colour->blue / 255.0);
+
+  geom->n_datasets++;
+  geom->dataset = xrealloc (geom->dataset,
+                            geom->n_datasets * sizeof (*geom->dataset));
+
+  geom->dataset[geom->n_datasets - 1] = strdup (name);
+}
+
+/* Plot a data point */
+void
+xrchart_datum (cairo_t *cr, const struct xrchart_geometry *geom,
+             int dataset UNUSED, double x, double y)
+{
+  double x_pos = (x - geom->x_min) * geom->abscissa_scale + geom->data_left;
+  double y_pos = (y - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
+
+  xrchart_draw_marker (cr, x_pos, y_pos, XRMARKER_SQUARE, 15);
+}
+
+void
+xrchart_vector_end (cairo_t *cr, struct xrchart_geometry *geom)
+{
+  cairo_stroke (cr);
+  cairo_restore (cr);
+  geom->in_path = false;
+}
+
+/* Plot a data point */
+void
+xrchart_vector (cairo_t *cr, struct xrchart_geometry *geom, double x, double y)
+{
+  const double x_pos =
+    (x - geom->x_min) * geom->abscissa_scale + geom->data_left ;
+
+  const double y_pos =
+    (y - geom->y_min) * geom->ordinate_scale + geom->data_bottom ;
+
+  if (geom->in_path)
+    cairo_line_to (cr, x_pos, y_pos);
+  else
+    {
+      cairo_move_to (cr, x_pos, y_pos);
+      geom->in_path = true;
+    }
+}
+
+
+
+/* Draw a line with slope SLOPE and intercept INTERCEPT.
+   between the points limit1 and limit2.
+   If lim_dim is XRCHART_DIM_Y then the limit{1,2} are on the
+   y axis otherwise the x axis
+*/
+void
+xrchart_line(cairo_t *cr, const struct xrchart_geometry *geom,
+           double slope, double intercept,
+          double limit1, double limit2, enum xrchart_dim lim_dim)
+{
+  double x1, y1;
+  double x2, y2;
+
+  if ( lim_dim == XRCHART_DIM_Y )
+    {
+      x1 = ( limit1 - intercept ) / slope;
+      x2 = ( limit2 - intercept ) / slope;
+      y1 = limit1;
+      y2 = limit2;
+    }
+  else
+    {
+      x1 = limit1;
+      x2 = limit2;
+      y1 = slope * x1 + intercept;
+      y2 = slope * x2 + intercept;
+    }
+
+  y1 = (y1 - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
+  y2 = (y2 - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
+  x1 = (x1 - geom->x_min) * geom->abscissa_scale + geom->data_left;
+  x2 = (x2 - geom->x_min) * geom->abscissa_scale + geom->data_left;
+
+  cairo_move_to (cr, x1, y1);
+  cairo_line_to (cr, x2, y2);
+  cairo_stroke (cr);
+}
diff --git a/src/output/cairo-chart.h b/src/output/cairo-chart.h
new file mode 100644 (file)
index 0000000..041a169
--- /dev/null
@@ -0,0 +1,165 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_CAIRO_CHART_H
+#define OUTPUT_CAIRO_CHART_H 1
+
+#include <cairo/cairo.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "libpspp/compiler.h"
+
+struct chart_item;
+
+struct xrchart_colour
+  {
+    uint8_t red;
+    uint8_t green;
+    uint8_t blue;
+  };
+
+/* The geometry of a chart. */
+struct xrchart_geometry
+  {
+    int data_top;
+    int data_right;
+    int data_bottom;
+    int data_left;
+
+    int abscissa_top;
+
+    int ordinate_right;
+
+    int title_bottom;
+
+    /* Legend. */
+    int legend_left;
+    int legend_right;
+    char **dataset;
+    int n_datasets;
+
+    /* Default font size for the plot. */
+    double font_size;
+
+    struct xrchart_colour fill_colour;
+
+    /* Stuff particular to cartesians and boxplots. */
+    double ordinate_scale;
+    double abscissa_scale;
+    double x_min;
+    double x_max;
+    double y_min;
+    double y_max;
+    bool in_path;
+  };
+
+void xrchart_geometry_init (cairo_t *, struct xrchart_geometry *,
+                            double width, double length);
+void xrchart_geometry_free (cairo_t *, struct xrchart_geometry *);
+
+#define XRCHART_N_COLOURS 9
+extern const struct xrchart_colour data_colour[];
+
+enum tick_orientation
+  {
+    TICK_ABSCISSA=0,
+    TICK_ORDINATE
+  };
+
+enum xrmarker_type
+  {
+    XRMARKER_CIRCLE,              /* Hollow circle. */
+    XRMARKER_ASTERISK,            /* Asterisk (*). */
+    XRMARKER_SQUARE               /* Hollow square. */
+  };
+
+void xrchart_draw_marker (cairo_t *, double x, double y, enum xrmarker_type,
+                          double size);
+
+void xrchart_label (cairo_t *, int horz_justify, int vert_justify,
+                    double font_size, const char *);
+
+/* Draw a tick mark at position
+   If label is non zero, then print it at the tick mark
+*/
+void draw_tick (cairo_t *, const struct xrchart_geometry *,
+                enum tick_orientation orientation, double position,
+                const char *label, ...)
+  PRINTF_FORMAT (5, 6);
+
+
+/* Write the title on a chart*/
+void xrchart_write_title (cairo_t *, const struct xrchart_geometry *,
+                          const char *title, ...)
+  PRINTF_FORMAT (3, 4);
+
+/* Set the scale for the abscissa */
+void xrchart_write_xscale (cairo_t *, struct xrchart_geometry *,
+                           double min, double max, int ticks);
+
+
+/* Set the scale for the ordinate */
+void xrchart_write_yscale (cairo_t *, struct xrchart_geometry *,
+                           double smin, double smax, int ticks);
+
+void xrchart_write_xlabel (cairo_t *, const struct xrchart_geometry *,
+                           const char *label) ;
+
+/* Write the ordinate label */
+void xrchart_write_ylabel (cairo_t *, const struct xrchart_geometry *,
+                           const char *label);
+
+void xrchart_write_legend (cairo_t *, const struct xrchart_geometry *);
+
+enum xrchart_dim
+  {
+    XRCHART_DIM_X,
+    XRCHART_DIM_Y
+  };
+
+void xrchart_vector_start (cairo_t *, struct xrchart_geometry *,
+                           const char *name);
+void xrchart_vector_end (cairo_t *, struct xrchart_geometry *);
+void xrchart_vector (cairo_t *, struct xrchart_geometry *, double x, double y);
+
+/* Plot a data point */
+void xrchart_datum (cairo_t *, const struct xrchart_geometry *,
+                    int dataset UNUSED, double x, double y);
+
+/* Draw a line with slope SLOPE and intercept INTERCEPT.
+   between the points limit1 and limit2.
+   If lim_dim is XRCHART_DIM_Y then the limit{1,2} are on the
+   y axis otherwise the x axis
+*/
+void xrchart_line (cairo_t *, const struct xrchart_geometry *,
+                   double slope, double intercept,
+                   double limit1, double limit2, enum xrchart_dim lim_dim);
+
+/* Drawing various kinds of charts. */
+void xrchart_draw_boxplot (const struct chart_item *, cairo_t *,
+                           struct xrchart_geometry *);
+void xrchart_draw_roc (const struct chart_item *, cairo_t *,
+                       struct xrchart_geometry *);
+void xrchart_draw_piechart (const struct chart_item *, cairo_t *,
+                            struct xrchart_geometry *);
+void xrchart_draw_histogram (const struct chart_item *, cairo_t *,
+                             struct xrchart_geometry *);
+void xrchart_draw_np_plot (const struct chart_item *, cairo_t *,
+                           struct xrchart_geometry *);
+void xrchart_draw_scree (const struct chart_item *, cairo_t *,
+                         struct xrchart_geometry *);
+
+#endif /* output/cairo-chart.h */
diff --git a/src/output/cairo.c b/src/output/cairo.c
new file mode 100644 (file)
index 0000000..4e8b1d3
--- /dev/null
@@ -0,0 +1,1129 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009, 2010 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/cairo.h>
+
+#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
+#include <libpspp/message.h>
+#include <libpspp/start-date.h>
+#include <libpspp/str.h>
+#include <libpspp/string-map.h>
+#include <libpspp/version.h>
+#include <output/cairo-chart.h>
+#include <output/chart-item-provider.h>
+#include <output/charts/boxplot.h>
+#include <output/charts/np-plot.h>
+#include <output/charts/piechart.h>
+#include <output/charts/plot-hist.h>
+#include <output/charts/roc-chart.h>
+#include <output/charts/scree.h>
+#include <output/driver-provider.h>
+#include <output/message-item.h>
+#include <output/options.h>
+#include <output/render.h>
+#include <output/tab.h>
+#include <output/table-item.h>
+#include <output/table.h>
+#include <output/text-item.h>
+
+#include <cairo/cairo-pdf.h>
+#include <cairo/cairo-ps.h>
+#include <cairo/cairo-svg.h>
+#include <cairo/cairo.h>
+#include <pango/pango-font.h>
+#include <pango/pango-layout.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "intprops.h"
+#include "minmax.h"
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
+#define H TABLE_HORZ
+#define V TABLE_VERT
+
+/* Measurements as we present to the rest of PSPP. */
+#define XR_POINT PANGO_SCALE
+#define XR_INCH (XR_POINT * 72)
+
+/* Conversions to and from points. */
+static double
+xr_to_pt (int x)
+{
+  return x / (double) XR_POINT;
+}
+
+/* Output types. */
+enum xr_output_type
+  {
+    XR_PDF,
+    XR_PS,
+    XR_SVG
+  };
+
+/* Cairo fonts. */
+enum xr_font_type
+  {
+    XR_FONT_PROPORTIONAL,
+    XR_FONT_EMPHASIS,
+    XR_FONT_FIXED,
+    XR_N_FONTS
+  };
+
+/* A font for use with Cairo. */
+struct xr_font
+  {
+    char *string;
+    PangoFontDescription *desc;
+    PangoLayout *layout;
+    PangoFontMetrics *metrics;
+  };
+
+/* Cairo output driver. */
+struct xr_driver
+  {
+    struct output_driver driver;
+
+    /* User parameters. */
+    bool headers;               /* Draw headers at top of page? */
+
+    struct xr_font fonts[XR_N_FONTS];
+    int font_height;            /* In XR units. */
+
+    int width;                  /* Page width minus margins. */
+    int length;                 /* Page length minus margins and header. */
+
+    int left_margin;            /* Left margin in XR units. */
+    int right_margin;           /* Right margin in XR units. */
+    int top_margin;             /* Top margin in XR units. */
+    int bottom_margin;          /* Bottom margin in XR units. */
+
+    int line_gutter;           /* Space around lines. */
+    int line_space;            /* Space between lines. */
+    int line_width;            /* Width of lines. */
+
+    enum xr_output_type file_type; /* Type of output file. */
+
+    /* Internal state. */
+    struct render_params *params;
+    char *command_name;
+    char *title;
+    char *subtitle;
+    cairo_t *cairo;
+    int page_number;           /* Current page number. */
+    int y;
+  };
+
+static const struct output_driver_class cairo_driver_class;
+
+static void xr_show_page (struct xr_driver *);
+static void draw_headers (struct xr_driver *);
+
+static bool load_font (struct xr_driver *, struct xr_font *);
+static void free_font (struct xr_font *);
+
+static void xr_draw_line (void *, int bb[TABLE_N_AXES][2],
+                          enum render_line_style styles[TABLE_N_AXES][2]);
+static void xr_measure_cell_width (void *, const struct table_cell *,
+                                   int *min, int *max);
+static int xr_measure_cell_height (void *, const struct table_cell *,
+                                   int width);
+static void xr_draw_cell (void *, const struct table_cell *,
+                          int bb[TABLE_N_AXES][2],
+                          int clip[TABLE_N_AXES][2]);
+\f
+/* Driver initialization. */
+
+static struct xr_driver *
+xr_driver_cast (struct output_driver *driver)
+{
+  assert (driver->class == &cairo_driver_class);
+  return UP_CAST (driver, struct xr_driver, driver);
+}
+
+static struct driver_option *
+opt (struct output_driver *d, struct string_map *options, const char *key,
+     const char *default_value)
+{
+  return driver_option_get (d, options, key, default_value);
+}
+
+static struct xr_driver *
+xr_allocate (const char *name, int device_type, struct string_map *o)
+{
+  struct output_driver *d;
+  struct xr_driver *xr;
+
+  xr = xzalloc (sizeof *xr);
+  d = &xr->driver;
+  output_driver_init (d, &cairo_driver_class, name, device_type);
+  xr->headers = true;
+  xr->font_height = XR_POINT * 10;
+  xr->fonts[XR_FONT_FIXED].string
+    = parse_string (opt (d, o, "fixed-font", "monospace"));
+  xr->fonts[XR_FONT_PROPORTIONAL].string
+    = parse_string (opt (d, o, "prop-font", "serif"));
+  xr->fonts[XR_FONT_EMPHASIS].string
+    = parse_string (opt (d, o, "emph-font", "serif italic"));
+  xr->line_gutter = XR_POINT;
+  xr->line_space = XR_POINT;
+  xr->line_width = XR_POINT / 2;
+  xr->page_number = 1;
+
+  return xr;
+}
+
+static bool
+xr_set_cairo (struct xr_driver *xr, cairo_t *cairo)
+{
+  int i;
+
+  xr->cairo = cairo;
+
+  cairo_set_line_width (xr->cairo, xr_to_pt (xr->line_width));
+
+  for (i = 0; i < XR_N_FONTS; i++)
+    if (!load_font (xr, &xr->fonts[i]))
+      return false;
+
+  if (xr->params == NULL)
+    {
+      int single_width, double_width;
+
+      xr->params = xmalloc (sizeof *xr->params);
+      xr->params->draw_line = xr_draw_line;
+      xr->params->measure_cell_width = xr_measure_cell_width;
+      xr->params->measure_cell_height = xr_measure_cell_height;
+      xr->params->draw_cell = xr_draw_cell;
+      xr->params->aux = xr;
+      xr->params->size[H] = xr->width;
+      xr->params->size[V] = xr->length;
+      xr->params->font_size[H] = xr->font_height / 2; /* XXX */
+      xr->params->font_size[V] = xr->font_height;
+
+      single_width = 2 * xr->line_gutter + xr->line_width;
+      double_width = 2 * xr->line_gutter + xr->line_space + 2 * xr->line_width;
+      for (i = 0; i < TABLE_N_AXES; i++)
+        {
+          xr->params->line_widths[i][RENDER_LINE_NONE] = 0;
+          xr->params->line_widths[i][RENDER_LINE_SINGLE] = single_width;
+          xr->params->line_widths[i][RENDER_LINE_DOUBLE] = double_width;
+        }
+    }
+
+  return true;
+}
+
+static struct output_driver *
+xr_create (const char *file_name, enum settings_output_devices device_type,
+           struct string_map *o, enum xr_output_type file_type)
+{
+  enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
+  struct output_driver *d;
+  struct xr_driver *xr;
+  cairo_surface_t *surface;
+  cairo_status_t status;
+  double width_pt, length_pt;
+  int paper_width, paper_length;
+
+  xr = xr_allocate (file_name, device_type, o);
+  d = &xr->driver;
+
+  xr->headers = parse_boolean (opt (d, o, "headers", "true"));
+
+  xr->file_type = file_type;
+
+  parse_paper_size (opt (d, o, "paper-size", ""), &paper_width, &paper_length);
+  xr->left_margin = parse_dimension (opt (d, o, "left-margin", ".5in"));
+  xr->right_margin = parse_dimension (opt (d, o, "right-margin", ".5in"));
+  xr->top_margin = parse_dimension (opt (d, o, "top-margin", ".5in"));
+  xr->bottom_margin = parse_dimension (opt (d, o, "bottom-margin", ".5in"));
+
+  if (xr->headers)
+    xr->top_margin += 3 * xr->font_height;
+  xr->width = paper_width - xr->left_margin - xr->right_margin;
+  xr->length = paper_length - xr->top_margin - xr->bottom_margin;
+
+  width_pt = paper_width / 1000.0;
+  length_pt = paper_length / 1000.0;
+  if (xr->file_type == XR_PDF)
+    surface = cairo_pdf_surface_create (file_name, width_pt, length_pt);
+  else if (xr->file_type == XR_PS)
+    surface = cairo_ps_surface_create (file_name, width_pt, length_pt);
+  else if (xr->file_type == XR_SVG)
+    surface = cairo_svg_surface_create (file_name, width_pt, length_pt);
+  else
+    NOT_REACHED ();
+
+  status = cairo_surface_status (surface);
+  if (status != CAIRO_STATUS_SUCCESS)
+    {
+      error (0, 0, _("opening output file \"%s\": %s"),
+             file_name, cairo_status_to_string (status));
+      cairo_surface_destroy (surface);
+      goto error;
+    }
+
+  xr->cairo = cairo_create (surface);
+  cairo_surface_destroy (surface);
+
+  cairo_translate (xr->cairo,
+                   xr_to_pt (xr->left_margin),
+                   xr_to_pt (xr->top_margin));
+
+  if (!xr_set_cairo (xr, xr->cairo))
+    goto error;
+
+  if (xr->width / (xr->font_height / 2) < MIN_WIDTH)
+    {
+      error (0, 0, _("The defined page is not wide enough to hold at least %d "
+                     "characters in the default font.  In fact, there's only "
+                     "room for %d characters."),
+             MIN_WIDTH,
+             xr->width / (xr->font_height / 2));
+      goto error;
+    }
+
+  if (xr->length / xr->font_height < MIN_LENGTH)
+    {
+      error (0, 0, _("The defined page is not long "
+                     "enough to hold margins and headers, plus least %d "
+                     "lines of the default fonts.  In fact, there's only "
+                     "room for %d lines."),
+             MIN_LENGTH,
+             xr->length / xr->font_height);
+      goto error;
+    }
+
+  return &xr->driver;
+
+ error:
+  output_driver_destroy (&xr->driver);
+  return NULL;
+}
+
+static struct output_driver *
+xr_pdf_create (const char *file_name, enum settings_output_devices device_type,
+               struct string_map *o)
+{
+  return xr_create (file_name, device_type, o, XR_PDF);
+}
+
+static struct output_driver *
+xr_ps_create (const char *file_name, enum settings_output_devices device_type,
+               struct string_map *o)
+{
+  return xr_create (file_name, device_type, o, XR_PS);
+}
+
+static struct output_driver *
+xr_svg_create (const char *file_name, enum settings_output_devices device_type,
+               struct string_map *o)
+{
+  return xr_create (file_name, device_type, o, XR_SVG);
+}
+
+static void
+xr_destroy (struct output_driver *driver)
+{
+  struct xr_driver *xr = xr_driver_cast (driver);
+  size_t i;
+
+  if (xr->cairo != NULL)
+    {
+      cairo_status_t status;
+
+      if (xr->y > 0)
+        xr_show_page (xr);
+
+      cairo_surface_finish (cairo_get_target (xr->cairo));
+      status = cairo_status (xr->cairo);
+      if (status != CAIRO_STATUS_SUCCESS)
+        error (0, 0, _("error drawing output for %s driver: %s"),
+               output_driver_get_name (driver),
+               cairo_status_to_string (status));
+      cairo_destroy (xr->cairo);
+    }
+
+  free (xr->command_name);
+  for (i = 0; i < XR_N_FONTS; i++)
+    free_font (&xr->fonts[i]);
+  free (xr->params);
+  free (xr);
+}
+
+static void
+xr_flush (struct output_driver *driver)
+{
+  struct xr_driver *xr = xr_driver_cast (driver);
+
+  cairo_surface_flush (cairo_get_target (xr->cairo));
+}
+
+static void
+xr_init_caption_cell (const char *caption, struct table_cell *cell)
+{
+  cell->contents = caption;
+  cell->options = TAB_LEFT;
+  cell->destructor = NULL;
+}
+
+static struct render_page *
+xr_render_table_item (struct xr_driver *xr, const struct table_item *item,
+                      int *caption_heightp)
+{
+  const char *caption = table_item_get_caption (item);
+
+  if (caption != NULL)
+    {
+      /* XXX doesn't do well with very large captions */
+      struct table_cell cell;
+      xr_init_caption_cell (caption, &cell);
+      *caption_heightp = xr_measure_cell_height (xr, &cell, xr->width);
+    }
+  else
+    *caption_heightp = 0;
+
+  return render_page_create (xr->params, table_item_get_table (item));
+}
+
+static void
+xr_output_table_item (struct xr_driver *xr,
+                      const struct table_item *table_item)
+{
+  struct render_break x_break;
+  struct render_page *page;
+  int caption_height;
+
+  if (xr->y > 0)
+    xr->y += xr->font_height;
+
+  page = xr_render_table_item (xr, table_item, &caption_height);
+  xr->params->size[V] = xr->length - caption_height;
+  for (render_break_init (&x_break, page, H);
+       render_break_has_next (&x_break); )
+    {
+      struct render_page *x_slice;
+      struct render_break y_break;
+
+      x_slice = render_break_next (&x_break, xr->width);
+      for (render_break_init (&y_break, x_slice, V);
+           render_break_has_next (&y_break); )
+        {
+          int space = xr->length - xr->y;
+          struct render_page *y_slice;
+
+          /* XXX doesn't allow for caption or space between segments */
+          if (render_break_next_size (&y_break) > space)
+            {
+              assert (xr->y > 0);
+              xr_show_page (xr);
+              continue;
+            }
+
+          y_slice = render_break_next (&y_break, space);
+          if (caption_height)
+            {
+              struct table_cell cell;
+              int bb[TABLE_N_AXES][2];
+
+              xr_init_caption_cell (table_item_get_caption (table_item),
+                                    &cell);
+              bb[H][0] = 0;
+              bb[H][1] = xr->width;
+              bb[V][0] = 0;
+              bb[V][1] = caption_height;
+              xr_draw_cell (xr, &cell, bb, bb);
+              xr->y += caption_height;
+              caption_height = 0;
+            }
+
+          render_page_draw (y_slice);
+          xr->y += render_page_get_size (y_slice, V);
+          render_page_unref (y_slice);
+        }
+      render_break_destroy (&y_break);
+    }
+  render_break_destroy (&x_break);
+}
+
+static void
+xr_output_text (struct xr_driver *xr, const char *text)
+{
+  struct table_item *table_item;
+
+  table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+  xr_output_table_item (xr, table_item);
+  table_item_unref (table_item);
+}
+
+static void
+xr_submit (struct output_driver *driver, const struct output_item *output_item)
+{
+  struct xr_driver *xr = xr_driver_cast (driver);
+  if (is_table_item (output_item))
+    xr_output_table_item (xr, to_table_item (output_item));
+  else if (is_chart_item (output_item))
+    {
+      if (xr->y > 0)
+        xr_show_page (xr);
+      xr_draw_chart (to_chart_item (output_item), xr->cairo, 0.0, 0.0,
+                     xr_to_pt (xr->width), xr_to_pt (xr->length));
+      xr_show_page (xr);
+    }
+  else if (is_text_item (output_item))
+    {
+      const struct text_item *text_item = to_text_item (output_item);
+      enum text_item_type type = text_item_get_type (text_item);
+      const char *text = text_item_get_text (text_item);
+
+      switch (type)
+        {
+        case TEXT_ITEM_TITLE:
+          free (xr->title);
+          xr->title = xstrdup (text);
+          break;
+
+        case TEXT_ITEM_SUBTITLE:
+          free (xr->subtitle);
+          xr->subtitle = xstrdup (text);
+          break;
+
+        case TEXT_ITEM_COMMAND_CLOSE:
+          break;
+
+        case TEXT_ITEM_BLANK_LINE:
+          if (xr->y > 0)
+            xr->y += xr->font_height;
+          break;
+
+        case TEXT_ITEM_EJECT_PAGE:
+          if (xr->y > 0)
+            xr_show_page (xr);
+          break;
+
+        default:
+          xr_output_text (xr, text);
+          break;
+        }
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, xr->command_name);
+      xr_output_text (xr, s);
+      free (s);
+    }
+}
+
+static void
+xr_show_page (struct xr_driver *xr)
+{
+  if (xr->headers)
+    {
+      xr->y = 0;
+      draw_headers (xr);
+    }
+  cairo_show_page (xr->cairo);
+
+  xr->page_number++;
+  xr->y = 0;
+}
+\f
+static void
+xr_layout_cell (struct xr_driver *, const struct table_cell *,
+                int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
+                PangoWrapMode, int *width, int *height);
+
+static void
+dump_line (struct xr_driver *xr, int x0, int y0, int x1, int y1)
+{
+  cairo_new_path (xr->cairo);
+  cairo_move_to (xr->cairo, xr_to_pt (x0), xr_to_pt (y0 + xr->y));
+  cairo_line_to (xr->cairo, xr_to_pt (x1), xr_to_pt (y1 + xr->y));
+  cairo_stroke (xr->cairo);
+}
+
+/* Draws a horizontal line X0...X2 at Y if LEFT says so,
+   shortening it to X0...X1 if SHORTEN is true.
+   Draws a horizontal line X1...X3 at Y if RIGHT says so,
+   shortening it to X2...X3 if SHORTEN is true. */
+static void
+horz_line (struct xr_driver *xr, int x0, int x1, int x2, int x3, int y,
+           enum render_line_style left, enum render_line_style right,
+           bool shorten)
+{
+  if (left != RENDER_LINE_NONE && right != RENDER_LINE_NONE && !shorten)
+    dump_line (xr, x0, y, x3, y);
+  else
+    {
+      if (left != RENDER_LINE_NONE)
+        dump_line (xr, x0, y, shorten ? x1 : x2, y);
+      if (right != RENDER_LINE_NONE)
+        dump_line (xr, shorten ? x2 : x1, y, x3, y);
+    }
+}
+
+/* Draws a vertical line Y0...Y2 at X if TOP says so,
+   shortening it to Y0...Y1 if SHORTEN is true.
+   Draws a vertical line Y1...Y3 at X if BOTTOM says so,
+   shortening it to Y2...Y3 if SHORTEN is true. */
+static void
+vert_line (struct xr_driver *xr, int y0, int y1, int y2, int y3, int x,
+           enum render_line_style top, enum render_line_style bottom,
+           bool shorten)
+{
+  if (top != RENDER_LINE_NONE && bottom != RENDER_LINE_NONE && !shorten)
+    dump_line (xr, x, y0, x, y3);
+  else
+    {
+      if (top != RENDER_LINE_NONE)
+        dump_line (xr, x, y0, x, shorten ? y1 : y2);
+      if (bottom != RENDER_LINE_NONE)
+        dump_line (xr, x, shorten ? y2 : y1, x, y3);
+    }
+}
+
+static void
+xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2],
+              enum render_line_style styles[TABLE_N_AXES][2])
+{
+  const int x0 = bb[H][0];
+  const int y0 = bb[V][0];
+  const int x3 = bb[H][1];
+  const int y3 = bb[V][1];
+  const int top = styles[H][0];
+  const int left = styles[V][0];
+  const int bottom = styles[H][1];
+  const int right = styles[V][1];
+
+  /* The algorithm here is somewhat subtle, to allow it to handle
+     all the kinds of intersections that we need.
+
+     Three additional ordinates are assigned along the x axis.  The
+     first is xc, midway between x0 and x3.  The others are x1 and
+     x2; for a single vertical line these are equal to xc, and for
+     a double vertical line they are the ordinates of the left and
+     right half of the double line.
+
+     yc, y1, and y2 are assigned similarly along the y axis.
+
+     The following diagram shows the coordinate system and output
+     for double top and bottom lines, single left line, and no
+     right line:
+
+                 x0       x1 xc  x2      x3
+               y0 ________________________
+                  |        #     #       |
+                  |        #     #       |
+                  |        #     #       |
+                  |        #     #       |
+                  |        #     #       |
+     y1 = y2 = yc |#########     #       |
+                  |        #     #       |
+                  |        #     #       |
+                  |        #     #       |
+                  |        #     #       |
+               y3 |________#_____#_______|
+  */
+  struct xr_driver *xr = xr_;
+
+  /* Offset from center of each line in a pair of double lines. */
+  int double_line_ofs = (xr->line_space + xr->line_width) / 2;
+
+  /* Are the lines along each axis single or double?
+     (It doesn't make sense to have different kinds of line on the
+     same axis, so we don't try to gracefully handle that case.) */
+  bool double_vert = top == RENDER_LINE_DOUBLE || bottom == RENDER_LINE_DOUBLE;
+  bool double_horz = left == RENDER_LINE_DOUBLE || right == RENDER_LINE_DOUBLE;
+
+  /* When horizontal lines are doubled,
+     the left-side line along y1 normally runs from x0 to x2,
+     and the right-side line along y1 from x3 to x1.
+     If the top-side line is also doubled, we shorten the y1 lines,
+     so that the left-side line runs only to x1,
+     and the right-side line only to x2.
+     Otherwise, the horizontal line at y = y1 below would cut off
+     the intersection, which looks ugly:
+               x0       x1     x2      x3
+             y0 ________________________
+                |        #     #       |
+                |        #     #       |
+                |        #     #       |
+                |        #     #       |
+             y1 |#########     ########|
+                |                      |
+                |                      |
+             y2 |######################|
+                |                      |
+                |                      |
+             y3 |______________________|
+     It is more of a judgment call when the horizontal line is
+     single.  We actually choose to cut off the line anyhow, as
+     shown in the first diagram above.
+  */
+  bool shorten_y1_lines = top == RENDER_LINE_DOUBLE;
+  bool shorten_y2_lines = bottom == RENDER_LINE_DOUBLE;
+  bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
+  int horz_line_ofs = double_vert ? double_line_ofs : 0;
+  int xc = (x0 + x3) / 2;
+  int x1 = xc - horz_line_ofs;
+  int x2 = xc + horz_line_ofs;
+
+  bool shorten_x1_lines = left == RENDER_LINE_DOUBLE;
+  bool shorten_x2_lines = right == RENDER_LINE_DOUBLE;
+  bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
+  int vert_line_ofs = double_horz ? double_line_ofs : 0;
+  int yc = (y0 + y3) / 2;
+  int y1 = yc - vert_line_ofs;
+  int y2 = yc + vert_line_ofs;
+
+  if (!double_horz)
+    horz_line (xr, x0, x1, x2, x3, yc, left, right, shorten_yc_line);
+  else
+    {
+      horz_line (xr, x0, x1, x2, x3, y1, left, right, shorten_y1_lines);
+      horz_line (xr, x0, x1, x2, x3, y2, left, right, shorten_y2_lines);
+    }
+
+  if (!double_vert)
+    vert_line (xr, y0, y1, y2, y3, xc, top, bottom, shorten_xc_line);
+  else
+    {
+      vert_line (xr, y0, y1, y2, y3, x1, top, bottom, shorten_x1_lines);
+      vert_line (xr, y0, y1, y2, y3, x2, top, bottom, shorten_x2_lines);
+    }
+}
+
+static void
+xr_measure_cell_width (void *xr_, const struct table_cell *cell,
+                       int *min_width, int *max_width)
+{
+  struct xr_driver *xr = xr_;
+  int bb[TABLE_N_AXES][2];
+  int clip[TABLE_N_AXES][2];
+  int h;
+
+  bb[H][0] = 0;
+  bb[H][1] = INT_MAX;
+  bb[V][0] = 0;
+  bb[V][1] = INT_MAX;
+  clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
+  xr_layout_cell (xr, cell, bb, clip, PANGO_WRAP_WORD, max_width, &h);
+
+  bb[H][1] = 1;
+  xr_layout_cell (xr, cell, bb, clip, PANGO_WRAP_WORD, min_width, &h);
+}
+
+static int
+xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width)
+{
+  struct xr_driver *xr = xr_;
+  int bb[TABLE_N_AXES][2];
+  int clip[TABLE_N_AXES][2];
+  int w, h;
+
+  bb[H][0] = 0;
+  bb[H][1] = width;
+  bb[V][0] = 0;
+  bb[V][1] = INT_MAX;
+  clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0;
+  xr_layout_cell (xr, cell, bb, clip, PANGO_WRAP_WORD, &w, &h);
+  return h;
+}
+
+static void
+xr_draw_cell (void *xr_, const struct table_cell *cell,
+              int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2])
+{
+  struct xr_driver *xr = xr_;
+  int w, h;
+
+  xr_layout_cell (xr, cell, bb, clip, PANGO_WRAP_WORD, &w, &h);
+}
+\f
+/* Writes STRING at location (X,Y) trimmed to the given MAX_WIDTH
+   and with the given cell OPTIONS for XR. */
+static int
+draw_text (struct xr_driver *xr, const char *string, int x, int y,
+           int max_width, unsigned int options)
+{
+  struct table_cell cell;
+  int bb[TABLE_N_AXES][2];
+  int w, h;
+
+  cell.contents = string;
+  cell.options = options;
+  bb[H][0] = x;
+  bb[V][0] = y;
+  bb[H][1] = x + max_width;
+  bb[V][1] = xr->font_height;
+  xr_layout_cell (xr, &cell, bb, bb, PANGO_WRAP_WORD_CHAR, &w, &h);
+  return w;
+}
+
+/* Writes LEFT left-justified and RIGHT right-justified within
+   (X0...X1) at Y.  LEFT or RIGHT or both may be null. */
+static void
+draw_header_line (struct xr_driver *xr, const char *left, const char *right,
+                  int x0, int x1, int y)
+{
+  int right_width = 0;
+  if (right != NULL)
+    right_width = (draw_text (xr, right, x0, y, x1 - x0, TAB_RIGHT)
+                   + xr->font_height / 2);
+  if (left != NULL)
+    draw_text (xr, left, x0, y, x1 - x0 - right_width, TAB_LEFT);
+}
+
+/* Draw top of page headers for XR. */
+static void
+draw_headers (struct xr_driver *xr)
+{
+  char *r1, *r2;
+  int x0, x1;
+  int y;
+
+  y = -3 * xr->font_height;
+  x0 = xr->font_height / 2;
+  x1 = xr->width - xr->font_height / 2;
+
+  /* Draw box. */
+  cairo_rectangle (xr->cairo, 0, xr_to_pt (y), xr_to_pt (xr->width),
+                   xr_to_pt (2 * (xr->font_height
+                                  + xr->line_width + xr->line_gutter)));
+  cairo_save (xr->cairo);
+  cairo_set_source_rgb (xr->cairo, 0.9, 0.9, 0.9);
+  cairo_fill_preserve (xr->cairo);
+  cairo_restore (xr->cairo);
+  cairo_stroke (xr->cairo);
+
+  y += xr->line_width + xr->line_gutter;
+
+  r1 = xasprintf (_("%s - Page %d"), get_start_date (), xr->page_number);
+  r2 = xasprintf ("%s - %s", version, host_system);
+
+  draw_header_line (xr, xr->title, r1, x0, x1, y);
+  y += xr->font_height;
+
+  draw_header_line (xr, xr->subtitle, r2, x0, x1, y);
+
+  free (r1);
+  free (r2);
+}
+\f
+static void
+xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell,
+                int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
+                PangoWrapMode wrap, int *width, int *height)
+{
+  struct xr_font *font;
+
+  font = (cell->options & TAB_FIX ? &xr->fonts[XR_FONT_FIXED]
+          : cell->options & TAB_EMPH ? &xr->fonts[XR_FONT_EMPHASIS]
+          : &xr->fonts[XR_FONT_PROPORTIONAL]);
+
+  pango_layout_set_text (font->layout, cell->contents, -1);
+
+  pango_layout_set_alignment (
+    font->layout,
+    ((cell->options & TAB_ALIGNMENT) == TAB_RIGHT ? PANGO_ALIGN_RIGHT
+     : (cell->options & TAB_ALIGNMENT) == TAB_LEFT ? PANGO_ALIGN_LEFT
+     : PANGO_ALIGN_CENTER));
+  pango_layout_set_width (font->layout,
+                          bb[H][1] == INT_MAX ? -1 : bb[H][1] - bb[H][0]);
+  pango_layout_set_wrap (font->layout, wrap);
+
+  if (clip[H][0] != clip[H][1])
+    {
+      cairo_save (xr->cairo);
+
+      if (clip[H][1] != INT_MAX || clip[V][1] != INT_MAX)
+        {
+          double x0 = xr_to_pt (clip[H][0]);
+          double y0 = xr_to_pt (clip[V][0] + xr->y);
+          double x1 = xr_to_pt (clip[H][1]);
+          double y1 = xr_to_pt (clip[V][1] + xr->y);
+
+          cairo_rectangle (xr->cairo, x0, y0, x1 - x0, y1 - y0);
+          cairo_clip (xr->cairo);
+        }
+
+      cairo_translate (xr->cairo,
+                       xr_to_pt (bb[H][0]),
+                       xr_to_pt (bb[V][0] + xr->y));
+      pango_cairo_show_layout (xr->cairo, font->layout);
+      cairo_restore (xr->cairo);
+    }
+
+  if (width != NULL || height != NULL)
+    {
+      int w, h;
+
+      pango_layout_get_size (font->layout, &w, &h);
+      if (width != NULL)
+        *width = w;
+      if (height != NULL)
+        *height = h;
+    }
+}
+\f
+/* Attempts to load FONT, initializing its other members based on
+   its 'string' member and the information in DRIVER.  Returns true
+   if successful, otherwise false. */
+static bool
+load_font (struct xr_driver *xr, struct xr_font *font)
+{
+  PangoContext *context;
+  PangoLanguage *language;
+
+  font->desc = pango_font_description_from_string (font->string);
+  if (font->desc == NULL)
+    {
+      error (0, 0, _("\"%s\": bad font specification"), font->string);
+      return false;
+    }
+  pango_font_description_set_absolute_size (font->desc, xr->font_height);
+
+  font->layout = pango_cairo_create_layout (xr->cairo);
+  pango_layout_set_font_description (font->layout, font->desc);
+
+  language = pango_language_get_default ();
+  context = pango_layout_get_context (font->layout);
+  font->metrics = pango_context_get_metrics (context, font->desc, language);
+
+  return true;
+}
+
+/* Frees FONT. */
+static void
+free_font (struct xr_font *font)
+{
+  free (font->string);
+  if (font->desc != NULL)
+    pango_font_description_free (font->desc);
+  pango_font_metrics_unref (font->metrics);
+  if (font->layout != NULL)
+    g_object_unref (font->layout);
+}
+
+struct output_driver_factory pdf_driver_factory = { "pdf", xr_pdf_create };
+struct output_driver_factory ps_driver_factory = { "ps", xr_ps_create };
+struct output_driver_factory svg_driver_factory = { "svg", xr_svg_create };
+
+static const struct output_driver_class cairo_driver_class =
+{
+  "cairo",
+  xr_destroy,
+  xr_submit,
+  xr_flush,
+};
+\f
+/* GUI rendering helpers. */
+
+struct xr_rendering
+  {
+    /* Table items. */
+    struct render_page *page;
+    struct xr_driver *xr;
+    int title_height;
+
+    /* Chart items. */
+    struct chart_item *chart;
+  };
+
+#define CHART_WIDTH 500
+#define CHART_HEIGHT 375
+
+struct xr_driver *
+xr_create_driver (cairo_t *cairo)
+{
+  struct xr_driver *xr;
+  struct string_map map;
+
+  string_map_init (&map);
+  xr = xr_allocate ("cairo", 0, &map);
+  string_map_destroy (&map);
+
+  xr->width = INT_MAX / 8;
+  xr->length = INT_MAX / 8;
+  if (!xr_set_cairo (xr, cairo))
+    {
+      output_driver_destroy (&xr->driver);
+      return NULL;
+    }
+  return xr;
+}
+
+static struct xr_rendering *
+xr_rendering_create_text (struct xr_driver *xr, const char *text, cairo_t *cr)
+{
+  struct table_item *table_item;
+  struct xr_rendering *r;
+
+  table_item = table_item_create (table_from_string (0, text), NULL);
+  r = xr_rendering_create (xr, &table_item->output_item, cr);
+  table_item_unref (table_item);
+
+  return r;
+}
+
+struct xr_rendering *
+xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
+                     cairo_t *cr)
+{
+  struct xr_rendering *r = NULL;
+
+  if (is_text_item (item))
+    r = xr_rendering_create_text (xr, text_item_get_text (to_text_item (item)),
+                                  cr);
+  else if (is_message_item (item))
+    {
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, NULL);
+      r = xr_rendering_create_text (xr, s, cr);
+      free (s);
+    }
+  else if (is_table_item (item))
+    {
+      r = xzalloc (sizeof *r);
+      r->xr = xr;
+      xr_set_cairo (xr, cr);
+      r->page = xr_render_table_item (xr, to_table_item (item),
+                                      &r->title_height);
+    }
+  else if (is_chart_item (item))
+    {
+      r = xzalloc (sizeof *r);
+      r->chart = to_chart_item (output_item_ref (item));
+    }
+
+  return r;
+}
+
+void
+xr_rendering_measure (struct xr_rendering *r, int *w, int *h)
+{
+  if (r->chart == NULL)
+    {
+      *w = render_page_get_size (r->page, H) / 1024;
+      *h = (render_page_get_size (r->page, V) + r->title_height) / 1024;
+    }
+  else
+    {
+      *w = CHART_WIDTH;
+      *h = CHART_HEIGHT;
+    }
+}
+
+void
+xr_rendering_draw (struct xr_rendering *r, cairo_t *cr)
+{
+  if (r->chart == NULL)
+    {
+      struct xr_driver *xr = r->xr;
+
+      xr_set_cairo (xr, cr);
+      xr->y = 0;
+      render_page_draw (r->page);
+    }
+  else
+    xr_draw_chart (r->chart, cr, 0, 0, CHART_WIDTH, CHART_HEIGHT);
+}
+
+void
+xr_draw_chart (const struct chart_item *chart_item, cairo_t *cr,
+               double x, double y, double width, double height)
+{
+  struct xrchart_geometry geom;
+
+  cairo_save (cr);
+  cairo_translate (cr, x, y + height);
+  cairo_scale (cr, 1.0, -1.0);
+  xrchart_geometry_init (cr, &geom, width, height);
+  if (is_boxplot (chart_item))
+    xrchart_draw_boxplot (chart_item, cr, &geom);
+  else if (is_histogram_chart (chart_item))
+    xrchart_draw_histogram (chart_item, cr, &geom);
+  else if (is_np_plot_chart (chart_item))
+    xrchart_draw_np_plot (chart_item, cr, &geom);
+  else if (is_piechart (chart_item))
+    xrchart_draw_piechart (chart_item, cr, &geom);
+  else if (is_roc_chart (chart_item))
+    xrchart_draw_roc (chart_item, cr, &geom);
+  else if (is_scree (chart_item))
+    xrchart_draw_scree (chart_item, cr, &geom);
+  else
+    NOT_REACHED ();
+  xrchart_geometry_free (cr, &geom);
+
+  cairo_restore (cr);
+}
+
+char *
+xr_draw_png_chart (const struct chart_item *item,
+                   const char *file_name_template, int number)
+{
+  const int width = 640;
+  const int length = 480;
+
+  cairo_surface_t *surface;
+  cairo_status_t status;
+  const char *number_pos;
+  char *file_name;
+  cairo_t *cr;
+
+  number_pos = strchr (file_name_template, '#');
+  if (number_pos != NULL)
+    file_name = xasprintf ("%.*s%d%s", (int) (number_pos - file_name_template),
+                           file_name_template, number, number_pos + 1);
+  else
+    file_name = xstrdup (file_name_template);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
+  cr = cairo_create (surface);
+
+  cairo_save (cr);
+  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+  cairo_rectangle (cr, 0, 0, width, length);
+  cairo_fill (cr);
+  cairo_restore (cr);
+
+  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+
+  xr_draw_chart (item, cr, 0.0, 0.0, width, length);
+
+  status = cairo_surface_write_to_png (surface, file_name);
+  if (status != CAIRO_STATUS_SUCCESS)
+    error (0, 0, _("writing output file \"%s\": %s"),
+           file_name, cairo_status_to_string (status));
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  return file_name;
+}
diff --git a/src/output/cairo.h b/src/output/cairo.h
new file mode 100644 (file)
index 0000000..80b2b87
--- /dev/null
@@ -0,0 +1,39 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_CAIRO_H
+#define OUTPUT_CAIRO_H 1
+
+#include <cairo/cairo.h>
+
+struct chart_item;
+struct output_item;
+
+/* Used by PSPPIRE to render in the GUI. */
+struct xr_driver *xr_create_driver (cairo_t *);
+struct xr_rendering *xr_rendering_create (struct xr_driver *,
+                                          const struct output_item *,
+                                          cairo_t *);
+void xr_rendering_measure (struct xr_rendering *, int *w, int *h);
+void xr_rendering_draw (struct xr_rendering *, cairo_t *);
+
+/* Render charts with Cairo. */
+void xr_draw_chart (const struct chart_item *, cairo_t *,
+                    double x, double y, double width, double height);
+char *xr_draw_png_chart (const struct chart_item *,
+                         const char *file_name_template, int number);
+
+#endif /* output/cairo.h */
diff --git a/src/output/chart-item-provider.h b/src/output/chart-item-provider.h
new file mode 100644 (file)
index 0000000..4f13fcf
--- /dev/null
@@ -0,0 +1,31 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2009 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_CHART_ITEM_PROVIDER_H
+#define OUTPUT_CHART_ITEM_PROVIDER_H 1
+
+#include <output/chart-item.h>
+#include <output/output-item.h>
+
+struct chart_item_class
+  {
+    void (*destroy) (struct chart_item *);
+  };
+
+void chart_item_init (struct chart_item *, const struct chart_item_class *,
+                      const char *title);
+
+#endif /* output/chart-provider.h */
diff --git a/src/output/chart-item.c b/src/output/chart-item.c
new file mode 100644 (file)
index 0000000..227994d
--- /dev/null
@@ -0,0 +1,88 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2009 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/chart-item.h>
+#include <output/chart-item-provider.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libpspp/cast.h>
+#include <libpspp/compiler.h>
+#include <output/driver.h>
+#include <output/output-item-provider.h>
+
+#include "gl/xalloc.h"
+
+/* Initializes ITEM as a chart item of the specified CLASS.  The new chart item
+   initially has the specified TITLE, which may be NULL if no title is yet
+   available.  The caller retains ownership of TITLE.
+
+   A chart item is an abstract class, that is, a plain chart_item is not useful
+   on its own.  Thus, this function is normally called from the initialization
+   function of some subclass of chart_item. */
+void
+chart_item_init (struct chart_item *item, const struct chart_item_class *class,
+                 const char *title)
+{
+  output_item_init (&item->output_item, &chart_item_class);
+  item->class = class;
+  item->title = title != NULL ? xstrdup (title) : NULL;
+}
+
+/* Returns ITEM's title, which is a null pointer if no title has been set. */
+const char *
+chart_item_get_title (const struct chart_item *item)
+{
+  return item->title;
+}
+
+/* Sets ITEM's title to TITLE, replacing any previous title.  Specify NULL for
+   TITLE to clear any title from ITEM.  The caller retains ownership of
+   TITLE.
+
+   This function may only be used on a chart_item that is unshared. */
+void
+chart_item_set_title (struct chart_item *item, const char *title)
+{
+  assert (!chart_item_is_shared (item));
+  free (item->title);
+  item->title = title != NULL ? xstrdup (title) : NULL;
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+chart_item_submit (struct chart_item *item)
+{
+  output_submit (&item->output_item);
+}
+\f
+static void
+chart_item_destroy (struct output_item *output_item)
+{
+  struct chart_item *item = to_chart_item (output_item);
+  char *title = item->title;
+  item->class->destroy (item);
+  free (title);
+}
+
+const struct output_item_class chart_item_class =
+  {
+    chart_item_destroy,
+  };
diff --git a/src/output/chart-item.h b/src/output/chart-item.h
new file mode 100644 (file)
index 0000000..c005a46
--- /dev/null
@@ -0,0 +1,100 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_CHART_ITEM_H
+#define OUTPUT_CHART_ITEM_H 1
+
+/* Chart items.
+
+   A chart item is a subclass of an output item (see output/output-item.h).
+
+   A chart item is abstract.  Every actual chart is a subclass of
+   chart_item. */
+
+#include <stdbool.h>
+#include <output/output-item.h>
+
+/* A chart item.
+
+   The members of struct chart_item should not be accessed directly.  Use one
+   of the accessor functions defined below. */
+struct chart_item
+  {
+    struct output_item output_item; /* Superclass */
+    const struct chart_item_class *class; /* Subclass. */
+    char *title;                /* May be null if there is no title. */
+  };
+
+const char *chart_item_get_title (const struct chart_item *);
+void chart_item_set_title (struct chart_item *, const char *);
+\f
+/* This boilerplate for chart_item, a subclass of output_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct output_item_class chart_item_class;
+
+/* Returns true if SUPER is a chart_item, otherwise false. */
+static inline bool
+is_chart_item (const struct output_item *super)
+{
+  return super->class == &chart_item_class;
+}
+
+/* Returns SUPER converted to chart_item.  SUPER must be a chart_item, as
+   reported by is_chart_item. */
+static inline struct chart_item *
+to_chart_item (const struct output_item *super)
+{
+  assert (is_chart_item (super));
+  return UP_CAST (super, struct chart_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+chart_item_super (const struct chart_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct chart_item *
+chart_item_ref (const struct chart_item *instance)
+{
+  return to_chart_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+chart_item_unref (struct chart_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+chart_item_is_shared (const struct chart_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void chart_item_submit (struct chart_item *);
+\f
+#endif /* output/chart-item.h */
diff --git a/src/output/chart.c b/src/output/chart.c
deleted file mode 100644 (file)
index e324901..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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/chart.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <float.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <plot.h>
-
-#include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/output.h>
-
-#include "error.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-extern struct som_table_class tab_table_class;
-
-struct chart *
-chart_create(void)
-{
-  struct chart *chart;
-  struct outp_driver *d;
-
-  d = outp_drivers (NULL);
-  if (d == NULL)
-    return NULL;
-
-  chart = xmalloc (sizeof *chart);
-  chart->lp = NULL;
-  d->class->initialise_chart(d, chart);
-  if (!chart->lp)
-    {
-      free (chart);
-      return NULL;
-    }
-
-  if (pl_openpl_r (chart->lp) < 0)      /* open Plotter */
-    return NULL;
-
-  pl_fspace_r (chart->lp, 0.0, 0.0, 1000.0, 1000.0); /* set coordinate system */
-  pl_flinewidth_r (chart->lp, 0.25);    /* set line thickness */
-  pl_pencolorname_r (chart->lp, "black");
-
-  pl_erase_r (chart->lp);               /* erase graphics display */
-  pl_filltype_r(chart->lp,0);
-
-  pl_savestate_r(chart->lp);
-
-  /* Set default chartetry */
-  chart->data_top =   900;
-  chart->data_right = 800;
-  chart->data_bottom = 120;
-  chart->data_left = 150;
-  chart->abscissa_top = 70;
-  chart->ordinate_right = 120;
-  chart->title_bottom = 920;
-  chart->legend_left = 810;
-  chart->legend_right = 1000;
-  chart->font_size = 0;
-  chart->in_path = false;
-  chart->dataset = NULL;
-  chart->n_datasets = 0;
-  strcpy(chart->fill_colour,"red");
-
-  /* Get default font size */
-  if ( !chart->font_size)
-    chart->font_size = pl_fontsize_r(chart->lp, -1);
-
-  /* Draw the data area */
-  pl_box_r(chart->lp,
-          chart->data_left, chart->data_bottom,
-          chart->data_right, chart->data_top);
-
-  return chart;
-}
-
-void
-chart_submit(struct chart *chart)
-{
-  int i;
-  struct som_entity s;
-  struct outp_driver *d;
-
-  if ( ! chart )
-     return ;
-
-  pl_restorestate_r(chart->lp);
-
-  s.class = &tab_table_class;
-  s.ext = chart;
-  s.type = SOM_CHART;
-  som_submit (&s);
-
-  if (pl_closepl_r (chart->lp) < 0)     /* close Plotter */
-    {
-      fprintf (stderr, "Couldn't close Plotter\n");
-    }
-
-  pl_deletepl_r(chart->lp);
-
-  pl_deleteplparams(chart->pl_params);
-
-  d = outp_drivers (NULL);
-  d->class->finalise_chart(d, chart);
-
-  for (i = 0 ; i < chart->n_datasets; ++i)
-    free (chart->dataset[i]);
-  free (chart->dataset);
-
-  free(chart);
-}
-
-void
-chart_init_separate (struct chart *ch, const char *type,
-                     const char *file_name_tmpl, int number)
-{
-  FILE *fp;
-  int number_pos;
-
-  number_pos = strchr (file_name_tmpl, '#') - file_name_tmpl;
-  ch->file_name = xasprintf ("%.*s%d%s",
-                             number_pos, file_name_tmpl,
-                             number,
-                             file_name_tmpl + number_pos + 1);
-  fp = fopen (ch->file_name, "wb");
-  if (fp == NULL)
-    {
-      error (0, errno, _("creating \"%s\""), ch->file_name);
-      free (ch->file_name);
-      ch->file_name = NULL;
-      return;
-    }
-
-  ch->pl_params = pl_newplparams ();
-  ch->lp = pl_newpl_r (type, 0, fp, stderr, ch->pl_params);
-}
-
-void
-chart_finalise_separate (struct chart *ch)
-{
-  free (ch->file_name);
-}
diff --git a/src/output/chart.h b/src/output/chart.h
deleted file mode 100644 (file)
index 4da12ec..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <float.h>
-#include <assert.h>
-#include <math.h>
-
-#include <math/chart-geometry.h>
-#include <libpspp/str.h>
-#include "manager.h"
-#include "output.h"
-
-#include "xalloc.h"
-
-#ifndef CHART_H
-#define CHART_H
-
-#ifndef NO_CHARTS
-#include <plot.h>
-#endif
-
-struct chart {
-
-#ifndef NO_CHARTS
-  plPlotter *lp ;
-  plPlotterParams *pl_params;
-#else
-  void *lp;
-#endif
-  char *file_name;
-  FILE *file;
-
-  /* The geometry of the chart
-     See diagram at the foot of this file.
-   */
-
-  int data_top   ;
-  int data_right ;
-  int data_bottom;
-  int data_left  ;
-
-  int abscissa_top;
-
-  int ordinate_right ;
-
-  int title_bottom ;
-
-  int legend_left ;
-  int legend_right ;
-  const char **dataset;
-  int n_datasets;
-
-
-  /* Default font size for the plot (if zero, then use plotter default) */
-  int font_size;
-
-  char fill_colour[10];
-
-  /* Stuff Particular to Cartesians (and Boxplots ) */
-  double ordinate_scale;
-  double abscissa_scale;
-  double x_min;
-  double x_max;
-  double y_min;
-  double y_max;
-  bool in_path;
-};
-
-
-
-struct chart * chart_create(void);
-void chart_submit(struct chart *ch);
-
-/* Helper functions for output drivers that put each chart into a
-   separate file. */
-void chart_init_separate (struct chart *, const char *type,
-                          const char *file_name_tmpl, int number);
-
-void chart_finalise_separate (struct chart *);
-
-#endif
diff --git a/src/output/charts/Makefile b/src/output/charts/Makefile
deleted file mode 100644 (file)
index c1a052e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-all:
-       $(MAKE) -C /home/res/jmd/PSPP/pspp 
diff --git a/src/output/charts/automake.mk b/src/output/charts/automake.mk
deleted file mode 100644 (file)
index ab0ff51..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-## Process this file with automake to produce Makefile.in  -*- makefile -*-
-
-noinst_LTLIBRARIES += src/output/charts/libcharts.la
-
-chart_sources = \
-       src/output/charts/barchart.c \
-       src/output/charts/barchart.h \
-       src/output/charts/box-whisker.c \
-       src/output/charts/box-whisker.h \
-       src/output/charts/cartesian.c \
-       src/output/charts/cartesian.h \
-       src/output/charts/piechart.c \
-       src/output/charts/piechart.h \
-       src/output/charts/plot-chart.h \
-       src/output/charts/plot-chart.c \
-       src/output/charts/plot-hist.c \
-       src/output/charts/plot-hist.h
-
-if WITHCHARTS
-src_output_charts_libcharts_la_SOURCES = \
-       $(chart_sources)
-
-EXTRA_DIST += src/output/charts/dummy-chart.c
-else
-src_output_charts_libcharts_la_SOURCES =  \
-       src/output/charts/dummy-chart.c
-
-EXTRA_DIST += $(chart_sources)
-
-AM_CPPFLAGS += -DNO_CHARTS
-
-endif
-
-EXTRA_DIST += src/output/charts/OChangeLog
diff --git a/src/output/charts/barchart.c b/src/output/charts/barchart.c
deleted file mode 100644 (file)
index f3b1001..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 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 <stdio.h>
-#include <plot.h>
-#include <stdarg.h>
-#include <math.h>
-#include <output/charts/barchart.h>
-#include <output/chart.h>
-#include <output/charts/plot-chart.h>
-
-#define CATAGORIES 6
-#define SUB_CATAGORIES 3
-
-static const    double x_min = 0;
-static const    double x_max = 15.0;
-
-static const char *cat_labels[] =
-  {
-    "Age",
-    "Intelligence",
-    "Wealth",
-    "Emotional",
-    "cat 5",
-    "cat 6",
-    "cat 7",
-    "cat 8",
-    "cat 9",
-    "cat 10",
-    "cat 11"
-  };
-
-
-
-
-/* Subcatagories */
-static const double data1[] =
-{
-  28,83,
-  34,
-  29,13,
-   9,4,
-   3,3,
-   2,0,
-   1,0,
-   0,
-   1,1
-};
-
-
-static const double data2[] =
-{
-  45,13,
-   9,4,
-   3,43,
-   2,0,
-   1,20,
-   0,0,
-  1,1,
-  0,0
-};
-
-static const double data3[] =
-  {
-    23,18,
-    0, 45,23, 9, 40, 24,4, 8
-  };
-
-
-static const char subcat_name[]="Gender";
-
-
-struct subcat {
-  const double *data;
-  const char *label;
-};
-
-static const struct subcat sub_catagory[SUB_CATAGORIES] =
-  {
-    {data1, "male"},
-    {data2, "female"},
-    {data3, "47xxy"}
-  };
-
-
-
-static const    double y_min = 0;
-static const    double y_max = 120.0;
-static const    double y_tick = 20.0;
-
-
-
-static void write_legend(struct chart *chart) ;
-
-
-void
-draw_barchart(struct chart *ch, const char *title,
-             const char *xlabel, const char *ylabel, enum bar_opts opt)
-{
-  double d;
-  int i;
-
-  double interval_size = fabs(ch->data_right - ch->data_left) / ( CATAGORIES );
-
-  double bar_width = interval_size / 1.1 ;
-
-  double ordinate_scale = fabs(ch->data_top -  ch->data_bottom) /
-    fabs(y_max - y_min) ;
-
-  if ( opt != BAR_STACKED )
-      bar_width /= SUB_CATAGORIES;
-
-  /* Move to data bottom-left */
-  pl_move_r(ch->lp, ch->data_left, ch->data_bottom);
-
-  pl_savestate_r(ch->lp);
-  pl_filltype_r(ch->lp,1);
-
-  /* Draw the data */
-  for (i = 0 ; i < CATAGORIES ; ++i )
-    {
-      int sc;
-      double ystart=0.0;
-      double x = i * interval_size;
-
-      pl_savestate_r(ch->lp);
-
-      draw_tick (ch, TICK_ABSCISSA, x + (interval_size/2 ), "%s",
-                cat_labels[i]);
-
-      for(sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
-       {
-
-         pl_savestate_r(ch->lp);
-         pl_fillcolorname_r(ch->lp,data_colour[sc % N_CHART_COLOURS]);
-
-         switch ( opt )
-           {
-           case BAR_GROUPED:
-             pl_fboxrel_r(ch->lp,
-                          x + (sc * bar_width ), 0,
-                          x + (sc + 1) * bar_width,
-                            sub_catagory[sc].data[i] * ordinate_scale );
-             break;
-
-
-           case BAR_STACKED:
-
-             pl_fboxrel_r(ch->lp,
-                          x, ystart,
-                          x + bar_width,
-                          ystart + sub_catagory[sc].data[i] * ordinate_scale );
-
-             ystart +=    sub_catagory[sc].data[i] * ordinate_scale ;
-
-             break;
-
-           default:
-             break;
-           }
-         pl_restorestate_r(ch->lp);
-       }
-
-      pl_restorestate_r(ch->lp);
-    }
-  pl_restorestate_r(ch->lp);
-
-  for ( d = y_min; d <= y_max ; d += y_tick )
-    {
-
-      draw_tick (ch, TICK_ORDINATE,
-                (d - y_min ) * ordinate_scale, "%g", d);
-
-    }
-
-  /* Write the abscissa label */
-  pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
-  pl_alabel_r(ch->lp,0,'t',xlabel);
-
-
-  /* Write the ordinate label */
-  pl_savestate_r(ch->lp);
-  pl_move_r(ch->lp,ch->data_bottom, ch->ordinate_right);
-  pl_textangle_r(ch->lp,90);
-  pl_alabel_r(ch->lp,0,0,ylabel);
-  pl_restorestate_r(ch->lp);
-
-
-  chart_write_title(ch, "%s", title);
-
-  write_legend(ch);
-
-
-}
-
-
-
-
-
-static void
-write_legend(struct chart *chart)
-{
-  int sc;
-
-  pl_savestate_r(chart->lp);
-
-  pl_filltype_r(chart->lp,1);
-
-  pl_move_r(chart->lp, chart->legend_left,
-           chart->data_bottom + chart->font_size * SUB_CATAGORIES * 1.5);
-
-  pl_alabel_r(chart->lp,0,'b',subcat_name);
-
-  for (sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
-    {
-      pl_fmove_r(chart->lp,
-                chart->legend_left,
-                chart->data_bottom + chart->font_size * sc  * 1.5);
-
-      pl_savestate_r(chart->lp);
-      pl_fillcolorname_r(chart->lp,data_colour[sc]);
-      pl_fboxrel_r (chart->lp,
-                   0,0,
-                   chart->font_size, chart->font_size);
-      pl_restorestate_r(chart->lp);
-
-      pl_fmove_r(chart->lp,
-                chart->legend_left + chart->font_size * 1.5,
-                chart->data_bottom + chart->font_size * sc  * 1.5);
-
-      pl_alabel_r(chart->lp,'l','b',sub_catagory[sc].label);
-    }
-
-
-  pl_restorestate_r(chart->lp);
-}
diff --git a/src/output/charts/barchart.h b/src/output/charts/barchart.h
deleted file mode 100644 (file)
index 0983272..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 BARCHART_H
-#define BARCHART_H
-
-#include <output/chart.h>
-
-enum  bar_opts {
-  BAR_GROUPED =  0,
-  BAR_STACKED,
-  BAR_RANGE
-};
-
-void draw_barchart(struct chart *ch, const char *title,
-             const char *xlabel, const char *ylabel, enum bar_opts opt);
-
-#endif
diff --git a/src/output/charts/box-whisker.c b/src/output/charts/box-whisker.c
deleted file mode 100644 (file)
index 33c445b..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 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 <math.h>
-#include <assert.h>
-#include <libpspp/misc.h>
-
-#include <output/charts/box-whisker.h>
-#include <output/charts/plot-chart.h>
-
-#include <output/chart.h>
-#include <math/chart-geometry.h>
-#include <math/box-whisker.h>
-
-/* Draw a box-and-whiskers plot
-*/
-
-/* Draw an OUTLIER on the plot CH
- * at CENTRELINE
- */
-static void
-draw_case (struct chart *ch, double centreline,
-          const struct outlier *outlier)
-{
-
-#define MARKER_CIRCLE 4
-#define MARKER_STAR 3
-
-  pl_fmarker_r(ch->lp,
-              centreline,
-              ch->data_bottom + (outlier->value - ch->y_min) * ch->ordinate_scale,
-              outlier->extreme ? MARKER_STAR : MARKER_CIRCLE,
-              20);
-
-  pl_moverel_r(ch->lp, 10,0);
-
-  pl_alabel_r(ch->lp, 'l', 'c', ds_cstr (&outlier->label));
-}
-
-
-void
-boxplot_draw_boxplot (struct chart *ch,
-                     double box_centre,
-                     double box_width,
-                     const struct box_whisker *bw,
-                     const char *name)
-{
-  double whisker[2];
-  double hinge[3];
-  struct ll *ll;
-
-  const struct ll_list *outliers;
-
-  const double box_left = box_centre - box_width / 2.0;
-
-  const double box_right = box_centre + box_width / 2.0;
-
-  double box_bottom ;
-  double box_top ;
-  double bottom_whisker ;
-  double top_whisker ;
-
-  box_whisker_whiskers (bw, whisker);
-  box_whisker_hinges (bw, hinge);
-
-  box_bottom = ch->data_bottom + (hinge[0] - ch->y_min ) * ch->ordinate_scale;
-
-  box_top = ch->data_bottom + (hinge[2] - ch->y_min ) * ch->ordinate_scale;
-
-  bottom_whisker = ch->data_bottom + (whisker[0] - ch->y_min) *
-    ch->ordinate_scale;
-
-  top_whisker = ch->data_bottom + (whisker[1] - ch->y_min) * ch->ordinate_scale;
-
-  pl_savestate_r(ch->lp);
-
-  /* Draw the box */
-  pl_savestate_r (ch->lp);
-  pl_fillcolorname_r (ch->lp, ch->fill_colour);
-  pl_filltype_r (ch->lp,1);
-  pl_fbox_r (ch->lp,
-           box_left,
-           box_bottom,
-           box_right,
-           box_top);
-
-  pl_restorestate_r (ch->lp);
-
-  /* Draw the median */
-  pl_savestate_r (ch->lp);
-  pl_linewidth_r (ch->lp, 5);
-  pl_fline_r (ch->lp,
-            box_left,
-            ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale,
-            box_right,
-            ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale);
-  pl_restorestate_r (ch->lp);
-
-  /* Draw the bottom whisker */
-  pl_fline_r (ch->lp,
-            box_left,
-            bottom_whisker,
-            box_right,
-            bottom_whisker);
-
-  /* Draw top whisker */
-  pl_fline_r (ch->lp,
-            box_left,
-            top_whisker,
-            box_right,
-            top_whisker);
-
-
-  /* Draw centre line.
-     (bottom half) */
-  pl_fline_r (ch->lp,
-            box_centre, bottom_whisker,
-            box_centre, box_bottom);
-
-  /* (top half) */
-  pl_fline_r (ch->lp,
-            box_centre, top_whisker,
-            box_centre, box_top);
-
-  outliers = box_whisker_outliers (bw);
-  for (ll = ll_head (outliers);
-       ll != ll_null (outliers); ll = ll_next (ll))
-    {
-      const struct outlier *outlier = ll_data (ll, struct outlier, ll);
-      draw_case (ch, box_centre, outlier);
-    }
-
-  /* Draw  tick  mark on x axis */
-  draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, "%s", name);
-
-  pl_restorestate_r(ch->lp);
-}
-
-void
-boxplot_draw_yscale (struct chart *ch, double y_max, double y_min)
-{
-  double y_tick;
-  double d;
-
-  if ( !ch )
-     return ;
-
-  ch->y_max  = y_max;
-  ch->y_min  = y_min;
-
-  y_tick = chart_rounded_tick (fabs(ch->y_max - ch->y_min) / 5.0);
-
-  ch->y_min = (ceil( ch->y_min  / y_tick ) - 1.0  ) * y_tick;
-
-  ch->y_max = ( floor( ch->y_max  / y_tick ) + 1.0  ) * y_tick;
-
-  ch->ordinate_scale = fabs(ch->data_top - ch->data_bottom)
-    / fabs(ch->y_max - ch->y_min) ;
-
-  /* Move to data bottom-left */
-  pl_move_r(ch->lp,
-           ch->data_left, ch->data_bottom);
-
-  for ( d = ch->y_min; d <= ch->y_max ; d += y_tick )
-    {
-      draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d);
-    }
-}
diff --git a/src/output/charts/box-whisker.h b/src/output/charts/box-whisker.h
deleted file mode 100644 (file)
index 7b2c4b8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 BOX_WHISKER_H
-#define BOX_WHISKER_H
-
-struct chart ;
-struct box_whisker;
-
-void boxplot_draw_boxplot (struct chart *ch,
-                          double box_centre,
-                          double box_width,
-                          const struct box_whisker *w,
-                          const char *name);
-
-
-void boxplot_draw_yscale (struct chart *ch , double y_max, double y_min);
-
-#endif
diff --git a/src/output/charts/boxplot-cairo.c b/src/output/charts/boxplot-cairo.c
new file mode 100644 (file)
index 0000000..ddecbfc
--- /dev/null
@@ -0,0 +1,179 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/cairo-chart.h>
+
+#include <math.h>
+
+#include <output/charts/boxplot.h>
+#include <math/box-whisker.h>
+#include <math/chart-geometry.h>
+
+/* Draw an OUTLIER on the plot CH
+ * at CENTRELINE
+ */
+static void
+draw_case (cairo_t *cr, const struct xrchart_geometry *geom, double centreline,
+          const struct outlier *outlier)
+{
+  double y = geom->data_bottom + (outlier->value - geom->y_min) * geom->ordinate_scale;
+  xrchart_draw_marker (cr, centreline, y,
+                     outlier->extreme ? XRMARKER_ASTERISK : XRMARKER_CIRCLE,
+                     20);
+
+  cairo_move_to (cr, centreline + 10, y);
+  xrchart_label (cr, 'l', 'c', geom->font_size, ds_cstr (&outlier->label));
+}
+
+static void
+boxplot_draw_box (cairo_t *cr, const struct xrchart_geometry *geom,
+                  double box_centre,
+                  double box_width,
+                  const struct box_whisker *bw,
+                  const char *name)
+{
+  double whisker[2];
+  double hinge[3];
+  struct ll *ll;
+
+  const struct ll_list *outliers;
+
+  const double box_left = box_centre - box_width / 2.0;
+
+  const double box_right = box_centre + box_width / 2.0;
+
+  double box_bottom ;
+  double box_top ;
+  double bottom_whisker ;
+  double top_whisker ;
+
+  box_whisker_whiskers (bw, whisker);
+  box_whisker_hinges (bw, hinge);
+
+  box_bottom = geom->data_bottom + (hinge[0] - geom->y_min ) * geom->ordinate_scale;
+
+  box_top = geom->data_bottom + (hinge[2] - geom->y_min ) * geom->ordinate_scale;
+
+  bottom_whisker = geom->data_bottom + (whisker[0] - geom->y_min) *
+    geom->ordinate_scale;
+
+  top_whisker = geom->data_bottom + (whisker[1] - geom->y_min) * geom->ordinate_scale;
+
+  /* Draw the box */
+  cairo_rectangle (cr,
+                   box_left,
+                   box_bottom,
+                   box_right - box_left,
+                   box_top - box_bottom);
+  cairo_save (cr);
+  cairo_set_source_rgb (cr,
+                        geom->fill_colour.red / 255.0,
+                        geom->fill_colour.green / 255.0,
+                        geom->fill_colour.blue / 255.0);
+  cairo_fill (cr);
+  cairo_restore (cr);
+  cairo_stroke (cr);
+
+  /* Draw the median */
+  cairo_save (cr);
+  cairo_set_line_width (cr, cairo_get_line_width (cr) * 5);
+  cairo_move_to (cr,
+                 box_left,
+                 geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale);
+  cairo_line_to (cr,
+                 box_right,
+                 geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale);
+  cairo_stroke (cr);
+  cairo_restore (cr);
+
+  /* Draw the bottom whisker */
+  cairo_move_to (cr, box_left, bottom_whisker);
+  cairo_line_to (cr, box_right, bottom_whisker);
+  cairo_stroke (cr);
+
+  /* Draw top whisker */
+  cairo_move_to (cr, box_left, top_whisker);
+  cairo_line_to (cr, box_right, top_whisker);
+  cairo_stroke (cr);
+
+  /* Draw centre line.
+     (bottom half) */
+  cairo_move_to (cr, box_centre, bottom_whisker);
+  cairo_line_to (cr, box_centre, box_bottom);
+  cairo_stroke (cr);
+
+  /* (top half) */
+  cairo_move_to (cr, box_centre, top_whisker);
+  cairo_line_to (cr, box_centre, box_top);
+  cairo_stroke (cr);
+
+  outliers = box_whisker_outliers (bw);
+  for (ll = ll_head (outliers);
+       ll != ll_null (outliers); ll = ll_next (ll))
+    {
+      const struct outlier *outlier = ll_data (ll, struct outlier, ll);
+      draw_case (cr, geom, box_centre, outlier);
+    }
+
+  /* Draw  tick  mark on x axis */
+  draw_tick(cr, geom, TICK_ABSCISSA, box_centre - geom->data_left, "%s", name);
+}
+
+static void
+boxplot_draw_yscale (cairo_t *cr, struct xrchart_geometry *geom,
+                     double y_max, double y_min)
+{
+  double y_tick;
+  double d;
+
+  geom->y_max = y_max;
+  geom->y_min = y_min;
+
+  y_tick = chart_rounded_tick (fabs (geom->y_max - geom->y_min) / 5.0);
+
+  geom->y_min = (ceil (geom->y_min / y_tick) - 1.0) * y_tick;
+
+  geom->y_max = (floor (geom->y_max / y_tick) + 1.0) * y_tick;
+
+  geom->ordinate_scale = (fabs (geom->data_top - geom->data_bottom)
+                          / fabs (geom->y_max - geom->y_min));
+
+  for (d = geom->y_min; d <= geom->y_max; d += y_tick)
+    draw_tick (cr, geom, TICK_ORDINATE,
+               (d - geom->y_min) * geom->ordinate_scale, "%g", d);
+}
+
+void
+xrchart_draw_boxplot (const struct chart_item *chart_item, cairo_t *cr,
+                      struct xrchart_geometry *geom)
+{
+  const struct boxplot *boxplot = to_boxplot (chart_item);
+  double box_width;
+  size_t i;
+
+  boxplot_draw_yscale (cr, geom, boxplot->y_max, boxplot->y_min);
+  xrchart_write_title (cr, geom, "%s", chart_item->title);
+
+  box_width = (geom->data_right - geom->data_left) / boxplot->n_boxes / 2.0;
+  for (i = 0; i < boxplot->n_boxes; i++)
+    {
+      const struct boxplot_box *box = &boxplot->boxes[i];
+      const double box_centre = (i * 2 + 1) * box_width + geom->data_left;
+      boxplot_draw_box (cr, geom, box_centre, box_width, box->bw, box->label);
+    }
+}
diff --git a/src/output/charts/boxplot.c b/src/output/charts/boxplot.c
new file mode 100644 (file)
index 0000000..7e92480
--- /dev/null
@@ -0,0 +1,70 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2008, 2009 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/charts/boxplot.h>
+
+#include <math/box-whisker.h>
+#include <output/chart-item-provider.h>
+
+struct boxplot *
+boxplot_create (double y_min, double y_max, const char *title)
+{
+  struct boxplot *boxplot = xmalloc (sizeof *boxplot);
+  chart_item_init (&boxplot->chart_item, &boxplot_class, title);
+  boxplot->y_min = y_min;
+  boxplot->y_max = y_max;
+  boxplot->boxes = NULL;
+  boxplot->n_boxes = boxplot->boxes_allocated = 0;
+  return boxplot;
+}
+
+void
+boxplot_add_box (struct boxplot *boxplot,
+                 struct box_whisker *bw, const char *label)
+{
+  struct boxplot_box *box;
+  if (boxplot->n_boxes >= boxplot->boxes_allocated)
+    boxplot->boxes = x2nrealloc (boxplot->boxes, &boxplot->boxes_allocated,
+                                 sizeof *boxplot->boxes);
+  box = &boxplot->boxes[boxplot->n_boxes++];
+  box->bw = bw;
+  box->label = xstrdup (label);
+}
+
+static void
+boxplot_chart_destroy (struct chart_item *chart_item)
+{
+  struct boxplot *boxplot = to_boxplot (chart_item);
+  size_t i;
+
+  for (i = 0; i < boxplot->n_boxes; i++)
+    {
+      struct boxplot_box *box = &boxplot->boxes[i];
+      struct statistic *statistic = &box->bw->parent.parent;
+      statistic->destroy (statistic);
+      free (box->label);
+    }
+  free (boxplot->boxes);
+  free (boxplot);
+}
+
+const struct chart_item_class boxplot_class =
+  {
+    boxplot_chart_destroy
+  };
diff --git a/src/output/charts/boxplot.h b/src/output/charts/boxplot.h
new file mode 100644 (file)
index 0000000..bd5a7a3
--- /dev/null
@@ -0,0 +1,108 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2009 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_CHARTS_BOXPLOT_H
+#define OUTPUT_CHARTS_BOXPLOT_H 1
+
+#include <stddef.h>
+#include <output/chart-item.h>
+
+/* Box-whiskers plot. */
+struct boxplot
+  {
+    struct chart_item chart_item;
+
+    /* Data. */
+    struct boxplot_box *boxes;
+    size_t n_boxes, boxes_allocated;
+
+    /* Derived from data and convenient for plotting. */
+    double y_min;               /* Minimum Y coordinate of extremum. */
+    double y_max;               /* Maximum Y coordinate of extremum. */
+  };
+
+/* One box within a box-whiskers plot. */
+struct boxplot_box
+  {
+    struct box_whisker *bw;
+    char *label;                /* Variable name or factor label. */
+  };
+
+struct boxplot *boxplot_create (double y_min, double y_max, const char *title);
+void boxplot_add_box (struct boxplot *,
+                      struct box_whisker *, const char *label);
+\f
+/* This boilerplate for boxplot, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct chart_item_class boxplot_class;
+
+/* Returns true if SUPER is a boxplot, otherwise false. */
+static inline bool
+is_boxplot (const struct chart_item *super)
+{
+  return super->class == &boxplot_class;
+}
+
+/* Returns SUPER converted to boxplot.  SUPER must be a boxplot, as
+   reported by is_boxplot. */
+static inline struct boxplot *
+to_boxplot (const struct chart_item *super)
+{
+  assert (is_boxplot (super));
+  return UP_CAST (super, struct boxplot, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+boxplot_super (const struct boxplot *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct boxplot *
+boxplot_ref (const struct boxplot *instance)
+{
+  return to_boxplot (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+boxplot_unref (struct boxplot *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+boxplot_is_shared (const struct boxplot *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+boxplot_submit (struct boxplot *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/boxplot.h */
diff --git a/src/output/charts/cartesian.c b/src/output/charts/cartesian.c
deleted file mode 100644 (file)
index cb2f346..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 <math.h>
-#include <assert.h>
-
-#include <output/chart.h>
-
-#include <output/charts/plot-chart.h>
-#include <output/charts/cartesian.h>
-#include <libpspp/compiler.h>
-
-
-/* Start a new vector called NAME */
-void
-chart_vector_start (struct chart *ch, const char *name)
-{
-  if ( ! ch )
-    return ;
-
-  pl_savestate_r (ch->lp);
-
-  pl_colorname_r (ch->lp, data_colour [ch->n_datasets % N_CHART_COLOURS]);
-
-  ch->n_datasets++;
-  ch->dataset = xrealloc (ch->dataset, ch->n_datasets * sizeof (*ch->dataset));
-
-  ch->dataset[ch->n_datasets - 1] = strdup (name);
-}
-
-/* Plot a data point */
-void
-chart_datum (struct chart *ch, int dataset UNUSED, double x, double y)
-{
-  if ( ! ch )
-    return ;
-
-  {
-    const double x_pos =
-      (x - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-
-    const double y_pos =
-      (y - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-
-    pl_savestate_r(ch->lp);
-
-    pl_fmarker_r(ch->lp, x_pos, y_pos, 6, 15);
-
-    pl_restorestate_r(ch->lp);
-  }
-}
-
-void
-chart_vector_end (struct chart *ch)
-{
-  pl_endpath_r (ch->lp);
-  pl_colorname_r (ch->lp, "black");
-  ch->in_path = false;
-  pl_restorestate_r (ch->lp);
-}
-
-/* Plot a data point */
-void
-chart_vector (struct chart *ch, double x, double y)
-{
-  if ( ! ch )
-    return ;
-
-  {
-    const double x_pos =
-      (x - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-
-    const double y_pos =
-      (y - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-
-    if ( ch->in_path)
-      pl_fcont_r (ch->lp, x_pos, y_pos);
-    else
-      {
-       pl_fmove_r (ch->lp, x_pos, y_pos);
-       ch->in_path = true;
-      }
-  }
-}
-
-
-
-/* Draw a line with slope SLOPE and intercept INTERCEPT.
-   between the points limit1 and limit2.
-   If lim_dim is CHART_DIM_Y then the limit{1,2} are on the
-   y axis otherwise the x axis
-*/
-void
-chart_line (struct chart *ch, double slope, double intercept,
-          double limit1, double limit2, enum CHART_DIM lim_dim)
-{
-  double x1, y1;
-  double x2, y2 ;
-
-  if ( ! ch )
-    return ;
-
-
-  if ( lim_dim == CHART_DIM_Y )
-    {
-      x1 = ( limit1 - intercept ) / slope ;
-      x2 = ( limit2 - intercept ) / slope ;
-      y1 = limit1;
-      y2 = limit2;
-    }
-  else
-    {
-      x1 = limit1;
-      x2 = limit2;
-      y1 = slope * x1 + intercept;
-      y2 = slope * x2 + intercept;
-    }
-
-  y1 = (y1 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-  y2 = (y2 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-  x1 = (x1 - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-  x2 = (x2 - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-
-  pl_savestate_r(ch->lp);
-
-  pl_fline_r(ch->lp, x1, y1, x2, y2);
-
-  pl_restorestate_r(ch->lp);
-}
diff --git a/src/output/charts/cartesian.h b/src/output/charts/cartesian.h
deleted file mode 100644 (file)
index 0874b9c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 CARTESIAN_H
-#define CARTESIAN_H
-
-
-enum CHART_DIM
-  {
-    CHART_DIM_X,
-    CHART_DIM_Y
-  };
-
-
-void chart_vector_start (struct chart *ch, const char *name);
-void chart_vector (struct chart *ch, double x, double y);
-void chart_vector_end (struct chart *ch);
-
-/* Plot a data point */
-void chart_datum (struct chart *ch, int dataset UNUSED, double x, double y);
-
-/* Draw a line with slope SLOPE and intercept INTERCEPT.
-   between the points limit1 and limit2.
-   If lim_dim is CHART_DIM_Y then the limit{1,2} are on the
-   y axis otherwise the x axis
-*/
-void chart_line (struct chart *ch, double slope, double intercept,
-               double limit1, double limit2, enum CHART_DIM lim_dim);
-
-
-#endif
diff --git a/src/output/charts/dummy-chart.c b/src/output/charts/dummy-chart.c
deleted file mode 100644 (file)
index e00a41f..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2005 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/>. */
-
-
-/* Stubs for plotting routines.
-   This module is linked only when charts are not supported */
-
-#include "config.h"
-#include <output/chart.h>
-#include <output/charts/box-whisker.h>
-#include <output/charts/piechart.h>
-#include <output/charts/plot-chart.h>
-#include <output/charts/plot-hist.h>
-#include <output/charts/cartesian.h>
-#include <gsl/gsl_histogram.h>
-#include <libpspp/compiler.h>
-
-#ifndef NO_CHARTS
-#error This file should be used only when compiling without charts.
-#endif
-
-void
-chart_write_legend (struct chart *ch UNUSED)
-{
-}
-
-void
-chart_vector (struct chart *ch UNUSED, double x UNUSED, double y UNUSED)
-{
-}
-
-void
-chart_vector_end (struct chart *ch UNUSED)
-{
-}
-
-void
-chart_vector_start (struct chart *ch UNUSED, const char *name UNUSED)
-{
-}
-
-void
-chart_write_title (struct chart *chart UNUSED, const char *title UNUSED, ...)
-{
-}
-
-
-void
-chart_write_xscale (struct chart *ch UNUSED,
-                   double min UNUSED, double max UNUSED, int ticks UNUSED)
-{
-}
-
-
-void
-chart_write_yscale (struct chart *ch UNUSED UNUSED,
-                   double smin UNUSED, double smax UNUSED, int ticks UNUSED)
-{
-}
-
-
-void
-chart_write_xlabel (struct chart *ch UNUSED, const char *label UNUSED)
-{
-}
-
-void
-chart_write_ylabel (struct chart *ch UNUSED, const char *label UNUSED)
-{
-}
-
-
-void
-chart_line (struct chart *ch UNUSED,
-           double slope UNUSED, double intercept UNUSED,
-           double limit1 UNUSED, double limit2 UNUSED,
-           enum CHART_DIM lim_dim UNUSED)
-{
-}
-
-
-void
-chart_datum (struct chart *ch UNUSED, int dataset UNUSED UNUSED,
-            double x UNUSED, double y UNUSED)
-{
-}
-
-void
-histogram_plot (const struct histogram *hist UNUSED,
-               const char *label UNUSED,
-               const struct moments1 *m UNUSED)
-{
-}
-
-void
-histogram_plot_n (const struct histogram *hist UNUSED,
-                 const char *label UNUSED,
-                 double n UNUSED, double mean UNUSED, double stddev UNUSED,
-                 bool show_normal UNUSED)
-{
-}
-
-
-void
-boxplot_draw_yscale (struct chart *ch UNUSED,
-                    double y_max UNUSED, double y_min UNUSED)
-{
-}
-
-void
-boxplot_draw_boxplot (struct chart *ch UNUSED,
-                     double box_centre UNUSED,
-                     double box_width UNUSED,
-                     const struct box_whisker *w UNUSED,
-                     const char *name UNUSED)
-{
-}
-
-
-
-
-void
-piechart_plot (const char *title UNUSED,
-              const struct slice *slices UNUSED, int n_slices UNUSED)
-{
-}
diff --git a/src/output/charts/np-plot-cairo.c b/src/output/charts/np-plot-cairo.c
new file mode 100644 (file)
index 0000000..a918652
--- /dev/null
@@ -0,0 +1,90 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/np-plot.h>
+
+#include <data/case.h>
+#include <data/casereader.h>
+#include <math/np.h>
+#include <output/cairo-chart.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static void
+np_plot_chart_draw (const struct chart_item *chart_item, cairo_t *cr,
+                    struct xrchart_geometry *geom)
+{
+  const struct np_plot_chart *npp = to_np_plot_chart (chart_item);
+  struct casereader *data;
+  struct ccase *c;
+
+  xrchart_write_title (cr, geom, _("Normal Q-Q Plot of %s"), npp->label);
+  xrchart_write_xlabel (cr, geom, _("Observed Value"));
+  xrchart_write_ylabel (cr, geom, _("Expected Normal"));
+  xrchart_write_xscale (cr, geom,
+                      npp->x_lower - npp->slack,
+                      npp->x_upper + npp->slack, 5);
+  xrchart_write_yscale (cr, geom, npp->y_first, npp->y_last, 5);
+
+  data = casereader_clone (npp->data);
+  for (; (c = casereader_read (data)) != NULL; case_unref (c))
+    xrchart_datum (cr, geom, 0,
+                 case_data_idx (c, NP_IDX_Y)->f,
+                 case_data_idx (c, NP_IDX_NS)->f);
+  casereader_destroy (data);
+
+  xrchart_line (cr, geom, npp->slope, npp->intercept,
+              npp->y_first, npp->y_last, XRCHART_DIM_Y);
+}
+
+static void
+dnp_plot_chart_draw (const struct chart_item *chart_item, cairo_t *cr,
+                     struct xrchart_geometry *geom)
+{
+  const struct np_plot_chart *dnpp = to_np_plot_chart (chart_item);
+  struct casereader *data;
+  struct ccase *c;
+
+  xrchart_write_title (cr, geom, _("Detrended Normal Q-Q Plot of %s"),
+                       dnpp->label);
+  xrchart_write_xlabel (cr, geom, _("Observed Value"));
+  xrchart_write_ylabel (cr, geom, _("Dev from Normal"));
+  xrchart_write_xscale (cr, geom, dnpp->y_min, dnpp->y_max, 5);
+  xrchart_write_yscale (cr, geom, dnpp->dns_min, dnpp->dns_max, 5);
+
+  data = casereader_clone (dnpp->data);
+  for (; (c = casereader_read (data)) != NULL; case_unref (c))
+    xrchart_datum (cr, geom, 0, case_data_idx (c, NP_IDX_Y)->f,
+                   case_data_idx (c, NP_IDX_DNS)->f);
+  casereader_destroy (data);
+
+  xrchart_line (cr, geom, 0, 0, dnpp->y_min, dnpp->y_max, XRCHART_DIM_X);
+}
+
+void
+xrchart_draw_np_plot (const struct chart_item *chart_item, cairo_t *cr,
+                      struct xrchart_geometry *geom)
+{
+  const struct np_plot_chart *npp = to_np_plot_chart (chart_item);
+
+  if (npp->detrended)
+    dnp_plot_chart_draw (chart_item, cr, geom);
+  else
+    np_plot_chart_draw (chart_item, cr, geom);
+}
diff --git a/src/output/charts/np-plot.c b/src/output/charts/np-plot.c
new file mode 100644 (file)
index 0000000..e912479
--- /dev/null
@@ -0,0 +1,107 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2008, 2009 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/charts/np-plot.h>
+
+#include <gsl/gsl_cdf.h>
+
+#include <data/casereader.h>
+#include <libpspp/cast.h>
+#include <math/np.h>
+#include <output/chart-item-provider.h>
+
+#include "gl/minmax.h"
+
+static struct chart_item *
+make_np_plot (const struct np *np, const struct casereader *reader,
+              const char *label, bool detrended)
+{
+  struct np_plot_chart *npp;
+
+  if (np->n < 1.0)
+    return NULL;
+
+  npp = xmalloc (sizeof *npp);
+  chart_item_init (&npp->chart_item, &np_plot_chart_class, label);
+  npp->data = casereader_clone (reader);
+  npp->y_min = np->y_min;
+  npp->y_max = np->y_max;
+  npp->dns_min = np->dns_min;
+  npp->dns_max = np->dns_max;
+  npp->detrended = detrended;
+
+  /* Slope and intercept of the ideal normal probability line. */
+  npp->slope = 1.0 / np->stddev;
+  npp->intercept = -np->mean / np->stddev;
+
+  npp->y_first = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
+  npp->y_last = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
+
+  /* Need to make sure that both the scatter plot and the ideal fit into the
+     plot. */
+  npp->x_lower = MIN (np->y_min, (npp->y_first - npp->intercept) / npp->slope);
+  npp->x_upper = MAX (np->y_max, (npp->y_last  - npp->intercept) / npp->slope);
+  npp->slack = (npp->x_upper - npp->x_lower) * 0.05;
+
+  return &npp->chart_item;
+}
+
+/* Creates and returns a normal probability plot corresponding to
+   the calculations in NP and the data in READER, and label the
+   plot with LABEL.  The data in READER must have Y-values in
+   value index NP_IDX_Y and NS-values in value index NP_IDX_NS.
+
+   Returns a null pointer if the data set is empty.
+
+   The caller retains ownership of NP and READER. */
+struct chart_item *
+np_plot_create (const struct np *np, const struct casereader *reader,
+                const char *label)
+{
+  return make_np_plot (np, reader, label, false);
+}
+
+/* Creates and returns a detrended normal probability plot
+   corresponding to the calculations in NP and the data in
+   READER, and label the plot with LABEL.  The data in READER
+   must have Y-values in value index NP_IDX_Y and DNS-values in
+   value index NP_IDX_DNS.
+
+   Returns a null pointer if the data set is empty.
+
+   The caller retains ownership of NP and READER. */
+struct chart_item *
+dnp_plot_create (const struct np *np, const struct casereader *reader,
+                 const char *label)
+{
+  return make_np_plot (np, reader, label, true);
+}
+
+static void
+np_plot_chart_destroy (struct chart_item *chart_item)
+{
+  struct np_plot_chart *npp = to_np_plot_chart (chart_item);
+  casereader_destroy (npp->data);
+  free (npp->label);
+  free (npp);
+}
+
+const struct chart_item_class np_plot_chart_class =
+  {
+    np_plot_chart_destroy
+  };
diff --git a/src/output/charts/np-plot.h b/src/output/charts/np-plot.h
new file mode 100644 (file)
index 0000000..82194e2
--- /dev/null
@@ -0,0 +1,110 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2004, 2008, 2009 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_CHARTS_NP_PLOT_H
+#define OUTPUT_CHARTS_NP_PLOT_H 1
+
+#include <output/chart-item.h>
+
+struct np;
+
+/* An NP or DNP plot. */
+struct np_plot_chart
+  {
+    struct chart_item chart_item;
+    char *label;
+    struct casereader *data;
+    bool detrended;
+
+    /* Copied directly from struct np. */
+    double y_min, y_max;
+    double dns_min, dns_max;
+
+    /* Calculated. */
+    double slope, intercept;
+    double y_first, y_last;
+    double x_lower, x_upper;
+    double slack;
+  };
+
+struct chart_item *np_plot_create (const struct np *,
+                                   const struct casereader *,
+                                   const char *label);
+struct chart_item *dnp_plot_create (const struct np *,
+                                    const struct casereader *,
+                                    const char *label);
+\f
+/* This boilerplate for np_plot_chart, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct chart_item_class np_plot_chart_class;
+
+/* Returns true if SUPER is a np_plot_chart, otherwise false. */
+static inline bool
+is_np_plot_chart (const struct chart_item *super)
+{
+  return super->class == &np_plot_chart_class;
+}
+
+/* Returns SUPER converted to np_plot_chart.  SUPER must be a np_plot_chart, as
+   reported by is_np_plot_chart. */
+static inline struct np_plot_chart *
+to_np_plot_chart (const struct chart_item *super)
+{
+  assert (is_np_plot_chart (super));
+  return UP_CAST (super, struct np_plot_chart, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+np_plot_chart_super (const struct np_plot_chart *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct np_plot_chart *
+np_plot_chart_ref (const struct np_plot_chart *instance)
+{
+  return to_np_plot_chart (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+np_plot_chart_unref (struct np_plot_chart *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+np_plot_chart_is_shared (const struct np_plot_chart *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+np_plot_chart_submit (struct np_plot_chart *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/np-plot.h */
diff --git a/src/output/charts/piechart-cairo.c b/src/output/charts/piechart-cairo.c
new file mode 100644 (file)
index 0000000..501c0bd
--- /dev/null
@@ -0,0 +1,123 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/piechart.h>
+
+#include <math.h>
+
+#include <output/cairo-chart.h>
+
+#include "gl/minmax.h"
+
+/* Draw a single slice of the pie */
+static void
+draw_segment(cairo_t *cr,
+            double x0, double y0,
+            double radius,
+            double start_angle, double segment_angle,
+            const struct xrchart_colour *colour)
+{
+  cairo_move_to (cr, x0, y0);
+  cairo_arc (cr, x0, y0, radius, start_angle, start_angle + segment_angle);
+  cairo_line_to (cr, x0, y0);
+  cairo_save (cr);
+  cairo_set_source_rgb (cr,
+                        colour->red / 255.0,
+                        colour->green / 255.0,
+                        colour->blue / 255.0);
+  cairo_fill_preserve (cr);
+  cairo_restore (cr);
+  cairo_stroke (cr);
+}
+
+void
+xrchart_draw_piechart (const struct chart_item *chart_item, cairo_t *cr,
+                       struct xrchart_geometry *geom)
+{
+  const struct piechart *pie = to_piechart (chart_item);
+  double total_magnitude;
+  double left_label, right_label;
+  double centre_x, centre_y;
+  double radius;
+  double angle;
+  int i;
+
+  centre_x = (geom->data_right + geom->data_left) / 2.0 ;
+  centre_y = (geom->data_top + geom->data_bottom) / 2.0 ;
+
+  left_label = geom->data_left + (geom->data_right - geom->data_left)/10.0;
+  right_label = geom->data_right - (geom->data_right - geom->data_left)/10.0;
+
+  radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
+                1.0 / 4.0 * (geom->data_right - geom->data_left));
+
+  radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
+                1.0 / 4.0 * (geom->data_right - geom->data_left));
+
+  xrchart_write_title (cr, geom, "%s", chart_item_get_title (chart_item));
+
+  total_magnitude = 0.0;
+  for (i = 0; i < pie->n_slices; i++)
+    total_magnitude += pie->slices[i].magnitude;
+
+  angle = 0.0;
+  for (i = 0; i < pie->n_slices ; ++i )
+    {
+      const double segment_angle =
+       pie->slices[i].magnitude / total_magnitude * 2 * M_PI ;
+
+      const double label_x = centre_x -
+       radius * sin(angle + segment_angle/2.0);
+
+      const double label_y = centre_y +
+       radius * cos(angle + segment_angle/2.0);
+
+      /* Fill the segment */
+      draw_segment (cr,
+                    centre_x, centre_y, radius,
+                    angle, segment_angle,
+                    &data_colour[i % XRCHART_N_COLOURS]);
+
+      /* Now add the labels */
+      if ( label_x < centre_x )
+       {
+          cairo_move_to (cr, label_x, label_y);
+          cairo_line_to (cr, left_label, label_y);
+          cairo_stroke (cr);
+         cairo_move_to (cr, left_label, label_y + 5);
+         xrchart_label (cr, 'l', 'x', geom->font_size,
+                         ds_cstr (&pie->slices[i].label));
+       }
+      else
+       {
+         cairo_move_to (cr, label_x, label_y);
+          cairo_line_to (cr, right_label, label_y);
+          cairo_stroke (cr);
+         cairo_move_to (cr, right_label, label_y + 5);
+         xrchart_label (cr, 'r', 'x', geom->font_size,
+                         ds_cstr (&pie->slices[i].label));
+       }
+
+      angle += segment_angle;
+    }
+
+  /* Draw an outline to the pie */
+  cairo_arc (cr, centre_x, centre_y, radius, 0, 2 * M_PI);
+  cairo_stroke (cr);
+}
+
index d7db80e921a6f573991ed0be14e1eaf583e8527d..0b9153d545b76d26340532a22b9e218bb29f15c6 100644 (file)
    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 <float.h>
-#include <assert.h>
-#include <math.h>
-#include <stdio.h>
-
-
 #include <output/charts/piechart.h>
-#include <output/charts/plot-chart.h>
-
-#include <output/chart.h>
-#include <libpspp/str.h>
-#include <data/value-labels.h>
-
-#include "minmax.h"
-
 
-/* Pie charts of course need to know Pi :) */
-#ifndef M_PI
-#define M_PI ( 22.0 / 7.0 )
-#endif
-
-
-
-/* Draw a single slice of the pie */
-static void
-draw_segment(struct chart *ch,
-            double centre_x, double centre_y,
-            double radius,
-            double start_angle, double segment_angle,
-            const char *colour) ;
+#include <stdlib.h>
 
+#include <libpspp/cast.h>
+#include <libpspp/str.h>
+#include <output/chart-item-provider.h>
 
+#include "gl/xalloc.h"
 
-/* Draw a piechart */
-void
-piechart_plot(const char *title, const struct slice *slices, int n_slices)
+/* Creates and returns a chart that will render a piechart with
+   the given TITLE and the N_SLICES described in SLICES. */
+struct chart_item *
+piechart_create (const char *title, const struct slice *slices, int n_slices)
 {
+  struct piechart *pie;
   int i;
-  double total_magnetude=0;
-
-  struct chart *ch;
-
-  double left_label;
-  double right_label;
 
-  double centre_x;
-  double centre_y;
-
-  double radius;
-
-  ch = chart_create ();
-  if (ch == NULL)
-    return;
-
-  left_label = ch->data_left + (ch->data_right - ch->data_left)/10.0;
-  right_label = ch->data_right - (ch->data_right - ch->data_left)/10.0;
-  centre_x = (ch->data_right + ch->data_left ) / 2.0;
-  centre_y = (ch->data_top + ch->data_bottom ) / 2.0;
-  radius = MIN (5.0 / 12.0 * (ch->data_top - ch->data_bottom),
-                1.0 / 4.0 * (ch->data_right - ch->data_left));
-
-  chart_write_title(ch, "%s", title);
-
-  for (i = 0 ; i < n_slices ; ++i )
-    total_magnetude += slices[i].magnetude;
-
-  for (i = 0 ; i < n_slices ; ++i )
+  pie = xmalloc (sizeof *pie);
+  chart_item_init (&pie->chart_item, &piechart_class, title);
+  pie->slices = xnmalloc (n_slices, sizeof *pie->slices);
+  for (i = 0; i < n_slices; i++)
     {
-      static double angle=0.0;
-
-      const double segment_angle =
-       slices[i].magnetude / total_magnetude * 2 * M_PI ;
-
-      const double label_x = centre_x -
-       radius * sin(angle + segment_angle/2.0);
-
-      const double label_y = centre_y +
-       radius * cos(angle + segment_angle/2.0);
-
-      /* Fill the segment */
-      draw_segment(ch,
-                  centre_x, centre_y, radius,
-                  angle, segment_angle,
-                  data_colour[i % N_CHART_COLOURS]);
-
-      /* Now add the labels */
-      if ( label_x < centre_x )
-       {
-         pl_line_r(ch->lp, label_x, label_y,
-                   left_label, label_y );
-         pl_moverel_r(ch->lp,0,5);
-         pl_alabel_r (ch->lp, 0, 0, ds_cstr (&slices[i].label));
-       }
-      else
-       {
-         pl_line_r(ch->lp,
-                   label_x, label_y,
-                   right_label, label_y
-                   );
-         pl_moverel_r(ch->lp,0,5);
-         pl_alabel_r (ch->lp, 'r', 0, ds_cstr (&slices[i].label));
-       }
-
-      angle += segment_angle;
+      const struct slice *src = &slices[i];
+      struct slice *dst = &pie->slices[i];
 
+      ds_init_string (&dst->label, &src->label);
+      dst->magnitude = src->magnitude;
     }
-
-  /* Draw an outline to the pie */
-  pl_filltype_r(ch->lp,0);
-  pl_fcircle_r (ch->lp, centre_x, centre_y, radius);
-
-  chart_submit(ch);
+  pie->n_slices = n_slices;
+  return &pie->chart_item;
 }
 
 static void
-fill_segment(struct chart *ch,
-            double x0, double y0,
-            double radius,
-            double start_angle, double segment_angle) ;
-
-
-/* Fill a segment with the current fill colour */
-static void
-fill_segment(struct chart *ch,
-            double x0, double y0,
-            double radius,
-            double start_angle, double segment_angle)
+piechart_destroy (struct chart_item *chart_item)
 {
+  struct piechart *pie = to_piechart (chart_item);
+  int i;
 
-  const double start_x  = x0 - radius * sin(start_angle);
-  const double start_y  = y0 + radius * cos(start_angle);
-
-  const double stop_x   =
-    x0 - radius * sin(start_angle + segment_angle);
-
-  const double stop_y   =
-    y0 + radius * cos(start_angle + segment_angle);
-
-  assert(segment_angle <= 2 * M_PI);
-  assert(segment_angle >= 0);
-
-  if ( segment_angle > M_PI )
-    {
-      /* Then we must draw it in two halves */
-      fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 );
-      fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0,
-                  segment_angle / 2.0 );
-    }
-  else
+  for (i = 0; i < pie->n_slices; i++)
     {
-      pl_move_r(ch->lp, x0, y0);
-
-      pl_cont_r(ch->lp, stop_x, stop_y);
-      pl_cont_r(ch->lp, start_x, start_y);
-
-      pl_arc_r(ch->lp,
-              x0, y0,
-              stop_x, stop_y,
-              start_x, start_y
-              );
-
-      pl_endpath_r(ch->lp);
+      struct slice *slice = &pie->slices[i];
+      ds_destroy (&slice->label);
     }
+  free (pie->slices);
+  free (pie);
 }
 
-
-
-/* Draw a single slice of the pie */
-static void
-draw_segment(struct chart *ch,
-            double x0, double y0,
-            double radius,
-            double start_angle, double segment_angle,
-            const char *colour)
-{
-  const double start_x  = x0 - radius * sin(start_angle);
-  const double start_y  = y0 + radius * cos(start_angle);
-
-  pl_savestate_r(ch->lp);
-
-  pl_savestate_r(ch->lp);
-  pl_colorname_r(ch->lp, colour);
-
-  pl_pentype_r(ch->lp,1);
-  pl_filltype_r(ch->lp,1);
-
-  fill_segment(ch, x0, y0, radius, start_angle, segment_angle);
-  pl_restorestate_r(ch->lp);
-
-  /* Draw line dividing segments */
-  pl_pentype_r(ch->lp, 1);
-  pl_fline_r(ch->lp, x0, y0, start_x, start_y);
-
-
-  pl_restorestate_r(ch->lp);
-}
-
+const struct chart_item_class piechart_class =
+  {
+    piechart_destroy
+  };
index 96540401e7406f61e33259a7117e983d18e78fb9..312a45ee08ce759f84e9c02e2991ca9acd3163f0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009 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
 #define PIECHART_H
 
 #include <libpspp/str.h>
+#include <output/chart-item.h>
 
-struct slice {
-  struct string label;
-  double magnetude;
-};
+struct piechart
+  {
+    struct chart_item chart_item;
+    struct slice *slices;
+    int n_slices;
+  };
 
-/* Draw a piechart */
-void piechart_plot(const char *title,
-                  const struct slice *slices, int n_slices);
+struct slice
+  {
+    struct string label;
+    double magnitude;
+  };
 
-#endif
+struct chart_item *piechart_create (const char *title,
+                                    const struct slice *, int n_slices);
+\f
+/* This boilerplate for piechart, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
 
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct chart_item_class piechart_class;
+
+/* Returns true if SUPER is a piechart, otherwise false. */
+static inline bool
+is_piechart (const struct chart_item *super)
+{
+  return super->class == &piechart_class;
+}
+
+/* Returns SUPER converted to piechart.  SUPER must be a piechart, as
+   reported by is_piechart. */
+static inline struct piechart *
+to_piechart (const struct chart_item *super)
+{
+  assert (is_piechart (super));
+  return UP_CAST (super, struct piechart, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+piechart_super (const struct piechart *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct piechart *
+piechart_ref (const struct piechart *instance)
+{
+  return to_piechart (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+piechart_unref (struct piechart *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+piechart_is_shared (const struct piechart *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+piechart_submit (struct piechart *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/piechart.h */
diff --git a/src/output/charts/plot-chart.c b/src/output/charts/plot-chart.c
deleted file mode 100644 (file)
index 5641db1..0000000
+++ /dev/null
@@ -1,256 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 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 <stdio.h>
-#include <plot.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <float.h>
-#include <assert.h>
-#include <math.h>
-
-#include <output/charts/plot-chart.h>
-
-#include <math/chart-geometry.h>
-
-
-
-#include <libpspp/str.h>
-#include <libpspp/assertion.h>
-#include <output/manager.h>
-#include <output/output.h>
-
-#include "xalloc.h"
-
-const char *const data_colour[N_CHART_COLOURS] =
-  {
-    "brown",
-    "red",
-    "orange",
-    "yellow",
-    "green",
-    "blue",
-    "violet",
-    "grey",
-    "pink"
-  };
-
-
-
-/* Draw a tick mark at position
-   If label is non zero, then print it at the tick mark
-*/
-void
-draw_tick(struct chart *chart,
-         enum tick_orientation orientation,
-         double position,
-         const char *label, ...)
-{
-  const int tickSize = 10;
-
-  assert(chart);
-
-  pl_savestate_r(chart->lp);
-
-  pl_move_r(chart->lp, chart->data_left, chart->data_bottom);
-
-  if ( orientation == TICK_ABSCISSA )
-    pl_flinerel_r(chart->lp, position, 0, position, -tickSize);
-  else if (orientation == TICK_ORDINATE )
-      pl_flinerel_r(chart->lp, 0, position, -tickSize, position);
-  else
-    NOT_REACHED ();
-
-  if ( label ) {
-    char buf[10];
-    va_list ap;
-    va_start(ap,label);
-    vsnprintf(buf,10,label,ap);
-
-    if ( orientation == TICK_ABSCISSA )
-      pl_alabel_r(chart->lp, 'c','t', buf);
-    else if (orientation == TICK_ORDINATE )
-      {
-       if ( fabs(position) < DBL_EPSILON )
-           pl_moverel_r(chart->lp, 0, 10);
-
-       pl_alabel_r(chart->lp, 'r','c', buf);
-      }
-
-    va_end(ap);
-  }
-
-  pl_restorestate_r(chart->lp);
-}
-
-
-/* Write the title on a chart*/
-void
-chart_write_title(struct chart *chart, const char *title, ...)
-{
-  va_list ap;
-  char buf[100];
-
-  if ( ! chart )
-         return ;
-
-  pl_savestate_r(chart->lp);
-  pl_ffontsize_r(chart->lp,chart->font_size * 1.5);
-  pl_move_r(chart->lp,chart->data_left, chart->title_bottom);
-
-  va_start(ap,title);
-  vsnprintf(buf,100,title,ap);
-  pl_alabel_r(chart->lp,0,0,buf);
-  va_end(ap);
-
-  pl_restorestate_r(chart->lp);
-}
-
-
-/* Set the scale for the abscissa */
-void
-chart_write_xscale(struct chart *ch, double min, double max, int ticks)
-{
-  double x;
-
-  const double tick_interval =
-    chart_rounded_tick( (max - min) / (double) ticks);
-
-  assert ( ch );
-
-
-  ch->x_max = ceil( max / tick_interval ) * tick_interval ;
-  ch->x_min = floor ( min / tick_interval ) * tick_interval ;
-
-
-  ch->abscissa_scale = fabs(ch->data_right - ch->data_left) /
-    fabs(ch->x_max - ch->x_min);
-
-  for(x = ch->x_min ; x <= ch->x_max; x += tick_interval )
-    {
-      draw_tick (ch, TICK_ABSCISSA,
-                (x - ch->x_min) * ch->abscissa_scale, "%g", x);
-    }
-
-}
-
-
-/* Set the scale for the ordinate */
-void
-chart_write_yscale(struct chart *ch, double smin, double smax, int ticks)
-{
-  double y;
-
-  const double tick_interval =
-    chart_rounded_tick( (smax - smin) / (double) ticks);
-
-  if ( !ch )
-         return;
-
-  ch->y_max = ceil  ( smax / tick_interval ) * tick_interval ;
-  ch->y_min = floor ( smin / tick_interval ) * tick_interval ;
-
-  ch->ordinate_scale =
-    fabs(ch->data_top -  ch->data_bottom) / fabs(ch->y_max - ch->y_min) ;
-
-  for(y = ch->y_min ; y <= ch->y_max; y += tick_interval )
-    {
-    draw_tick (ch, TICK_ORDINATE,
-              (y - ch->y_min) * ch->ordinate_scale, "%g", y);
-    }
-}
-
-
-/* Write the abscissa label */
-void
-chart_write_xlabel(struct chart *ch, const char *label)
-{
-  if ( ! ch )
-    return ;
-
-  pl_savestate_r(ch->lp);
-
-  pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
-  pl_alabel_r(ch->lp,0,'t',label);
-
-  pl_restorestate_r(ch->lp);
-
-}
-
-
-
-/* Write the ordinate label */
-void
-chart_write_ylabel(struct chart *ch, const char *label)
-{
-  if ( ! ch )
-    return ;
-
-  pl_savestate_r(ch->lp);
-
-  pl_move_r(ch->lp, ch->data_bottom, ch->ordinate_right);
-  pl_textangle_r(ch->lp, 90);
-  pl_alabel_r(ch->lp, 0, 0, label);
-
-  pl_restorestate_r(ch->lp);
-}
-
-
-void
-chart_write_legend (struct chart *ch)
-{
-  int i;
-  const int vstep = ch->font_size * 2;
-  const int xpad = 10;
-  const int ypad = 10;
-  const int swatch = 20;
-  const int legend_top = ch->data_top;
-  const int legend_bottom = legend_top -
-    (vstep * ch->n_datasets + 2 * ypad );
-
-  if ( ! ch )
-    return ;
-
-  pl_savestate_r (ch->lp);
-
-  pl_box_r (ch->lp, ch->legend_left, legend_top,
-           ch->legend_right - xpad, legend_bottom);
-
-  for (i = 0 ; i < ch->n_datasets ; ++i )
-    {
-      const int ypos = vstep * (i + 1);
-      const int xpos = ch->legend_left + xpad;
-      pl_move_r (ch->lp, xpos, legend_top - ypos);
-
-      pl_savestate_r(ch->lp);
-       pl_fillcolorname_r (ch->lp, data_colour [ i % N_CHART_COLOURS]);
-
-       pl_pentype_r (ch->lp, 1);
-       pl_filltype_r (ch->lp, 1);
-       pl_boxrel_r (ch->lp, 0, 0, swatch, swatch);
-
-
-      pl_moverel_r (ch->lp, swatch, 0);
-      pl_alabel_r (ch->lp, 0, 0, ch->dataset[i]);
-
-      pl_restorestate_r (ch->lp);
-    }
-
-  pl_restorestate_r (ch->lp);
-}
diff --git a/src/output/charts/plot-chart.h b/src/output/charts/plot-chart.h
deleted file mode 100644 (file)
index cfbaa4d..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 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 <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <float.h>
-#include <assert.h>
-#include <math.h>
-
-
-#include <math/chart-geometry.h>
-#include <output/chart.h>
-
-#include <libpspp/compiler.h>
-#include <libpspp/str.h>
-#include <output/manager.h>
-#include <output/output.h>
-
-#include "xalloc.h"
-
-#ifndef PLOT_CHART_H
-#define PLOT_CHART_H
-
-#define N_CHART_COLOURS 9
-extern const char *const data_colour[];
-
-enum tick_orientation
-  {
-    TICK_ABSCISSA=0,
-    TICK_ORDINATE
-  };
-
-
-/* Draw a tick mark at position
-   If label is non zero, then print it at the tick mark
-*/
-void draw_tick(struct chart *chart,
-         enum tick_orientation orientation,
-         double position,
-              const char *label, ...)
-  PRINTF_FORMAT (4, 5);
-
-
-/* Write the title on a chart*/
-void   chart_write_title(struct chart *chart, const char *title, ...)
-  PRINTF_FORMAT (2, 3);
-
-
-/* Set the scale for the abscissa */
-void  chart_write_xscale(struct chart *ch, double min, double max, int ticks);
-
-
-/* Set the scale for the ordinate */
-void  chart_write_yscale(struct chart *ch, double smin, double smax, int ticks);
-
-void chart_write_xlabel(struct chart *ch, const char *label) ;
-
-/* Write the ordinate label */
-void  chart_write_ylabel(struct chart *ch, const char *label);
-
-void chart_write_legend (struct chart *ch);
-
-#endif
diff --git a/src/output/charts/plot-hist-cairo.c b/src/output/charts/plot-hist-cairo.c
new file mode 100644 (file)
index 0000000..a70fa17
--- /dev/null
@@ -0,0 +1,162 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/plot-hist.h>
+
+#include <gsl/gsl_randist.h>
+
+#include <data/val-type.h>
+#include <output/cairo-chart.h>
+
+#include "gl/xvasprintf.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Write the legend of the chart */
+static void
+histogram_write_legend (cairo_t *cr, const struct xrchart_geometry *geom,
+                        double n, double mean, double stddev)
+{
+  double y = geom->data_bottom;
+  cairo_save (cr);
+
+  if (n != SYSMIS)
+    {
+      char *buf = xasprintf ("N = %.2f", n);
+      cairo_move_to (cr, geom->legend_left, y);
+      xrchart_label (cr, 'l', 'b', geom->font_size, buf);
+      y += geom->font_size * 1.5;
+      free (buf);
+    }
+
+  if (mean != SYSMIS)
+    {
+      char *buf = xasprintf ("Mean = %.1f", mean);
+      cairo_move_to (cr,geom->legend_left, y);
+      xrchart_label (cr, 'l', 'b', geom->font_size, buf);
+      y += geom->font_size * 1.5;
+      free (buf);
+    }
+
+  if (stddev != SYSMIS)
+    {
+      char *buf = xasprintf ("Std. Dev = %.2f", stddev);
+      cairo_move_to (cr, geom->legend_left, y);
+      xrchart_label (cr, 'l', 'b', geom->font_size, buf);
+      free (buf);
+    }
+
+  cairo_restore (cr);
+}
+
+static void
+hist_draw_bar (cairo_t *cr, const struct xrchart_geometry *geom,
+               const gsl_histogram *h, int bar)
+{
+  double upper;
+  double lower;
+  double height;
+
+  const size_t bins = gsl_histogram_bins (h);
+  const double x_pos = (geom->data_right - geom->data_left) * bar / (double) bins ;
+  const double width = (geom->data_right - geom->data_left) / (double) bins ;
+
+  assert ( 0 == gsl_histogram_get_range (h, bar, &lower, &upper));
+
+  assert ( upper >= lower);
+
+  height = gsl_histogram_get (h, bar) *
+    (geom->data_top - geom->data_bottom) / gsl_histogram_max_val (h);
+
+  cairo_rectangle (cr, geom->data_left + x_pos, geom->data_bottom,
+                   width, height);
+  cairo_save (cr);
+  cairo_set_source_rgb (cr,
+                        geom->fill_colour.red / 255.0,
+                        geom->fill_colour.green / 255.0,
+                        geom->fill_colour.blue / 255.0);
+  cairo_fill_preserve (cr);
+  cairo_restore (cr);
+  cairo_stroke (cr);
+
+  draw_tick (cr, geom, TICK_ABSCISSA,
+             x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
+}
+
+void
+xrchart_draw_histogram (const struct chart_item *chart_item, cairo_t *cr,
+                        struct xrchart_geometry *geom)
+{
+  struct histogram_chart *h = to_histogram_chart (chart_item);
+  int i;
+  int bins;
+
+  xrchart_write_title (cr, geom, _("HISTOGRAM"));
+
+  xrchart_write_ylabel (cr, geom, _("Frequency"));
+  xrchart_write_xlabel (cr, geom, chart_item_get_title (chart_item));
+
+  if (h->gsl_hist == NULL)
+    {
+      /* Probably all values are SYSMIS. */
+      return;
+    }
+
+  bins = gsl_histogram_bins (h->gsl_hist);
+
+  xrchart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist), 5);
+
+  for (i = 0; i < bins; i++)
+    hist_draw_bar (cr, geom, h->gsl_hist, i);
+
+  histogram_write_legend (cr, geom, h->n, h->mean, h->stddev);
+
+  if (h->show_normal
+      && h->n != SYSMIS && h->mean != SYSMIS && h->stddev != SYSMIS)
+    {
+      /* Draw the normal curve */
+      double d;
+      double x_min, x_max, not_used;
+      double abscissa_scale;
+      double ordinate_scale;
+      double range;
+
+      gsl_histogram_get_range (h->gsl_hist, 0, &x_min, &not_used);
+      range = not_used - x_min;
+      gsl_histogram_get_range (h->gsl_hist, bins - 1, &not_used, &x_max);
+
+      abscissa_scale = (geom->data_right - geom->data_left) / (x_max - x_min);
+      ordinate_scale = (geom->data_top - geom->data_bottom) /
+       gsl_histogram_max_val (h->gsl_hist);
+
+      cairo_move_to (cr, geom->data_left, geom->data_bottom);
+      for (d = geom->data_left;
+          d <= geom->data_right;
+          d += (geom->data_right - geom->data_left) / 100.0)
+       {
+         const double x = (d - geom->data_left) / abscissa_scale + x_min;
+         const double y = h->n * range *
+           gsl_ran_gaussian_pdf (x - h->mean, h->stddev);
+
+          cairo_line_to (cr, d, geom->data_bottom  + y * ordinate_scale);
+
+       }
+      cairo_stroke (cr);
+    }
+}
index fbf1925e635e165c3c096d119bace8123fa0d5bc..5925df6d1a35af5d0122f75312b497bc01e68eb8 100644 (file)
 #include <config.h>
 
 #include <stdio.h>
-#include <plot.h>
 #include <math.h>
-#include <gsl/gsl_histogram.h>
 #include <gsl/gsl_randist.h>
 #include <assert.h>
 
 #include <output/charts/plot-hist.h>
-#include <output/charts/plot-chart.h>
+#include <output/chart-item-provider.h>
 
-#include <data/variable.h>
-#include <libpspp/hash.h>
-#include <output/chart.h>
+#include <libpspp/cast.h>
 #include <math/histogram.h>
 #include <math/moments.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Write the legend of the chart */
-static void
-histogram_write_legend (struct chart *ch, double n, double mean, double stddev)
+/* Plots a histogram of the data in HIST with the given LABEL.
+   Labels the histogram with each of N, MEAN, and STDDEV that is
+   not SYSMIS.  If all three are not SYSMIS and SHOW_NORMAL is
+   true, also draws a normal curve on the histogram. */
+struct chart_item *
+histogram_chart_create (const gsl_histogram *hist, const char *label,
+                        double n, double mean, double stddev,
+                        bool show_normal)
 {
-  char buf[100];
-
-  if (!ch)
-    return ;
-
-  pl_savestate_r (ch->lp);
-
-  sprintf (buf, "N = %.2f", n);
-  pl_move_r (ch->lp, ch->legend_left, ch->data_bottom);
-  pl_alabel_r (ch->lp, 0, 'b', buf);
-
-  sprintf (buf, "Mean = %.1f", mean);
-  pl_fmove_r (ch->lp,ch->legend_left,ch->data_bottom + ch->font_size * 1.5);
-  pl_alabel_r (ch->lp, 0, 'b', buf);
-
-  sprintf (buf, "Std. Dev = %.2f", stddev);
-  pl_fmove_r (ch->lp, ch->legend_left, ch->data_bottom + ch->font_size * 1.5 * 2);
-  pl_alabel_r (ch->lp, 0, 'b', buf);
-
-  pl_restorestate_r (ch->lp);
+  struct histogram_chart *h;
+
+  h = xmalloc (sizeof *h);
+  chart_item_init (&h->chart_item, &histogram_chart_class, label);
+  h->gsl_hist = hist != NULL ? gsl_histogram_clone (hist) : NULL;
+  h->n = n;
+  h->mean = mean;
+  h->stddev = stddev;
+  h->show_normal = show_normal;
+  return &h->chart_item;
 }
 
-static void hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar);
-
-
 static void
-hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar)
-{
-  if (!ch)
-    return ;
-
-  {
-    double upper;
-    double lower;
-    double height;
-
-    const size_t bins = gsl_histogram_bins (hist->gsl_hist);
-    const double x_pos = (ch->data_right - ch->data_left) * bar / (double) bins ;
-    const double width = (ch->data_right - ch->data_left) / (double) bins ;
-
-    assert ( 0 == gsl_histogram_get_range (hist->gsl_hist, bar, &lower, &upper));
-
-    assert ( upper >= lower);
-
-    height = gsl_histogram_get (hist->gsl_hist, bar) *
-     (ch->data_top - ch->data_bottom) / gsl_histogram_max_val (hist->gsl_hist);
-
-    pl_savestate_r (ch->lp);
-    pl_move_r (ch->lp,ch->data_left, ch->data_bottom);
-    pl_fillcolorname_r (ch->lp, ch->fill_colour);
-    pl_filltype_r (ch->lp,1);
-
-
-    pl_fboxrel_r (ch->lp,
-                x_pos, 0,
-                x_pos + width, height);
-
-    pl_restorestate_r (ch->lp);
-
-    draw_tick (ch, TICK_ABSCISSA,
-               x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
-  }
-}
-
-
-
-void
-histogram_plot (const struct histogram *hist,
-               const char *label,
-               const struct moments1 *m)
-{
-  double mean, var, n;
-
-  moments1_calculate (m, &n, &mean, &var, NULL,  NULL);
-
-  histogram_plot_n (hist, label, n, mean, sqrt(var), m);
-}
-
-
-/* This function is deprecated.  Don't use it in new code */
-void
-histogram_plot_n (const struct histogram *hist,
-                 const char *label,
-                 double n, double mean, double stddev,
-                 bool show_normal)
+histogram_chart_destroy (struct chart_item *chart_item)
 {
-  int i;
-  int bins;
-
-  struct chart *ch = chart_create ();
-
-  chart_write_title (ch, _("HISTOGRAM"));
-
-  chart_write_ylabel (ch, _("Frequency"));
-  chart_write_xlabel (ch, label);
-
-  if ( ! hist ) /* If this happens, probably all values are SYSMIS */
-    {
-      chart_submit (ch);
-      return;
-    }
-  else
-    {
-      bins = gsl_histogram_bins (hist->gsl_hist);
-    }
-
-  chart_write_yscale (ch, 0, gsl_histogram_max_val (hist->gsl_hist), 5);
-
-  for ( i = 0 ; i < bins ; ++i )
-    hist_draw_bar (ch, hist, i);
-
-  histogram_write_legend (ch, n, mean, stddev);
-
-  if (show_normal)
-    {
-      /* Draw the normal curve */
-
-      double d ;
-      double x_min, x_max, not_used ;
-      double abscissa_scale ;
-      double ordinate_scale ;
-      double range ;
-
-      gsl_histogram_get_range (hist->gsl_hist, 0, &x_min, &not_used);
-      range = not_used - x_min;
-      gsl_histogram_get_range (hist->gsl_hist, bins - 1, &not_used, &x_max);
-
-      abscissa_scale = (ch->data_right - ch->data_left) / (x_max - x_min);
-      ordinate_scale = (ch->data_top - ch->data_bottom) /
-       gsl_histogram_max_val (hist->gsl_hist) ;
-
-      pl_move_r (ch->lp, ch->data_left, ch->data_bottom);
-      for ( d = ch->data_left;
-           d <= ch->data_right ;
-           d += (ch->data_right - ch->data_left) / 100.0)
-       {
-         const double x = (d - ch->data_left) / abscissa_scale + x_min ;
-         const double y = n * range *
-           gsl_ran_gaussian_pdf (x - mean, stddev);
-
-         pl_fcont_r (ch->lp,  d,  ch->data_bottom  + y * ordinate_scale);
-
-       }
-      pl_endpath_r (ch->lp);
-    }
-
-  chart_submit (ch);
+  struct histogram_chart *h = UP_CAST (chart_item, struct histogram_chart,
+                                       chart_item);
+  if (h->gsl_hist != NULL)
+    gsl_histogram_free (h->gsl_hist);
+  free (h);
 }
 
-
+const struct chart_item_class histogram_chart_class =
+  {
+    histogram_chart_destroy
+  };
index 606206d5012c47d4e7b239e0a0230bf1788cea8e..237b8b3c11ef7d2ac612675ef879b456a96cf714 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009 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
    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 PLOT_HIST_H
-#define PLOT_HIST_H
+#ifndef OUTPUT_PLOT_HIST_H
+#define OUTPUT_PLOT_HIST_H
 
+#include <gsl/gsl_histogram.h>
 #include <stdbool.h>
 
-struct chart;
-struct moments1;
-struct histogram;
+#include "output/chart-item.h"
 
-/* Plot M onto histogram HIST and label it with LABEL */
-void histogram_plot (const struct histogram *hist,
-                    const char *label,  const struct moments1 *m);
+struct histogram_chart
+  {
+    struct chart_item chart_item;
+    gsl_histogram *gsl_hist;
+    double n;
+    double mean;
+    double stddev;
+    bool show_normal;
+  };
 
+/* Creates and returns a new chart that depicts a histogram of
+   the data in HIST with the given LABEL.  Labels the histogram
+   with each of N, MEAN, and STDDEV that is not SYSMIS.  If all
+   three are not SYSMIS and SHOW_NORMAL is true, also draws a
+   normal curve on the histogram. */
+struct chart_item *histogram_chart_create (const gsl_histogram *,
+                                           const char *label, double n,
+                                           double mean, double stddev,
+                                           bool show_normal);
+\f
+/* This boilerplate for histogram_chart, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
 
-/* A wrapper aroud histogram_plot.
-   Don't use this function.  It's legacy only */
-void histogram_plot_n (const struct histogram *hist,
-                      const char *label,
-                      double n, double mean, double var,
-                      bool show_normal);
+#include <assert.h>
+#include <libpspp/cast.h>
 
+extern const struct chart_item_class histogram_chart_class;
 
-#endif
+/* Returns true if SUPER is a histogram_chart, otherwise false. */
+static inline bool
+is_histogram_chart (const struct chart_item *super)
+{
+  return super->class == &histogram_chart_class;
+}
+
+/* Returns SUPER converted to histogram_chart.  SUPER must be a histogram_chart, as
+   reported by is_histogram_chart. */
+static inline struct histogram_chart *
+to_histogram_chart (const struct chart_item *super)
+{
+  assert (is_histogram_chart (super));
+  return UP_CAST (super, struct histogram_chart, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+histogram_chart_super (const struct histogram_chart *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct histogram_chart *
+histogram_chart_ref (const struct histogram_chart *instance)
+{
+  return to_histogram_chart (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+histogram_chart_unref (struct histogram_chart *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+histogram_chart_is_shared (const struct histogram_chart *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+histogram_chart_submit (struct histogram_chart *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/plot-hist.h */
diff --git a/src/output/charts/roc-chart-cairo.c b/src/output/charts/roc-chart-cairo.c
new file mode 100644 (file)
index 0000000..b5c22ac
--- /dev/null
@@ -0,0 +1,73 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/roc-chart.h>
+
+#include <data/case.h>
+#include <data/casereader.h>
+#include <language/stats/roc.h>
+#include <output/cairo-chart.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+void
+xrchart_draw_roc (const struct chart_item *chart_item, cairo_t *cr,
+                  struct xrchart_geometry *geom)
+{
+  const struct roc_chart *rc = to_roc_chart (chart_item);
+  size_t i;
+
+  xrchart_write_title (cr, geom, _("ROC Curve"));
+  xrchart_write_xlabel (cr, geom, _("1 - Specificity"));
+  xrchart_write_ylabel (cr, geom, _("Sensitivity"));
+
+  xrchart_write_xscale (cr, geom, 0, 1, 5);
+  xrchart_write_yscale (cr, geom, 0, 1, 5);
+
+  if ( rc->reference )
+    {
+      xrchart_line (cr, geom, 1.0, 0,
+                    0.0, 1.0,
+                    XRCHART_DIM_X);
+    }
+
+  for (i = 0; i < rc->n_vars; ++i)
+    {
+      const struct roc_var *rv = &rc->vars[i];
+      struct casereader *r = casereader_clone (rv->cutpoint_reader);
+      struct ccase *cc;
+
+      xrchart_vector_start (cr, geom, rv->name);
+      for (; (cc = casereader_read (r)) != NULL; case_unref (cc))
+       {
+         double se = case_data_idx (cc, ROC_TP)->f;
+         double sp = case_data_idx (cc, ROC_TN)->f;
+
+         se /= case_data_idx (cc, ROC_FN)->f + case_data_idx (cc, ROC_TP)->f ;
+         sp /= case_data_idx (cc, ROC_TN)->f + case_data_idx (cc, ROC_FP)->f ;
+
+         xrchart_vector (cr, geom, 1 - sp, se);
+       }
+      xrchart_vector_end (cr, geom);
+      casereader_destroy (r);
+    }
+
+  xrchart_write_legend (cr, geom);
+}
+
diff --git a/src/output/charts/roc-chart.c b/src/output/charts/roc-chart.c
new file mode 100644 (file)
index 0000000..5af8f27
--- /dev/null
@@ -0,0 +1,75 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/roc-chart.h>
+
+#include <output/chart-item-provider.h>
+#include <data/casereader.h>
+#include <language/stats/roc.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct roc_chart *
+roc_chart_create (bool reference)
+{
+  struct roc_chart *rc = xmalloc (sizeof *rc);
+  chart_item_init (&rc->chart_item, &roc_chart_class, NULL);
+  rc->reference = reference;
+  rc->vars = NULL;
+  rc->n_vars = 0;
+  rc->allocated_vars = 0;
+  return rc;
+}
+
+void
+roc_chart_add_var (struct roc_chart *rc, const char *var_name,
+                   const struct casereader *cutpoint_reader)
+{
+  struct roc_var *rv;
+
+  if (rc->n_vars >= rc->allocated_vars)
+    rc->vars = x2nrealloc (rc->vars, &rc->allocated_vars, sizeof *rc->vars);
+
+  rv = &rc->vars[rc->n_vars++];
+  rv->name = xstrdup (var_name);
+  rv->cutpoint_reader = casereader_clone (cutpoint_reader);
+}
+
+static void
+roc_chart_destroy (struct chart_item *chart_item)
+{
+  struct roc_chart *rc = UP_CAST (chart_item, struct roc_chart, chart_item);
+  size_t i;
+
+  for (i = 0; i < rc->n_vars; i++)
+    {
+      struct roc_var *rv = &rc->vars[i];
+      free (rv->name);
+      casereader_destroy (rv->cutpoint_reader);
+    }
+  free (rc->vars);
+  free (rc);
+}
+
+const struct chart_item_class roc_chart_class =
+  {
+    roc_chart_destroy
+  };
diff --git a/src/output/charts/roc-chart.h b/src/output/charts/roc-chart.h
new file mode 100644 (file)
index 0000000..a995f93
--- /dev/null
@@ -0,0 +1,103 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_CHARTS_ROC_CHART_H
+#define OUTPUT_CHARTS_ROC_CHART_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <output/chart-item.h>
+
+struct roc_chart
+  {
+    struct chart_item chart_item;
+    bool reference;
+    struct roc_var *vars;
+    size_t n_vars;
+    size_t allocated_vars;
+  };
+
+struct roc_var
+  {
+    char *name;
+    struct casereader *cutpoint_reader;
+  };
+
+struct roc_chart *roc_chart_create (bool reference);
+void roc_chart_add_var (struct roc_chart *, const char *var_name,
+                        const struct casereader *cutpoint_reader);
+\f
+/* This boilerplate for roc_chart, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct chart_item_class roc_chart_class;
+
+/* Returns true if SUPER is a roc_chart, otherwise false. */
+static inline bool
+is_roc_chart (const struct chart_item *super)
+{
+  return super->class == &roc_chart_class;
+}
+
+/* Returns SUPER converted to roc_chart.  SUPER must be a roc_chart, as
+   reported by is_roc_chart. */
+static inline struct roc_chart *
+to_roc_chart (const struct chart_item *super)
+{
+  assert (is_roc_chart (super));
+  return UP_CAST (super, struct roc_chart, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+roc_chart_super (const struct roc_chart *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct roc_chart *
+roc_chart_ref (const struct roc_chart *instance)
+{
+  return to_roc_chart (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+roc_chart_unref (struct roc_chart *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+roc_chart_is_shared (const struct roc_chart *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+roc_chart_submit (struct roc_chart *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/roc-chart.h */
diff --git a/src/output/charts/scree-cairo.c b/src/output/charts/scree-cairo.c
new file mode 100644 (file)
index 0000000..d48a364
--- /dev/null
@@ -0,0 +1,65 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/scree.h>
+
+#include <math.h>
+
+#include <output/cairo-chart.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+void
+xrchart_draw_scree (const struct chart_item *chart_item, cairo_t *cr,
+                    struct xrchart_geometry *geom)
+{
+  const struct scree *rc = to_scree (chart_item);
+  size_t i;
+  double min, max;
+
+  xrchart_write_title (cr, geom, _("Scree Plot"));
+  xrchart_write_xlabel (cr, geom, rc->xlabel);
+  xrchart_write_ylabel (cr, geom, _("Eigenvalue"));
+
+  gsl_vector_minmax (rc->eval, &min, &max);
+
+  if ( fabs (max) > fabs (min))
+    max = fabs (max);
+  else
+    max = fabs (min);
+
+  xrchart_write_yscale (cr, geom, 0, max, max);
+  xrchart_write_xscale (cr, geom, 0, rc->eval->size + 1, rc->eval->size + 1);
+
+  xrchart_vector_start (cr, geom, "");
+  for (i = 0 ; i < rc->eval->size; ++i)
+    {
+      const double x = 1 + i;
+      const double y = gsl_vector_get (rc->eval, i);
+      xrchart_vector (cr, geom, x, y);
+    }
+  xrchart_vector_end (cr, geom);
+
+  for (i = 0 ; i < rc->eval->size; ++i)
+    {
+      const double x = 1 + i;
+      const double y = gsl_vector_get (rc->eval, i);
+      xrchart_datum (cr, geom, 0, x, y);
+    }
+}
diff --git a/src/output/charts/scree.c b/src/output/charts/scree.c
new file mode 100644 (file)
index 0000000..ffa7756
--- /dev/null
@@ -0,0 +1,55 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/charts/scree.h>
+
+#include <output/chart-item-provider.h>
+
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct scree *
+scree_create (const gsl_vector *eigenvalues, const char *xlabel)
+{
+  struct scree *rc = xmalloc (sizeof *rc);
+  chart_item_init (&rc->chart_item, &scree_class, NULL);
+
+  rc->eval = gsl_vector_alloc (eigenvalues->size);
+  gsl_vector_memcpy (rc->eval, eigenvalues);
+
+  rc->xlabel = xstrdup (xlabel);
+
+  return rc;
+}
+
+static void
+scree_destroy (struct chart_item *chart_item)
+{
+  struct scree *rc = to_scree (chart_item);
+
+  gsl_vector_free (rc->eval);
+  free (rc->xlabel);
+  free (rc);
+}
+
+const struct chart_item_class scree_class =
+  {
+    scree_destroy
+  };
diff --git a/src/output/charts/scree.h b/src/output/charts/scree.h
new file mode 100644 (file)
index 0000000..43f5b82
--- /dev/null
@@ -0,0 +1,97 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_CHARTS_SCREE_H
+#define OUTPUT_CHARTS_SCREE_H 1
+
+#include <gsl/gsl_vector.h>
+#include <output/chart-item.h>
+
+/* A scree plot. */
+struct scree
+  {
+    struct chart_item chart_item;
+    gsl_vector *eval;
+    char *xlabel;
+  };
+
+/* Create a "Scree Plot" of EIGENVALUES with LABEL on the X Axis */
+struct scree *scree_create (const gsl_vector *eigenvalues, const char *label);
+
+/* Return the chart underlying SCREE */
+struct chart *scree_get_chart (struct scree *scree);
+\f
+/* This boilerplate for scree, a subclass of chart_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct chart_item_class scree_class;
+
+/* Returns true if SUPER is a scree, otherwise false. */
+static inline bool
+is_scree (const struct chart_item *super)
+{
+  return super->class == &scree_class;
+}
+
+/* Returns SUPER converted to scree.  SUPER must be a scree, as
+   reported by is_scree. */
+static inline struct scree *
+to_scree (const struct chart_item *super)
+{
+  assert (is_scree (super));
+  return UP_CAST (super, struct scree, chart_item);
+}
+
+/* Returns INSTANCE converted to chart_item. */
+static inline struct chart_item *
+scree_super (const struct scree *instance)
+{
+  return CONST_CAST (struct chart_item *, &instance->chart_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct scree *
+scree_ref (const struct scree *instance)
+{
+  return to_scree (chart_item_ref (&instance->chart_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+scree_unref (struct scree *instance)
+{
+  chart_item_unref (&instance->chart_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+scree_is_shared (const struct scree *instance)
+{
+  return chart_item_is_shared (&instance->chart_item);
+}
+
+static inline void
+scree_submit (struct scree *instance)
+{
+  chart_item_submit (&instance->chart_item);
+}
+\f
+#endif /* output/charts/scree.h */
diff --git a/src/output/csv.c b/src/output/csv.c
new file mode 100644 (file)
index 0000000..004558f
--- /dev/null
@@ -0,0 +1,255 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009, 2010 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 <errno.h>
+#include <stdlib.h>
+
+#include "data/file-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/string-map.h"
+#include "output/text-item.h"
+#include "output/driver-provider.h"
+#include "output/options.h"
+#include "output/message-item.h"
+#include "output/table-item.h"
+#include "output/table-provider.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Comma-separated value output driver. */
+struct csv_driver
+  {
+    struct output_driver driver;
+
+    char *separator;            /* Comma or tab. */
+    char *file_name;            /* Output file name. */
+    char *command_name;         /* Current command. */
+    FILE *file;                 /* Output file. */
+    int n_items;                /* Number of items output so far. */
+  };
+
+static const struct output_driver_class csv_driver_class;
+
+static struct csv_driver *
+csv_driver_cast (struct output_driver *driver)
+{
+  assert (driver->class == &csv_driver_class);
+  return UP_CAST (driver, struct csv_driver, driver);
+}
+
+static struct driver_option *
+opt (struct output_driver *d, struct string_map *options, const char *key,
+     const char *default_value)
+{
+  return driver_option_get (d, options, key, default_value);
+}
+
+static struct output_driver *
+csv_create (const char *file_name, enum settings_output_devices device_type,
+            struct string_map *o)
+{
+  struct output_driver *d;
+  struct csv_driver *csv;
+
+  csv = xzalloc (sizeof *csv);
+  d = &csv->driver;
+  output_driver_init (&csv->driver, &csv_driver_class, file_name, device_type);
+
+  csv->separator = parse_string (opt (d, o, "separator", ","));
+  csv->file_name = parse_string (opt (d, o, "output-file", "pspp.csv"));
+  csv->file = fn_open (csv->file_name, "w");
+  csv->n_items = 0;
+
+  if (csv->file == NULL)
+    {
+      error (0, errno, _("csv: opening output file \"%s\""), csv->file_name);
+      output_driver_destroy (d);
+      return NULL;
+    }
+
+  return d;
+}
+
+static void
+csv_destroy (struct output_driver *driver)
+{
+  struct csv_driver *csv = csv_driver_cast (driver);
+
+  if (csv->file != NULL)
+    fn_close (csv->file_name, csv->file);
+
+  free (csv->separator);
+  free (csv->file_name);
+  free (csv);
+}
+
+static void
+csv_flush (struct output_driver *driver)
+{
+  struct csv_driver *csv = csv_driver_cast (driver);
+  if (csv->file != NULL)
+    fflush (csv->file);
+}
+
+static void
+csv_output_field (FILE *file, const char *field)
+{
+  while (*field == ' ')
+    field++;
+
+  if (field[strcspn (field, "\"\n\r,\t")])
+    {
+      const char *p;
+
+      putc ('"', file);
+      for (p = field; *p != '\0'; p++)
+        {
+          if (*p == '"')
+            putc ('"', file);
+          putc (*p, file);
+        }
+      putc ('"', file);
+    }
+  else
+    fputs (field, file);
+}
+
+static void
+csv_output_field_format (FILE *file, const char *format, ...)
+  PRINTF_FORMAT (2, 3);
+
+static void
+csv_output_field_format (FILE *file, const char *format, ...)
+{
+  va_list args;
+  char *s;
+
+  va_start (args, format);
+  s = xvasprintf (format, args);
+  va_end (args);
+
+  csv_output_field (file, s);
+  free (s);
+}
+
+static void
+csv_put_separator (struct csv_driver *csv)
+{
+  if (csv->n_items++ > 0)
+    putc ('\n', csv->file);
+}
+
+static void
+csv_submit (struct output_driver *driver,
+            const struct output_item *output_item)
+{
+  struct csv_driver *csv = csv_driver_cast (driver);
+
+  output_driver_track_current_command (output_item, &csv->command_name);
+
+  if (is_table_item (output_item))
+    {
+      struct table_item *table_item = to_table_item (output_item);
+      const char *caption = table_item_get_caption (table_item);
+      const struct table *t = table_item_get_table (table_item);
+      int x, y;
+
+      csv_put_separator (csv);
+
+      if (caption != NULL)
+        {
+          csv_output_field_format (csv->file, "Table: %s", caption);
+          putc ('\n', csv->file);
+        }
+
+      for (y = 0; y < table_nr (t); y++)
+        {
+          for (x = 0; x < table_nc (t); x++)
+            {
+              struct table_cell cell;
+
+              table_get_cell (t, x, y, &cell);
+
+              if (x > 0)
+                fputs (csv->separator, csv->file);
+
+              if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
+                csv_output_field (csv->file, "");
+              else
+                csv_output_field (csv->file, cell.contents);
+
+              table_cell_free (&cell);
+            }
+          putc ('\n', csv->file);
+        }
+    }
+  else if (is_text_item (output_item))
+    {
+      const struct text_item *text_item = to_text_item (output_item);
+      enum text_item_type type = text_item_get_type (text_item);
+      const char *text = text_item_get_text (text_item);
+
+      if (type == TEXT_ITEM_COMMAND_OPEN || type == TEXT_ITEM_COMMAND_CLOSE
+          || type == TEXT_ITEM_SYNTAX)
+        return;
+
+      csv_put_separator (csv);
+      switch (type)
+        {
+        case TEXT_ITEM_TITLE:
+          csv_output_field_format (csv->file, "Title: %s", text);
+          break;
+
+        case TEXT_ITEM_SUBTITLE:
+          csv_output_field_format (csv->file, "Subtitle: %s", text);
+          break;
+
+        default:
+          csv_output_field (csv->file, text);
+          break;
+        }
+      putc ('\n', csv->file);
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, csv->command_name);
+      csv_put_separator (csv);
+      csv_output_field (csv->file, s);
+      free (s);
+      putc ('\n', csv->file);
+    }
+}
+
+struct output_driver_factory csv_driver_factory = { "csv", csv_create };
+
+static const struct output_driver_class csv_driver_class =
+  {
+    "csv",
+    csv_destroy,
+    csv_submit,
+    csv_flush,
+  };
diff --git a/src/output/driver-provider.h b/src/output/driver-provider.h
new file mode 100644 (file)
index 0000000..df31637
--- /dev/null
@@ -0,0 +1,101 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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_DRIVER_PROVIDER_H
+#define OUTPUT_DRIVER_PROVIDER_H 1
+
+#include <stdbool.h>
+
+#include "data/settings.h"
+#include "libpspp/compiler.h"
+#include "output/driver.h"
+
+struct output_item;
+struct string_map;
+
+/* A configured output driver. */
+struct output_driver
+  {
+    const struct output_driver_class *class; /* Driver class. */
+    char *name;                              /* Name of this driver. */
+    enum settings_output_devices device_type; /* One of SETTINGS_DEVICE_*. */
+  };
+
+void output_driver_init (struct output_driver *,
+                         const struct output_driver_class *,
+                         const char *name, enum settings_output_devices);
+void output_driver_destroy (struct output_driver *);
+
+const char *output_driver_get_name (const struct output_driver *);
+
+/* One kind of output driver.
+
+   Output driver implementations must not call msg() to report errors.  This
+   can lead to reentrance in the output driver, because msg() may report error
+   messages using the output drivers.  Instead, this code should report errors
+   with error(), which will never call into the output drivers.  */
+struct output_driver_class
+  {
+    /* Name of this driver class. */
+    const char *name;
+
+    /* Closes and frees DRIVER. */
+    void (*destroy) (struct output_driver *driver);
+
+    /* Passes ITEM to DRIVER to be written as output.  The caller retains
+       ownership of ITEM (but DRIVER may keep a copy of it by incrementing the
+       reference count by calling output_item_ref). */
+    void (*submit) (struct output_driver *driver,
+                    const struct output_item *item);
+
+    /* Ensures that any output items passed to the 'submit' function for DRIVER
+       have actually been displayed.
+
+       This is called from the text-based UI before showing the command prompt,
+       to ensure that the user has actually been shown any preceding output If
+       it doesn't make sense for DRIVER to be used this way, then this function
+       need not do anything. */
+    void (*flush) (struct output_driver *driver);
+  };
+
+/* Useful for output driver implementation. */
+void output_driver_track_current_command (const struct output_item *, char **);
+\f
+/* An abstract way for the output subsystem to create an output driver. */
+struct output_driver_factory
+  {
+    /* The file extension, without the leading dot, e.g. "pdf". */
+    const char *extension;
+
+    /* Creates a new output driver of this class.  NAME and TYPE should be
+       passed directly to output_driver_init.  Returns the new output driver if
+       successful, otherwise a null pointer.
+
+       It is up to the driver class to decide how to interpret OPTIONS.  The
+       create function should delete pairs that it understands from OPTIONS,
+       because the caller may issue errors about unknown options for any pairs
+       that remain.  The functions in output/options.h can be useful.
+
+       The returned driver should not have been registered (with
+       output_driver_register).  The caller will register the driver (if this
+       is desirable). */
+    struct output_driver *(*create) (const char *name,
+                                     enum settings_output_devices type,
+                                     struct string_map *options);
+  };
+
+
+#endif /* output/driver-provider.h */
diff --git a/src/output/driver.c b/src/output/driver.c
new file mode 100644 (file)
index 0000000..2036445
--- /dev/null
@@ -0,0 +1,348 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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/driver.h"
+#include "output/driver-provider.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "data/file-name.h"
+#include "data/settings.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/llx.h"
+#include "libpspp/string-map.h"
+#include "libpspp/string-set.h"
+#include "libpspp/str.h"
+#include "output/message-item.h"
+#include "output/output-item.h"
+#include "output/text-item.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static const struct output_driver_factory *factories[];
+
+/* Drivers currently registered with output_driver_register(). */
+static struct llx_list drivers = LLX_INITIALIZER (drivers);
+
+static struct output_item *deferred_syntax;
+static bool in_command;
+
+void
+output_close (void)
+{
+  while (!llx_is_empty (&drivers))
+    {
+      struct output_driver *d = llx_pop_head (&drivers, &llx_malloc_mgr);
+      output_driver_destroy (d);
+    }
+}
+
+void
+output_get_supported_formats (struct string_set *formats)
+{
+  const struct output_driver_factory **fp;
+
+  for (fp = factories; *fp != NULL; fp++)
+    string_set_insert (formats, (*fp)->extension);
+}
+
+static void
+output_submit__ (struct output_item *item)
+{
+  struct llx *llx, *next;
+
+  for (llx = llx_head (&drivers); llx != llx_null (&drivers); llx = next)
+    {
+      struct output_driver *d = llx_data (llx);
+      enum settings_output_type type;
+
+      next = llx_next (llx);
+
+      if (is_message_item (item))
+        {
+          const struct msg *m = message_item_get_msg (to_message_item (item));
+          if (m->severity == MSG_S_NOTE)
+            type = SETTINGS_OUTPUT_NOTE;
+          else
+            type = SETTINGS_OUTPUT_ERROR;
+        }
+      else if (is_text_item (item)
+               && text_item_get_type (to_text_item (item)) == TEXT_ITEM_SYNTAX)
+        type = SETTINGS_OUTPUT_SYNTAX;
+      else
+        type = SETTINGS_OUTPUT_RESULT;
+
+      if (settings_get_output_routing (type) & d->device_type)
+        d->class->submit (d, item);
+    }
+
+  output_item_unref (item);
+}
+
+static void
+flush_deferred_syntax (void)
+{
+  if (deferred_syntax != NULL)
+    {
+      output_submit__ (deferred_syntax);
+      deferred_syntax = NULL;
+    }
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+output_submit (struct output_item *item)
+{
+  if (is_text_item (item))
+    {
+      struct text_item *text = to_text_item (item);
+      switch (text_item_get_type (text))
+        {
+        case TEXT_ITEM_SYNTAX:
+          if (!in_command)
+            {
+              flush_deferred_syntax ();
+              deferred_syntax = item;
+              return;
+            }
+          break;
+
+        case TEXT_ITEM_COMMAND_OPEN:
+          output_submit__ (item);
+          flush_deferred_syntax ();
+          in_command = true;
+          return;
+
+        case TEXT_ITEM_COMMAND_CLOSE:
+          in_command = false;
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  output_submit__ (item);
+}
+
+/* Flushes output to screen devices, so that the user can see
+   output that doesn't fill up an entire page. */
+void
+output_flush (void)
+{
+  struct llx *llx;
+
+  for (llx = llx_head (&drivers); llx != llx_null (&drivers);
+       llx = llx_next (llx))
+    {
+      struct output_driver *d = llx_data (llx);
+      if (d->device_type & SETTINGS_DEVICE_TERMINAL && d->class->flush != NULL)
+        d->class->flush (d);
+    }
+}
+\f
+void
+output_driver_init (struct output_driver *driver,
+                    const struct output_driver_class *class,
+                    const char *name, enum settings_output_devices type)
+{
+  driver->class = class;
+  driver->name = xstrdup (name);
+  driver->device_type = type;
+}
+
+void
+output_driver_destroy (struct output_driver *driver)
+{
+  if (driver != NULL)
+    {
+      char *name = driver->name;
+      if (output_driver_is_registered (driver))
+        output_driver_unregister (driver);
+      if (driver->class->destroy)
+        driver->class->destroy (driver);
+      free (name);
+    }
+}
+
+const char *
+output_driver_get_name (const struct output_driver *driver)
+{
+  return driver->name;
+}
+\f
+void
+output_driver_register (struct output_driver *driver)
+{
+  assert (!output_driver_is_registered (driver));
+  llx_push_tail (&drivers, driver, &llx_malloc_mgr);
+}
+
+void
+output_driver_unregister (struct output_driver *driver)
+{
+  llx_remove (llx_find (llx_head (&drivers), llx_null (&drivers), driver),
+              &llx_malloc_mgr);
+}
+
+bool
+output_driver_is_registered (const struct output_driver *driver)
+{
+  return llx_find (llx_head (&drivers), llx_null (&drivers), driver) != NULL;
+}
+\f
+/* Useful functions for output driver implementation. */
+
+void
+output_driver_track_current_command (const struct output_item *output_item,
+                                     char **command_namep)
+{
+  if (is_text_item (output_item))
+    {
+      const struct text_item *item = to_text_item (output_item);
+      const char *text = text_item_get_text (item);
+      enum text_item_type type = text_item_get_type (item);
+
+      if (type == TEXT_ITEM_COMMAND_OPEN)
+        {
+          free (*command_namep);
+          *command_namep = xstrdup (text);
+        }
+      else if (type == TEXT_ITEM_COMMAND_CLOSE)
+        {
+          free (*command_namep);
+          *command_namep = NULL;
+        }
+    }
+}
+\f
+extern const struct output_driver_factory txt_driver_factory;
+extern const struct output_driver_factory list_driver_factory;
+extern const struct output_driver_factory html_driver_factory;
+extern const struct output_driver_factory odt_driver_factory;
+extern const struct output_driver_factory csv_driver_factory;
+#ifdef HAVE_CAIRO
+extern const struct output_driver_factory pdf_driver_factory;
+extern const struct output_driver_factory ps_driver_factory;
+extern const struct output_driver_factory svg_driver_factory;
+#endif
+
+static const struct output_driver_factory *factories[] =
+  {
+    &txt_driver_factory,
+    &list_driver_factory,
+    &html_driver_factory,
+    &odt_driver_factory,
+    &csv_driver_factory,
+#ifdef HAVE_CAIRO
+    &pdf_driver_factory,
+    &ps_driver_factory,
+    &svg_driver_factory,
+#endif
+    NULL
+  };
+
+static const struct output_driver_factory *
+find_factory (const char *format)
+{
+  const struct output_driver_factory **fp;
+
+  for (fp = factories; *fp != NULL; fp++)
+    {
+      const struct output_driver_factory *f = *fp;
+
+      if (!strcmp (f->extension, format))
+        return f;
+    }
+  return &txt_driver_factory;
+}
+
+static enum settings_output_devices
+default_device_type (const char *file_name)
+{
+  return (!strcmp (file_name, "-")
+          ? SETTINGS_DEVICE_TERMINAL
+          : SETTINGS_DEVICE_LISTING);
+}
+
+struct output_driver *
+output_driver_create (struct string_map *options)
+{
+  enum settings_output_devices device_type;
+  const struct output_driver_factory *f;
+  struct output_driver *driver;
+  char *device_string;
+  char *file_name;
+  char *format;
+
+  file_name = string_map_find_and_delete (options, "output-file");
+  if (file_name == NULL)
+    file_name = xstrdup ("-");
+
+  format = string_map_find_and_delete (options, "format");
+  if (format == NULL)
+    {
+      const char *extension = strrchr (file_name, '.');
+      format = xstrdup (extension != NULL ? extension + 1 : "");
+    }
+
+  /* XXX should use parse_enum(). */
+  device_string = string_map_find_and_delete (options, "device");
+  if (device_string == NULL || device_string[0] == '\0')
+    device_type = default_device_type (file_name);
+  else if (!strcmp (device_string, "terminal"))
+    device_type = SETTINGS_DEVICE_TERMINAL;
+  else if (!strcmp (device_string, "listing"))
+    device_type = SETTINGS_DEVICE_LISTING;
+  else
+    {
+      error (0, 0, _("%s is not a valid device type (the choices are "
+                     "\"terminal\" and \"listing\")"), device_string);
+      device_type = default_device_type (file_name);
+    }
+
+  f = find_factory (format);
+  driver = f->create (file_name, device_type, options);
+  if (driver != NULL)
+    {
+      const struct string_map_node *node;
+      const char *key;
+
+      STRING_MAP_FOR_EACH_KEY (key, node, options)
+        error (0, 0, _("%s: unknown option \"%s\""), file_name, key);
+    }
+  string_map_clear (options);
+
+  free (file_name);
+  free (format);
+  free (device_string);
+
+  return driver;
+}
diff --git a/src/output/driver.h b/src/output/driver.h
new file mode 100644 (file)
index 0000000..9380207
--- /dev/null
@@ -0,0 +1,38 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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_DRIVER_H
+#define OUTPUT_DRIVER_H 1
+
+#include <stdbool.h>
+
+struct output_item;
+struct string_set;
+struct string_map;
+
+void output_submit (struct output_item *);
+
+void output_flush (void);
+
+void output_close (void);
+void output_get_supported_formats (struct string_set *);
+
+struct output_driver *output_driver_create (struct string_map *options);
+void output_driver_register (struct output_driver *);
+void output_driver_unregister (struct output_driver *);
+bool output_driver_is_registered (const struct output_driver *);
+
+#endif /* output/driver.h */
diff --git a/src/output/dummy-chart.c b/src/output/dummy-chart.c
deleted file mode 100644 (file)
index 7758ad7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 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 <stdio.h>
-#include <libpspp/compiler.h>
-#include "chart.h"
-
-
-struct chart *
-chart_create(void)
-{
-  return NULL;
-}
-
-void
-chart_submit(struct chart *chart UNUSED)
-{
-}
-
-void
-chart_init_separate (struct chart *ch UNUSED, const char *type UNUSED,
-                     const char *file_name_tmpl UNUSED, int number UNUSED)
-{
-}
-
-void
-chart_finalise_separate (struct chart *ch UNUSED)
-{
-}
index 893c18527b7ff30e431762ede6658332e6fc5e46..636450a9a353c1d43ccac0f7c4a54b665e946401 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010 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
@@ -15,8 +15,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "chart.h"
-#include "htmlP.h"
+
 #include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <data/file-name.h>
-#include "error.h"
-#include "output.h"
-#include "manager.h"
-#include "table.h"
-#include <libpspp/version.h>
+#include "data/file-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "output/cairo.h"
+#include "output/chart-item.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+#include "output/options.h"
+#include "output/output-item-provider.h"
+#include "output/table-provider.h"
+#include "output/table-item.h"
+#include "output/text-item.h"
 
+#include "error.h"
 #include "xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* HTML driver options: (defaults listed first)
+struct html_driver
+  {
+    struct output_driver driver;
 
-   output-file="pspp.html"
-   chart-files="pspp-#.png"
-*/
+    char *file_name;
+    char *chart_file_name;
+
+    char *command_name;
+    FILE *file;
+    size_t chart_cnt;
+
+    bool in_syntax;
+  };
 
+static const struct output_driver_class html_driver_class;
+
+static void html_output_table (struct html_driver *, struct table_item *);
 static void escape_string (FILE *file,
                            const char *text, size_t length,
                            const char *space);
-static bool handle_option (struct outp_driver *this,
-                           const char *key, const struct string *val);
 static void print_title_tag (FILE *file, const char *name,
                              const char *content);
 
-static bool
-html_open_driver (struct outp_driver *this, struct substring options)
+static struct html_driver *
+html_driver_cast (struct output_driver *driver)
 {
-  struct html_driver_ext *x;
-
-  this->ext = x = xmalloc (sizeof *x);
-  x->file_name = xstrdup ("pspp.html");
-  x->chart_file_name = xstrdup ("pspp-#.png");
-  x->file = NULL;
-  x->chart_cnt = 0;
+  assert (driver->class == &html_driver_class);
+  return UP_CAST (driver, struct html_driver, driver);
+}
 
-  outp_parse_options (options, handle_option, this);
+static struct driver_option *
+opt (struct output_driver *d, struct string_map *options, const char *key,
+     const char *default_value)
+{
+  return driver_option_get (d, options, key, default_value);
+}
 
-  x->file = fn_open (x->file_name, "w");
-  if (x->file == NULL)
+static struct output_driver *
+html_create (const char *file_name, enum settings_output_devices device_type,
+             struct string_map *o)
+{
+  struct output_driver *d;
+  struct html_driver *html;
+
+  html = xzalloc (sizeof *html);
+  d = &html->driver;
+  output_driver_init (&html->driver, &html_driver_class, file_name,
+                      device_type);
+
+  html->file_name = xstrdup (file_name);
+  html->chart_file_name = parse_chart_file_name (opt (d, o, "charts",
+                                                      file_name));
+  html->file = NULL;
+  html->chart_cnt = 1;
+
+  html->file = fn_open (html->file_name, "w");
+  if (html->file == NULL)
     {
-      error (0, errno, _("opening HTML output file: %s"), x->file_name);
+      error (0, errno, _("opening HTML output file: %s"), html->file_name);
       goto error;
     }
 
   fputs ("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n"
-         "   \"http://www.w3.org/TR/html4/loose.dtd\">\n", x->file);
-  fputs ("<HTML>\n", x->file);
-  fputs ("<HEAD>\n", x->file);
-  /* The <TITLE> tag is required, so we use a default if the user
-     didn't provide one. */
-  print_title_tag (x->file,
-                   "TITLE", outp_title ? outp_title : _("PSPP Output"));
-  fprintf (x->file, "<META NAME=\"generator\" CONTENT=\"%s\">\n", version);
+         "   \"http://www.w3.org/TR/html4/loose.dtd\">\n", html->file);
+  fputs ("<HTML>\n", html->file);
+  fputs ("<HEAD>\n", html->file);
+  print_title_tag (html->file, "TITLE", _("PSPP Output"));
+  fprintf (html->file, "<META NAME=\"generator\" CONTENT=\"%s\">\n", version);
+  fputs ("<META http-equiv=\"Content-Style-Type\" content=\"text/css\">\n",
+         html->file);
   fputs ("<META HTTP-EQUIV=\"Content-Type\" "
-         "CONTENT=\"text/html; charset=ISO-8859-1\">\n", x->file);
-  fputs ("</HEAD>\n", x->file);
-  fputs ("<BODY BGCOLOR=\"#ffffff\" TEXT=\"#000000\"\n", x->file);
-  fputs (" LINK=\"#1f00ff\" ALINK=\"#ff0000\" VLINK=\"#9900dd\">\n", x->file);
-  print_title_tag (x->file, "H1", outp_title);
-  print_title_tag (x->file, "H2", outp_subtitle);
-
-  return true;
+         "CONTENT=\"text/html; charset=ISO-8859-1\">\n", html->file);
+  fputs ("<STYLE>\n"
+         "<!--\n"
+         "body {\n"
+         "  background: white;\n"
+         "  color: black;\n"
+         "  padding: 0em 12em 0em 3em;\n"
+         "  margin: 0\n"
+         "}\n"
+         "body>p {\n"
+         "  margin: 0pt 0pt 0pt 0em\n"
+         "}\n"
+         "body>p + p {\n"
+         "  text-indent: 1.5em;\n"
+         "}\n"
+         "h1 {\n"
+         "  font-size: 150%;\n"
+         "  margin-left: -1.33em\n"
+         "}\n"
+         "h2 {\n"
+         "  font-size: 125%;\n"
+         "  font-weight: bold;\n"
+         "  margin-left: -.8em\n"
+         "}\n"
+         "h3 {\n"
+         "  font-size: 100%;\n"
+         "  font-weight: bold;\n"
+         "  margin-left: -.5em }\n"
+         "h4 {\n"
+         "  font-size: 100%;\n"
+         "  margin-left: 0em\n"
+         "}\n"
+         "h1, h2, h3, h4, h5, h6 {\n"
+         "  font-family: sans-serif;\n"
+         "  color: blue\n"
+         "}\n"
+         "html {\n"
+         "  margin: 0\n"
+         "}\n"
+         "code {\n"
+         "  font-family: sans-serif\n"
+         "}\n"
+         "table {\n"
+         "  border-collapse: collapse;\n"
+         "  margin-bottom: 1em\n"
+         "}\n"
+         "th { background: #dddddd; font-weight: normal; font-style: oblique }\n"
+         "caption {\n"
+         "  text-align: left\n"
+         "}\n"
+         "-->\n"
+         "</STYLE>\n",
+         html->file);
+  fputs ("</HEAD>\n", html->file);
+  fputs ("<BODY BGCOLOR=\"#ffffff\" TEXT=\"#000000\"\n", html->file);
+  fputs (" LINK=\"#1f00ff\" ALINK=\"#ff0000\" VLINK=\"#9900dd\">\n", html->file);
+
+  return d;
 
  error:
-  this->class->close_driver (this);
-  return false;
+  output_driver_destroy (d);
+  return NULL;
 }
 
 /* Emits <NAME>CONTENT</NAME> to the output, escaping CONTENT as
@@ -109,114 +193,139 @@ print_title_tag (FILE *file, const char *name, const char *content)
     }
 }
 
-static bool
-html_close_driver (struct outp_driver *this)
+static void
+html_destroy (struct output_driver *driver)
 {
-  struct html_driver_ext *x = this->ext;
-  bool ok;
+  struct html_driver *html = html_driver_cast (driver);
 
-  if (x->file != NULL)
+  if (html->file != NULL)
     {
-      fprintf (x->file,
+      if (html->in_syntax)
+        {
+          fprintf (html->file, "</PRE>\n");
+          html->in_syntax = false;
+        }
+      fprintf (html->file,
                "</BODY>\n"
                "</HTML>\n"
                "<!-- end of file -->\n");
-      ok = fn_close (x->file_name, x->file) == 0;
-      x->file = NULL;
+      fn_close (html->file_name, html->file);
     }
-  else
-    ok = true;
-  free (x->chart_file_name);
-  free (x->file_name);
-  free (x);
+  free (html->chart_file_name);
+  free (html->file_name);
+  free (html->command_name);
+  free (html);
+}
 
-  return ok;
+static bool
+is_syntax_item (const struct output_item *item)
+{
+  return (is_text_item (item)
+          && text_item_get_type (to_text_item (item)) == TEXT_ITEM_SYNTAX);
 }
 
-/* Link the image contained in FILE_NAME to the
-   HTML stream in FILE. */
 static void
-link_image (FILE *file, char *file_name)
+html_submit (struct output_driver *driver,
+             const struct output_item *output_item)
 {
-  fprintf (file, "<IMG SRC=\"%s\"/>", file_name);
- }
+  struct html_driver *html = html_driver_cast (driver);
 
-/* Generic option types. */
-enum
-  {
-    string_arg,
-    nonneg_int_arg
-  };
+  output_driver_track_current_command (output_item, &html->command_name);
 
-/* All the options that the HTML driver supports. */
-static const struct outp_option option_tab[] =
-  {
-    {"output-file",            string_arg,     0},
-    {"chart-files",            string_arg,     1},
-    {NULL, 0, 0},
-  };
+  if (html->in_syntax && !is_syntax_item (output_item))
+    {
+      fprintf (html->file, "</PRE>\n");
+      html->in_syntax = false;
+    }
 
-static bool
-handle_option (struct outp_driver *this,
-               const char *key, const struct string *val)
-{
-  struct html_driver_ext *x = this->ext;
-  int subcat;
+  if (is_table_item (output_item))
+    {
+      struct table_item *table_item = to_table_item (output_item);
+      html_output_table (html, table_item);
+    }
+  else if (is_chart_item (output_item) && html->chart_file_name != NULL)
+    {
+      struct chart_item *chart_item = to_chart_item (output_item);
+      char *file_name;
 
-  switch (outp_match_keyword (key, option_tab, &subcat))
+      file_name = xr_draw_png_chart (chart_item, html->chart_file_name,
+                                     html->chart_cnt++);
+      if (file_name != NULL)
+        {
+          fprintf (html->file, "<IMG SRC=\"%s\"/>", file_name);
+          free (file_name);
+        }
+    }
+  else if (is_text_item (output_item))
     {
-    case -1:
-      error (0, 0,
-             _("unknown configuration parameter `%s' for HTML device driver"),
-             key);
-      break;
-    case string_arg:
-      switch (subcat)
+      struct text_item *text_item = to_text_item (output_item);
+      const char *s = text_item_get_text (text_item);
+
+      switch (text_item_get_type (text_item))
         {
-        case 0:
-          free (x->file_name);
-          x->file_name = ds_xstrdup (val);
+        case TEXT_ITEM_TITLE:
+          print_title_tag (html->file, "H1", s);
+          break;
+
+        case TEXT_ITEM_SUBTITLE:
+          print_title_tag (html->file, "H2", s);
           break;
-        case 1:
-          if (ds_find_char (val, '#') != SIZE_MAX)
+
+        case TEXT_ITEM_COMMAND_OPEN:
+          fprintf (html->file, "<DIV class=\"");
+          escape_string (html->file, s, strlen (s), "_");
+          fprintf (html->file, "\">");
+          print_title_tag (html->file, "H3", s);
+          break;
+
+        case TEXT_ITEM_COMMAND_CLOSE:
+          fprintf (html->file, "</DIV>\n");
+          break;
+
+        case TEXT_ITEM_SUBHEAD:
+          print_title_tag (html->file, "H4", s);
+          break;
+
+        case TEXT_ITEM_SYNTAX:
+          if (!html->in_syntax)
             {
-              free (x->chart_file_name);
-              x->chart_file_name = ds_xstrdup (val);
+              fprintf (html->file, "<PRE class=\"syntax\">");
+              html->in_syntax = true;
             }
           else
-            error (0, 0, _("`chart-files' value must contain `#'"));
+            putc ('\n', html->file);
+          escape_string (html->file, s, strlen (s), " ");
           break;
-        default:
-          NOT_REACHED ();
-        }
-      break;
-    default:
-      NOT_REACHED ();
-    }
 
-  return true;
-}
+        case TEXT_ITEM_PARAGRAPH:
+          print_title_tag (html->file, "P", s);
+          break;
 
-static void output_tab_table (struct outp_driver *, struct tab_table *);
+        case TEXT_ITEM_MONOSPACE:
+          print_title_tag (html->file, "PRE", s); /* should be <P><TT> */
+          break;
 
-static void
-html_submit (struct outp_driver *this, struct som_entity *s)
-{
-  extern struct som_table_class tab_table_class;
-  struct html_driver_ext *x = this->ext;
+        case TEXT_ITEM_BLANK_LINE:
+          fputs ("<BR>", html->file);
+          break;
 
-  assert (s->class == &tab_table_class ) ;
+        case TEXT_ITEM_EJECT_PAGE:
+          /* Nothing to do. */
+          break;
 
-  switch (s->type)
+        case TEXT_ITEM_COMMENT:
+        case TEXT_ITEM_ECHO:
+          /* We print out syntax anyway, so nothing to do here either. */
+          break;
+        }
+    }
+  else if (is_message_item (output_item))
     {
-    case SOM_TABLE:
-      output_tab_table ( this, (struct tab_table *) s->ext);
-      break;
-    case SOM_CHART:
-      link_image (x->file, ((struct chart *)s->ext)->file_name);
-      break;
-    default:
-      NOT_REACHED ();
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, html->command_name);
+      print_title_tag (html->file, "P", s);
+      free (s);
     }
 }
 
@@ -245,6 +354,9 @@ escape_string (FILE *file,
         case ' ':
           fputs (space, file);
           break;
+        case '"':
+          fputs ("&quot;", file);
+          break;
         default:
           putc (c, file);
           break;
@@ -252,148 +364,134 @@ escape_string (FILE *file,
     }
 }
 
-/* Outputs content for a cell with options OPTS and contents
-   TEXT. */
-void
-html_put_cell_contents (struct outp_driver *this,
-                        unsigned int opts, const struct substring text)
+static void
+put_border (FILE *file, int n_borders, int style, const char *border_name)
 {
-  struct html_driver_ext *x = this->ext;
-
-  if (!(opts & TAB_EMPTY))
-    {
-      if (opts & TAB_EMPH)
-        fputs ("<EM>", x->file);
-      if (opts & TAB_FIX)
-        {
-          fputs ("<TT>", x->file);
-          escape_string (x->file, ss_data (text), ss_length (text), "&nbsp;");
-          fputs ("</TT>", x->file);
-        }
-      else
-        {
-          size_t initial_spaces = ss_span (text, ss_cstr (CC_SPACES));
-          escape_string (x->file,
-                         ss_data (text) + initial_spaces,
-                         ss_length (text) - initial_spaces,
-                         " ");
-        }
-      if (opts & TAB_EMPH)
-        fputs ("</EM>", x->file);
-    }
+  fprintf (file, "%sborder-%s: %s",
+           n_borders == 0 ? " STYLE=\"" : "; ",
+           border_name,
+           style == TAL_1 ? "thin solid" : "double");
 }
 
-/* Write table T to THIS output driver. */
 static void
-output_tab_table (struct outp_driver *this, struct tab_table *t)
+html_output_table (struct html_driver *html, struct table_item *item)
 {
-  struct html_driver_ext *x = this->ext;
+  const struct table *t = table_item_get_table (item);
+  const char *caption;
+  int x, y;
 
-  if (t->nr == 1 && t->nc == 1)
-    {
-      fputs ("<P>", x->file);
-      html_put_cell_contents (this, t->ct[0], *t->cc);
-      fputs ("</P>\n", x->file);
+  fputs ("<TABLE>\n", html->file);
 
-      return;
+  caption = table_item_get_caption (item);
+  if (caption != NULL)
+    {
+      fputs ("  <CAPTION>", html->file);
+      escape_string (html->file, caption, strlen (caption), " ");
+      fputs ("</CAPTION>\n", html->file);
     }
 
-  fputs ("<TABLE BORDER=1>\n", x->file);
-
-  if (t->title != NULL)
+  for (y = 0; y < table_nr (t); y++)
     {
-      fprintf (x->file, "  <CAPTION>");
-      escape_string (x->file, t->title, strlen (t->title), " ");
-      fputs ("</CAPTION>\n", x->file);
-    }
+      fputs ("  <TR>\n", html->file);
+      for (x = 0; x < table_nc (t); x++)
+        {
+          struct table_cell cell;
+          const char *tag;
+          bool is_header;
+          int alignment, colspan, rowspan;
+          int top, left, right, bottom, n_borders;
+          const char *s;
+
+          table_get_cell (t, x, y, &cell);
+          if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
+            continue;
+
+          /* Output <TD> or <TH> tag. */
+          is_header = (y < table_ht (t)
+                       || y >= table_nr (t) - table_hb (t)
+                       || x < table_hl (t)
+                       || x >= table_nc (t) - table_hr (t));
+          tag = is_header ? "TH" : "TD";
+          fprintf (html->file, "    <%s", tag);
+
+          alignment = cell.options & TAB_ALIGNMENT;
+          if (alignment != TAB_LEFT)
+            fprintf (html->file, " ALIGN=%s",
+                     alignment == TAB_RIGHT ? "RIGHT" : "CENTER");
+
+          colspan = table_cell_colspan (&cell);
+          if (colspan > 1)
+            fprintf (html->file, " COLSPAN=%d", colspan);
+
+          rowspan = table_cell_rowspan (&cell);
+          if (rowspan > 1)
+            fprintf (html->file, " ROWSPAN=%d", rowspan);
+
+          /* Cell borders. */
+          n_borders = 0;
+          
+          top = table_get_rule (t, TABLE_VERT, x, y);
+          if (top > TAL_GAP)
+            put_border (html->file, n_borders++, top, "top");
+
+          if (y == table_nr (t) - 1)
+            {
+              bottom = table_get_rule (t, TABLE_VERT, x, y + 1);
+              if (bottom > TAL_GAP)
+                put_border (html->file, n_borders++, bottom, "bottom");
+            }
 
-  {
-    int r;
-    unsigned char *ct = t->ct;
-
-    for (r = 0; r < t->nr; r++)
-      {
-       int c;
-
-       fputs ("  <TR>\n", x->file);
-       for (c = 0; c < t->nc; c++, ct++)
-         {
-            struct substring *cc;
-            const char *tag;
-            struct tab_joined_cell *j = NULL;
-
-            cc = t->cc + c + r * t->nc;
-           if (*ct & TAB_JOIN)
-              {
-                j = (struct tab_joined_cell *) ss_data (*cc);
-                cc = &j->contents;
-                if (j->x1 != c || j->y1 != r)
-                  continue;
-              }
-
-            /* Output <TD> or <TH> tag. */
-            tag = (r < t->t || r >= t->nr - t->b
-                   || c < t->l || c >= t->nc - t->r) ? "TH" : "TD";
-            fprintf (x->file, "    <%s ALIGN=%s",
-                     tag,
-                     (*ct & TAB_ALIGN_MASK) == TAB_LEFT ? "LEFT"
-                     : (*ct & TAB_ALIGN_MASK) == TAB_RIGHT ? "RIGHT"
-                     : "CENTER");
-           if (*ct & TAB_JOIN)
-             {
-               if (j->x2 - j->x1 > 1)
-                 fprintf (x->file, " COLSPAN=%d", j->x2 - j->x1);
-               if (j->y2 - j->y1 > 1)
-                 fprintf (x->file, " ROWSPAN=%d", j->y2 - j->y1);
-             }
-           putc ('>', x->file);
-
-            /* Output cell contents. */
-            html_put_cell_contents (this, *ct, *cc);
-
-            /* Output </TH> or </TD>. */
-           fprintf (x->file, "</%s>\n", tag);
-         }
-       fputs ("  </TR>\n", x->file);
-      }
-  }
-
-  fputs ("</TABLE>\n\n", x->file);
-}
+          left = table_get_rule (t, TABLE_HORZ, x, y);
+          if (left > TAL_GAP)
+            put_border (html->file, n_borders++, left, "left");
 
-static void
-html_initialise_chart (struct outp_driver *this UNUSED, struct chart *ch)
-{
-  struct html_driver_ext *x = this->ext;
-  chart_init_separate (ch, "png", x->chart_file_name, ++x->chart_cnt);
-}
+          if (x == table_nc (t) - 1)
+            {
+              right = table_get_rule (t, TABLE_HORZ, x + 1, y);
+              if (right > TAL_GAP)
+                put_border (html->file, n_borders++, right, "right");
+            }
 
-static void
-html_finalise_chart(struct outp_driver *d UNUSED, struct chart *ch)
-{
-  chart_finalise_separate (ch);
-}
+          if (n_borders > 0)
+            fputs ("\"", html->file);
 
+          putc ('>', html->file);
 
+          /* Output cell contents. */
+          s = cell.contents;
+          if (cell.options & TAB_EMPH)
+            fputs ("<EM>", html->file);
+          if (cell.options & TAB_FIX)
+            {
+              fputs ("<TT>", html->file);
+              escape_string (html->file, s, strlen (s), "&nbsp;");
+              fputs ("</TT>", html->file);
+            }
+          else
+            {
+              s += strspn (s, CC_SPACES);
+              escape_string (html->file, s, strlen (s), " ");
+            }
+          if (cell.options & TAB_EMPH)
+            fputs ("</EM>", html->file);
 
-/* HTML driver class. */
-const struct outp_class html_class =
-  {
-    "html",
-    1,
+          /* Output </TH> or </TD>. */
+          fprintf (html->file, "</%s>\n", tag);
 
-    html_open_driver,
-    html_close_driver,
+          table_cell_free (&cell);
+        }
+      fputs ("  </TR>\n", html->file);
+    }
 
-    NULL,
-    NULL,
-    NULL,
+  fputs ("</TABLE>\n\n", html->file);
+}
 
-    html_submit,
+struct output_driver_factory html_driver_factory = { "html", html_create };
 
+static const struct output_driver_class html_driver_class =
+  {
+    "html",
+    html_destroy,
+    html_submit,
     NULL,
-    NULL,
-    NULL,
-    html_initialise_chart,
-    html_finalise_chart
   };
diff --git a/src/output/htmlP.h b/src/output/htmlP.h
deleted file mode 100644 (file)
index 05340f4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 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/>. */
-
-#if !htmlP_h
-#define htmlP_h 1
-
-#include <data/file-name.h>
-
-/* HTML output driver extension record. */
-struct html_driver_ext
-  {
-    char *file_name;
-    char *chart_file_name;
-    FILE *file;
-
-    size_t chart_cnt;
-  };
-
-extern const struct outp_class html_class;
-
-struct outp_driver;
-void html_put_cell_contents (struct outp_driver *this,
-                             unsigned int opts, struct substring text);
-
-#endif /* !htmlP_h */
index 67657f6247cc8ec731cf8154c4f45aa48d369003..6b7332771c0f5e7727ffe631c04d11e1ab63a5ac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2010 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
 
 #include <config.h>
 
-#include <output/journal.h>
+#include "output/journal.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <data/file-name.h>
-#include <libpspp/str.h>
+#include "data/file-name.h"
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+#include "output/text-item.h"
 
-#include "fwriteerror.h"
-#include "error.h"
-#include "xalloc.h"
+#include "gl/error.h"
+#include "gl/fwriteerror.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Journaling enabled? */
-static bool journal_enabled = false;
+struct journal_driver
+  {
+    struct output_driver driver;
+    FILE *file;
+    char *command_name;
+  };
 
-/* Name of the journal file. */
-static char *journal_file_name = NULL;
+static const struct output_driver_class journal_class;
 
-/* Journal file. */
-static FILE *journal_file = NULL;
+/* Journal driver, if journaling is enabled. */
+static struct journal_driver *journal;
 
-/* Enables journaling. */
-void
-journal_enable (void)
+/* Name of journal file. */
+static char *journal_file_name;
+
+static struct journal_driver *
+journal_driver_cast (struct output_driver *driver)
 {
-  journal_enabled = true;
+  assert (driver->class == &journal_class);
+  return UP_CAST (driver, struct journal_driver, driver);
 }
 
-/* Disables journaling. */
-void
-journal_disable (void)
+static void
+journal_close (void)
 {
-  journal_enabled = false;
-  if (journal_file != NULL)
-    fflush (journal_file);
+  if (journal != NULL && journal->file != NULL)
+    {
+      if (fwriteerror (journal->file))
+        error (0, errno, _("error writing \"%s\""), journal_file_name);
+      journal->file = NULL;
+    }
 }
 
-/* Sets the name of the journal file to FILE_NAME. */
-void
-journal_set_file_name (const char *file_name)
+static void
+journal_destroy (struct output_driver *driver)
 {
-  assert (file_name != NULL);
+  struct journal_driver *j = journal_driver_cast (driver);
+
+  journal_close ();
+  free (j->command_name);
+  free (j);
 
-  if (journal_file != NULL)
+  journal = NULL;
+}
+
+static void
+journal_output (struct journal_driver *j, const char *s)
+{
+  if (j->file == NULL)
     {
-      if (fwriteerror (journal_file))
-        error (0, errno, _("error writing \"%s\""), journal_file_name);
+      j->file = fopen (journal_file_name, "a");
+      if (j->file == NULL)
+        {
+          error (0, errno, _("%s: open failed"), journal_file_name);
+          output_driver_destroy (&j->driver);
+          return;
+        }
     }
 
-  free (journal_file_name);
-  journal_file_name = xstrdup (file_name);
+  fprintf (j->file, "%s\n", s);
 }
 
-/* Writes LINE to the journal file (if journaling is enabled).
-   If PREFIX is non-null, the line will be prefixed by "> ". */
-void
-journal_write (bool prefix, const char *line)
+static void
+journal_submit (struct output_driver *driver, const struct output_item *item)
 {
-  if (!journal_enabled)
-    return;
+  struct journal_driver *j = journal_driver_cast (driver);
+
+  output_driver_track_current_command (item, &j->command_name);
+
+  if (is_text_item (item))
+    {
+      const struct text_item *text_item = to_text_item (item);
+      enum text_item_type type = text_item_get_type (text_item);
 
-  if (journal_file == NULL)
+      if (type == TEXT_ITEM_SYNTAX)
+        journal_output (j, text_item_get_text (text_item));
+    }
+  else if (is_message_item (item))
+    {
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, j->command_name);
+      journal_output (j, s);
+      free (s);
+    }
+}
+
+static const struct output_driver_class journal_class =
+  {
+    "journal",
+    journal_destroy,
+    journal_submit,
+    NULL                        /* flush */
+  };
+\f
+/* Enables journaling. */
+void
+journal_enable (void)
+{
+  if (journal == NULL)
     {
+      /* If no journal file name is configured, use the default. */
       if (journal_file_name == NULL)
        {
          const char *output_path = default_output_path ();
          journal_file_name = xasprintf ("%s%s", output_path, "pspp.jnl");
        }
-      journal_file = fopen (journal_file_name, "w");
-      if (journal_file == NULL)
-        {
-          error (0, errno, _("error creating \"%s\""), journal_file_name);
-          journal_enabled = false;
-          return;
-        }
+
+      /* Create journal driver. */
+      journal = xzalloc (sizeof *journal);
+      output_driver_init (&journal->driver, &journal_class, "journal",
+                          SETTINGS_DEVICE_UNFILTERED);
+      journal->file = NULL;
+      journal->command_name = NULL;
+
+      /* Register journal driver. */
+      output_driver_register (&journal->driver);
     }
+}
+
+/* Disables journaling. */
+void
+journal_disable (void)
+{
+  if (journal != NULL)
+    output_driver_destroy (&journal->driver);
+}
 
-  if (prefix)
-    fputs ("> ", journal_file);
-  fputs (line, journal_file);
-  if (strchr (line, '\n') == NULL)
-    putc ('\n', journal_file);
-  fflush (journal_file);
+/* Sets the name of the journal file to FILE_NAME. */
+void
+journal_set_file_name (const char *file_name)
+{
+  journal_close ();
+  free (journal_file_name);
+  journal_file_name = xstrdup (file_name);
 }
index 3509ff09890b4329a7b62bba36771a34ef516b92..5051193a67ea3c7d03ed61be1fddfe0167273173 100644 (file)
@@ -29,6 +29,5 @@
 void journal_enable (void);
 void journal_disable (void);
 void journal_set_file_name (const char *);
-void journal_write (bool prefix, const char *);
 
 #endif /* output/journal.h */
diff --git a/src/output/manager.c b/src/output/manager.c
deleted file mode 100644 (file)
index 0b2fdfe..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 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 "manager.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <libpspp/assertion.h>
-#include "output.h"
-
-/* Table. */
-int table_num = 1;
-int subtable_num;
-\f
-/* Increments table_num so different procedures' output can be
-   distinguished. */
-void
-som_new_series (void)
-{
-  if (subtable_num != 0)
-    {
-      table_num++;
-      subtable_num = 0;
-    }
-}
-
-/* Ejects the paper for all active devices. */
-void
-som_eject_page (void)
-{
-  struct outp_driver *d;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    outp_eject_page (d);
-}
-
-/* Flushes output on all active devices. */
-void
-som_flush (void)
-{
-  struct outp_driver *d;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    outp_flush (d);
-}
-
-/* Skip down a single line on all active devices. */
-void
-som_blank_line (void)
-{
-  struct outp_driver *d;
-
-  for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-    if (d->page_open && d->cp_y != 0)
-      d->cp_y += d->font_height;
-}
-\f
-/* Driver. */
-static struct outp_driver *d = 0;
-
-/* Table. */
-static struct som_entity *t = 0;
-
-/* Flags. */
-static unsigned flags;
-
-/* Number of columns, rows. */
-static int nc, nr;
-
-/* Number of columns or rows in left, right, top, bottom headers. */
-static int hl, hr, ht, hb;
-
-/* Column style. */
-static int cs;
-
-/* Table height, width. */
-static int th, tw;
-
-static void render_columns (void);
-static void render_simple (void);
-static void render_segments (void);
-
-static void output_entity (struct outp_driver *, struct som_entity *);
-
-/* Output table T to appropriate output devices. */
-void
-som_submit (struct som_entity *t)
-{
-#if DEBUGGING
-  static int entry;
-
-  assert (entry++ == 0);
-#endif
-
-  if ( t->type == SOM_TABLE)
-    {
-      t->class->table (t);
-      t->class->flags (&flags);
-      t->class->count (&nc, &nr);
-      t->class->headers (&hl, &hr, &ht, &hb);
-
-
-#if DEBUGGING
-      if (hl + hr > nc || ht + hb > nr)
-       {
-         printf ("headers: (l,r)=(%d,%d), (t,b)=(%d,%d) in table size (%d,%d)\n",
-                 hl, hr, ht, hb, nc, nr);
-         NOT_REACHED ();
-       }
-      else if (hl + hr == nc)
-       printf ("warning: headers (l,r)=(%d,%d) in table width %d\n", hl, hr, nc);
-      else if (ht + hb == nr)
-       printf ("warning: headers (t,b)=(%d,%d) in table height %d\n", ht, hb, nr);
-#endif
-
-      t->class->columns (&cs);
-
-      if (!(flags & SOMF_NO_TITLE))
-       subtable_num++;
-
-    }
-
-  {
-    struct outp_driver *d;
-
-    for (d = outp_drivers (NULL); d; d = outp_drivers (d))
-       output_entity (d, t);
-
-  }
-
-#if DEBUGGING
-  assert (--entry == 0);
-#endif
-}
-
-/* Output entity ENTITY to driver DRIVER. */
-static void
-output_entity (struct outp_driver *driver, struct som_entity *entity)
-{
-  bool fits_width, fits_length;
-  d = driver;
-
-  outp_open_page (d);
-  if (d->class->special || entity->type == SOM_CHART)
-    {
-      driver->class->submit (d, entity);
-      return;
-    }
-
-  t = entity;
-
-  t->class->driver (d);
-  t->class->area (&tw, &th);
-  fits_width = t->class->fits_width (d->width);
-  fits_length = t->class->fits_length (d->length);
-  if (!fits_width || !fits_length)
-    {
-      int tl, tr, tt, tb;
-      tl = fits_width ? hl : 0;
-      tr = fits_width ? hr : 0;
-      tt = fits_length ? ht : 0;
-      tb = fits_length ? hb : 0;
-      t->class->set_headers (tl, tr, tt, tb);
-      t->class->driver (d);
-      t->class->area (&tw, &th);
-    }
-
-  if (!(flags & SOMF_NO_SPACING) && d->cp_y != 0)
-    d->cp_y += d->font_height;
-
-  if (cs != SOM_COL_NONE
-      && 2 * (tw + d->prop_em_width) <= d->width
-      && nr - (ht + hb) > 5)
-    render_columns ();
-  else if (tw < d->width && th + d->cp_y < d->length)
-    render_simple ();
-  else
-    render_segments ();
-
-  t->class->set_headers (hl, hr, ht, hb);
-}
-
-/* Render the table into multiple columns. */
-static void
-render_columns (void)
-{
-  int y0, y1;
-  int max_len = 0;
-  int index = 0;
-
-  assert (cs == SOM_COL_DOWN);
-  assert (d->cp_x == 0);
-
-  for (y0 = ht; y0 < nr - hb; y0 = y1)
-    {
-      int len;
-
-      t->class->cumulate (SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
-
-      if (y0 == y1)
-       {
-         assert (d->cp_y);
-         outp_eject_page (d);
-       }
-      else
-        {
-         if (len > max_len)
-           max_len = len;
-
-         t->class->title (index++, 0);
-         t->class->render (0, y0, nc, y1);
-
-         d->cp_x += tw + 2 * d->prop_em_width;
-         if (d->cp_x + tw > d->width)
-           {
-             d->cp_x = 0;
-             d->cp_y += max_len;
-             max_len = 0;
-           }
-       }
-    }
-
-  if (d->cp_x > 0)
-    {
-      d->cp_x = 0;
-      d->cp_y += max_len;
-    }
-}
-
-/* Render the table by itself on the current page. */
-static void
-render_simple (void)
-{
-  assert (d->cp_x == 0);
-  assert (tw < d->width && th + d->cp_y < d->length);
-
-  t->class->title (0, 0);
-  t->class->render (hl, ht, nc - hr, nr - hb);
-  d->cp_y += th;
-}
-
-/* General table breaking routine. */
-static void
-render_segments (void)
-{
-  int count = 0;
-
-  int x_index;
-  int x0, x1;
-
-  assert (d->cp_x == 0);
-
-  for (x_index = 0, x0 = hl; x0 < nc - hr; x0 = x1, x_index++)
-    {
-      int y_index;
-      int y0, y1;
-
-      t->class->cumulate (SOM_COLUMNS, x0, &x1, d->width, NULL);
-      if (x_index == 0 && x1 != nc - hr)
-       x_index++;
-
-      for (y_index = 0, y0 = ht; y0 < nr - hb; y0 = y1, y_index++)
-       {
-         int len;
-
-         if (count++ != 0 && d->cp_y != 0)
-           d->cp_y += d->font_height;
-
-         t->class->cumulate (SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
-         if (y_index == 0 && y1 != nr - hb)
-           y_index++;
-
-         if (y0 == y1)
-           {
-             assert (d->cp_y);
-             outp_eject_page (d);
-           }
-          else
-            {
-             t->class->title (x_index ? x_index : y_index,
-                              x_index ? y_index : 0);
-             t->class->render (x0, y0, x1, y1);
-
-             d->cp_y += len;
-           }
-       }
-    }
-}
diff --git a/src/output/manager.h b/src/output/manager.h
deleted file mode 100644 (file)
index 58d0c12..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 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/>. */
-
-#if !som_h
-#define som_h 1
-
-/* Structured Output Manager.
-
-   som considers the output stream to be a series of tables.  Each
-   table is made up of a rectangular grid of cells.  Cells can be
-   joined to form larger cells.  Rows and columns can be separated by
-   rules of various types.  Tables too large to fit on a single page
-   will be divided into sections.  Rows and columns can be designated
-   as headers, which causes them to be repeated in each section.
-
-   Every table is an instance of a particular table class.  A table
-   class is responsible for keeping track of cell data, for handling
-   requests from the som, and finally for rendering cell data to the
-   output drivers.  Tables may implement these operations in any way
-   desired, and in fact almost every operation performed by som may be
-   overridden in a table class.  */
-
-#include <stdbool.h>
-
-enum som_type
-  {
-    SOM_TABLE,
-    SOM_CHART
-  } ;
-
-/* Entity (Table or Chart) . */
-struct som_entity
-  {
-    const struct som_table_class *class;       /* Table class. */
-    enum som_type type;                 /* Table or Chart */
-    void *ext;                         /* Owned by */
-  };
-
-/* Group styles. */
-enum
-  {
-    SOM_COL_NONE,                      /* No columns. */
-    SOM_COL_DOWN                       /* Columns down first. */
-  };
-
-/* Cumulation types. */
-enum
-  {
-    SOM_ROWS, SOM_ROW = SOM_ROWS,      /* Rows. */
-    SOM_COLUMNS, SOM_COLUMN = SOM_COLUMNS      /* Columns. */
-  };
-
-/* Flags. */
-enum
-  {
-    SOMF_NONE = 0,
-    SOMF_NO_SPACING = 01,      /* No spacing before the table. */
-    SOMF_NO_TITLE = 02         /* No title. */
-  };
-
-/* Table class. */
-struct outp_driver;
-struct som_table_class
-  {
-    /* Set table, driver. */
-    void (*table) (struct som_entity *);
-    void (*driver) (struct outp_driver *);
-
-    /* Query columns and rows. */
-    void (*count) (int *n_columns, int *n_rows);
-    void (*area) (int *horiz, int *vert);
-    void (*width) (int *columns);
-    void (*height) (int *rows);
-    void (*columns) (int *style);
-    int (*breakable) (int row);                                /* ? */
-    void (*headers) (int *l, int *r, int *t, int *b);
-    void (*join) (int *(column[2]), int *(row[2]));    /* ? */
-    void (*cumulate) (int cumtype, int start, int *end, int max, int *actual);
-    void (*flags) (unsigned *);
-    bool (*fits_width) (int width);
-    bool (*fits_length) (int length);
-
-    /* Set columns and rows. */
-    void (*set_width) (int column, int width);         /* ? */
-    void (*set_height) (int row, int height);          /* ? */
-    void (*set_headers) (int l, int r, int t, int b);
-
-    /* Rendering. */
-    void (*title) (int x, int y);
-    void (*render) (int x1, int y1, int x2, int y2);
-  };
-
-/* Table indexes. */
-extern int table_num;
-extern int subtable_num;
-
-/* Submission. */
-void som_new_series (void);
-void som_submit (struct som_entity *t);
-
-/* Miscellaneous. */
-void som_eject_page (void);
-void som_blank_line (void);
-void som_flush (void);
-
-#endif /* som_h */
diff --git a/src/output/measure.c b/src/output/measure.c
new file mode 100644 (file)
index 0000000..8f6e666
--- /dev/null
@@ -0,0 +1,311 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009 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/measure.h>
+
+#include <ctype.h>
+#include <errno.h>
+#if HAVE_LC_PAPER
+#include <langinfo.h>
+#endif
+#include <libpspp/str.h>
+#include <stdlib.h>
+
+#include <data/file-name.h>
+
+#include "gl/error.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static double parse_unit (const char *);
+static bool parse_paper_size (const char *, int *h, int *v);
+static bool get_standard_paper_size (struct substring name, int *h, int *v);
+static bool read_paper_conf (const char *file_name, int *h, int *v);
+static bool get_default_paper_size (int *h, int *v);
+
+/* Determines the size of a dimensional measurement and returns
+   the size in units of 1/72000".  Units are assumed to be
+   millimeters unless otherwise specified.  Returns -1 on
+   error. */
+int
+measure_dimension (const char *dimen)
+{
+  double raw, factor;
+  char *tail;
+
+  /* Number. */
+  raw = strtod (dimen, &tail);
+  if (raw < 0.0)
+    goto syntax_error;
+
+  /* Unit. */
+  factor = parse_unit (tail);
+  if (factor == 0.0)
+    goto syntax_error;
+
+  return raw * factor;
+
+syntax_error:
+  error (0, 0, _("`%s' is not a valid length."), dimen);
+  return -1;
+}
+
+/* Stores the dimensions, in 1/72000" units, of paper identified
+   by SIZE into *H and *V.  SIZE can be the name of a kind of
+   paper ("a4", "letter", ...) or a pair of dimensions
+   ("210x297", "8.5x11in", ...).  Returns true on success, false
+   on failure.  On failure, *H and *V are set for A4 paper. */
+bool
+measure_paper (const char *size, int *h, int *v)
+{
+  struct substring s;
+  bool ok;
+
+  s = ss_cstr (size);
+  ss_trim (&s, ss_cstr (CC_SPACES));
+
+  if (ss_is_empty (s))
+    {
+      /* Treat empty string as default paper size. */
+      ok = get_default_paper_size (h, v);
+    }
+  else if (isdigit (ss_first (s)))
+    {
+      /* Treat string that starts with digit as explicit size. */
+      ok = parse_paper_size (size, h, v);
+      if (!ok)
+        error (0, 0, _("syntax error in paper size `%s'"), size);
+    }
+  else
+    {
+      /* Check against standard paper sizes. */
+      ok = get_standard_paper_size (s, h, v);
+    }
+
+  /* Default to A4 on error. */
+  if (!ok)
+    {
+      *h = 210 * (72000 / 25.4);
+      *v = 297 * (72000 / 25.4);
+    }
+  return ok;
+}
+\f
+/* Parses UNIT as a dimensional unit.  Returns the multiplicative
+   factor needed to change a quantity measured in that unit into
+   1/72000" units.  If UNIT is empty, it is treated as
+   millimeters.  If the unit is unrecognized, returns 0. */
+static double
+parse_unit (const char *unit)
+{
+  struct unit
+    {
+      char name[3];
+      double factor;
+    };
+
+  static const struct unit units[] =
+    {
+      {"pt", 72000 / 72},
+      {"pc", 72000 / 72 * 12.0},
+      {"in", 72000},
+      {"cm", 72000 / 2.54},
+      {"mm", 72000 / 25.4},
+      {"", 72000 / 25.4},
+    };
+
+  const struct unit *p;
+
+  unit += strspn (unit, CC_SPACES);
+  for (p = units; p < units + sizeof units / sizeof *units; p++)
+    if (!strcasecmp (unit, p->name))
+      return p->factor;
+  return 0.0;
+}
+
+/* Stores the dimensions in 1/72000" units of paper identified by
+   SIZE, which is of form `HORZ x VERT [UNIT]' where HORZ and
+   VERT are numbers and UNIT is an optional unit of measurement,
+   into *H and *V.  Return true on success. */
+static bool
+parse_paper_size (const char *size, int *h, int *v)
+{
+  double raw_h, raw_v, factor;
+  char *tail;
+
+  /* Width. */
+  raw_h = strtod (size, &tail);
+  if (raw_h <= 0.0)
+    return false;
+
+  /* Delimiter. */
+  tail += strspn (tail, CC_SPACES "x,");
+
+  /* Length. */
+  raw_v = strtod (tail, &tail);
+  if (raw_v <= 0.0)
+    return false;
+
+  /* Unit. */
+  factor = parse_unit (tail);
+  if (factor == 0.0)
+    return false;
+
+  *h = raw_h * factor + .5;
+  *v = raw_v * factor + .5;
+  return true;
+}
+
+static bool
+get_standard_paper_size (struct substring name, int *h, int *v)
+{
+  static const char *sizes[][2] =
+    {
+      {"a0", "841 x 1189 mm"},
+      {"a1", "594 x 841 mm"},
+      {"a2", "420 x 594 mm"},
+      {"a3", "297 x 420 mm"},
+      {"a4", "210 x 297 mm"},
+      {"a5", "148 x 210 mm"},
+      {"b5", "176 x 250 mm"},
+      {"a6", "105 x 148 mm"},
+      {"a7", "74 x 105 mm"},
+      {"a8", "52 x 74 mm"},
+      {"a9", "37 x 52 mm"},
+      {"a10", "26 x 37 mm"},
+      {"b0", "1000 x 1414 mm"},
+      {"b1", "707 x 1000 mm"},
+      {"b2", "500 x 707 mm"},
+      {"b3", "353 x 500 mm"},
+      {"b4", "250 x 353 mm"},
+      {"letter", "612 x 792 pt"},
+      {"legal", "612 x 1008 pt"},
+      {"executive", "522 x 756 pt"},
+      {"note", "612 x 792 pt"},
+      {"11x17", "792 x 1224 pt"},
+      {"tabloid", "792 x 1224 pt"},
+      {"statement", "396 x 612 pt"},
+      {"halfletter", "396 x 612 pt"},
+      {"halfexecutive", "378 x 522 pt"},
+      {"folio", "612 x 936 pt"},
+      {"quarto", "610 x 780 pt"},
+      {"ledger", "1224 x 792 pt"},
+      {"archA", "648 x 864 pt"},
+      {"archB", "864 x 1296 pt"},
+      {"archC", "1296 x 1728 pt"},
+      {"archD", "1728 x 2592 pt"},
+      {"archE", "2592 x 3456 pt"},
+      {"flsa", "612 x 936 pt"},
+      {"flse", "612 x 936 pt"},
+      {"csheet", "1224 x 1584 pt"},
+      {"dsheet", "1584 x 2448 pt"},
+      {"esheet", "2448 x 3168 pt"},
+    };
+
+  size_t i;
+
+  for (i = 0; i < sizeof sizes / sizeof *sizes; i++)
+    if (ss_equals_case (ss_cstr (sizes[i][0]), name))
+      {
+        bool ok = parse_paper_size (sizes[i][1], h, v);
+        assert (ok);
+        return ok;
+      }
+  error (0, 0, _("unknown paper type `%.*s'"),
+         (int) ss_length (name), ss_data (name));
+  return false;
+}
+
+/* Reads file FILE_NAME to find a paper size.  Stores the
+   dimensions, in 1/72000" units, into *H and *V.  Returns true
+   on success, false on failure. */
+static bool
+read_paper_conf (const char *file_name, int *h, int *v)
+{
+  struct string line = DS_EMPTY_INITIALIZER;
+  int line_number = 0;
+  FILE *file;
+
+  file = fopen (file_name, "r");
+  if (file == NULL)
+    {
+      error (0, errno, _("error opening \"%s\""), file_name);
+      return false;
+    }
+
+  for (;;)
+    {
+      struct substring name;
+
+      if (!ds_read_config_line (&line, &line_number, file))
+       {
+         if (ferror (file))
+           error (0, errno, _("error reading \"%s\""), file_name);
+         break;
+       }
+
+      name = ds_ss (&line);
+      ss_trim (&name, ss_cstr (CC_SPACES));
+      if (!ss_is_empty (name))
+        {
+          bool ok = get_standard_paper_size (name, h, v);
+          fclose (file);
+          ds_destroy (&line);
+          return ok;
+        }
+    }
+
+  fclose (file);
+  ds_destroy (&line);
+  error (0, 0, _("paper size file \"%s\" does not state a paper size"),
+         file_name);
+  return false;
+}
+
+/* The user didn't specify a paper size, so let's choose a
+   default based on his environment.  Stores the
+   dimensions, in 1/72000" units, into *H and *V.  Returns true
+   on success, false on failure. */
+static bool
+get_default_paper_size (int *h, int *v)
+{
+  /* libpaper in Debian (and other distributions?) allows the
+     paper size to be specified in $PAPERSIZE or in a file
+     specified in $PAPERCONF. */
+  if (getenv ("PAPERSIZE") != NULL)
+    return get_standard_paper_size (ss_cstr (getenv ("PAPERSIZE")), h, v);
+  if (getenv ("PAPERCONF") != NULL)
+    return read_paper_conf (getenv ("PAPERCONF"), h, v);
+
+#if HAVE_LC_PAPER
+  /* LC_PAPER is a non-standard glibc extension. */
+  *h = (int) nl_langinfo(_NL_PAPER_WIDTH) * (72000 / 25.4);
+  *v = (int) nl_langinfo(_NL_PAPER_HEIGHT) * (72000 / 25.4);
+  if (*h > 0 && *v > 0)
+     return true;
+#endif
+
+  /* libpaper defaults to /etc/papersize. */
+  if (fn_exists ("/etc/papersize"))
+    return read_paper_conf ("/etc/papersize", h, v);
+
+  /* Can't find a default. */
+  return false;
+}
+
diff --git a/src/output/measure.h b/src/output/measure.h
new file mode 100644 (file)
index 0000000..4b6fab3
--- /dev/null
@@ -0,0 +1,25 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009 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_MEASURE_H
+#define OUTPUT_MEASURE_H 1
+
+#include <stdbool.h>
+
+int measure_dimension (const char *dimen);
+bool measure_paper (const char *size, int *h, int *v);
+
+#endif /* output/measure.h */
diff --git a/src/output/message-item.c b/src/output/message-item.c
new file mode 100644 (file)
index 0000000..feb1d32
--- /dev/null
@@ -0,0 +1,66 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Sonftware 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/message-item.h"
+
+#include <stdlib.h>
+
+#include "libpspp/message.h"
+#include "output/driver.h"
+#include "output/output-item-provider.h"
+
+#include "gl/xalloc.h"
+
+struct message_item *
+message_item_create (const struct msg *msg)
+{
+  struct message_item *item;
+
+  item = xmalloc (sizeof *msg);
+  output_item_init (&item->output_item, &message_item_class);
+  item->msg = msg_dup (msg);
+
+  return item;
+}
+
+const struct msg *
+message_item_get_msg (const struct message_item *item)
+{
+  return item->msg;
+}
+
+static void
+message_item_destroy (struct output_item *output_item)
+{
+  struct message_item *item = to_message_item (output_item);
+  msg_destroy (item->msg);
+  free (item);
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+message_item_submit (struct message_item *item)
+{
+  output_submit (&item->output_item);
+}
+
+const struct output_item_class message_item_class =
+  {
+    message_item_destroy,
+  };
diff --git a/src/output/message-item.h b/src/output/message-item.h
new file mode 100644 (file)
index 0000000..a97b227
--- /dev/null
@@ -0,0 +1,101 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 Free Sonftware 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_MESSAGE_ITEM_H
+#define OUTPUT_MESSAGE_ITEM_H 1
+
+/* Message items.
+
+   A message item is a subclass of an output item (see
+   output/output-item.h).
+
+   A message item is an error, warning, or note to the user.
+
+   Message items should not be submitted directly to the output subsystem.
+   Instead, use the msg() function in libpspp/message.h, which will ensure that
+   the message gets routed properly for the PSPP user interface in use. */
+
+#include <stdbool.h>
+#include <output/output-item.h>
+
+/* A message item. */
+struct message_item
+  {
+    struct output_item output_item;
+    struct msg *msg;
+  };
+
+struct message_item *message_item_create (const struct msg *);
+
+const struct msg *message_item_get_msg (const struct message_item *);
+\f
+/* This boilerplate for message_item, a subclass of output_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct output_item_class message_item_class;
+
+/* Returns true if SUPER is a message_item, otherwise false. */
+static inline bool
+is_message_item (const struct output_item *super)
+{
+  return super->class == &message_item_class;
+}
+
+/* Returns SUPER converted to message_item.  SUPER must be a message_item, as
+   reported by is_message_item. */
+static inline struct message_item *
+to_message_item (const struct output_item *super)
+{
+  assert (is_message_item (super));
+  return UP_CAST (super, struct message_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+message_item_super (const struct message_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct message_item *
+message_item_ref (const struct message_item *instance)
+{
+  return to_message_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+message_item_unref (struct message_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+message_item_is_shared (const struct message_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void message_item_submit (struct message_item *);
+\f
+#endif /* output/message-item.h */
diff --git a/src/output/mk-class-boilerplate b/src/output/mk-class-boilerplate
new file mode 100755 (executable)
index 0000000..b2191aa
--- /dev/null
@@ -0,0 +1,77 @@
+#! /usr/bin/perl
+
+while (<>) {
+    if (my ($class, $super) = /boilerplate for ([a-zA-Z0-9_]+), a subclass of ([a-zA-Z0-9_]+)/) {
+       while (<>) {
+           last if /\f/;
+       }
+       print <<EOF;
+/* This boilerplate for ${class}, a subclass of ${super}, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct ${super}_class ${class}_class;
+
+/* Returns true if SUPER is a ${class}, otherwise false. */
+static inline bool
+is_${class} (const struct ${super} *super)
+{
+  return super->class == &${class}_class;
+}
+
+/* Returns SUPER converted to ${class}.  SUPER must be a ${class}, as
+   reported by is_${class}. */
+static inline struct ${class} *
+to_${class} (const struct ${super} *super)
+{
+  assert (is_${class} (super));
+  return UP_CAST (super, struct ${class}, ${super});
+}
+
+/* Returns INSTANCE converted to ${super}. */
+static inline struct ${super} *
+${class}_super (const struct ${class} *instance)
+{
+  return CONST_CAST (struct ${super} *, &instance->${super});
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct ${class} *
+${class}_ref (const struct ${class} *instance)
+{
+  return to_${class} (${super}_ref (&instance->${super}));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+${class}_unref (struct ${class} *instance)
+{
+  ${super}_unref (&instance->${super});
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+${class}_is_shared (const struct ${class} *instance)
+{
+  return ${super}_is_shared (&instance->${super});
+}
+
+EOF
+       if ($super ne 'output_item') {
+           print <<EOF;
+static inline void
+${class}_submit (struct ${class} *instance)
+{
+  ${super}_submit (&instance->${super});
+}
+EOF
+       } else {
+           print "void ${class}_submit (struct ${class} *);\n";
+       }
+    }
+    print;
+}
diff --git a/src/output/msglog.c b/src/output/msglog.c
new file mode 100644 (file)
index 0000000..d5c6806
--- /dev/null
@@ -0,0 +1,119 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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/msglog.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "data/file-name.h"
+#include "data/settings.h"
+#include "libpspp/cast.h"
+#include "output/driver-provider.h"
+#include "output/message-item.h"
+
+#include "gl/error.h"
+#include "gl/fwriteerror.h"
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct msglog_driver
+  {
+    struct output_driver driver;
+    FILE *file;
+    char *file_name;
+    char *command_name;
+  };
+
+static const struct output_driver_class msglog_class;
+
+static struct msglog_driver *
+msglog_driver_cast (struct output_driver *driver)
+{
+  assert (driver->class == &msglog_class);
+  return UP_CAST (driver, struct msglog_driver, driver);
+}
+
+struct output_driver *
+msglog_create (const char *file_name)
+{
+  enum settings_output_devices type;
+  struct msglog_driver *ml;
+  FILE *file;
+
+  file = fn_open (file_name, "w");
+  if (file == NULL)
+    {
+      error (0, errno, _("%s: open failed"), file_name);
+      return NULL;
+    }
+
+  type = (!strcmp (file_name, "-") || isatty (fileno (file))
+          ? SETTINGS_DEVICE_TERMINAL
+          : SETTINGS_DEVICE_UNFILTERED);
+
+  ml = xzalloc (sizeof *ml);
+  output_driver_init (&ml->driver, &msglog_class, file_name, type);
+  ml->file = file;
+  ml->file_name = xstrdup (file_name);
+  ml->command_name = NULL;
+
+  output_driver_register (&ml->driver);
+
+  return &ml->driver;
+}
+
+static void
+msglog_destroy (struct output_driver *driver)
+{
+  struct msglog_driver *ml = msglog_driver_cast (driver);
+
+  fn_close (ml->file_name, ml->file);
+  free (ml->file_name);
+  free (ml->command_name);
+  free (ml);
+}
+
+static void
+msglog_submit (struct output_driver *driver, const struct output_item *item)
+{
+  struct msglog_driver *ml = msglog_driver_cast (driver);
+
+  output_driver_track_current_command (item, &ml->command_name);
+
+  if (is_message_item (item))
+    {
+      const struct message_item *message_item = to_message_item (item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, ml->command_name);
+      fprintf (ml->file, "%s\n", s);
+      free (s);
+    }
+}
+
+static const struct output_driver_class msglog_class =
+  {
+    "msglog",
+    msglog_destroy,
+    msglog_submit,
+    NULL
+  };
diff --git a/src/output/msglog.h b/src/output/msglog.h
new file mode 100644 (file)
index 0000000..e5d5498
--- /dev/null
@@ -0,0 +1,24 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010 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_MSGLOG_H
+#define OUTPUT_MSGLOG_H 1
+
+/* Output driver to log errors, warnings, and notes to files. */
+
+struct output_driver *msglog_create (const char *file_name);
+
+#endif /* output/msglog.h */
diff --git a/src/output/odt.c b/src/output/odt.c
new file mode 100644 (file)
index 0000000..0b55ac9
--- /dev/null
@@ -0,0 +1,553 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009, 2010 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>
+
+/* A driver for creating OpenDocument Format text files from PSPP's output */
+
+#include <errno.h>
+#include <libgen.h>
+#include <libxml/xmlwriter.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
+#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"
+
+#include "gl/xalloc.h"
+#include "gl/error.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#define _xml(X) (const xmlChar *)(X)
+
+struct odt_driver
+{
+  struct output_driver driver;
+
+  char *file_name;            /* Output file name. */
+  bool debug;
+
+  /* The name of the temporary directory used to construct the ODF */
+  char *dirname;
+
+  /* Writer for the content.xml file */
+  xmlTextWriterPtr content_wtr;
+
+  /* Writer fot the manifest.xml file */
+  xmlTextWriterPtr manifest_wtr;
+
+  /* Number of tables so far. */
+  int table_num;
+
+  /* Name of current command. */
+  char *command_name;
+};
+
+static const struct output_driver_class odt_driver_class;
+
+static struct odt_driver *
+odt_driver_cast (struct output_driver *driver)
+{
+  assert (driver->class == &odt_driver_class);
+  return UP_CAST (driver, struct odt_driver, driver);
+}
+
+/* Create the "mimetype" file needed by ODF */
+static bool
+create_mimetype (const char *dirname)
+{
+  FILE *fp;
+  struct string filename;
+  ds_init_cstr (&filename, dirname);
+  ds_put_cstr (&filename, "/mimetype");
+  fp = fopen (ds_cstr (&filename), "w");
+
+  if (fp == NULL)
+    {
+      error (0, errno, _("failed to create output file %s"),
+             ds_cstr (&filename));
+      ds_destroy (&filename);
+      return false;
+    }
+  ds_destroy (&filename);
+
+  fprintf (fp, "application/vnd.oasis.opendocument.text");
+  fclose (fp);
+
+  return true;
+}
+
+/* Create a new XML file called FILENAME in the temp directory, and return a writer for it */
+static xmlTextWriterPtr
+create_writer (const struct odt_driver *driver, const char *filename)
+{
+  char *copy = NULL;
+  xmlTextWriterPtr w;
+  struct string str;
+  ds_init_cstr (&str, driver->dirname);
+  ds_put_cstr (&str, "/");
+  ds_put_cstr (&str, filename);
+
+  /* dirname modifies its argument, so we must copy it */
+  copy = xstrdup (ds_cstr (&str));
+  mkdir (dirname (copy), 0700);
+  free (copy);
+
+  w = xmlNewTextWriterFilename (ds_cstr (&str), 0);
+
+  ds_destroy (&str);
+
+  xmlTextWriterStartDocument (w, NULL, "UTF-8", NULL);
+
+  return w;
+}
+
+
+static void
+register_file (struct odt_driver *odt, const char *filename)
+{
+  assert (odt->manifest_wtr);
+  xmlTextWriterStartElement (odt->manifest_wtr, _xml("manifest:file-entry"));
+  xmlTextWriterWriteAttribute (odt->manifest_wtr, _xml("manifest:media-type"),  _xml("text/xml"));
+  xmlTextWriterWriteAttribute (odt->manifest_wtr, _xml("manifest:full-path"),  _xml (filename));
+  xmlTextWriterEndElement (odt->manifest_wtr);
+}
+
+static void
+write_style_data (struct odt_driver *odt)
+{
+  xmlTextWriterPtr w = create_writer (odt, "styles.xml");
+  register_file (odt, "styles.xml");
+
+  xmlTextWriterStartElement (w, _xml ("office:document-styles"));
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:office"),
+                              _xml ("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:style"),
+                              _xml ("urn:oasis:names:tc:opendocument:xmlns:style:1.0"));
+
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:fo"),
+                              _xml ("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0") );
+
+  xmlTextWriterWriteAttribute (w, _xml ("office:version"),  _xml ("1.1"));
+                              
+
+
+  xmlTextWriterStartElement (w, _xml ("office:styles"));
+
+
+  {
+    xmlTextWriterStartElement (w, _xml ("style:style"));
+    xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+                                _xml ("Standard"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+                                _xml ("paragraph"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+                                _xml ("text"));
+
+    xmlTextWriterEndElement (w); /* style:style */
+  }
+
+  {
+    xmlTextWriterStartElement (w, _xml ("style:style"));
+    xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+                                _xml ("Table_20_Contents"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:display-name"),
+                                _xml ("Table Contents"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+                                _xml ("paragraph"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:parent-style-name"),
+                                _xml ("Standard"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+                                _xml ("extra"));
+
+    xmlTextWriterEndElement (w); /* style:style */
+  }
+
+  {
+    xmlTextWriterStartElement (w, _xml ("style:style"));
+    xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+                                _xml ("Table_20_Heading"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:display-name"),
+                                _xml ("Table Heading"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+                                _xml ("paragraph"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:parent-style-name"),
+                                _xml ("Table_20_Contents"));
+
+    xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+                                _xml ("extra"));
+
+
+    xmlTextWriterStartElement (w, _xml ("style:text-properties"));
+    xmlTextWriterWriteAttribute (w, _xml ("fo:font-weight"), _xml ("bold"));
+    xmlTextWriterWriteAttribute (w, _xml ("style:font-weight-asian"), _xml ("bold"));
+    xmlTextWriterWriteAttribute (w, _xml ("style:font-weight-complex"), _xml ("bold"));
+    xmlTextWriterEndElement (w); /* style:text-properties */
+
+    xmlTextWriterEndElement (w); /* style:style */
+  }
+
+
+  xmlTextWriterEndElement (w); /* office:styles */
+  xmlTextWriterEndElement (w); /* office:document-styles */
+
+  xmlTextWriterEndDocument (w);
+  xmlFreeTextWriter (w);
+}
+
+static void
+write_meta_data (struct odt_driver *odt)
+{
+  xmlTextWriterPtr w = create_writer (odt, "meta.xml");
+  register_file (odt, "meta.xml");
+
+  xmlTextWriterStartElement (w, _xml ("office:document-meta"));
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:office"), _xml ("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:dc"),  _xml ("http://purl.org/dc/elements/1.1/"));
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:meta"), _xml ("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"));
+  xmlTextWriterWriteAttribute (w, _xml ("xmlns:ooo"), _xml("http://openoffice.org/2004/office"));
+  xmlTextWriterWriteAttribute (w, _xml ("office:version"),  _xml("1.1"));
+
+  xmlTextWriterStartElement (w, _xml ("office:meta"));
+  {
+    xmlTextWriterStartElement (w, _xml ("meta:generator"));
+    xmlTextWriterWriteString (w, _xml (stat_version));
+    xmlTextWriterEndElement (w);
+  }
+
+
+  {
+    char buf[30];
+    struct passwd *pw = getpwuid (getuid ());
+    time_t t = time (NULL);
+    struct tm *tm =  localtime (&t);
+
+    strftime (buf, 30, "%Y-%m-%dT%H:%M:%S", tm);
+
+    xmlTextWriterStartElement (w, _xml ("meta:initial-creator"));
+    xmlTextWriterWriteString (w, _xml (strtok (pw->pw_gecos, ",")));
+    xmlTextWriterEndElement (w);
+
+    xmlTextWriterStartElement (w, _xml ("meta:creation-date"));
+    xmlTextWriterWriteString (w, _xml (buf));
+    xmlTextWriterEndElement (w);
+
+    xmlTextWriterStartElement (w, _xml ("dc:creator"));
+    xmlTextWriterWriteString (w, _xml (strtok (pw->pw_gecos, ",")));
+
+    xmlTextWriterEndElement (w);
+
+    xmlTextWriterStartElement (w, _xml ("dc:date"));
+    xmlTextWriterWriteString (w, _xml (buf));
+    xmlTextWriterEndElement (w);
+  }
+
+  xmlTextWriterEndElement (w);
+  xmlTextWriterEndElement (w);
+  xmlTextWriterEndDocument (w);
+  xmlFreeTextWriter (w);
+}
+
+enum
+{
+  output_file_arg,
+  boolean_arg,
+};
+
+static struct driver_option *
+opt (struct output_driver *d, struct string_map *options, const char *key,
+     const char *default_value)
+{
+  return driver_option_get (d, options, key, default_value);
+}
+
+static struct output_driver *
+odt_create (const char *file_name, enum settings_output_devices device_type,
+            struct string_map *o)
+{
+  struct output_driver *d;
+  struct odt_driver *odt;
+
+  odt = xzalloc (sizeof *odt);
+  d = &odt->driver;
+  output_driver_init (d, &odt_driver_class, file_name, device_type);
+
+  odt->file_name = xstrdup (file_name);
+  odt->debug = parse_boolean (opt (d, o, "debug", "false"));
+
+  odt->dirname = xstrdup ("odt-XXXXXX");
+  mkdtemp (odt->dirname);
+
+  if (!create_mimetype (odt->dirname))
+    {
+      output_driver_destroy (d);
+      return NULL;
+    }
+
+  /* Create the manifest */
+  odt->manifest_wtr = create_writer (odt, "META-INF/manifest.xml");
+
+  xmlTextWriterStartElement (odt->manifest_wtr, _xml("manifest:manifest"));
+  xmlTextWriterWriteAttribute (odt->manifest_wtr, _xml("xmlns:manifest"),
+                              _xml("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"));
+
+
+  /* Add a manifest entry for the document as a whole */
+  xmlTextWriterStartElement (odt->manifest_wtr, _xml("manifest:file-entry"));
+  xmlTextWriterWriteAttribute (odt->manifest_wtr, _xml("manifest:media-type"),  _xml("application/vnd.oasis.opendocument.text"));
+  xmlTextWriterWriteAttribute (odt->manifest_wtr, _xml("manifest:full-path"),  _xml("/"));
+  xmlTextWriterEndElement (odt->manifest_wtr);
+
+
+  write_meta_data (odt);
+  write_style_data (odt);
+
+  odt->content_wtr = create_writer (odt, "content.xml");
+  register_file (odt, "content.xml");
+
+
+  /* Some necessary junk at the start */
+  xmlTextWriterStartElement (odt->content_wtr, _xml("office:document-content"));
+  xmlTextWriterWriteAttribute (odt->content_wtr, _xml("xmlns:office"),
+                              _xml("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+
+  xmlTextWriterWriteAttribute (odt->content_wtr, _xml("xmlns:text"),
+                              _xml("urn:oasis:names:tc:opendocument:xmlns:text:1.0"));
+
+  xmlTextWriterWriteAttribute (odt->content_wtr, _xml("xmlns:table"),
+                              _xml("urn:oasis:names:tc:opendocument:xmlns:table:1.0"));
+
+  xmlTextWriterWriteAttribute (odt->content_wtr, _xml("office:version"), _xml("1.1"));
+
+  xmlTextWriterStartElement (odt->content_wtr, _xml("office:body"));
+  xmlTextWriterStartElement (odt->content_wtr, _xml("office:text"));
+
+
+
+  /* Close the manifest */
+  xmlTextWriterEndElement (odt->manifest_wtr);
+  xmlTextWriterEndDocument (odt->manifest_wtr);
+  xmlFreeTextWriter (odt->manifest_wtr);
+
+  return d;
+}
+
+static void
+odt_destroy (struct output_driver *driver)
+{
+  struct odt_driver *odt = odt_driver_cast (driver);
+
+  if (odt->content_wtr != NULL)
+    {
+      struct string zip_cmd;
+
+      xmlTextWriterEndElement (odt->content_wtr); /* office:text */
+      xmlTextWriterEndElement (odt->content_wtr); /* office:body */
+      xmlTextWriterEndElement (odt->content_wtr); /* office:document-content */
+
+      xmlTextWriterEndDocument (odt->content_wtr);
+      xmlFreeTextWriter (odt->content_wtr);
+
+      /* Zip up the directory */
+      ds_init_empty (&zip_cmd);
+      ds_put_format (&zip_cmd,
+                     "cd %s ; rm -f ../%s; zip -q -X ../%s mimetype; zip -q -X -u -r ../%s .",
+                     odt->dirname, odt->file_name, odt->file_name, odt->file_name);
+      system (ds_cstr (&zip_cmd));
+      ds_destroy (&zip_cmd);
+    }
+
+  if ( !odt->debug )
+    {
+      /* Remove the temp dir */
+      struct string rm_cmd;
+
+      ds_init_empty (&rm_cmd);
+      ds_put_format (&rm_cmd, "rm -r %s", odt->dirname);
+      system (ds_cstr (&rm_cmd));
+      ds_destroy (&rm_cmd);
+    }
+  else
+    fprintf (stderr, "Not removing directory %s\n", odt->dirname);
+
+  free (odt->command_name);
+  free (odt->dirname);
+  free (odt);
+}
+
+static void
+odt_submit_table (struct odt_driver *odt, struct table_item *item)
+{
+  const struct table *tab = table_item_get_table (item);
+  const char *caption = table_item_get_caption (item);
+  int r, c;
+
+  /* Write a heading for the table */
+  if (caption != NULL)
+    {
+      xmlTextWriterStartElement (odt->content_wtr, _xml("text:h"));
+      xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("text:level"),
+                                         "%d", 2);
+      xmlTextWriterWriteString (odt->content_wtr,
+                                _xml (table_item_get_caption (item)) );
+      xmlTextWriterEndElement (odt->content_wtr);
+    }
+
+  /* Start table */
+  xmlTextWriterStartElement (odt->content_wtr, _xml("table:table"));
+  xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:name"), 
+                                    "TABLE-%d", odt->table_num++);
+
+
+  /* Start column definitions */
+  xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-column"));
+  xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:number-columns-repeated"), "%d", table_nc (tab));
+  xmlTextWriterEndElement (odt->content_wtr);
+
+
+  /* Deal with row headers */
+  if ( table_ht (tab) > 0)
+    xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-header-rows"));
+    
+
+  /* Write all the rows */
+  for (r = 0 ; r < table_nr (tab); ++r)
+    {
+      /* Start row definition */
+      xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-row"));
+
+      /* Write all the columns */
+      for (c = 0 ; c < table_nc (tab) ; ++c)
+       {
+          struct table_cell cell;
+
+          table_get_cell (tab, c, r, &cell);
+
+          if (c == cell.d[TABLE_HORZ][0] && r == cell.d[TABLE_VERT][0])
+            {
+              int colspan = table_cell_colspan (&cell);
+              int rowspan = table_cell_rowspan (&cell);
+
+              xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-cell"));
+              xmlTextWriterWriteAttribute (odt->content_wtr, _xml("office:value-type"), _xml("string"));
+
+              if (colspan > 1)
+                xmlTextWriterWriteFormatAttribute (
+                  odt->content_wtr, _xml("table:number-columns-spanned"),
+                  "%d", colspan);
+
+              if (rowspan > 1)
+                xmlTextWriterWriteFormatAttribute (
+                  odt->content_wtr, _xml("table:number-rows-spanned"),
+                  "%d", rowspan);
+
+             xmlTextWriterStartElement (odt->content_wtr, _xml("text:p"));
+
+             if ( r < table_ht (tab) || c < table_hl (tab) )
+               xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Heading"));
+             else
+               xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Contents"));
+
+             xmlTextWriterWriteString (odt->content_wtr, _xml(cell.contents));
+
+             xmlTextWriterEndElement (odt->content_wtr); /* text:p */
+             xmlTextWriterEndElement (odt->content_wtr); /* table:table-cell */
+           }
+         else
+           {
+             xmlTextWriterStartElement (odt->content_wtr, _xml("table:covered-table-cell"));
+             xmlTextWriterEndElement (odt->content_wtr);
+           }
+
+          table_cell_free (&cell);
+       }
+  
+      xmlTextWriterEndElement (odt->content_wtr); /* row */
+
+      if ( table_ht (tab) > 0 && r == table_ht (tab) - 1)
+       xmlTextWriterEndElement (odt->content_wtr); /* table-header-rows */
+    }
+
+  xmlTextWriterEndElement (odt->content_wtr); /* table */
+}
+
+static void
+odt_output_text (struct odt_driver *odt, const char *text)
+{
+  xmlTextWriterStartElement (odt->content_wtr, _xml("text:p"));
+  xmlTextWriterWriteString (odt->content_wtr, _xml(text));
+  xmlTextWriterEndElement (odt->content_wtr);
+}
+
+/* Submit a table to the ODT driver */
+static void
+odt_submit (struct output_driver *driver,
+            const struct output_item *output_item)
+{
+  struct odt_driver *odt = odt_driver_cast (driver);
+
+  output_driver_track_current_command (output_item, &odt->command_name);
+
+  if (is_table_item (output_item))
+    odt_submit_table (odt, to_table_item (output_item));
+  else if (is_text_item (output_item))
+    {
+      /* XXX apply different styles based on text_item's type.  */
+      odt_output_text (odt, text_item_get_text (to_text_item (output_item)));
+    }
+  else if (is_message_item (output_item))
+    {
+      const struct message_item *message_item = to_message_item (output_item);
+      const struct msg *msg = message_item_get_msg (message_item);
+      char *s = msg_to_string (msg, odt->command_name);
+      odt_output_text (odt, s);
+      free (s);
+    }
+}
+
+struct output_driver_factory odt_driver_factory = { "odt", odt_create };
+
+static const struct output_driver_class odt_driver_class =
+{
+  "odf",
+  odt_destroy,
+  odt_submit,
+  NULL,
+};
diff --git a/src/output/options.c b/src/output/options.c
new file mode 100644 (file)
index 0000000..593adf5
--- /dev/null
@@ -0,0 +1,338 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009, 2010 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/options.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/str.h"
+#include "libpspp/string-map.h"
+#include "output/driver-provider.h"
+#include "output/measure.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Creates and returns a new struct driver_option that contains copies of
+   all of the supplied arguments.  All of the arguments must be nonnull,
+   except that VALUE may be NULL (if the user did not supply a value for this
+   option).
+
+   Refer to struct driver_option for the meaning of each argument. */
+struct driver_option *
+driver_option_create (const char *driver_name, const char *name,
+                      const char *value, const char *default_value)
+{
+  struct driver_option *o = xmalloc (sizeof *o);
+  o->driver_name = xstrdup (driver_name);
+  o->name = xstrdup (name);
+  o->value = value != NULL ? xstrdup (value) : NULL;
+  o->default_value = xstrdup (default_value);
+  return o;
+}
+
+/* Creates and returns a new struct driver_option for output driver DRIVER
+   (which is needed only to the extent that its name will be used in error
+   messages).  The option named NAME is extracted from OPTIONS.  DEFAULT_VALUE
+   is the default value of the option, used if the given option was not
+   supplied or was invalid. */
+struct driver_option *
+driver_option_get (struct output_driver *driver, struct string_map *options,
+                   const char *name, const char *default_value)
+{
+  struct driver_option *option;
+  char *value;
+
+  value = string_map_find_and_delete (options, name);
+  option = driver_option_create (output_driver_get_name (driver), name, value,
+                                 default_value);
+  free (value);
+  return option;
+}
+
+/* Frees driver option O. */
+void
+driver_option_destroy (struct driver_option *o)
+{
+  if (o != NULL)
+    {
+      free (o->driver_name);
+      free (o->name);
+      free (o->value);
+      free (o->default_value);
+      free (o);
+    }
+}
+
+/* Stores the paper size of the value of option O into *H and *V, in 1/72000"
+   units.  Any syntax accepted by measure_paper() may be used.
+
+   Destroys O. */
+void
+parse_paper_size (struct driver_option *o, int *h, int *v)
+{
+  if (o->value == NULL || !measure_paper (o->value, h, v))
+    measure_paper (o->default_value, h, v);
+  driver_option_destroy (o);
+}
+
+static int
+do_parse_boolean (const char *driver_name, const char *key,
+                  const char *value)
+{
+  if (!strcmp (value, "on") || !strcmp (value, "true")
+      || !strcmp (value, "yes") || !strcmp (value, "1"))
+    return true;
+  else if (!strcmp (value, "off") || !strcmp (value, "false")
+           || !strcmp (value, "no") || !strcmp (value, "0"))
+    return false;
+  else
+    {
+      error (0, 0, _("%s: \"%s\" is \"%s\" but a Boolean value is required"),
+             driver_name, value, key);
+      return -1;
+    }
+}
+
+/* Parses and return O's value as a Boolean value.  "true" and "false", "yes"
+   and "no", "on" and "off", and "1" and "0" are acceptable boolean strings.
+
+   Destroys O. */
+bool
+parse_boolean (struct driver_option *o)
+{
+  bool retval;
+
+  retval = do_parse_boolean (o->driver_name, o->name, o->default_value) > 0;
+  if (o->value != NULL)
+    {
+      int value = do_parse_boolean (o->driver_name, o->name, o->value);
+      if (value >= 0)
+        retval = value;
+    }
+
+  driver_option_destroy (o);
+
+  return retval;
+}
+
+/* Parses O's value as an enumeration constant.  The arguments to this function
+   consist of a series of string/int pairs, terminated by a null pointer value.
+   O's value is compared to each string in turn, and parse_enum() returns the
+   int associated with the first matching string.  If there is no match, or if
+   O has no user-specified value, then O's default value is treated the same
+   way.  If the default value still does not match, parse_enum() returns 0.
+
+   Example: parse_enum (o, "a", 1, "b", 2, (char *) NULL) returns 1 if O's
+   value if "a", 2 if O's value is "b".
+
+   Destroys O. */
+int
+parse_enum (struct driver_option *o, ...)
+{
+  va_list args;
+  int retval;
+
+  retval = 0;
+  va_start (args, o);
+  for (;;)
+    {
+      const char *s;
+      int value;
+
+      s = va_arg (args, const char *);
+      if (s == NULL)
+        {
+          if (o->value != NULL)
+            {
+              struct string choices;
+              int i;
+
+              ds_init_empty (&choices);
+              va_end (args);
+              va_start (args, o);
+              for (i = 0; ; i++)
+                {
+                  s = va_arg (args, const char *);
+                  if (s == NULL)
+                    break;
+                  value = va_arg (args, int);
+
+                  if (i > 0)
+                    ds_put_cstr (&choices, ", ");
+                  ds_put_format (&choices, "`%s'", s);
+                }
+
+              error (0, 0, _("%s: \"%s\" is \"%s\" but one of the following "
+                             "is required: %s"),
+                     o->driver_name, o->name, o->value, ds_cstr (&choices));
+              ds_destroy (&choices);
+            }
+          break;
+        }
+      value = va_arg (args, int);
+
+      if (o->value != NULL && !strcmp (s, o->value))
+        {
+          retval = value;
+          break;
+        }
+      else if (!strcmp (s, o->default_value))
+        retval = value;
+    }
+  va_end (args);
+  driver_option_destroy (o);
+  return retval;
+}
+
+/* Parses O's value as an integer in the range MIN_VALUE to MAX_VALUE
+   (inclusive) and returns the integer.
+
+   Destroys O. */
+int
+parse_int (struct driver_option *o, int min_value, int max_value)
+{
+  int retval = strtol (o->default_value, NULL, 0);
+
+  if (o->value != NULL)
+    {
+      int value;
+      char *tail;
+
+      errno = 0;
+      value = strtol (o->value, &tail, 0);
+      if (tail != o->value && *tail == '\0' && errno != ERANGE
+          && value >= min_value && value <= max_value)
+        retval = value;
+      else if (max_value == INT_MAX)
+        {
+          if (min_value == 0)
+            error (0, 0, _("%s: \"%s\" is \"%s\" but a nonnegative integer "
+                           "is required"),
+                   o->driver_name, o->name, o->value);
+          else if (min_value == 1)
+            error (0, 0, _("%s: \"%s\" is \"%s\" but a positive integer is "
+                           "required"), o->driver_name, o->name, o->value);
+          else if (min_value == INT_MIN)
+            error (0, 0, _("%s: \"%s\" is \"%s\" but an integer is required"),
+                   o->driver_name, o->name, o->value);
+          else
+            error (0, 0, _("%s: \"%s\" is \"%s\" but an integer greater "
+                           "than %d is required"),
+                   o->driver_name, o->name, o->value, min_value - 1);
+        }
+      else
+        error (0, 0, _("%s: \"%s\" is \"%s\"  but an integer between %d and "
+                       "%d is required"),
+               o->driver_name, o->name, o->value, min_value, max_value);
+    }
+
+  driver_option_destroy (o);
+  return retval;
+}
+
+/* Parses O's value as a dimension, as understood by measure_dimension(), and
+   returns its length in units of 1/72000".
+
+   Destroys O. */
+int
+parse_dimension (struct driver_option *o)
+{
+  int retval;
+
+  retval = o->value != NULL ? measure_dimension (o->value) : -1;
+  if (retval == -1)
+    retval = measure_dimension (o->default_value);
+
+  driver_option_destroy (o);
+  return retval;
+}
+
+/* Parses O's value as a string and returns it as a malloc'd string that the
+   caller is responsible for freeing.
+
+   Destroys O. */
+char *
+parse_string (struct driver_option *o)
+{
+  char *retval = xstrdup (o->value != NULL ? o->value : o->default_value);
+  driver_option_destroy (o);
+  return retval;
+}
+
+static char *
+default_chart_file_name (const char *file_name)
+{
+  if (strcmp (file_name, "-"))
+    {
+      const char *extension = strrchr (file_name, '.');
+      int stem_length = extension ? extension - file_name : strlen (file_name);
+      return xasprintf ("%.*s-#.png", stem_length, file_name);
+    }
+  else
+    return NULL;
+}
+
+/* Parses and returns a chart file name, or NULL if no charts should be output.
+   If a nonnull string is returned, it will contain at least one '#' character,
+   which the client will presumably replace by a number as part of writing
+   charts to separate files.
+
+   If O->value is "none", then this function returns NULL.
+
+   If O->value is non-NULL but not "none", returns a copy of that string (if it
+   contains '#').
+
+   If O->value is NULL, then O's default_value should be the name of the main
+   output file.  Returns NULL if default_value is "-", and otherwise returns a
+   copy of string string with its extension stripped off and "-#.png" appended.
+
+   Destroys O. */
+char *
+parse_chart_file_name (struct driver_option *o)
+{
+  char *chart_file_name;
+
+  if (o->value != NULL)
+    {
+      if (!strcmp (o->value, "none"))
+        chart_file_name = NULL;
+      else if (strchr (o->value, '#') != NULL)
+        chart_file_name = xstrdup (o->value);
+      else
+        {
+          error (0, 0, _("%s: \"%s\" is \"%s\" but a file name that contains "
+                         "\"#\" is required."),
+                 o->name, o->value, o->driver_name);
+          chart_file_name = default_chart_file_name (o->default_value);
+        }
+    }
+  else
+    chart_file_name = default_chart_file_name (o->default_value);
+
+  driver_option_destroy (o);
+
+  return chart_file_name;
+}
diff --git a/src/output/options.h b/src/output/options.h
new file mode 100644 (file)
index 0000000..3f9e705
--- /dev/null
@@ -0,0 +1,55 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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_OPTIONS_H
+#define OUTPUT_OPTIONS_H 1
+
+/* Helper functions for driver option parsing. */
+
+#include <stdbool.h>
+#include "libpspp/compiler.h"
+
+struct output_driver;
+struct string_map;
+
+/* An option being parsed. */
+struct driver_option
+  {
+    char *driver_name;          /* Driver's name, for use in error messages. */
+    char *name;                 /* Option name, for use in error messages.  */
+    char *value;                /* Value supplied by user (NULL if none). */
+    char *default_value;        /* Default value supplied by driver. */
+  };
+
+struct driver_option *driver_option_create (const char *driver_name,
+                                            const char *name,
+                                            const char *value,
+                                            const char *default_value);
+struct driver_option *driver_option_get (struct output_driver *,
+                                         struct string_map *,
+                                         const char *name,
+                                         const char *default_value);
+void driver_option_destroy (struct driver_option *);
+
+void parse_paper_size (struct driver_option *, int *h, int *v);
+bool parse_boolean (struct driver_option *);
+int parse_enum (struct driver_option *, ...) SENTINEL(0);
+int parse_int (struct driver_option *, int min_value, int max_value);
+int parse_dimension (struct driver_option *);
+char *parse_string (struct driver_option *);
+char *parse_chart_file_name (struct driver_option *);
+
+#endif /* output/options.h */
diff --git a/src/output/output-item-provider.h b/src/output/output-item-provider.h
new file mode 100644 (file)
index 0000000..a810f97
--- /dev/null
@@ -0,0 +1,35 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_ITEM_PROVIDER_H
+#define OUTPUT_ITEM_PROVIDER_H 1
+
+#include <output/output-item.h>
+
+/* Class structure for an output item.
+
+   This structure must be provided by an output_item subclass to initialize an
+   instance of output_item. */
+struct output_item_class
+  {
+    /* Destroys and frees ITEM.  Called when output_item_unref() drops ITEM's
+       reference count to 0. */
+    void (*destroy) (struct output_item *item);
+  };
+
+void output_item_init (struct output_item *, const struct output_item_class *);
+
+#endif /* output/output-item-provider.h */
diff --git a/src/output/output-item.c b/src/output/output-item.c
new file mode 100644 (file)
index 0000000..e1c889f
--- /dev/null
@@ -0,0 +1,73 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/output-item-provider.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
+
+#include "xalloc.h"
+\f
+/* Increases ITEM's reference count, indicating that it has an additional
+   owner.  An output item that is shared among multiple owners must not be
+   modified. */
+struct output_item *
+output_item_ref (const struct output_item *item_)
+{
+  struct output_item *item = CONST_CAST (struct output_item *, item_);
+  item->ref_cnt++;
+  return item;
+}
+
+/* Decreases ITEM's reference count, indicating that it has one fewer owner.
+   If ITEM no longer has any owners, it is freed. */
+void
+output_item_unref (struct output_item *item)
+{
+  if (item != NULL)
+    {
+      assert (item->ref_cnt > 0);
+      if (--item->ref_cnt == 0)
+        item->class->destroy (item);
+    }
+}
+
+/* Returns true if ITEM has more than one owner.  An output item that is shared
+   among multiple owners must not be modified. */
+bool
+output_item_is_shared (const struct output_item *item)
+{
+  return item->ref_cnt > 1;
+}
+\f
+/* Initializes ITEM as an output item of the specified CLASS, initially with a
+   reference count of 1.
+
+   An output item is an abstract class, that is, a plain output_item is not
+   useful on its own.  Thus, this function is normally called from the
+   initialization function of some subclass of output_item. */
+void
+output_item_init (struct output_item *item,
+                  const struct output_item_class *class)
+{
+  item->class = class;
+  item->ref_cnt = 1;
+}
diff --git a/src/output/output-item.h b/src/output/output-item.h
new file mode 100644 (file)
index 0000000..b45e008
--- /dev/null
@@ -0,0 +1,52 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_ITEM_H
+#define OUTPUT_ITEM_H 1
+
+/* Output items.
+
+   An output item is a self-contained chunk of output.  The
+   following kinds of output items currently exist:
+
+        - Tables (see output/table-item.h).
+
+        - Charts (see output/chart-item.h).
+
+        - Text strings (see output/text-item.h).
+
+        - Messages (see output/message-item.h).
+*/
+
+#include <libpspp/cast.h>
+#include <stdbool.h>
+
+/* A single output item. */
+struct output_item
+  {
+    const struct output_item_class *class;
+
+    /* Reference count.  An output item may be shared between multiple owners,
+       indicated by a reference count greater than 1.  When this is the case,
+       the output item must not be modified. */
+    int ref_cnt;
+  };
+
+struct output_item *output_item_ref (const struct output_item *);
+void output_item_unref (struct output_item *);
+bool output_item_is_shared (const struct output_item *);
+
+#endif /* output/output-item.h */
diff --git a/src/output/output.c b/src/output/output.c
deleted file mode 100644 (file)
index 843b0d4..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 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 <ctype.h>
-#include <errno.h>
-#if HAVE_LC_PAPER
-#include <langinfo.h>
-#endif
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <data/file-name.h>
-#include <data/settings.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <output/htmlP.h>
-#include <output/output.h>
-
-#include "error.h"
-#include "intprops.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* FIXME? Should the output configuration format be changed to
-   drivername:classname:devicetype:options, where devicetype is zero
-   or more of screen, printer, listing? */
-
-/* FIXME: Have the reentrancy problems been solved? */
-
-/* Where the output driver name came from. */
-enum
-  {
-    OUTP_S_COMMAND_LINE,       /* Specified by the user. */
-    OUTP_S_INIT_FILE           /* `default' or the init file. */
-  };
-
-/* Names the output drivers to be used. */
-struct outp_names
-  {
-    char *name;                        /* Name of the output driver. */
-    int source;                        /* OUTP_S_* */
-    struct outp_names *next, *prev;
-  };
-
-/* Defines an init file macro. */
-struct outp_defn
-  {
-    char *key;
-    struct string value;
-    struct outp_defn *next, *prev;
-  };
-
-static struct outp_defn *outp_macros;
-static struct outp_names *outp_configure_vec;
-
-/* A list of driver classes. */
-struct outp_driver_class_list
-  {
-    const struct outp_class *class;
-    struct outp_driver_class_list *next;
-  };
-
-static struct outp_driver_class_list *outp_class_list;
-static struct outp_driver *outp_driver_list;
-
-char *outp_title;
-char *outp_subtitle;
-
-/* A set of OUTP_DEV_* bits indicating the devices that are
-   disabled. */
-static int disabled_devices;
-
-static void destroy_driver (struct outp_driver *);
-static void configure_driver (const struct substring, const struct substring,
-                              const struct substring, const struct substring);
-
-/* Add a class to the class list. */
-static void
-add_class (const struct outp_class *class)
-{
-  struct outp_driver_class_list *new_list = xmalloc (sizeof *new_list);
-
-  new_list->class = class;
-
-  if (!outp_class_list)
-    {
-      outp_class_list = new_list;
-      new_list->next = NULL;
-    }
-  else
-    {
-      new_list->next = outp_class_list;
-      outp_class_list = new_list;
-    }
-}
-
-/* Finds the outp_names in outp_configure_vec with name between BP and
-   EP exclusive. */
-static struct outp_names *
-search_names (char *bp, char *ep)
-{
-  struct outp_names *n;
-
-  for (n = outp_configure_vec; n; n = n->next)
-    if ((int) strlen (n->name) == ep - bp && !memcmp (n->name, bp, ep - bp))
-      return n;
-  return NULL;
-}
-
-/* Deletes outp_names NAME from outp_configure_vec. */
-static void
-delete_name (struct outp_names * n)
-{
-  free (n->name);
-  if (n->prev)
-    n->prev->next = n->next;
-  if (n->next)
-    n->next->prev = n->prev;
-  if (n == outp_configure_vec)
-    outp_configure_vec = n->next;
-  free (n);
-}
-
-/* Adds the name between BP and EP exclusive to list
-   outp_configure_vec with source SOURCE. */
-static void
-add_name (char *bp, char *ep, int source)
-{
-  struct outp_names *n = xmalloc (sizeof *n);
-  n->name = xmalloc (ep - bp + 1);
-  memcpy (n->name, bp, ep - bp);
-  n->name[ep - bp] = 0;
-  n->source = source;
-  n->next = outp_configure_vec;
-  n->prev = NULL;
-  if (outp_configure_vec)
-    outp_configure_vec->prev = n;
-  outp_configure_vec = n;
-}
-
-/* Checks that outp_configure_vec is empty, complains and clears
-   it if it isn't. */
-static void
-check_configure_vec (void)
-{
-  struct outp_names *n;
-
-  for (n = outp_configure_vec; n; n = n->next)
-    if (n->source == OUTP_S_COMMAND_LINE)
-      error (0, 0, _("unknown output driver `%s'"), n->name);
-    else
-      error (0, 0, _("output driver `%s' referenced but never defined"),
-             n->name);
-  outp_configure_clear ();
-}
-
-/* Searches outp_configure_vec for the name between BP and EP
-   exclusive.  If found, it is deleted, then replaced by the names
-   given in EP+1, if any. */
-static void
-expand_name (char *bp, char *ep)
-{
-  struct outp_names *n = search_names (bp, ep);
-  if (!n)
-    return;
-  delete_name (n);
-
-  bp = ep + 1;
-  for (;;)
-    {
-      while (isspace ((unsigned char) *bp))
-       bp++;
-      ep = bp;
-      while (*ep && !isspace ((unsigned char) *ep))
-       ep++;
-      if (bp == ep)
-       return;
-      if (!search_names (bp, ep))
-       add_name (bp, ep, OUTP_S_INIT_FILE);
-      bp = ep;
-    }
-}
-
-/* Looks for a macro with key KEY, and returns the corresponding value
-   if found, or NULL if not. */
-static const char *
-find_defn_value (const char *key)
-{
-  static char buf[INT_STRLEN_BOUND (int) + 1];
-  struct outp_defn *d;
-
-  for (d = outp_macros; d; d = d->next)
-    if (!strcmp (key, d->key))
-      return ds_cstr (&d->value);
-  if (!strcmp (key, "viewwidth"))
-    {
-      sprintf (buf, "%d", settings_get_viewwidth ());
-      return buf;
-    }
-  else if (!strcmp (key, "viewlength"))
-    {
-      sprintf (buf, "%d", settings_get_viewlength ());
-      return buf;
-    }
-  else
-    return getenv (key);
-}
-
-/* Initializes global variables. */
-void
-outp_init (void)
-{
-  extern struct outp_class ascii_class;
-  extern struct outp_class postscript_class;
-
-  char def[] = "default";
-
-  add_class (&html_class);
-  add_class (&postscript_class);
-  add_class (&ascii_class);
-
-  add_name (def, &def[strlen (def)], OUTP_S_INIT_FILE);
-}
-
-/* Deletes all the output macros. */
-static void
-delete_macros (void)
-{
-  struct outp_defn *d, *next;
-
-  for (d = outp_macros; d; d = next)
-    {
-      next = d->next;
-      free (d->key);
-      ds_destroy (&d->value);
-      free (d);
-    }
-}
-
-static void
-init_default_drivers (void)
-{
-  error (0, 0, _("using default output driver configuration"));
-  configure_driver (ss_cstr ("list"),
-                    ss_cstr ("ascii"),
-                    ss_cstr ("listing"),
-                    ss_cstr ("length=66 width=79 output-file=\"pspp.list\""));
-}
-
-/* Reads the initialization file; initializes
-   outp_driver_list. */
-void
-outp_read_devices (void)
-{
-  int result = 0;
-
-  char *init_fn;
-
-  FILE *f = NULL;
-  struct string line;
-  int line_number;
-
-  init_fn = fn_search_path (fn_getenv_default ("STAT_OUTPUT_INIT_FILE",
-                                              "devices"),
-                           fn_getenv_default ("STAT_OUTPUT_INIT_PATH",
-                                              config_path));
-
-  ds_init_empty (&line);
-
-  if (init_fn == NULL)
-    {
-      error (0, 0, _("cannot find output initialization file "
-                     "(use `-vv' to view search path)"));
-      goto exit;
-    }
-
-  f = fopen (init_fn, "r");
-  if (f == NULL)
-    {
-      error (0, errno, _("cannot open \"%s\""), init_fn);
-      goto exit;
-    }
-
-  line_number = 0;
-  for (;;)
-    {
-      char *cp;
-
-      if (!ds_read_config_line (&line, &line_number, f))
-       {
-         if (ferror (f))
-           error (0, errno, _("reading \"%s\""), init_fn);
-         break;
-       }
-      for (cp = ds_cstr (&line); isspace ((unsigned char) *cp); cp++);
-      if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
-       outp_configure_macro (&cp[7]);
-      else if (*cp)
-       {
-         char *ep;
-         for (ep = cp; *ep && *ep != ':' && *ep != '='; ep++);
-         if (*ep == '=')
-           expand_name (cp, ep);
-         else if (*ep == ':')
-           {
-             struct outp_names *n = search_names (cp, ep);
-             if (n)
-               {
-                 outp_configure_driver_line (ds_ss (&line));
-                 delete_name (n);
-               }
-           }
-         else
-           error_at_line (0, 0, init_fn, line_number, _("syntax error"));
-       }
-    }
-  result = 1;
-
-  check_configure_vec ();
-
-exit:
-  if (f && -1 == fclose (f))
-    error (0, errno, _("error closing \"%s\""), init_fn);
-  free (init_fn);
-  ds_destroy (&line);
-  delete_macros ();
-
-  if (result)
-    {
-      if (outp_driver_list == NULL)
-        error (0, 0, _("no active output drivers"));
-    }
-  else
-    error (0, 0, _("error reading device definition file"));
-
-  if (!result || outp_driver_list == NULL)
-    init_default_drivers ();
-}
-
-/* Clear the list of drivers to configure. */
-void
-outp_configure_clear (void)
-{
-  struct outp_names *n, *next;
-
-  for (n = outp_configure_vec; n; n = next)
-    {
-      next = n->next;
-      free (n->name);
-      free (n);
-    }
-  outp_configure_vec = NULL;
-}
-
-/* Adds the name BP to the list of drivers to configure into
-   outp_driver_list. */
-void
-outp_configure_add (char *bp)
-{
-  char *ep = &bp[strlen (bp)];
-  if (!search_names (bp, ep))
-    add_name (bp, ep, OUTP_S_COMMAND_LINE);
-}
-
-/* Defines one configuration macro based on the text in BP, which
-   should be of the form `KEY=VALUE'. */
-void
-outp_configure_macro (char *bp)
-{
-  struct outp_defn *d;
-  char *ep;
-
-  while (isspace ((unsigned char) *bp))
-    bp++;
-  ep = bp;
-  while (*ep && !isspace ((unsigned char) *ep) && *ep != '=')
-    ep++;
-
-  d = xmalloc (sizeof *d);
-  d->key = xmalloc (ep - bp + 1);
-  memcpy (d->key, bp, ep - bp);
-  d->key[ep - bp] = 0;
-
-  /* Earlier definitions for a particular KEY override later ones. */
-  if (find_defn_value (d->key))
-    {
-      free (d->key);
-      free (d);
-      return;
-    }
-
-  if (*ep == '=')
-    ep++;
-  while (isspace ((unsigned char) *ep))
-    ep++;
-
-  ds_init_cstr (&d->value, ep);
-  fn_interp_vars (ds_ss (&d->value), find_defn_value, &d->value);
-  d->next = outp_macros;
-  d->prev = NULL;
-  if (outp_macros)
-    outp_macros->prev = d;
-  outp_macros = d;
-}
-
-/* Destroys all the drivers in driver list *DL and sets *DL to
-   NULL. */
-static void
-destroy_list (struct outp_driver ** dl)
-{
-  struct outp_driver *d, *next;
-
-  for (d = *dl; d; d = next)
-    {
-      destroy_driver (d);
-      next = d->next;
-      free (d);
-    }
-  *dl = NULL;
-}
-
-/* Closes all the output drivers. */
-void
-outp_done (void)
-{
-  struct outp_driver_class_list *n = outp_class_list ;
-  outp_configure_clear ();
-  destroy_list (&outp_driver_list);
-
-  while (n)
-    {
-      struct outp_driver_class_list *next = n->next;
-      free(n);
-      n = next;
-    }
-  outp_class_list = NULL;
-
-  free (outp_title);
-  outp_title = NULL;
-
-  free (outp_subtitle);
-  outp_subtitle = NULL;
-}
-
-/* Display on stdout a list of all registered driver classes. */
-void
-outp_list_classes (void)
-{
-  int width = settings_get_viewwidth ();
-  struct outp_driver_class_list *c;
-
-  printf (_("Driver classes:\n\t"));
-  width -= 8;
-  for (c = outp_class_list; c; c = c->next)
-    {
-      if ((int) strlen (c->class->name) + 1 > width)
-       {
-         printf ("\n\t");
-         width = settings_get_viewwidth () - 8;
-       }
-      else
-       putc (' ', stdout);
-      fputs (c->class->name, stdout);
-    }
-  putc('\n', stdout);
-}
-
-/* Obtains a token from S and advances its position.  Errors are
-   reported against the given DRIVER_NAME.
-   The token is stored in TOKEN.  Returns true if successful,
-   false on syntax error.
-
-   Caller is responsible for skipping leading spaces. */
-static bool
-get_option_token (struct substring *s, const char *driver_name,
-                  struct string *token)
-{
-  int c;
-
-  ds_clear (token);
-  c = ss_get_char (s);
-  if (c == EOF)
-    {
-      error (0, 0, _("syntax error parsing options for \"%s\" driver"),
-             driver_name);
-      return false;
-    }
-  else if (c == '\'' || c == '"')
-    {
-      int quote = c;
-
-      for (;;)
-        {
-          c = ss_get_char (s);
-          if (c == quote)
-            break;
-          else if (c == EOF)
-            {
-              error (0, 0,
-                     _("reached end of options inside quoted string "
-                       "parsing options for \"%s\" driver"),
-                     driver_name);
-              return false;
-            }
-          else if (c != '\\')
-            ds_put_char (token, c);
-          else
-            {
-              int out;
-
-              c = ss_get_char (s);
-              switch (c)
-                {
-                case '\'':
-                  out = '\'';
-                  break;
-                case '"':
-                  out = '"';
-                  break;
-                case '\\':
-                  out = '\\';
-                  break;
-                case 'a':
-                  out = '\a';
-                  break;
-                case 'b':
-                  out = '\b';
-                  break;
-                case 'f':
-                  out = '\f';
-                  break;
-                case 'n':
-                  out = '\n';
-                  break;
-                case 'r':
-                  out = '\r';
-                  break;
-                case 't':
-                  out = '\t';
-                  break;
-                case 'v':
-                  out = '\v';
-                  break;
-                case '0':
-                case '1':
-                case '2':
-                case '3':
-                case '4':
-                case '5':
-                case '6':
-                case '7':
-                  out = c - '0';
-                  while (ss_first (*s) >= '0' && ss_first (*s) <= '7')
-                    out = out * 8 + (ss_get_char (s) - '0');
-                  break;
-                case 'x':
-                case 'X':
-                  out = 0;
-                  while (isxdigit (ss_first (*s)))
-                    {
-                      c = ss_get_char (s);
-                      out *= 16;
-                      if (isdigit (c))
-                        out += c - '0';
-                      else
-                        out += tolower (c) - 'a' + 10;
-                    }
-                  break;
-                default:
-                  error (0, 0, _("syntax error in string constant "
-                                 "parsing options for \"%s\" driver"),
-                         driver_name);
-                  return false;
-                }
-              ds_put_char (token, out);
-            }
-        }
-    }
-  else
-    {
-      for (;;)
-        {
-          ds_put_char (token, c);
-
-          c = ss_first (*s);
-          if (c == EOF || c == '=' || isspace (c))
-            break;
-          ss_advance (s, 1);
-        }
-    }
-
-  return 1;
-}
-
-bool
-outp_parse_options (struct substring options,
-                    bool (*callback) (struct outp_driver *, const char *key,
-                                      const struct string *value),
-                    struct outp_driver *driver)
-{
-  struct string key = DS_EMPTY_INITIALIZER;
-  struct string value = DS_EMPTY_INITIALIZER;
-  struct substring left = options;
-  bool ok = true;
-
-  do
-    {
-      ss_ltrim (&left, ss_cstr (CC_SPACES));
-      if (ss_is_empty (left))
-        break;
-
-      if (!get_option_token (&left, driver->name, &key))
-        break;
-
-      ss_ltrim (&left, ss_cstr (CC_SPACES));
-      if (!ss_match_char (&left, '='))
-       {
-         error (0, 0, _("syntax error expecting `=' "
-                         "parsing options for driver \"%s\""),
-                 driver->name);
-         break;
-       }
-
-      ss_ltrim (&left, ss_cstr (CC_SPACES));
-      if (!get_option_token (&left, driver->name, &value))
-        break;
-
-      ok = callback (driver, ds_cstr (&key), &value);
-    }
-  while (ok);
-
-  ds_destroy (&key);
-  ds_destroy (&value);
-
-  return ok;
-}
-
-/* Find the driver in outp_driver_list with name NAME. */
-static struct outp_driver *
-find_driver (char *name)
-{
-  struct outp_driver *d;
-
-  for (d = outp_driver_list; d; d = d->next)
-    if (!strcmp (d->name, name))
-      return d;
-  return NULL;
-}
-
-/* Adds a driver to outp_driver_list pursuant to the
-   specification provided.  */
-static void
-configure_driver (struct substring driver_name, struct substring class_name,
-                  struct substring device_type, struct substring options)
-{
-  struct outp_driver *d, *iter;
-  struct outp_driver_class_list *c;
-
-  struct substring token;
-  size_t save_idx = 0;
-  int device;
-
-  /* Find class. */
-  for (c = outp_class_list; c; c = c->next)
-    if (!ss_compare (ss_cstr (c->class->name), class_name))
-      break;
-  if (c == NULL)
-    {
-      error (0, 0, _("unknown output driver class `%.*s'"),
-             (int) ss_length (class_name), ss_data (class_name));
-      return;
-    }
-
-  /* Parse device type. */
-  device = 0;
-  while (ss_tokenize (device_type, ss_cstr (CC_SPACES), &save_idx, &token))
-    if (!ss_compare (token, ss_cstr ("listing")))
-      device |= OUTP_DEV_LISTING;
-    else if (!ss_compare (token, ss_cstr ("screen")))
-      device |= OUTP_DEV_SCREEN;
-    else if (!ss_compare (token, ss_cstr ("printer")))
-      device |= OUTP_DEV_PRINTER;
-    else
-      error (0, 0, _("unknown device type `%.*s'"),
-             (int) ss_length (token), ss_data (token));
-
-  /* Open the device. */
-  d = xmalloc (sizeof *d);
-  d->next = d->prev = NULL;
-  d->class = c->class;
-  d->name = ss_xstrdup (driver_name);
-  d->page_open = false;
-  d->device = device;
-  d->cp_x = d->cp_y = 0;
-  d->ext = NULL;
-  d->prc = NULL;
-
-  /* Open driver. */
-  if (!d->class->open_driver (d, options))
-    {
-      error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
-             d->name, d->class->name);
-      free (d->name);
-      free (d);
-      return;
-    }
-
-  /* Find like-named driver and delete. */
-  iter = find_driver (d->name);
-  if (iter != NULL)
-    destroy_driver (iter);
-
-  /* Add to list. */
-  d->next = outp_driver_list;
-  d->prev = NULL;
-  if (outp_driver_list != NULL)
-    outp_driver_list->prev = d;
-  outp_driver_list = d;
-}
-
-/* String LINE is in format:
-   DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
-   Adds a driver to outp_driver_list pursuant to the specification
-   provided.  */
-void
-outp_configure_driver_line (struct substring line_)
-{
-  struct string line = DS_EMPTY_INITIALIZER;
-  struct substring tokens[4];
-  size_t save_idx;
-  size_t i;
-
-  fn_interp_vars (line_, find_defn_value, &line);
-
-  save_idx = 0;
-  for (i = 0; i < 4; i++)
-    {
-      struct substring *token = &tokens[i];
-      ds_separate (&line, ss_cstr (i < 3 ? ":" : ""), &save_idx, token);
-      ss_trim (token, ss_cstr (CC_SPACES));
-    }
-
-  if (!ss_is_empty (tokens[0]) && !ss_is_empty (tokens[1]))
-    configure_driver (tokens[0], tokens[1], tokens[2], tokens[3]);
-  else
-    error (0, 0,
-           _("driver definition line missing driver name or class name"));
-
-  ds_destroy (&line);
-}
-
-/* Destroys output driver D. */
-static void
-destroy_driver (struct outp_driver *d)
-{
-  outp_close_page (d);
-  if (d->class)
-    {
-      struct outp_driver_class_list *c;
-
-      d->class->close_driver (d);
-
-      for (c = outp_class_list; c; c = c->next)
-       if (c->class == d->class)
-         break;
-      assert (c != NULL);
-    }
-  free (d->name);
-
-  /* Remove this driver from the global driver list. */
-  if (d->prev)
-    d->prev->next = d->next;
-  if (d->next)
-    d->next->prev = d->prev;
-  if (d == outp_driver_list)
-    outp_driver_list = d->next;
-}
-
-/* Tries to match S as one of the keywords in TAB, with
-   corresponding information structure INFO.  Returns category
-   code and stores subcategory in *SUBCAT on success.  Returns -1
-   on failure. */
-int
-outp_match_keyword (const char *s, const struct outp_option *tab, int *subcat)
-{
-  for (; tab->keyword != NULL; tab++)
-    if (!strcmp (s, tab->keyword))
-      {
-        *subcat = tab->subcat;
-        return tab->cat;
-      }
-  return -1;
-}
-
-/* Parses UNIT as a dimensional unit.  Returns the multiplicative
-   factor needed to change a quantity measured in that unit into
-   1/72000" units.  If UNIT is empty, it is treated as
-   millimeters.  If the unit is unrecognized, returns 0. */
-static double
-parse_unit (const char *unit)
-{
-  struct unit
-    {
-      char name[3];
-      double factor;
-    };
-
-  static const struct unit units[] =
-    {
-      {"pt", 72000 / 72},
-      {"pc", 72000 / 72 * 12.0},
-      {"in", 72000},
-      {"cm", 72000 / 2.54},
-      {"mm", 72000 / 25.4},
-      {"", 72000 / 25.4},
-    };
-
-  const struct unit *p;
-
-  unit += strspn (unit, CC_SPACES);
-  for (p = units; p < units + sizeof units / sizeof *units; p++)
-    if (!strcasecmp (unit, p->name))
-      return p->factor;
-  return 0.0;
-}
-
-/* Determines the size of a dimensional measurement and returns
-   the size in units of 1/72000".  Units are assumed to be
-   millimeters unless otherwise specified.  Returns 0 on
-   error. */
-int
-outp_evaluate_dimension (const char *dimen)
-{
-  double raw, factor;
-  char *tail;
-
-  /* Number. */
-  raw = strtod (dimen, &tail);
-  if (raw <= 0.0)
-    goto syntax_error;
-
-  /* Unit. */
-  factor = parse_unit (tail);
-  if (factor == 0.0)
-    goto syntax_error;
-
-  return raw * factor;
-
-syntax_error:
-  error (0, 0, _("`%s' is not a valid length."), dimen);
-  return 0;
-}
-
-/* Stores the dimensions in 1/72000" units of paper identified by
-   SIZE, which is of form `HORZ x VERT [UNIT]' where HORZ and
-   VERT are numbers and UNIT is an optional unit of measurement,
-   into *H and *V.  Return true on success. */
-static bool
-parse_paper_size (const char *size, int *h, int *v)
-{
-  double raw_h, raw_v, factor;
-  char *tail;
-
-  /* Width. */
-  raw_h = strtod (size, &tail);
-  if (raw_h <= 0.0)
-    return false;
-
-  /* Delimiter. */
-  tail += strspn (tail, CC_SPACES "x,");
-
-  /* Length. */
-  raw_v = strtod (tail, &tail);
-  if (raw_v <= 0.0)
-    return false;
-
-  /* Unit. */
-  factor = parse_unit (tail);
-  if (factor == 0.0)
-    return false;
-
-  *h = raw_h * factor + .5;
-  *v = raw_v * factor + .5;
-  return true;
-}
-
-static bool
-get_standard_paper_size (struct substring name, int *h, int *v)
-{
-  static const char *sizes[][2] =
-    {
-      {"a0", "841 x 1189 mm"},
-      {"a1", "594 x 841 mm"},
-      {"a2", "420 x 594 mm"},
-      {"a3", "297 x 420 mm"},
-      {"a4", "210 x 297 mm"},
-      {"a5", "148 x 210 mm"},
-      {"b5", "176 x 250 mm"},
-      {"a6", "105 x 148 mm"},
-      {"a7", "74 x 105 mm"},
-      {"a8", "52 x 74 mm"},
-      {"a9", "37 x 52 mm"},
-      {"a10", "26 x 37 mm"},
-      {"b0", "1000 x 1414 mm"},
-      {"b1", "707 x 1000 mm"},
-      {"b2", "500 x 707 mm"},
-      {"b3", "353 x 500 mm"},
-      {"b4", "250 x 353 mm"},
-      {"letter", "612 x 792 pt"},
-      {"legal", "612 x 1008 pt"},
-      {"executive", "522 x 756 pt"},
-      {"note", "612 x 792 pt"},
-      {"11x17", "792 x 1224 pt"},
-      {"tabloid", "792 x 1224 pt"},
-      {"statement", "396 x 612 pt"},
-      {"halfletter", "396 x 612 pt"},
-      {"halfexecutive", "378 x 522 pt"},
-      {"folio", "612 x 936 pt"},
-      {"quarto", "610 x 780 pt"},
-      {"ledger", "1224 x 792 pt"},
-      {"archA", "648 x 864 pt"},
-      {"archB", "864 x 1296 pt"},
-      {"archC", "1296 x 1728 pt"},
-      {"archD", "1728 x 2592 pt"},
-      {"archE", "2592 x 3456 pt"},
-      {"flsa", "612 x 936 pt"},
-      {"flse", "612 x 936 pt"},
-      {"csheet", "1224 x 1584 pt"},
-      {"dsheet", "1584 x 2448 pt"},
-      {"esheet", "2448 x 3168 pt"},
-    };
-
-  size_t i;
-
-  for (i = 0; i < sizeof sizes / sizeof *sizes; i++)
-    if (ss_equals_case (ss_cstr (sizes[i][0]), name))
-      {
-        bool ok = parse_paper_size (sizes[i][1], h, v);
-        assert (ok);
-        return ok;
-      }
-  error (0, 0, _("unknown paper type `%.*s'"),
-         (int) ss_length (name), ss_data (name));
-  return false;
-}
-
-/* Reads file FILE_NAME to find a paper size.  Stores the
-   dimensions, in 1/72000" units, into *H and *V.  Returns true
-   on success, false on failure. */
-static bool
-read_paper_conf (const char *file_name, int *h, int *v)
-{
-  struct string line = DS_EMPTY_INITIALIZER;
-  int line_number = 0;
-  FILE *file;
-
-  file = fopen (file_name, "r");
-  if (file == NULL)
-    {
-      error (0, errno, _("error opening \"%s\""), file_name);
-      return false;
-    }
-
-  for (;;)
-    {
-      struct substring name;
-
-      if (!ds_read_config_line (&line, &line_number, file))
-       {
-         if (ferror (file))
-           error (0, errno, _("error reading \"%s\""), file_name);
-         break;
-       }
-
-      name = ds_ss (&line);
-      ss_trim (&name, ss_cstr (CC_SPACES));
-      if (!ss_is_empty (name))
-        {
-          bool ok = get_standard_paper_size (name, h, v);
-          fclose (file);
-          ds_destroy (&line);
-          return ok;
-        }
-    }
-
-  fclose (file);
-  ds_destroy (&line);
-  error (0, 0, _("paper size file \"%s\" does not state a paper size"),
-         file_name);
-  return false;
-}
-
-/* The user didn't specify a paper size, so let's choose a
-   default based on his environment.  Stores the
-   dimensions, in 1/72000" units, into *H and *V.  Returns true
-   on success, false on failure. */
-static bool
-get_default_paper_size (int *h, int *v)
-{
-  /* libpaper in Debian (and other distributions?) allows the
-     paper size to be specified in $PAPERSIZE or in a file
-     specified in $PAPERCONF. */
-  if (getenv ("PAPERSIZE") != NULL)
-    return get_standard_paper_size (ss_cstr (getenv ("PAPERSIZE")), h, v);
-  if (getenv ("PAPERCONF") != NULL)
-    return read_paper_conf (getenv ("PAPERCONF"), h, v);
-
-#if HAVE_LC_PAPER
-  /* LC_PAPER is a non-standard glibc extension. */
-  *h = (int) nl_langinfo(_NL_PAPER_WIDTH) * (72000 / 25.4);
-  *v = (int) nl_langinfo(_NL_PAPER_HEIGHT) * (72000 / 25.4);
-  if (*h > 0 && *v > 0)
-     return true;
-#endif
-
-  /* libpaper defaults to /etc/papersize. */
-  if (fn_exists ("/etc/papersize"))
-    return read_paper_conf ("/etc/papersize", h, v);
-
-  /* Can't find a default. */
-  return false;
-}
-
-/* Stores the dimensions, in 1/72000" units, of paper identified
-   by SIZE into *H and *V.  SIZE can be the name of a kind of
-   paper ("a4", "letter", ...) or a pair of dimensions
-   ("210x297", "8.5x11in", ...).  Returns true on success, false
-   on failure.  On failure, *H and *V are set for A4 paper. */
-bool
-outp_get_paper_size (const char *size, int *h, int *v)
-{
-  struct substring s;
-  bool ok;
-
-  s = ss_cstr (size);
-  ss_trim (&s, ss_cstr (CC_SPACES));
-
-  if (ss_is_empty (s))
-    {
-      /* Treat empty string as default paper size. */
-      ok = get_default_paper_size (h, v);
-    }
-  else if (isdigit (ss_first (s)))
-    {
-      /* Treat string that starts with digit as explicit size. */
-      ok = parse_paper_size (size, h, v);
-      if (!ok)
-        error (0, 0, _("syntax error in paper size `%s'"), size);
-    }
-  else
-    {
-      /* Check against standard paper sizes. */
-      ok = get_standard_paper_size (s, h, v);
-    }
-
-  /* Default to A4 on error. */
-  if (!ok)
-    {
-      *h = 210 * (72000 / 25.4);
-      *v = 297 * (72000 / 25.4);
-    }
-  return ok;
-}
-
-/* If D is NULL, returns the first enabled driver if any, NULL if
-   none.  Otherwise D must be the last driver returned by this
-   function, in which case the next enabled driver is returned or NULL
-   if that was the last. */
-struct outp_driver *
-outp_drivers (struct outp_driver *d)
-{
-  for (;;)
-    {
-      if (d == NULL)
-       d = outp_driver_list;
-      else
-       d = d->next;
-
-      if (d == NULL
-         || (d->device == 0 || (d->device & disabled_devices) != d->device))
-       break;
-    }
-
-  return d;
-}
-
-/* Enables (if ENABLE is true) or disables (if ENABLE is false) the
-   device(s) given in mask DEVICE. */
-void
-outp_enable_device (bool enable, int device)
-{
-  if (enable)
-    disabled_devices &= ~device;
-  else
-    disabled_devices |= device;
-}
-
-/* Opens a page on driver D (if one is not open). */
-void
-outp_open_page (struct outp_driver *d)
-{
-  if (!d->page_open)
-    {
-      d->cp_x = d->cp_y = 0;
-
-      d->page_open = true;
-      if (d->class->open_page != NULL)
-        d->class->open_page (d);
-    }
-}
-
-/* Closes the page on driver D (if one is open). */
-void
-outp_close_page (struct outp_driver *d)
-{
-  if (d->page_open)
-    {
-      if (d->class->close_page != NULL)
-        d->class->close_page (d);
-      d->page_open = false;
-    }
-}
-
-/* Ejects the page on device D, if a page is open and non-blank,
-   and opens a new page.  */
-void
-outp_eject_page (struct outp_driver *d)
-{
-  if (d->page_open && d->cp_y != 0)
-    outp_close_page (d);
-  outp_open_page (d);
-}
-
-/* Flushes output to screen devices, so that the user can see
-   output that doesn't fill up an entire page. */
-void
-outp_flush (struct outp_driver *d)
-{
-  if (d->device & OUTP_DEV_SCREEN && d->class->flush != NULL)
-    {
-      outp_close_page (d);
-      d->class->flush (d);
-    }
-}
-
-/* Returns the width of string S, in device units, when output on
-   device D. */
-int
-outp_string_width (struct outp_driver *d, const char *s, enum outp_font font)
-{
-  struct outp_text text;
-  int width;
-
-  text.font = font;
-  text.justification = OUTP_LEFT;
-  text.string = ss_cstr (s);
-  text.h = text.v = INT_MAX;
-  d->class->text_metrics (d, &text, &width, NULL);
-
-  return width;
-}
diff --git a/src/output/output.h b/src/output/output.h
deleted file mode 100644 (file)
index fc66874..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 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_OUTPUT_H
-#define OUTPUT_OUTPUT_H 1
-
-#include <libpspp/str.h>
-
-
-/* Line styles.  */
-enum outp_line_style
-  {
-    OUTP_L_NONE,               /* No line. */
-    OUTP_L_SINGLE,             /* Single line. */
-    OUTP_L_DOUBLE,             /* Double line. */
-    OUTP_L_COUNT
-  };
-
-/* Text justification. */
-enum outp_justification
-  {
-    OUTP_RIGHT,                 /* Right justification. */
-    OUTP_LEFT,                  /* Left justification. */
-    OUTP_CENTER,                /* Center justification. */
-  };
-
-enum outp_font
-  {
-    OUTP_FIXED,                 /* Fixed-width font. */
-    OUTP_PROPORTIONAL,          /* Proportional font. */
-    OUTP_EMPHASIS,              /* Proportional font used for emphasis. */
-    OUTP_FONT_CNT               /* Number of fonts. */
-  };
-
-/* Describes text output. */
-struct outp_text
-  {
-    enum outp_font font;
-    enum outp_justification justification;
-    struct substring string;
-    int h, v;                  /* Horizontal, vertical size. */
-    int x, y;                  /* Position. */
-  };
-
-struct som_entity;
-struct outp_driver;
-struct chart;
-
-/* Defines a class of output driver. */
-struct outp_class
-  {
-    const char *name;          /* Name of this driver class. */
-    int special;               /* Boolean value. */
-
-    bool (*open_driver) (struct outp_driver *, struct substring options);
-    bool (*close_driver) (struct outp_driver *);
-
-    void (*open_page) (struct outp_driver *);
-    void (*close_page) (struct outp_driver *);
-
-    void (*flush) (struct outp_driver *);
-
-    /* special != 0 only. */
-    void (*submit) (struct outp_driver *, struct som_entity *);
-
-    /* special == 0 only.  */
-    void (*line) (struct outp_driver *, int x0, int y0, int x1, int y1,
-                  enum outp_line_style top, enum outp_line_style left,
-                  enum outp_line_style bottom, enum outp_line_style right);
-    void (*text_metrics) (struct outp_driver *, const struct outp_text *,
-                          int *width, int *height);
-    void (*text_draw) (struct outp_driver *, const struct outp_text *);
-    void (*initialise_chart)(struct outp_driver *, struct chart *);
-    void (*finalise_chart)(struct outp_driver *, struct chart *);
-  };
-
-/* Device types. */
-enum
-  {
-    OUTP_DEV_NONE = 0,         /* None of the below. */
-    OUTP_DEV_LISTING = 001,    /* Listing device. */
-    OUTP_DEV_SCREEN = 002,     /* Screen device. */
-    OUTP_DEV_PRINTER = 004,    /* Printer device. */
-  };
-
-/* Defines the configuration of an output driver. */
-struct outp_driver
-  {
-    struct outp_driver *next, *prev; /* List of drivers. */
-    const struct outp_class *class;    /* Driver class. */
-    char *name;                        /* Name of this driver. */
-    bool page_open;            /* 1=page is open, 0=page is closed. */
-    int device;                        /* Zero or more of OUTP_DEV_*. */
-    int cp_x, cp_y;            /* Current position. */
-
-    int width, length;         /* Page size. */
-    int font_height;           /* Default font character height. */
-    int prop_em_width;         /* Proportional font em width. */
-    int fixed_width;           /* Fixed-pitch font character width. */
-    int horiz_line_width[OUTP_L_COUNT];        /* Width of horizontal lines. */
-    int vert_line_width[OUTP_L_COUNT]; /* Width of vertical lines. */
-
-    void *ext;                 /* Private extension record. */
-    void *prc;                 /* Per-procedure extension record. */
-  };
-
-/* Option structure for the keyword recognizer. */
-struct outp_option
-  {
-    const char *keyword;       /* Keyword name. */
-    int cat;                   /* Category. */
-    int subcat;                        /* Subcategory. */
-  };
-
-
-/* Title, subtitle. */
-extern char *outp_title;
-extern char *outp_subtitle;
-
-void outp_init (void);
-void outp_read_devices (void);
-void outp_configure_driver_line (struct substring);
-void outp_done (void);
-
-void outp_configure_clear (void);
-void outp_configure_add (char *);
-void outp_configure_macro (char *);
-
-void outp_list_classes (void);
-
-void outp_enable_device (bool enable, int device);
-struct outp_driver *outp_drivers (struct outp_driver *);
-
-bool outp_parse_options (struct substring options,
-                         bool (*) (struct outp_driver *, const char *key,
-                                   const struct string *value),
-                         struct outp_driver *);
-int outp_match_keyword (const char *, const struct outp_option *, int *);
-
-int outp_evaluate_dimension (const char *);
-bool outp_get_paper_size (const char *, int *h, int *v);
-
-void outp_open_page (struct outp_driver *);
-void outp_close_page (struct outp_driver *);
-void outp_eject_page (struct outp_driver *);
-void outp_flush (struct outp_driver *);
-
-int outp_string_width (struct outp_driver *, const char *, enum outp_font);
-
-/* Imported from som-frnt.c. */
-void som_destroy_driver (struct outp_driver *);
-
-#endif /* output/output.h */
diff --git a/src/output/postscript.c b/src/output/postscript.c
deleted file mode 100644 (file)
index 11116b9..0000000
+++ /dev/null
@@ -1,1446 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 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 <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <libpspp/assertion.h>
-#include <libpspp/bit-vector.h>
-#include <libpspp/compiler.h>
-#include <libpspp/freaderror.h>
-#include <libpspp/hash.h>
-#include <libpspp/misc.h>
-#include <libpspp/start-date.h>
-#include <libpspp/version.h>
-
-#include <data/file-name.h>
-
-#include "afm.h"
-#include "chart.h"
-#include "error.h"
-#include "manager.h"
-#include "output.h"
-
-#include "intprops.h"
-#include "minmax.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* PostScript driver options: (defaults listed first)
-
-   output-file="pspp.ps"
-
-   paper-size=letter (see "papersize" file)
-   orientation=portrait|landscape
-   headers=on|off
-
-   left-margin=0.5in
-   right-margin=0.5in
-   top-margin=0.5in
-   bottom-margin=0.5in
-
-   prop-font=Times-Roman
-   emph-font=Times-Italic
-   fixed-font=Courier
-   font-size=10000
-
-   line-gutter=1pt
-   line-spacing=1pt
-   line-width=0.5pt
- */
-
-/* The number of `psus' (PostScript driver UnitS) per inch. */
-#define PSUS 72000
-
-/* A PostScript font. */
-struct font
-  {
-    struct afm *metrics;        /* Metrics. */
-    char *embed_fn;             /* Name of file to embed. */
-    char *encoding_fn;          /* Name of file with encoding. */
-  };
-
-/* PostScript output driver extension record. */
-struct ps_driver_ext
-  {
-    char *file_name;            /* Output file name. */
-    FILE *file;                 /* Output file. */
-
-    bool draw_headers;          /* Draw headers at top of page? */
-    int page_number;           /* Current page number. */
-
-    bool portrait;              /* Portrait mode? */
-    int paper_width;            /* Width of paper before dropping margins. */
-    int paper_length;           /* Length of paper before dropping margins. */
-    int left_margin;           /* Left margin in psus. */
-    int right_margin;          /* Right margin in psus. */
-    int top_margin;            /* Top margin in psus. */
-    int bottom_margin;         /* Bottom margin in psus. */
-
-    int line_gutter;           /* Space around lines. */
-    int line_space;            /* Space between lines. */
-    int line_width;            /* Width of lines. */
-
-    struct font *fonts[OUTP_FONT_CNT];
-    int last_font;              /* Index of last font set with setfont. */
-  };
-
-/* Transform logical y-ordinate Y into a page ordinate. */
-#define YT(Y) (this->length - (Y))
-
-static bool handle_option (struct outp_driver *this, const char *key,
-                           const struct string *val);
-static void draw_headers (struct outp_driver *this);
-
-static void write_ps_prologue (struct outp_driver *);
-
-static char *quote_ps_name (const char *string);
-
-static struct font *load_font (const char *string);
-static void free_font (struct font *);
-static void setup_font (struct outp_driver *this, struct font *, int index);
-\f
-/* Driver initialization. */
-
-static bool
-ps_open_driver (struct outp_driver *this, struct substring options)
-{
-  struct ps_driver_ext *x;
-  size_t i;
-
-  this->width = this->length = 0;
-  this->font_height = PSUS * 10 / 72;
-
-  this->ext = x = xmalloc (sizeof *x);
-  x->file_name = xstrdup ("pspp.ps");
-  x->file = NULL;
-  x->draw_headers = true;
-  x->page_number = 0;
-  x->portrait = true;
-  outp_get_paper_size ("", &x->paper_width, &x->paper_length);
-  x->left_margin = PSUS / 2;
-  x->right_margin = PSUS / 2;
-  x->top_margin = PSUS / 2;
-  x->bottom_margin = PSUS / 2;
-  x->line_gutter = PSUS / 72;
-  x->line_space = PSUS / 72;
-  x->line_width = PSUS / 144;
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    x->fonts[i] = NULL;
-
-  outp_parse_options (options, handle_option, this);
-
-  x->file = fn_open (x->file_name, "w");
-  if (x->file == NULL)
-    {
-      error (0, errno, _("opening PostScript output file \"%s\""),
-             x->file_name);
-      goto error;
-    }
-
-  if (x->portrait)
-    {
-      this->width = x->paper_width;
-      this->length = x->paper_length;
-    }
-  else
-    {
-      this->width = x->paper_length;
-      this->length = x->paper_width;
-    }
-  this->width -= x->left_margin + x->right_margin;
-  this->length -= x->top_margin + x->bottom_margin;
-  if (x->draw_headers)
-    {
-      int header_length = 3 * this->font_height;
-      this->length -= header_length;
-      x->top_margin += header_length;
-    }
-
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    if (x->fonts[i] == NULL)
-      {
-        const char *default_fonts[OUTP_FONT_CNT];
-        default_fonts[OUTP_FIXED] = "Courier.afm";
-        default_fonts[OUTP_PROPORTIONAL] = "Times-Roman.afm";
-        default_fonts[OUTP_EMPHASIS] = "Times-Italic.afm";
-        x->fonts[i] = load_font (default_fonts[i]);
-        if (x->fonts[i] == NULL)
-          goto error;
-      }
-
-  if (this->length / this->font_height < 15)
-    {
-      error (0, 0, _("The defined PostScript page is not long "
-                     "enough to hold margins and headers, plus least 15 "
-                     "lines of the default fonts.  In fact, there's only "
-                     "room for %d lines of each font at the default size "
-                     "of %d.%03d points."),
-          this->length / this->font_height,
-          this->font_height / 1000, this->font_height % 1000);
-      goto error;
-    }
-
-  this->fixed_width =
-    afm_get_character (x->fonts[OUTP_FIXED]->metrics, '0')->width
-    * this->font_height / 1000;
-  this->prop_em_width =
-    afm_get_character (x->fonts[OUTP_PROPORTIONAL]->metrics, '0')->width
-    * this->font_height / 1000;
-
-  this->horiz_line_width[OUTP_L_NONE] = 0;
-  this->horiz_line_width[OUTP_L_SINGLE] = 2 * x->line_gutter + x->line_width;
-  this->horiz_line_width[OUTP_L_DOUBLE] = (2 * x->line_gutter + x->line_space
-                                           + 2 * x->line_width);
-  memcpy (this->vert_line_width, this->horiz_line_width,
-          sizeof this->vert_line_width);
-
-  write_ps_prologue (this);
-
-  return true;
-
- error:
-  this->class->close_driver (this);
-  return false;
-}
-
-static bool
-ps_close_driver (struct outp_driver *this)
-{
-  struct ps_driver_ext *x = this->ext;
-  bool ok = true;
-  size_t i;
-
-  if (x->file != NULL)
-    {
-      fprintf (x->file,
-               "%%%%Trailer\n"
-               "%%%%Pages: %d\n"
-               "%%%%EOF\n",
-               x->page_number);
-
-      ok = fn_close (x->file_name, x->file) == 0;
-      if (!ok)
-        error (0, errno, _("closing PostScript output file \"%s\""),
-               x->file_name);
-    }
-
-  free (x->file_name);
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    free_font (x->fonts[i]);
-  free (x);
-
-  return ok;
-}
-
-/* Generic option types. */
-enum
-{
-  output_file_arg,
-  paper_size_arg,
-  orientation_arg,
-  line_style_arg,
-  boolean_arg,
-  pos_int_arg,
-  dimension_arg,
-  string_arg,
-  nonneg_int_arg
-};
-
-/* All the options that the PostScript driver supports. */
-static const struct outp_option option_tab[] =
-{
-  {"output-file",              output_file_arg,0},
-  {"paper-size",               paper_size_arg, 0},
-  {"orientation",              orientation_arg,0},
-
-  {"headers",                  boolean_arg,    1},
-
-  {"prop-font",                string_arg,     OUTP_PROPORTIONAL},
-  {"emph-font",                string_arg,     OUTP_EMPHASIS},
-  {"fixed-font",               string_arg,     OUTP_FIXED},
-
-  {"left-margin",              pos_int_arg,    0},
-  {"right-margin",             pos_int_arg,    1},
-  {"top-margin",               pos_int_arg,    2},
-  {"bottom-margin",            pos_int_arg,    3},
-  {"font-size",                        pos_int_arg,    4},
-
-  {"line-width",               dimension_arg,  0},
-  {"line-gutter",              dimension_arg,  1},
-  {"line-width",               dimension_arg,  2},
-  {NULL, 0, 0},
-};
-
-static bool
-handle_option (struct outp_driver *this, const char *key,
-               const struct string *val)
-{
-  struct ps_driver_ext *x = this->ext;
-  int subcat;
-  char *value = ds_cstr (val);
-
-  switch (outp_match_keyword (key, option_tab, &subcat))
-    {
-    case -1:
-      error (0, 0,
-             _("unknown configuration parameter `%s' for PostScript device "
-               "driver"), key);
-      break;
-    case output_file_arg:
-      free (x->file_name);
-      x->file_name = xstrdup (value);
-      break;
-    case paper_size_arg:
-      outp_get_paper_size (value, &this->width, &this->length);
-      break;
-    case orientation_arg:
-      if (!strcmp (value, "portrait"))
-       x->portrait = true;
-      else if (!strcmp (value, "landscape"))
-       x->portrait = false;
-      else
-       error (0, 0, _("unknown orientation `%s' (valid orientations are "
-                       "`portrait' and `landscape')"), value);
-      break;
-    case boolean_arg:
-      if (!strcmp (value, "on") || !strcmp (value, "true")
-          || !strcmp (value, "yes") || atoi (value))
-        x->draw_headers = true;
-      else if (!strcmp (value, "off") || !strcmp (value, "false")
-               || !strcmp (value, "no") || !strcmp (value, "0"))
-        x->draw_headers = false;
-      else
-        {
-          error (0, 0, _("boolean value expected for %s"), key);
-          return false;
-        }
-      break;
-    case pos_int_arg:
-      {
-       char *tail;
-       int arg;
-
-       errno = 0;
-       arg = strtol (value, &tail, 0);
-       if (arg < 1 || errno == ERANGE || *tail)
-         {
-           error (0, 0, _("positive integer value required for `%s'"), key);
-           break;
-         }
-       if ((subcat == 4 || subcat == 5) && arg < 1000)
-         {
-           error (0, 0, _("default font size must be at least 1 point (value "
-                           "of 1000 for key `%s')"), key);
-           break;
-         }
-       switch (subcat)
-         {
-         case 0:
-           x->left_margin = arg;
-           break;
-         case 1:
-           x->right_margin = arg;
-           break;
-         case 2:
-           x->top_margin = arg;
-           break;
-         case 3:
-           x->bottom_margin = arg;
-           break;
-         case 4:
-           this->font_height = arg;
-           break;
-         default:
-           NOT_REACHED ();
-         }
-      }
-      break;
-    case dimension_arg:
-      {
-       int dimension = outp_evaluate_dimension (value);
-
-       if (dimension <= 0)
-          break;
-       switch (subcat)
-         {
-         case 0:
-           x->line_width = dimension;
-           break;
-         case 1:
-           x->line_gutter = dimension;
-           break;
-         case 2:
-           x->line_width = dimension;
-           break;
-         default:
-           NOT_REACHED ();
-         }
-      }
-      break;
-    case string_arg:
-      {
-        struct font *font = load_font (value);
-        if (font != NULL)
-          {
-            struct font **dst = &x->fonts[subcat];
-            if (*dst != NULL)
-              free_font (*dst);
-            *dst = font;
-          }
-      }
-      break;
-    default:
-      NOT_REACHED ();
-    }
-
-  return true;
-}
-
-/* Looks for a PostScript font file or config file in all the
-   appropriate places.  Returns the file name on success, NULL on
-   failure. */
-static char *
-find_ps_file (const char *name)
-{
-  if (fn_is_absolute (name))
-    return xstrdup (name);
-  else
-    {
-      char *base_name = xasprintf ("psfonts/%s", name);
-      char *file_name = fn_search_path (base_name, config_path);
-      free (base_name);
-      return file_name;
-    }
-}
-\f
-/* Basic file operations. */
-
-/* Writes the PostScript prologue to file F. */
-static void
-write_ps_prologue (struct outp_driver *this)
-{
-  struct ps_driver_ext *x = this->ext;
-  size_t embedded_cnt, preloaded_cnt;
-  size_t i;
-
-  fputs ("%!PS-Adobe-3.0\n", x->file);
-  fputs ("%%Pages: (atend)\n", x->file);
-
-  embedded_cnt = preloaded_cnt = 0;
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    {
-      bool embed = x->fonts[i]->embed_fn != NULL;
-      embedded_cnt += embed;
-      preloaded_cnt += !embed;
-    }
-  if (preloaded_cnt > 0)
-    {
-      fputs ("%%DocumentNeededResources: font", x->file);
-      for (i = 0; i < OUTP_FONT_CNT; i++)
-        {
-          struct font *f = x->fonts[i];
-          if (f->embed_fn == NULL)
-            fprintf (x->file, " %s", afm_get_findfont_name (f->metrics));
-        }
-      fputs ("\n", x->file);
-    }
-  if (embedded_cnt > 0)
-    {
-      fputs ("%%DocumentSuppliedResources: font", x->file);
-      for (i = 0; i < OUTP_FONT_CNT; i++)
-        {
-          struct font *f = x->fonts[i];
-          if (f->embed_fn != NULL)
-            fprintf (x->file, " %s", afm_get_findfont_name (f->metrics));
-        }
-      fputs ("\n", x->file);
-    }
-  fputs ("%%Copyright: This prologue is public domain.\n", x->file);
-  fprintf (x->file, "%%%%Creator: %s\n", version);
-  fprintf (x->file, "%%%%DocumentMedia: Plain %g %g 75 white ()\n",
-           x->paper_width / (PSUS / 72.0), x->paper_length / (PSUS / 72.0));
-  fprintf (x->file, "%%%%Orientation: %s\n",
-           x->portrait ? "Portrait" : "Landscape");
-  fputs ("%%EndComments\n", x->file);
-  fputs ("%%BeginDefaults\n", x->file);
-  fputs ("%%PageResources: font", x->file);
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    fprintf (x->file, " %s", afm_get_findfont_name (x->fonts[i]->metrics));
-  fputs ("\n", x->file);
-  fputs ("%%EndDefaults\n", x->file);
-  fputs ("%%BeginProlog\n", x->file);
-  fputs ("/ED{exch def}bind def\n", x->file);
-  fputs ("/L{moveto lineto stroke}bind def\n", x->file);
-  fputs ("/D{moveto lineto moveto lineto stroke}bind def\n", x->file);
-  fputs ("/S{show}bind def\n", x->file);
-  fputs ("/GS{glyphshow}def\n", x->file);
-  fputs ("/RF{\n", x->file);
-  fputs (" exch dup maxlength 1 add dict begin\n", x->file);
-  fputs (" {\n", x->file);
-  fputs ("  1 index/FID ne{def}{pop pop}ifelse\n", x->file);
-  fputs (" }forall\n", x->file);
-  fputs (" /Encoding ED\n", x->file);
-  fputs (" currentdict end\n", x->file);
-  fputs ("}bind def\n", x->file);
-  fputs ("/F{setfont}bind def\n", x->file);
-  fputs ("/EP{\n", x->file);
-  fputs (" pg restore\n", x->file);
-  fputs (" showpage\n", x->file);
-  fputs ("}bind def\n", x->file);
-  fputs ("/GB{\n", x->file);
-  fputs (" /y2 ED/x2 ED/y1 ED/x1 ED\n", x->file);
-  fputs (" x1 y1 moveto x2 y1 lineto x2 y2 lineto x1 y2 lineto closepath\n",
-         x->file);
-  fputs (" gsave 0.9 setgray fill grestore stroke\n", x->file);
-  fputs ("}bind def\n", x->file);
-  fputs ("/K{0 rmoveto}bind def\n", x->file);
-  fputs ("%%EndProlog\n", x->file);
-  fputs ("%%BeginSetup\n", x->file);
-  for (i = 0; i < OUTP_FONT_CNT; i++)
-    setup_font (this, x->fonts[i], i);
-  fputs ("%%EndSetup\n", x->file);
-}
-
-/* Returns STRING as a Postscript name, which is just '/'
-   followed by STRING unless characters need to be quoted.
-   The caller must free the string. */
-static char *
-quote_ps_name (const char *string)
-{
-  const char *cp;
-
-  for (cp = string; *cp != '\0'; cp++)
-    {
-      unsigned char c = *cp;
-      if (!isalpha (c) && strchr ("^_|!$&:;.,-+", c) == NULL
-          && (cp == string || !isdigit (c)))
-        {
-          struct string out = DS_EMPTY_INITIALIZER;
-          ds_put_char (&out, '<');
-         for (cp = string; *cp != '\0'; cp++)
-            {
-              c = *cp;
-              ds_put_format (&out, "%02x", c);
-            }
-         ds_put_cstr (&out, ">cvn");
-          return ds_cstr (&out);
-        }
-    }
-  return xasprintf ("/%s", string);
-}
-
-static void
-ps_open_page (struct outp_driver *this)
-{
-  struct ps_driver_ext *x = this->ext;
-
-  /* Assure page independence. */
-  x->last_font = -1;
-
-  x->page_number++;
-
-  fprintf (x->file,
-          "%%%%Page: %d %d\n"
-          "%%%%BeginPageSetup\n"
-          "/pg save def 0.001 dup scale\n",
-          x->page_number, x->page_number);
-
-  if (!x->portrait)
-    fprintf (x->file,
-            "%d 0 translate 90 rotate\n",
-            x->paper_width);
-
-  if (x->bottom_margin != 0 || x->left_margin != 0)
-    fprintf (x->file,
-            "%d %d translate\n",
-            x->left_margin, x->bottom_margin);
-
-  fprintf (x->file,
-          "/LW %d def %d setlinewidth\n"
-          "%%%%EndPageSetup\n",
-          x->line_width, x->line_width);
-
-  if (x->draw_headers)
-    draw_headers (this);
-}
-
-static void
-ps_close_page (struct outp_driver *this)
-{
-  struct ps_driver_ext *x = this->ext;
-  fputs ("%%PageTrailer\n"
-         "EP\n",
-         x->file);
-}
-
-static void
-ps_submit (struct outp_driver *this UNUSED, struct som_entity *s)
-{
-  switch (s->type)
-    {
-    case SOM_CHART:
-      break;
-    default:
-      NOT_REACHED ();
-    }
-}
-\f
-/* Draws a line from (x0,y0) to (x1,y1). */
-static void
-dump_line (struct outp_driver *this, int x0, int y0, int x1, int y1)
-{
-  struct ps_driver_ext *ext = this->ext;
-  fprintf (ext->file, "%d %d %d %d L\n", x0, YT (y0), x1, YT (y1));
-}
-
-/* Draws a horizontal line X0...X2 at Y if LEFT says so,
-   shortening it to X0...X1 if SHORTEN is true.
-   Draws a horizontal line X1...X3 at Y if RIGHT says so,
-   shortening it to X2...X3 if SHORTEN is true. */
-static void
-horz_line (struct outp_driver *this,
-           int x0, int x1, int x2, int x3, int y,
-           enum outp_line_style left, enum outp_line_style right,
-           bool shorten)
-{
-  if (left != OUTP_L_NONE && right != OUTP_L_NONE && !shorten)
-    dump_line (this, x0, y, x3, y);
-  else
-    {
-      if (left != OUTP_L_NONE)
-        dump_line (this, x0, y, shorten ? x1 : x2, y);
-      if (right != OUTP_L_NONE)
-        dump_line (this, shorten ? x2 : x1, y, x3, y);
-    }
-}
-
-/* Draws a vertical line Y0...Y2 at X if TOP says so,
-   shortening it to Y0...Y1 if SHORTEN is true.
-   Draws a vertical line Y1...Y3 at X if BOTTOM says so,
-   shortening it to Y2...Y3 if SHORTEN is true. */
-static void
-vert_line (struct outp_driver *this,
-           int y0, int y1, int y2, int y3, int x,
-           enum outp_line_style top, enum outp_line_style bottom,
-           bool shorten)
-{
-  if (top != OUTP_L_NONE && bottom != OUTP_L_NONE && !shorten)
-    dump_line (this, x, y0, x, y3);
-  else
-    {
-      if (top != OUTP_L_NONE)
-        dump_line (this, x, y0, x, shorten ? y1 : y2);
-      if (bottom != OUTP_L_NONE)
-        dump_line (this, x, shorten ? y2 : y1, x, y3);
-    }
-}
-
-/* Draws a generalized intersection of lines in the rectangle
-   (X0,Y0)-(X3,Y3).  The line coming from the top to the center
-   is of style TOP, from left to center of style LEFT, from
-   bottom to center of style BOTTOM, and from right to center of
-   style RIGHT. */
-static void
-ps_line (struct outp_driver *this,
-         int x0, int y0, int x3, int y3,
-         enum outp_line_style top, enum outp_line_style left,
-         enum outp_line_style bottom, enum outp_line_style right)
-{
-  /* The algorithm here is somewhat subtle, to allow it to handle
-     all the kinds of intersections that we need.
-
-     Three additional ordinates are assigned along the x axis.  The
-     first is xc, midway between x0 and x3.  The others are x1 and
-     x2; for a single vertical line these are equal to xc, and for
-     a double vertical line they are the ordinates of the left and
-     right half of the double line.
-
-     yc, y1, and y2 are assigned similarly along the y axis.
-
-     The following diagram shows the coordinate system and output
-     for double top and bottom lines, single left line, and no
-     right line:
-
-                 x0       x1 xc  x2      x3
-               y0 ________________________
-                  |        #     #       |
-                  |        #     #       |
-                  |        #     #       |
-                  |        #     #       |
-                  |        #     #       |
-     y1 = y2 = yc |#########     #       |
-                  |        #     #       |
-                  |        #     #       |
-                  |        #     #       |
-                  |        #     #       |
-               y3 |________#_____#_______|
-  */
-  struct ps_driver_ext *ext = this->ext;
-
-  /* Offset from center of each line in a pair of double lines. */
-  int double_line_ofs = (ext->line_space + ext->line_width) / 2;
-
-  /* Are the lines along each axis single or double?
-     (It doesn't make sense to have different kinds of line on the
-     same axis, so we don't try to gracefully handle that case.) */
-  bool double_vert = top == OUTP_L_DOUBLE || bottom == OUTP_L_DOUBLE;
-  bool double_horz = left == OUTP_L_DOUBLE || right == OUTP_L_DOUBLE;
-
-  /* When horizontal lines are doubled,
-     the left-side line along y1 normally runs from x0 to x2,
-     and the right-side line along y1 from x3 to x1.
-     If the top-side line is also doubled, we shorten the y1 lines,
-     so that the left-side line runs only to x1,
-     and the right-side line only to x2.
-     Otherwise, the horizontal line at y = y1 below would cut off
-     the intersection, which looks ugly:
-               x0       x1     x2      x3
-             y0 ________________________
-                |        #     #       |
-                |        #     #       |
-                |        #     #       |
-                |        #     #       |
-             y1 |#########     ########|
-                |                      |
-                |                      |
-             y2 |######################|
-                |                      |
-                |                      |
-             y3 |______________________|
-     It is more of a judgment call when the horizontal line is
-     single.  We actually choose to cut off the line anyhow, as
-     shown in the first diagram above.
-  */
-  bool shorten_y1_lines = top == OUTP_L_DOUBLE;
-  bool shorten_y2_lines = bottom == OUTP_L_DOUBLE;
-  bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
-  int horz_line_ofs = double_vert ? double_line_ofs : 0;
-  int xc = (x0 + x3) / 2;
-  int x1 = xc - horz_line_ofs;
-  int x2 = xc + horz_line_ofs;
-
-  bool shorten_x1_lines = left == OUTP_L_DOUBLE;
-  bool shorten_x2_lines = right == OUTP_L_DOUBLE;
-  bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
-  int vert_line_ofs = double_horz ? double_line_ofs : 0;
-  int yc = (y0 + y3) / 2;
-  int y1 = yc - vert_line_ofs;
-  int y2 = yc + vert_line_ofs;
-
-  if (!double_horz)
-    horz_line (this, x0, x1, x2, x3, yc, left, right, shorten_yc_line);
-  else
-    {
-      horz_line (this, x0, x1, x2, x3, y1, left, right, shorten_y1_lines);
-      horz_line (this, x0, x1, x2, x3, y2, left, right, shorten_y2_lines);
-    }
-
-  if (!double_vert)
-    vert_line (this, y0, y1, y2, y3, xc, top, bottom, shorten_xc_line);
-  else
-    {
-      vert_line (this, y0, y1, y2, y3, x1, top, bottom, shorten_x1_lines);
-      vert_line (this, y0, y1, y2, y3, x2, top, bottom, shorten_x2_lines);
-    }
-}
-
-/* Writes STRING at location (X,Y) trimmed to the given MAX_WIDTH
-   and with the given JUSTIFICATION for THIS driver. */
-static int
-draw_text (struct outp_driver *this,
-           const char *string, int x, int y, int max_width,
-           enum outp_justification justification)
-{
-  struct outp_text text;
-  int width;
-
-  text.font = OUTP_PROPORTIONAL;
-  text.justification = justification;
-  text.string = ss_cstr (string);
-  text.h = max_width;
-  text.v = this->font_height;
-  text.x = x;
-  text.y = y;
-  this->class->text_metrics (this, &text, &width, NULL);
-  this->class->text_draw (this, &text);
-  return width;
-}
-
-/* Writes LEFT left-justified and RIGHT right-justified within
-   (X0...X1) at Y.  LEFT or RIGHT or both may be null. */
-static void
-draw_header_line (struct outp_driver *this,
-                  const char *left, const char *right,
-                  int x0, int x1, int y)
-{
-  int right_width = 0;
-  if (right != NULL)
-    right_width = (draw_text (this, right, x0, y, x1 - x0, OUTP_RIGHT)
-                   + this->prop_em_width);
-  if (left != NULL)
-    draw_text (this, left, x0, y, x1 - x0 - right_width, OUTP_LEFT);
-}
-
-/* Draw top of page headers for THIS driver. */
-static void
-draw_headers (struct outp_driver *this)
-{
-  struct ps_driver_ext *ext = this->ext;
-  char *r1, *r2;
-  int x0, x1;
-  int y;
-
-  y = -3 * this->font_height;
-  x0 = this->prop_em_width;
-  x1 = this->width - this->prop_em_width;
-
-  /* Draw box. */
-  fprintf (ext->file, "%d %d %d %d GB\n",
-          0, YT (y),
-           this->width, YT (y + 2 * this->font_height + ext->line_gutter));
-  y += ext->line_width + ext->line_gutter;
-
-  r1 = xasprintf (_("%s - Page %d"), get_start_date (), ext->page_number);
-  r2 = xasprintf ("%s - %s", version, host_system);
-
-  draw_header_line (this, outp_title, r1, x0, x1, y);
-  y += this->font_height;
-
-  draw_header_line (this, outp_subtitle, r2, x0, x1, y);
-
-  free (r1);
-  free (r2);
-}
-\f
-/* Writes the CHAR_CNT characters in CHARS at (X0,Y0), using the
-   given FONT.
-   The characters are justified according to JUSTIFICATION in a
-   field that has WIDTH_LEFT space remaining after the characters
-   themselves are accounted for.
-   Before character I is written, its x-position is adjusted by
-   KERNS[I]. */
-static void
-write_text (struct outp_driver *this,
-            int x0, int y0,
-            enum outp_font font,
-            enum outp_justification justification,
-            const struct afm_character **chars, int *kerns, size_t char_cnt,
-            int width_left)
-{
-  struct ps_driver_ext *ext = this->ext;
-  struct afm *afm = ext->fonts[font]->metrics;
-  struct string out;
-  size_t i, j;
-
-  if (justification == OUTP_RIGHT)
-    x0 += width_left;
-  else if (justification == OUTP_CENTER)
-    x0 += width_left / 2;
-  y0 += afm_get_ascent (afm) * this->font_height / 1000;
-
-  fprintf (ext->file, "\n%d %d moveto\n", x0, YT (y0));
-
-  if (ext->last_font != font)
-    {
-      ext->last_font = font;
-      fprintf (ext->file, "F%d setfont\n", font);
-    }
-
-  ds_init_empty (&out);
-  for (i = 0; i < char_cnt; i = j)
-    {
-      for (j = i + 1; j < char_cnt; j++)
-        if (kerns[j] != 0)
-          break;
-
-      if (kerns[i] != 0)
-        fprintf (ext->file, "%d K", kerns[i]);
-      while (i < j)
-        {
-          size_t encoded = afm_encode_string (afm, chars + i, j - i, &out);
-          if (encoded > 0)
-            {
-              fprintf (ext->file, "%sS\n", ds_cstr (&out));
-              ds_clear (&out);
-              i += encoded;
-            }
-
-          if (i < j)
-            {
-              fprintf (ext->file, "/%s GS\n", chars[i]->name);
-              i++;
-            }
-        }
-    }
-  ds_destroy (&out);
-}
-
-/* State of a text formatting operation. */
-struct text_state
-  {
-    /* Input. */
-    const struct outp_text *text;
-    bool draw;
-
-    /* Output. */
-    const struct afm_character **glyphs;
-    int *glyph_kerns;
-
-    /* State. */
-    size_t glyph_cnt;           /* Number of glyphs output. */
-    int width_left;            /* Width left over. */
-    int height_left;            /* Height left over. */
-
-    /* State as of last space. */
-    const char *space_char;     /* Just past last space. */
-    size_t space_glyph_cnt;     /* Number of glyphs as of last space. */
-    int space_width_left;       /* Width left over as of last space. */
-
-    /* Statistics. */
-    int max_width;             /* Widest line so far. */
-  };
-
-/* Adjusts S to complete a line of text,
-   and draws the current line if appropriate. */
-static void
-finish_line (struct outp_driver *this, struct text_state *s)
-{
-  int width;
-
-  if (s->draw)
-    {
-      write_text (this,
-                  s->text->x, s->text->y + (s->text->v - s->height_left),
-                  s->text->font,
-                  s->text->justification,
-                  s->glyphs, s->glyph_kerns, s->glyph_cnt,
-                  s->width_left);
-      s->glyph_cnt = 0;
-    }
-
-  /* Update maximum width. */
-  width = s->text->h - s->width_left;
-  if (width > s->max_width)
-    s->max_width = width;
-
-  /* Move to next line. */
-  s->width_left = s->text->h;
-  s->height_left -= this->font_height;
-
-  /* No spaces on this line yet. */
-  s->space_char = NULL;
-}
-
-/* Format TEXT on THIS driver.
-   If DRAW is nonzero, draw the text.
-   The width of the widest line is stored into *WIDTH, if WIDTH
-   is nonnull.
-   The total height of the text written is stored into *HEIGHT,
-   if HEIGHT is nonnull. */
-static void
-text (struct outp_driver *this, const struct outp_text *text, bool draw,
-      int *width, int *height)
-{
-  struct ps_driver_ext *ext = this->ext;
-  struct afm *afm = ext->fonts[text->font]->metrics;
-  const char *cp;
-  size_t glyph_cap;
-  struct text_state s;
-
-  s.text = text;
-  s.draw = draw;
-
-  s.glyphs = NULL;
-  s.glyph_kerns = NULL;
-  glyph_cap = 0;
-
-  s.glyph_cnt = 0;
-  s.width_left = s.text->h;
-  s.height_left = s.text->v;
-
-  s.space_char = 0;
-
-  s.max_width = 0;
-
-  cp = ss_data (s.text->string);
-  while (s.height_left >= this->font_height && cp < ss_end (s.text->string))
-    {
-      const struct afm_character *cur;
-      int char_width;
-      int kern_adjust;
-
-      if (*cp == '\n')
-        {
-          finish_line (this, &s);
-          cp++;
-          continue;
-        }
-
-      /* Get character and resolve ligatures. */
-      cur = afm_get_character (afm, *cp);
-      while (++cp < ss_end (s.text->string))
-        {
-          const struct afm_character *next = afm_get_character (afm, *cp);
-          const struct afm_character *ligature = afm_get_ligature (cur, next);
-          if (ligature == NULL)
-            break;
-          cur = ligature;
-        }
-      char_width = cur->width * this->font_height / 1000;
-
-      /* Get kern adjustment. */
-      if (s.glyph_cnt > 0)
-        kern_adjust = (afm_get_kern_adjustment (s.glyphs[s.glyph_cnt - 1], cur)
-                       * this->font_height / 1000);
-      else
-        kern_adjust = 0;
-
-      /* Record the current status if this is a space character. */
-      if (cur->code == ' ' && cp > ss_data (s.text->string))
-       {
-         s.space_char = cp;
-         s.space_glyph_cnt = s.glyph_cnt;
-          s.space_width_left = s.width_left;
-       }
-
-      /* Enough room on this line? */
-      if (char_width + kern_adjust > s.width_left)
-       {
-         if (s.space_char == NULL)
-            {
-              finish_line (this, &s);
-              kern_adjust = 0;
-            }
-          else
-            {
-              cp = s.space_char;
-              s.glyph_cnt = s.space_glyph_cnt;
-              s.width_left = s.space_width_left;
-              finish_line (this, &s);
-              continue;
-            }
-       }
-
-      if (s.glyph_cnt >= glyph_cap)
-        {
-          glyph_cap = 2 * (glyph_cap + 8);
-          s.glyphs = xnrealloc (s.glyphs, glyph_cap, sizeof *s.glyphs);
-          s.glyph_kerns = xnrealloc (s.glyph_kerns,
-                                     glyph_cap, sizeof *s.glyph_kerns);
-        }
-      s.glyphs[s.glyph_cnt] = cur;
-      s.glyph_kerns[s.glyph_cnt] = kern_adjust;
-      s.glyph_cnt++;
-
-      s.width_left -= char_width + kern_adjust;
-    }
-  if (s.height_left >= this->font_height && s.glyph_cnt > 0)
-    finish_line (this, &s);
-
-  if (width != NULL)
-    *width = s.max_width;
-  if (height != NULL)
-    *height = text->v - s.height_left;
-  free (s.glyphs);
-  free (s.glyph_kerns);
-}
-
-static void
-ps_text_metrics (struct outp_driver *this, const struct outp_text *t,
-                 int *width, int *height)
-{
-  text (this, t, false, width, height);
-}
-
-static void
-ps_text_draw (struct outp_driver *this, const struct outp_text *t)
-{
-  assert (this->page_open);
-  text (this, t, true, NULL, NULL);
-}
-\f
-static void
-ps_chart_initialise (struct outp_driver *this UNUSED, struct chart *ch)
-{
-#ifdef NO_CHARTS
-  ch->lp = NULL;
-#else
-  struct ps_driver_ext *x = this->ext;
-  char page_size[128];
-  int size;
-  int x_origin, y_origin;
-
-  ch->file = tmpfile ();
-  if (ch->file == NULL)
-    {
-      ch->lp = NULL;
-      return;
-    }
-
-  size = this->width < this->length ? this->width : this->length;
-  x_origin = x->left_margin + (size - this->width) / 2;
-  y_origin = x->bottom_margin + (size - this->length) / 2;
-
-  snprintf (page_size, sizeof page_size,
-            "a,xsize=%.3f,ysize=%.3f,xorigin=%.3f,yorigin=%.3f",
-            (double) size / PSUS, (double) size / PSUS,
-            (double) x_origin / PSUS, (double) y_origin / PSUS);
-
-  ch->pl_params = pl_newplparams ();
-  pl_setplparam (ch->pl_params, "PAGESIZE", page_size);
-  ch->lp = pl_newpl_r ("ps", NULL, ch->file, stderr, ch->pl_params);
-#endif
-}
-
-static void
-ps_chart_finalise (struct outp_driver *this UNUSED, struct chart *ch UNUSED)
-{
-#ifndef NO_CHARTS
-  struct ps_driver_ext *x = this->ext;
-  char buf[BUFSIZ];
-  static int doc_num = 0;
-
-  outp_eject_page (this);
-  fprintf (x->file,
-           "/sp save def\n"
-           "%d %d translate 1000 dup scale\n"
-           "userdict begin\n"
-           "/showpage { } def\n"
-           "0 setgray 0 setlinecap 1 setlinewidth\n"
-           "0 setlinejoin 10 setmiterlimit [ ] 0 setdash newpath clear\n"
-           "%%%%BeginDocument: %d\n",
-           -x->left_margin, -x->bottom_margin,
-           doc_num++);
-
-  rewind (ch->file);
-  while (fwrite (buf, 1, fread (buf, 1, sizeof buf, ch->file), x->file))
-    continue;
-  fclose (ch->file);
-
-  fputs ("%%EndDocument\n"
-         "end\n"
-         "sp restore\n",
-         x->file);
-  outp_close_page (this);
-#endif
-}
-\f
-static void embed_font (struct outp_driver *this, struct font *font);
-static void reencode_font (struct outp_driver *this, struct font *font);
-
-/* Loads and returns the font for STRING, which has the format
-   "AFM,PFA,ENC", where AFM is the AFM file's name, PFA is the
-   PFA or PFB file's name, and ENC is the encoding file's name.
-   PFA and ENC are optional.
-   Returns a null pointer if unsuccessful. */
-static struct font *
-load_font (const char *string_)
-{
-  char *string = xstrdup (string_);
-  struct font *font;
-  char *position = string;
-  char *token;
-  char *afm_file_name;
-
-  font = xmalloc (sizeof *font);
-  font->metrics = NULL;
-  font->embed_fn = NULL;
-  font->encoding_fn = NULL;
-
-  token = strsep (&position, ",");
-  if (token == NULL)
-    {
-      error (0, 0, _("\"%s\": bad font specification"), string);
-      goto error;
-    }
-
-  /* Read AFM file. */
-  afm_file_name = find_ps_file (token);
-  if (afm_file_name == NULL)
-    {
-      error (0, 0, _("could not find AFM file \"%s\""), token);
-      goto error;
-    }
-  font->metrics = afm_open (afm_file_name);
-  free (afm_file_name);
-  if (font->metrics == NULL)
-    goto error;
-
-  /* Find font file to embed. */
-  token = strsep (&position, ",");
-  if (token != NULL && *token != '\0')
-    {
-      font->embed_fn = find_ps_file (token);
-      if (font->embed_fn == NULL)
-        error (0, 0, _("could not find font \"%s\""), token);
-    }
-
-  /* Find encoding. */
-  token = strsep (&position, ",");
-  if (token != NULL && *token == '\0')
-    {
-      font->encoding_fn = find_ps_file (token);
-      if (font->encoding_fn == NULL)
-        error (0, 0, _("could not find encoding \"%s\""), token);
-    }
-
-  free (string);
-  return font;
-
- error:
-  free (string);
-  free_font (font);
-  return NULL;
-}
-
-/* Frees FONT. */
-static void
-free_font (struct font *font)
-{
-  if (font != NULL)
-    {
-      afm_close (font->metrics);
-      free (font->embed_fn);
-      free (font->encoding_fn);
-      free (font);
-    }
-}
-
-/* Emits PostScript code to embed FONT (if necessary), scale it
-   to the proper size, re-encode it (if necessary), and store the
-   resulting font as an object named F#, where INDEX is
-   substituted for #. */
-static void
-setup_font (struct outp_driver *this, struct font *font, int index)
-{
-  struct ps_driver_ext *x = this->ext;
-  char *ps_name;
-
-  if (font->embed_fn != NULL)
-    embed_font (this, font);
-  else
-    fprintf (x->file, "%%%%IncludeResource: font %s\n",
-             afm_get_findfont_name (font->metrics));
-
-  ps_name = quote_ps_name (afm_get_findfont_name (font->metrics));
-  fprintf (x->file, "%s findfont %d scalefont\n", ps_name, this->font_height);
-  free (ps_name);
-
-  if (font->encoding_fn != NULL)
-    reencode_font (this, font);
-
-  fprintf (x->file, "/F%d ED\n", index);
-}
-
-/* Copies up to COPY_BYTES bytes from SRC to DST, stopping at
-   end-of-file or on error. */
-static void
-copy_bytes_literally (FILE *src, FILE *dst, unsigned long copy_bytes)
-{
-  while (copy_bytes > 0)
-    {
-      char buffer[BUFSIZ];
-      unsigned long chunk_bytes = MIN (copy_bytes, sizeof buffer);
-      size_t read_bytes = fread (buffer, 1, chunk_bytes, src);
-      size_t write_bytes = fwrite (buffer, 1, read_bytes, dst);
-      if (write_bytes != chunk_bytes)
-        break;
-      copy_bytes -= chunk_bytes;
-    }
-}
-
-/* Copies up to COPY_BYTES bytes from SRC to DST, stopping at
-   end-of-file or on error.  The bytes are translated into
-   hexadecimal during copying and broken into lines with
-   new-line characters. */
-static void
-copy_bytes_as_hex (FILE *src, FILE *dst, unsigned long copy_bytes)
-{
-  unsigned long i;
-
-  for (i = 0; i < copy_bytes; i++)
-    {
-      int c = getc (src);
-      if (c == EOF)
-        break;
-      if (i > 0 && i % 36 == 0)
-        putc ('\n', dst);
-      fprintf (dst, "%02X", c);
-    }
-  putc ('\n', dst);
-}
-
-/* Embeds the given FONT into THIS driver's output stream. */
-static void
-embed_font (struct outp_driver *this, struct font *font)
-{
-  struct ps_driver_ext *x = this->ext;
-  FILE *file;
-  int c;
-
-  file = fopen (font->embed_fn, "rb");
-  if (file == NULL)
-    {
-      error (errno, 0, _("cannot open font file \"%s\""), font->embed_fn);
-      return;
-    }
-
-  fprintf (x->file, "%%%%BeginResource: font %s\n",
-           afm_get_findfont_name (font->metrics));
-
-  c = getc (file);
-  ungetc (c, file);
-  if (c != 128)
-    {
-      /* PFA file.  Copy literally. */
-      copy_bytes_literally (file, x->file, ULONG_MAX);
-    }
-  else
-    {
-      /* PFB file.  Translate as specified in Adobe Technical
-         Note #5040. */
-      while ((c = getc (file)) == 128)
-        {
-          int type;
-          unsigned long length;
-
-          type = getc (file);
-          if (type == 3)
-            break;
-
-          length = getc (file);
-          length |= (unsigned long) getc (file) << 8;
-          length |= (unsigned long) getc (file) << 16;
-          length |= (unsigned long) getc (file) << 24;
-
-          if (type == 1)
-            copy_bytes_literally (file, x->file, length);
-          else if (type == 2)
-            copy_bytes_as_hex (file, x->file, length);
-          else
-            break;
-        }
-    }
-  if (freaderror (file))
-    error (errno, 0, _("reading font file \"%s\""), font->embed_fn);
-  fputs ("%%EndResource\n", x->file);
-}
-
-/* Re-encodes FONT according to the specified encoding. */
-static void
-reencode_font (struct outp_driver *this, struct font *font)
-{
-  struct ps_driver_ext *x = this->ext;
-
-  struct string line;
-
-  int line_number;
-  FILE *file;
-
-  char *tab[256];
-
-  int i;
-
-  file = fopen (font->encoding_fn, "r");
-  if (file == NULL)
-    {
-      error (errno, 0, _("cannot open font encoding file \"%s\""),
-             font->encoding_fn);
-      return;
-    }
-
-  for (i = 0; i < 256; i++)
-    tab[i] = NULL;
-
-  line_number = 0;
-
-  ds_init_empty (&line);
-  while (ds_read_config_line (&line, &line_number, file))
-    {
-      char *pschar, *code;
-      char *save_ptr, *tail;
-      int code_val;
-
-      if (ds_is_empty (&line) == 0)
-        continue;
-
-      pschar = strtok_r (ds_cstr (&line), " \t\r\n", &save_ptr);
-      code = strtok_r (NULL, " \t\r\n", &save_ptr);
-      if (pschar == NULL || code == NULL)
-        continue;
-
-      code_val = strtol (code, &tail, 0);
-      if (*tail)
-        {
-          error_at_line (0, 0, font->encoding_fn, line_number,
-                         _("invalid numeric format"));
-          continue;
-        }
-      if (code_val < 0 || code_val > 255)
-        continue;
-      if (tab[code_val] != 0)
-        free (tab[code_val]);
-      tab[code_val] = xstrdup (pschar);
-    }
-  ds_destroy (&line);
-
-  fputs ("[", x->file);
-  for (i = 0; i < 256; i++)
-    {
-      char *name = quote_ps_name (tab[i] != NULL ? tab[i] : ".notdef");
-      fprintf (x->file, "%s\n", name);
-      free (name);
-      free (tab[i]);
-    }
-  fputs ("] RF\n", x->file);
-
-  if (freaderror (file) != 0)
-    error (errno, 0, _("closing Postscript encoding \"%s\""),
-           font->encoding_fn);
-}
-
-/* PostScript driver class. */
-const struct outp_class postscript_class =
-{
-  "postscript",
-  0,
-
-  ps_open_driver,
-  ps_close_driver,
-
-  ps_open_page,
-  ps_close_page,
-  NULL,
-
-  ps_submit,
-
-  ps_line,
-  ps_text_metrics,
-  ps_text_draw,
-
-  ps_chart_initialise,
-  ps_chart_finalise
-};
diff --git a/src/output/render.c b/src/output/render.c
new file mode 100644 (file)
index 0000000..05db149
--- /dev/null
@@ -0,0 +1,1302 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmap.h"
+#include "output/render.h"
+#include "output/table.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+/* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
+#define H TABLE_HORZ
+#define V TABLE_VERT
+\f
+/* A layout for rendering a specific table on a specific device.
+
+   May represent the layout of an entire table presented to
+   render_page_create(), or a rectangular subregion of a table broken out using
+   render_page_next() to allow a table to be broken across multiple pages. */
+struct render_page
+  {
+    const struct render_params *params; /* Parameters of the target device. */
+    struct table *table;                /* Table rendered. */
+    int ref_cnt;
+
+    /* Local copies of table->n and table->h, for convenience. */
+    int n[TABLE_N_AXES];
+    int h[TABLE_N_AXES][2];
+
+    /* cp[H] represents x positions within the table.
+       cp[H][0] = 0.
+       cp[H][1] = the width of the leftmost vertical rule.
+       cp[H][2] = cp[H][1] + the width of the leftmost column.
+       cp[H][3] = cp[H][2] + the width of the second-from-left vertical rule.
+       and so on:
+       cp[H][2 * nc] = x position of the rightmost vertical rule.
+       cp[H][2 * nc + 1] = total table width including all rules.
+
+       Similarly, cp[V] represents y positions within the table.
+       cp[V][0] = 0.
+       cp[V][1] = the height of the topmost horizontal rule.
+       cp[V][2] = cp[V][1] + the height of the topmost column.
+       cp[V][3] = cp[V][2] + the height of the second-from-top horizontal rule.
+       and so on:
+       cp[V][2 * nr] = y position of the bottommost horizontal rule.
+       cp[V][2 * nr + 1] = total table height including all rules.
+
+       Rules and columns can have width or height 0, in which case consecutive
+       values in this array are equal. */
+    int *cp[TABLE_N_AXES];
+
+    /* render_break_next() can break a table such that some cells are not fully
+       contained within a render_page.  This will happen if a cell is too wide
+       or two tall to fit on a single page, or if a cell spans multiple rows or
+       columns and the page only includes some of those rows or columns.
+
+       This hash table contains "struct render_overflow"s that represents each
+       such cell that doesn't completely fit on this page.
+
+       Each overflow cell borders at least one header edge of the table and may
+       border more.  (A single table cell that is so large that it fills the
+       entire page can overflow on all four sides!) */
+    struct hmap overflows;
+
+    /* If a single column (or row) is too wide (or tall) to fit on a page
+       reasonably, then render_break_next() will split a single row or column
+       across multiple render_pages.  This member indicates when this has
+       happened:
+
+       is_edge_cutoff[H][0] is true if pixels have been cut off the left side
+       of the leftmost column in this page, and false otherwise.
+
+       is_edge_cutoff[H][1] is true if pixels have been cut off the right side
+       of the rightmost column in this page, and false otherwise.
+
+       is_edge_cutoff[V][0] and is_edge_cutoff[V][1] are similar for the top
+       and bottom of the table.
+
+       The effect of is_edge_cutoff is to prevent rules along the edge in
+       question from being rendered.
+
+       When is_edge_cutoff is true for a given edge, the 'overflows' hmap will
+       contain a node for each cell along that edge. */
+    bool is_edge_cutoff[TABLE_N_AXES][2];
+
+    /* If part of a joined cell would be cut off by breaking a table along
+       'axis' at the rule with offset 'z' (where 0 <= z <= n[axis]), then
+       join_crossing[axis][z] is the thickness of the rule that would be cut
+       off.
+
+       This is used to know to allocate extra space for breaking at such a
+       position, so that part of the cell's content is not lost.
+
+       This affects breaking a table only when headers are present.  When
+       headers are not present, the rule's thickness is used for cell content,
+       so no part of the cell's content is lost (and in fact it is duplicated
+       across both pages). */
+    int *join_crossing[TABLE_N_AXES];
+  };
+
+/* Returns the offset in struct render_page's cp[axis] array of the rule with
+   index RULE_IDX.  That is, if RULE_IDX is 0, then the offset is that of the
+   leftmost or topmost rule; if RULE_IDX is 1, then the offset is that of the
+   next rule to the right (or below); and so on. */
+static int
+rule_ofs (int rule_idx)
+{
+  return rule_idx * 2;
+}
+
+/* Returns the offset in struct render_page's cp[axis] array of the rule with
+   index RULE_IDX_R, which counts from the right side (or bottom) of the page
+   left (or up), according to whether AXIS is H or V, respectively.  That is,
+   if RULE_IDX_R is 0, then the offset is that of the rightmost or bottommost
+   rule; if RULE_IDX is 1, then the offset is that of the next rule to the left
+   (or above); and so on. */
+static int
+rule_ofs_r (const struct render_page *page, int axis, int rule_idx_r)
+{
+  return (page->n[axis] - rule_idx_r) * 2;
+}
+
+/* Returns the offset in struct render_page's cp[axis] array of the cell with
+   index CELL_IDX.  That is, if CELL_IDX is 0, then the offset is that of the
+   leftmost or topmost cell; if CELL_IDX is 1, then the offset is that of the
+   next cell to the right (or below); and so on. */
+static int
+cell_ofs (int cell_idx)
+{
+  return cell_idx * 2 + 1;
+}
+
+/* Returns the width of PAGE along AXIS from OFS0 to OFS1, exclusive. */
+static int
+axis_width (const struct render_page *page, int axis, int ofs0, int ofs1)
+{
+  return page->cp[axis][ofs1] - page->cp[axis][ofs0];
+}
+
+/* Returns the width of the headers in PAGE along AXIS. */
+static int
+headers_width (const struct render_page *page, int axis)
+{
+  int h0 = page->h[axis][0];
+  int w0 = axis_width (page, axis, rule_ofs (0), cell_ofs (h0));
+  int n = page->n[axis];
+  int h1 = page->h[axis][1];
+  int w1 = axis_width (page, axis, rule_ofs_r (page, axis, h1), cell_ofs (n));
+  return w0 + w1;
+}
+
+/* Returns the width of cell X along AXIS in PAGE. */
+static int
+cell_width (const struct render_page *page, int axis, int x)
+{
+  return axis_width (page, axis, cell_ofs (x), cell_ofs (x) + 1);
+}
+
+/* Returns the width of cells X0 through X1, exclusive, along AXIS in PAGE. */
+static int
+joined_width (const struct render_page *page, int axis, int x0, int x1)
+{
+  return axis_width (page, axis, cell_ofs (x0), cell_ofs (x1) - 1);
+}
+
+/* Returns the width of the widest cell, excluding headers, along AXIS in
+   PAGE. */
+static int
+max_cell_width (const struct render_page *page, int axis)
+{
+  int n = page->n[axis];
+  int x0 = page->h[axis][0];
+  int x1 = n - page->h[axis][1];
+  int x, max;
+
+  max = 0;
+  for (x = x0; x < x1; x++)
+    {
+      int w = cell_width (page, axis, x);
+      if (w > max)
+        max = w;
+    }
+  return max;
+}
+\f
+/* A cell that doesn't completely fit on the render_page. */
+struct render_overflow
+  {
+    struct hmap_node node;      /* In render_page's 'overflows' hmap. */
+
+    /* Occupied region of page.
+
+       d[H][0] is the leftmost column.
+       d[H][1] is the rightmost column, plus 1.
+       d[V][0] is the top row.
+       d[V][1] is the bottom row, plus 1.
+
+       The cell in its original table might occupy a larger region.  This
+       member reflects the size of the cell in the current render_page, after
+       trimming off any rows or columns due to page-breaking. */
+    int d[TABLE_N_AXES];
+
+    /* The space that has been trimmed off the cell:
+
+       overflow[H][0]: space trimmed off its left side.
+       overflow[H][1]: space trimmed off its right side.
+       overflow[V][0]: space trimmed off its top.
+       overflow[V][1]: space trimmed off its bottom.
+
+       During rendering, this information is used to position the rendered
+       portion of the cell within the available space.
+
+       When a cell is rendered, sometimes it is permitted to spill over into
+       space that is ordinarily reserved for rules.  Either way, this space is
+       still included in overflow values.
+
+       Suppose, for example, that a cell that joins 2 columns has a width of 60
+       pixels and content "abcdef", that the 2 columns that it joins have
+       widths of 20 and 30 pixels, respectively, and that therefore the rule
+       between the two joined columns has a width of 10 (20 + 10 + 30 = 60).
+       It might render like this, if each character is 10x10, and showing a few
+       extra table cells for context:
+
+                                     +------+
+                                     |abcdef|
+                                     +--+---+
+                                     |gh|ijk|
+                                     +--+---+
+
+       If this render_page is broken at the rule that separates "gh" from
+       "ijk", then the page that contains the left side of the "abcdef" cell
+       will have overflow[H][1] of 10 + 30 = 40 for its portion of the cell,
+       and the page that contains the right side of the cell will have
+       overflow[H][0] of 20 + 10 = 30.  The two resulting pages would look like
+       this:
+
+
+                                       +---
+                                       |abc
+                                       +--+
+                                       |gh|
+                                       +--+
+
+       and:
+
+                                       ----+
+                                       cdef|
+                                       +---+
+                                       |ijk|
+                                       +---+
+    */
+    int overflow[TABLE_N_AXES][2];
+  };
+
+/* Returns a hash value for (X,Y). */
+static unsigned int
+hash_overflow (int x, int y)
+{
+  return hash_int (x + (y << 16), 0);
+}
+
+/* Searches PAGE's set of render_overflow for one whose top-left cell is
+   (X,Y).  Returns it, if there is one, otherwise a null pointer. */
+static const struct render_overflow *
+find_overflow (const struct render_page *page, int x, int y)
+{
+  if (!hmap_is_empty (&page->overflows))
+    {
+      const struct render_overflow *of;
+
+      HMAP_FOR_EACH_WITH_HASH (of, struct render_overflow, node,
+                               hash_overflow (x, y), &page->overflows)
+        if (x == of->d[H] && y == of->d[V])
+          return of;
+    }
+
+  return NULL;
+}
+\f
+/* Row or column dimensions.  Used to figure the size of a table in
+   render_page_create() and discarded after that. */
+struct render_row
+  {
+    /* Width without considering rows (or columns) that span more than one (or
+       column). */
+    int unspanned;
+
+    /* Width taking spanned rows (or columns) into consideration. */
+    int width;
+  };
+
+/* Modifies the 'width' members of the N elements of ROWS so that their sum,
+   when added to rule widths RULES[1] through RULES[N - 1] inclusive, is at
+   least WIDTH. */
+static void
+distribute_spanned_width (int width,
+                          struct render_row *rows, const int *rules, int n)
+{
+  int total_unspanned;
+  double w, d0, d1, d;
+  int x;
+
+  /* Sum up the unspanned widths of the N rows for use as weights. */
+  total_unspanned = 0;
+  for (x = 0; x < n; x++)
+    total_unspanned += rows[x].unspanned;
+  for (x = 0; x < n - 1; x++)
+    total_unspanned += rules[x + 1];
+  if (total_unspanned >= width)
+    return;
+
+  /* The algorithm used here is based on the following description from HTML 4:
+
+         For cells that span multiple columns, a simple approach consists of
+         apportioning the min/max widths evenly to each of the constituent
+         columns.  A slightly more complex approach is to use the min/max
+         widths of unspanned cells to weight how spanned widths are
+         apportioned.  Experiments suggest that a blend of the two approaches
+         gives good results for a wide range of tables.
+
+     We blend the two approaches half-and-half, except that we cannot use the
+     unspanned weights when 'total_unspanned' is 0 (because that would cause a
+     division by zero).
+
+     This implementation uses floating-point types and operators, but all the
+     values involved are integers.  For integers smaller than 53 bits, this
+     should not lose any precision, and it should degrade gracefully for larger
+     values.
+
+     The calculation we want to do is this:
+
+        w0 = width / n
+        w1 = width * (column's unspanned width) / (total unspanned width)
+        (column's width) = (w0 + w1) / 2
+
+     We implement it as a precise calculation in integers by multiplying w0 and
+     w1 by the common denominator of all three calculations (d), dividing that
+     out in the column width calculation, and then keeping the remainder for
+     the next iteration.
+  */
+  d0 = n;
+  d1 = total_unspanned * 2.0;
+  d = d0 * d1;
+  if (total_unspanned > 0)
+    d *= 2.0;
+  w = floor (d / 2.0);
+  for (x = 0; x < n; x++)
+    {
+      w += width * d1;
+      if (total_unspanned > 0)
+        {
+          double unspanned = rows[x].unspanned * 2.0;
+          if (x < n - 1)
+            unspanned += rules[x + 1];
+          if (x > 0)
+            unspanned += rules[x];
+          w += width * unspanned * d0;
+        }
+
+      rows[x].width = w / d;
+      w -= rows[x].width * d;
+    }
+}
+
+/* Initializes PAGE->cp[AXIS] from the row widths in ROWS and the rule widths
+   in RULES. */
+static void
+accumulate_row_widths (const struct render_page *page, enum table_axis axis,
+                       const struct render_row *rows, const int *rules)
+{
+  int n = page->n[axis];
+  int *cp;
+  int z;
+
+  cp = page->cp[axis];
+  cp[0] = 0;
+  for (z = 0; z < n; z++)
+    {
+      cp[1] = cp[0] + rules[z];
+      cp[2] = cp[1] + rows[z].width;
+      cp += 2;
+    }
+  cp[1] = cp[0] + rules[n];
+}
+
+/* Returns the sum of widths of the N ROWS and N+1 RULES. */
+static int
+calculate_table_width (int n, const struct render_row *rows, int *rules)
+{
+  int width;
+  int x;
+
+  width = 0;
+  for (x = 0; x < n; x++)
+    width += rows[x].width;
+  for (x = 0; x <= n; x++)
+    width += rules[x];
+
+  return width;
+}
+\f
+/* Rendering utility functions. */
+
+/* Returns the line style to use for drawing a rule of the given TYPE. */
+static enum render_line_style
+rule_to_render_type (unsigned char type)
+{
+  switch (type)
+    {
+    case TAL_0:
+    case TAL_GAP:
+      return RENDER_LINE_NONE;
+    case TAL_1:
+      return RENDER_LINE_SINGLE;
+    case TAL_2:
+      return RENDER_LINE_DOUBLE;
+    default:
+      NOT_REACHED ();
+    }
+}
+
+/* Returns the width of the rule in TABLE that is at offset Z along axis A, if
+   rendered with PARAMS.  */
+static int
+measure_rule (const struct render_params *params, const struct table *table,
+              enum table_axis a, int z)
+{
+  enum table_axis b = !a;
+  unsigned int rules;
+  int d[TABLE_N_AXES];
+  int width, i;
+
+  /* Determine all types of rules that are present, as a bitmap in 'rules'
+     where rule type 't' is present if bit 2**t is set. */
+  rules = 0;
+  d[a] = z;
+  for (d[b] = 0; d[b] < table->n[b]; d[b]++)
+    rules |= 1u << table_get_rule (table, a, d[H], d[V]);
+
+  /* Calculate maximum width of the rules that are present. */
+  width = 0;
+  for (i = 0; i < N_LINES; i++)
+    if (rules & (1u << i))
+      width = MAX (width, params->line_widths[a][rule_to_render_type (i)]);
+
+  return width;
+}
+
+/* Allocates and returns a new render_page using PARAMS and TABLE.  Allocates
+   space for all of the members of the new page, but the caller must initialize
+   the 'cp' member itself. */
+static struct render_page *
+render_page_allocate (const struct render_params *params,
+                      struct table *table)
+{
+  struct render_page *page;
+  int i;
+
+  page = xmalloc (sizeof *page);
+  page->params = params;
+  page->table = table;
+  page->ref_cnt = 1;
+  page->n[H] = table->n[H];
+  page->n[V] = table->n[V];
+  page->h[H][0] = table->h[H][0];
+  page->h[H][1] = table->h[H][1];
+  page->h[V][0] = table->h[V][0];
+  page->h[V][1] = table->h[V][1];
+
+  for (i = 0; i < TABLE_N_AXES; i++)
+    {
+      page->cp[i] = xmalloc ((2 * page->n[i] + 2) * sizeof *page->cp[i]);
+      page->join_crossing[i] = xzalloc ((page->n[i] + 1) * sizeof *page->join_crossing[i]);
+    }
+
+  hmap_init (&page->overflows);
+  memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff);
+
+  return page;
+}
+
+/* Allocates and returns a new render_page for PARAMS and TABLE, initializing
+   cp[H] in the new page from ROWS and RULES.  The caller must still initialize
+   cp[V]. */
+static struct render_page *
+create_page_with_exact_widths (const struct render_params *params,
+                               struct table *table,
+                               const struct render_row *rows, int *rules)
+{
+  struct render_page *page = render_page_allocate (params, table);
+  accumulate_row_widths (page, H, rows, rules);
+  return page;
+}
+
+/* Allocates and returns a new render_page for PARAMS and TABLE.
+
+   Initializes cp[H] in the new page by setting the width of each row 'i' to
+   somewhere between the minimum cell width ROW_MIN[i].width and the maximum
+   ROW_MAX[i].width.  Sets the width of rules to those in RULES.
+
+   W_MIN is the sum of ROWS_MIN[].width.
+
+   W_MAX is the sum of ROWS_MAX[].width.
+
+   The caller must still initialize cp[V]. */
+static struct render_page *
+create_page_with_interpolated_widths (const struct render_params *params,
+                                      struct table *table,
+                                      const struct render_row *rows_min,
+                                      const struct render_row *rows_max,
+                                      int w_min, int w_max, const int *rules)
+{
+  /* This implementation uses floating-point types and operators, but all the
+     values involved are integers.  For integers smaller than 53 bits, this
+     should not lose any precision, and it should degrade gracefully for larger
+     values. */
+  const int n = table->n[H];
+  const double avail = params->size[H] - w_min;
+  const double wanted = w_max - w_min;
+  struct render_page *page;
+  double w;
+  int *cph;
+  int x;
+
+  assert (wanted > 0);
+
+  page = render_page_allocate (params, table);
+
+  cph = page->cp[H];
+  *cph = 0;
+  w = (int) wanted / 2;
+  for (x = 0; x < n; x++)
+    {
+      int extra;
+
+      w += avail * (rows_max[x].width - rows_min[x].width);
+      extra = w / wanted;
+      w -= extra * wanted;
+
+      cph[1] = cph[0] + rules[x];
+      cph[2] = cph[1] + rows_min[x].width + extra;
+      cph += 2;
+    }
+  cph[1] = cph[0] + rules[n];
+
+  assert (page->cp[H][n * 2 + 1] == params->size[H]);
+  return page;
+}
+
+\f
+static void
+set_join_crossings (struct render_page *page, enum table_axis axis,
+                    const struct table_cell *cell, int *rules)
+{
+  int z;
+
+  for (z = cell->d[axis][0] + 1; z <= cell->d[axis][1] - 1; z++)
+    page->join_crossing[axis][z] = rules[z];
+}
+
+/* Creates and returns a new render_page for rendering TABLE on a device
+   described by PARAMS.
+
+   The new render_page will be suitable for rendering on a device whose page
+   size is PARAMS->size, but the caller is responsible for actually breaking it
+   up to fit on such a device, using the render_break abstraction.  */
+struct render_page *
+render_page_create (const struct render_params *params,
+                    const struct table *table_)
+{
+  struct render_page *page;
+  struct table *table;
+  enum { MIN, MAX };
+  struct render_row *columns[2];
+  struct render_row *rows;
+  int table_widths[2];
+  int *rules[TABLE_N_AXES];
+  int nr, nc;
+  int x, y;
+  int i;
+  enum table_axis axis;
+
+  table = table_ref (table_);
+  nc = table_nc (table);
+  nr = table_nr (table);
+
+  /* Figure out rule widths. */
+  for (axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      int n = table->n[axis] + 1;
+      int z;
+
+      rules[axis] = xnmalloc (n, sizeof *rules);
+      for (z = 0; z < n; z++)
+        rules[axis][z] = measure_rule (params, table, axis, z);
+    }
+
+  /* Calculate minimum and maximum widths of cells that do not
+     span multiple columns. */
+  for (i = 0; i < 2; i++)
+    columns[i] = xzalloc (nc * sizeof *columns[i]);
+  for (y = 0; y < nr; y++)
+    for (x = 0; x < nc; )
+      {
+        struct table_cell cell;
+
+        table_get_cell (table, x, y, &cell);
+        if (y == cell.d[V][0] && table_cell_colspan (&cell) == 1)
+          {
+            int w[2];
+            int i;
+
+            params->measure_cell_width (params->aux, &cell, &w[MIN], &w[MAX]);
+            for (i = 0; i < 2; i++)
+              if (columns[i][x].unspanned < w[i])
+                columns[i][x].unspanned = w[i];
+          }
+        x = cell.d[H][1];
+        table_cell_free (&cell);
+      }
+
+  /* Distribute widths of spanned columns. */
+  for (i = 0; i < 2; i++)
+    for (x = 0; x < nc; x++)
+      columns[i][x].width = columns[i][x].unspanned;
+  for (y = 0; y < nr; y++)
+    for (x = 0; x < nc; )
+      {
+        struct table_cell cell;
+
+        table_get_cell (table, x, y, &cell);
+        if (y == cell.d[V][0] && table_cell_colspan (&cell) > 1)
+          {
+            int w[2];
+
+            params->measure_cell_width (params->aux, &cell, &w[MIN], &w[MAX]);
+            for (i = 0; i < 2; i++)
+              distribute_spanned_width (w[i], &columns[i][cell.d[H][0]],
+                                        rules[H], table_cell_colspan (&cell));
+          }
+        x = cell.d[H][1];
+        table_cell_free (&cell);
+      }
+
+  /* Decide final column widths. */
+  for (i = 0; i < 2; i++)
+    table_widths[i] = calculate_table_width (table_nc (table),
+                                             columns[i], rules[H]);
+  if (table_widths[MAX] <= params->size[H])
+    {
+      /* Fits even with maximum widths.  Use them. */
+      page = create_page_with_exact_widths (params, table, columns[MAX],
+                                            rules[H]);
+    }
+  else if (table_widths[MIN] <= params->size[H])
+    {
+      /* Fits with minimum widths, so distribute the leftover space. */
+      page = create_page_with_interpolated_widths (
+        params, table, columns[MIN], columns[MAX],
+        table_widths[MIN], table_widths[MAX], rules[H]);
+    }
+  else
+    {
+      /* Doesn't fit even with minimum widths.  Assign minimums for now, and
+         later we can break it horizontally into multiple pages. */
+      page = create_page_with_exact_widths (params, table, columns[MIN],
+                                            rules[H]);
+    }
+
+  /* Calculate heights of cells that do not span multiple rows. */
+  rows = xzalloc (nr * sizeof *rows);
+  for (y = 0; y < nr; y++)
+    {
+      for (x = 0; x < nc; )
+        {
+          struct render_row *r = &rows[y];
+          struct table_cell cell;
+
+          table_get_cell (table, x, y, &cell);
+          if (y == cell.d[V][0])
+            {
+              if (table_cell_rowspan (&cell) == 1)
+                {
+                  int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
+                  int h = params->measure_cell_height (params->aux, &cell, w);
+                  if (h > r->unspanned)
+                    r->unspanned = r->width = h;
+                }
+              else
+                set_join_crossings (page, V, &cell, rules[V]);
+
+              if (table_cell_colspan (&cell) > 1)
+                set_join_crossings (page, H, &cell, rules[H]);
+            }
+          x = cell.d[H][1];
+          table_cell_free (&cell);
+        }
+    }
+  for (i = 0; i < 2; i++)
+    free (columns[i]);
+
+  /* Distribute heights of spanned rows. */
+  for (y = 0; y < nr; y++)
+    for (x = 0; x < nc; )
+      {
+        struct table_cell cell;
+
+        table_get_cell (table, x, y, &cell);
+        if (y == cell.d[V][0] && table_cell_rowspan (&cell) > 1)
+          {
+            int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]);
+            int h = params->measure_cell_height (params->aux, &cell, w);
+            distribute_spanned_width (h, &rows[cell.d[V][0]], rules[V],
+                                      table_cell_rowspan (&cell));
+          }
+        x = cell.d[H][1];
+        table_cell_free (&cell);
+      }
+
+  /* Decide final row heights. */
+  accumulate_row_widths (page, V, rows, rules[V]);
+  free (rows);
+
+  /* Measure headers.  If they are "too big", get rid of them.  */
+  for (axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      int hw = headers_width (page, axis);
+      if (hw * 2 >= page->params->size[axis]
+          || hw + max_cell_width (page, axis) > page->params->size[axis])
+        {
+          page->table = table_unshare (page->table);
+          page->table->h[axis][0] = page->table->h[axis][1] = 0;
+          page->h[axis][0] = page->h[axis][1] = 0;
+        }
+    }
+
+  free (rules[H]);
+  free (rules[V]);
+
+  return page;
+}
+
+/* Increases PAGE's reference count. */
+struct render_page *
+render_page_ref (const struct render_page *page_)
+{
+  struct render_page *page = CONST_CAST (struct render_page *, page_);
+  page->ref_cnt++;
+  return page;
+}
+
+/* Decreases PAGE's reference count and destroys PAGE if this causes the
+   reference count to fall to zero. */
+void
+render_page_unref (struct render_page *page)
+{
+  if (page != NULL && --page->ref_cnt == 0)
+    {
+      struct render_overflow *overflow, *next;
+
+      HMAP_FOR_EACH_SAFE (overflow, next, struct render_overflow, node,
+                          &page->overflows)
+        free (overflow);
+      hmap_destroy (&page->overflows);
+
+      table_unref (page->table);
+      free (page->cp[H]);
+      free (page->cp[V]);
+      free (page);
+    }
+}
+
+/* Returns the size of PAGE along AXIS.  (This might be larger than the page
+   size specified in the parameters passed to render_page_create().  Use a
+   render_break to break up a render_page into page-sized chunks.) */
+int
+render_page_get_size (const struct render_page *page, enum table_axis axis)
+{
+  return page->cp[axis][page->n[axis] * 2 + 1];
+}
+\f
+/* Drawing render_pages. */
+
+static enum render_line_style
+get_rule (const struct render_page *page, enum table_axis axis,
+          const int d[TABLE_N_AXES])
+{
+  return rule_to_render_type (table_get_rule (page->table,
+                                              axis, d[H] / 2, d[V] / 2));
+}
+
+static bool
+is_rule (int z)
+{
+  return !(z & 1);
+}
+
+static void
+render_rule (const struct render_page *page, const int d[TABLE_N_AXES])
+{
+  enum render_line_style styles[TABLE_N_AXES][2];
+  enum table_axis a;
+
+  for (a = 0; a < TABLE_N_AXES; a++)
+    {
+      enum table_axis b = !a;
+
+      styles[a][0] = styles[a][1] = RENDER_LINE_NONE;
+
+      if (!is_rule (d[a])
+          || (page->is_edge_cutoff[a][0] && d[a] == 0)
+          || (page->is_edge_cutoff[a][1] && d[a] == page->n[a] * 2))
+        continue;
+
+      if (is_rule (d[b]))
+        {
+          if (d[b] > 0)
+            {
+              int e[TABLE_N_AXES];
+              e[H] = d[H];
+              e[V] = d[V];
+              e[b]--;
+              styles[a][0] = get_rule (page, a, e);
+            }
+
+          if (d[b] / 2 < page->table->n[b])
+            styles[a][1] = get_rule (page, a, d);
+        }
+      else
+        styles[a][0] = styles[a][1] = get_rule (page, a, d);
+    }
+
+  if (styles[H][0] != RENDER_LINE_NONE || styles[H][1] != RENDER_LINE_NONE
+      || styles[V][0] != RENDER_LINE_NONE || styles[V][1] != RENDER_LINE_NONE)
+    {
+      int bb[TABLE_N_AXES][2];
+
+      bb[H][0] = page->cp[H][d[H]];
+      bb[H][1] = page->cp[H][d[H] + 1];
+      bb[V][0] = page->cp[V][d[V]];
+      bb[V][1] = page->cp[V][d[V] + 1];
+      page->params->draw_line (page->params->aux, bb, styles);
+    }
+}
+
+static void
+render_cell (const struct render_page *page, const struct table_cell *cell)
+{
+  const struct render_overflow *of;
+  int bb[TABLE_N_AXES][2];
+  int clip[TABLE_N_AXES][2];
+
+  bb[H][0] = clip[H][0] = page->cp[H][cell->d[H][0] * 2 + 1];
+  bb[H][1] = clip[H][1] = page->cp[H][cell->d[H][1] * 2];
+  bb[V][0] = clip[V][0] = page->cp[V][cell->d[V][0] * 2 + 1];
+  bb[V][1] = clip[V][1] = page->cp[V][cell->d[V][1] * 2];
+
+  of = find_overflow (page, cell->d[H][0], cell->d[V][0]);
+  if (of)
+    {
+      enum table_axis axis;
+
+      for (axis = 0; axis < TABLE_N_AXES; axis++)
+        {
+          if (of->overflow[axis][0])
+            {
+              bb[axis][0] -= of->overflow[axis][0];
+              if (cell->d[axis][0] == 0)
+                clip[axis][0] = page->cp[axis][cell->d[axis][0] * 2];
+            }
+          if (of->overflow[axis][1])
+            {
+              bb[axis][1] += of->overflow[axis][1];
+              if (cell->d[axis][1] == page->n[axis])
+                clip[axis][1] = page->cp[axis][cell->d[axis][1] * 2 + 1];
+            }
+        }
+    }
+
+  page->params->draw_cell (page->params->aux, cell, bb, clip);
+}
+
+/* Renders PAGE, by calling the 'draw_line' and 'draw_cell' functions from the
+   render_params provided to render_page_create(). */
+void
+render_page_draw (const struct render_page *page)
+{
+  int x, y;
+
+  for (y = 0; y <= page->n[V] * 2; y++)
+    for (x = 0; x <= page->n[H] * 2; )
+      if (is_rule (x) || is_rule (y))
+        {
+          int d[TABLE_N_AXES];
+          d[H] = x;
+          d[V] = y;
+          render_rule (page, d);
+          x++;
+        }
+      else
+        {
+          struct table_cell cell;
+
+          table_get_cell (page->table, x / 2, y / 2, &cell);
+          if (y / 2 == cell.d[V][0])
+            render_cell (page, &cell);
+          x = rule_ofs (cell.d[H][1]);
+          table_cell_free (&cell);
+        }
+}
+\f
+/* Breaking up tables to fit on a page. */
+
+static int needed_size (const struct render_break *, int cell);
+static bool cell_is_breakable (const struct render_break *, int cell);
+static struct render_page *render_page_select (const struct render_page *,
+                                               enum table_axis,
+                                               int z0, int p0,
+                                               int z1, int p1);
+
+/* Initializes render_break B for breaking PAGE along AXIS.
+
+   Ownership of PAGE is transferred to B.  The caller must use
+   render_page_ref() if it needs to keep a copy of PAGE. */
+void
+render_break_init (struct render_break *b, struct render_page *page,
+                   enum table_axis axis)
+{
+  b->page = page;
+  b->axis = axis;
+  b->cell = page->h[axis][0];
+  b->pixel = 0;
+  b->hw = headers_width (page, axis);
+}
+
+/* Frees B and unrefs the render_page that it owns. */
+void
+render_break_destroy (struct render_break *b)
+{
+  if (b != NULL)
+    render_page_unref (b->page);
+}
+
+/* Returns true if B still has cells that are yet to be returned,
+   false if all of B's page has been processed. */
+bool
+render_break_has_next (const struct render_break *b)
+{
+  const struct render_page *page = b->page;
+  enum table_axis axis = b->axis;
+
+  return b->cell < page->n[axis] - page->h[axis][1];
+}
+
+/* Returns the minimum SIZE argument that, if passed to render_break_next(),
+   will avoid a null return value (if cells are still left). */
+int
+render_break_next_size (const struct render_break *b)
+{
+  const struct render_page *page = b->page;
+  enum table_axis axis = b->axis;
+
+  return (!render_break_has_next (b) ? 0
+          : !cell_is_breakable (b, b->cell) ? needed_size (b, b->cell + 1)
+          : b->hw + page->params->font_size[axis]);
+}
+
+/* Returns a new render_page that is up to SIZE pixels wide along B's axis.
+   Returns a null pointer if B has already been completely broken up, or if
+   SIZE is too small to reasonably render any cells.  The latter will never
+   happen if SIZE is at least as large as the page size passed to
+   render_page_create() along B's axis. */
+struct render_page *
+render_break_next (struct render_break *b, int size)
+{
+  const struct render_page *page = b->page;
+  enum table_axis axis = b->axis;
+  struct render_page *subpage;
+  int cell, pixel;
+
+  if (!render_break_has_next (b))
+    return NULL;
+
+  pixel = 0;
+  for (cell = b->cell; cell < page->n[axis] - page->h[axis][1]; cell++)
+    if (needed_size (b, cell + 1) > size)
+      {
+        if (!cell_is_breakable (b, cell))
+          {
+            if (cell == b->cell)
+              return NULL;
+          }
+        else
+          pixel = (cell == b->cell
+                   ? b->pixel + size - b->hw
+                   : size - needed_size (b, cell));
+        break;
+      }
+
+  subpage = render_page_select (page, axis, b->cell, b->pixel,
+                                pixel ? cell + 1 : cell,
+                                pixel ? cell_width (page, axis, cell) - pixel
+                                : 0);
+  b->cell = cell;
+  b->pixel = pixel;
+  return subpage;
+}
+
+/* Returns the width that would be required along B's axis to render a page
+   from B's current position up to but not including CELL. */
+static int
+needed_size (const struct render_break *b, int cell)
+{
+  const struct render_page *page = b->page;
+  enum table_axis axis = b->axis;
+  int size;
+
+  size = joined_width (page, axis, b->cell, cell) + b->hw - b->pixel;
+  if (page->h[axis][0] && page->h[axis][1])
+    size += page->join_crossing[axis][b->cell];
+
+  return size;
+}
+
+/* Returns true if CELL along B's axis may be broken across a page boundary.
+
+   This is just a heuristic.  Breaking cells across page boundaries can save
+   space, but it looks ugly. */
+static bool
+cell_is_breakable (const struct render_break *b, int cell)
+{
+  const struct render_page *page = b->page;
+  enum table_axis axis = b->axis;
+
+  return cell_width (page, axis, cell) > page->params->size[axis] / 2;
+}
+\f
+/* render_page_select() and helpers. */
+
+struct render_page_selection
+  {
+    const struct render_page *page; /* Page whose slice we are selecting. */
+    struct render_page *subpage; /* New page under construction. */
+    enum table_axis a;   /* Axis of 'page' along which 'subpage' is a slice. */
+    enum table_axis b;   /* The opposite of 'a'. */
+    int z0;              /* First cell along 'a' being selected. */
+    int z1;              /* Last cell being selected, plus 1. */
+    int p0;              /* Number of pixels to trim off left side of z0. */
+    int p1;              /* Number of pixels to trim off right side of z1-1. */
+  };
+
+static void cell_to_subpage (struct render_page_selection *,
+                             const struct table_cell *,
+                             int subcell[TABLE_N_AXES]);
+static const struct render_overflow *find_overflow_for_cell (
+  struct render_page_selection *, const struct table_cell *);
+static struct render_overflow *insert_overflow (struct render_page_selection *,
+                                                const struct table_cell *);
+
+/* Creates and returns a new render_page whose contents are a subregion of
+   PAGE's contents.  The new render_page includes cells Z0 through Z1 along
+   AXIS, plus any headers on AXIS.
+
+   If P0 is nonzero, then it is a number of pixels to exclude from the left or
+   top (according to AXIS) of cell Z0.  Similarly, P1 is a number of pixels to
+   exclude from the right or bottom of cell Z1 - 1.  (P0 and P1 are used to
+   render cells that are too large to fit on a single page.)
+
+   The whole of axis !AXIS is included.  (The caller may follow up with another
+   call to render_page_select() to select on !AXIS to select on that axis as
+   well.)
+
+   The caller retains ownership of PAGE, which is not modified. */
+static struct render_page *
+render_page_select (const struct render_page *page, enum table_axis axis,
+                    int z0, int p0, int z1, int p1)
+{
+  struct render_page_selection s;
+  enum table_axis a = axis;
+  enum table_axis b = !a;
+  struct render_page *subpage;
+  struct render_overflow *ro;
+  int *dcp, *scp;
+  int *jc;
+  int z;
+
+
+  /* Optimize case where all of PAGE is selected by just incrementing the
+     reference count. */
+  if (z0 == page->h[a][0] && p0 == 0
+      && z1 == page->n[a] - page->h[a][1] && p1 == 0)
+    {
+      struct render_page *page_rw = (struct render_page *) page;
+      page_rw->ref_cnt++;
+      return page_rw;
+    }
+
+  /* Allocate subpage. */
+  subpage = render_page_allocate (page->params,
+                                  table_select_slice (
+                                    table_ref (page->table),
+                                    a, z0, z1, true));
+
+  /* An edge is cut off if it was cut off in PAGE or if we're trimming pixels
+     off that side of the page and there are no headers. */
+  subpage->is_edge_cutoff[a][0] =
+    subpage->h[a][0] == 0 && (p0 || (z0 == 0 && page->is_edge_cutoff[a][0]));
+  subpage->is_edge_cutoff[a][1] =
+    subpage->h[a][1] == 0 && (p1 || (z1 == page->n[a]
+                                     && page->is_edge_cutoff[a][1]));
+  subpage->is_edge_cutoff[b][0] = page->is_edge_cutoff[b][0];
+  subpage->is_edge_cutoff[b][1] = page->is_edge_cutoff[b][1];
+
+  /* Select join crossings from PAGE into subpage. */
+  jc = subpage->join_crossing[a];
+  for (z = 0; z < page->h[a][0]; z++)
+    *jc++ = page->join_crossing[a][z];
+  for (z = z0; z <= z1; z++)
+    *jc++ = page->join_crossing[a][z];
+  for (z = page->n[a] - page->h[a][1]; z < page->n[a]; z++)
+    *jc++ = page->join_crossing[a][z];
+  assert (jc == &subpage->join_crossing[a][subpage->n[a] + 1]);
+
+  memcpy (subpage->join_crossing[b], page->join_crossing[b],
+          (subpage->n[b] + 1) * sizeof **subpage->join_crossing);
+
+  /* Select widths from PAGE into subpage. */
+  scp = page->cp[a];
+  dcp = subpage->cp[a];
+  *dcp = 0;
+  for (z = 0; z <= rule_ofs (subpage->h[a][0]); z++, dcp++)
+    dcp[1] = dcp[0] + (scp[z + 1] - scp[z]);
+  for (z = cell_ofs (z0); z <= cell_ofs (z1 - 1); z++, dcp++)
+    {
+      dcp[1] = dcp[0] + (scp[z + 1] - scp[z]);
+      if (z == cell_ofs (z0))
+        {
+          dcp[1] -= p0;
+          if (page->h[a][0] && page->h[a][1])
+            dcp[1] += page->join_crossing[a][z / 2];
+        }
+      if (z == cell_ofs (z1 - 1))
+        dcp[1] -= p1;
+    }
+  for (z = rule_ofs_r (page, a, subpage->h[a][1]);
+       z <= rule_ofs_r (page, a, 0); z++, dcp++)
+    dcp[1] = dcp[0] + (scp[z + 1] - scp[z]);
+  assert (dcp == &subpage->cp[a][2 * subpage->n[a] + 1]);
+
+  for (z = 0; z < page->n[b] * 2 + 2; z++)
+    subpage->cp[b][z] = page->cp[b][z];
+
+  /* Add new overflows. */
+  s.page = page;
+  s.a = a;
+  s.b = b;
+  s.z0 = z0;
+  s.z1 = z1;
+  s.p0 = p0;
+  s.p1 = p1;
+  s.subpage = subpage;
+
+  for (z = 0; z < page->n[b]; z++)
+    {
+      struct table_cell cell;
+      int d[TABLE_N_AXES];
+
+      d[a] = z0;
+      d[b] = z;
+      table_get_cell (page->table, d[H], d[V], &cell);
+      if ((z == cell.d[b][0] && (p0 || cell.d[a][0] < z0))
+          || (z == cell.d[b][1] - 1 && p1))
+        {
+          ro = insert_overflow (&s, &cell);
+          ro->overflow[a][0] += p0 + axis_width (page, a,
+                                                 cell_ofs (cell.d[a][0]),
+                                                 cell_ofs (z0));
+          if (z1 == z0 + 1)
+            ro->overflow[a][1] += p1;
+          if (page->h[a][0] && page->h[a][1])
+            ro->overflow[a][0] -= page->join_crossing[a][cell.d[a][0] + 1];
+          if (cell.d[a][1] > z1)
+            ro->overflow[a][1] += axis_width (page, a, cell_ofs (z1),
+                                              cell_ofs (cell.d[a][1]));
+        }
+      table_cell_free (&cell);
+    }
+
+  for (z = 0; z < page->n[b]; z++)
+    {
+      struct table_cell cell;
+      int d[TABLE_N_AXES];
+
+      /* XXX need to handle p1 below */
+      d[a] = z1 - 1;
+      d[b] = z;
+      table_get_cell (page->table, d[H], d[V], &cell);
+      if (z == cell.d[b][0] && cell.d[a][1] > z1
+          && find_overflow_for_cell (&s, &cell) == NULL)
+        {
+          ro = insert_overflow (&s, &cell);
+          ro->overflow[a][1] += axis_width (page, a, cell_ofs (z1),
+                                            cell_ofs (cell.d[a][1]));
+        }
+      table_cell_free (&cell);
+    }
+
+  /* Copy overflows from PAGE into subpage. */
+  HMAP_FOR_EACH (ro, struct render_overflow, node, &page->overflows)
+    {
+      struct table_cell cell;
+
+      table_get_cell (page->table, ro->d[H], ro->d[V], &cell);
+      if (cell.d[a][1] > z0 && cell.d[a][0] < z1
+          && find_overflow_for_cell (&s, &cell) == NULL)
+        insert_overflow (&s, &cell);
+      table_cell_free (&cell);
+    }
+
+  return subpage;
+}
+
+/* Given CELL, a table_cell within S->page, stores in SUBCELL the (x,y)
+   coordinates of the top-left cell as it will appear in S->subpage.
+
+   CELL must actually intersect the region of S->page that is being selected
+   by render_page_select() or the results will not make any sense. */
+static void
+cell_to_subpage (struct render_page_selection *s,
+                 const struct table_cell *cell, int subcell[TABLE_N_AXES])
+{
+  enum table_axis a = s->a;
+  enum table_axis b = s->b;
+  int ha0 = s->subpage->h[a][0];
+
+  subcell[a] = MAX (cell->d[a][0] - s->z0 + ha0, ha0);
+  subcell[b] = cell->d[b][0];
+}
+
+/* Given CELL, a table_cell within S->page, returns the render_overflow for
+   that cell in S->subpage, if there is one, and a null pointer otherwise.
+
+   CELL must actually intersect the region of S->page that is being selected
+   by render_page_select() or the results will not make any sense. */
+static const struct render_overflow *
+find_overflow_for_cell (struct render_page_selection *s,
+                        const struct table_cell *cell)
+{
+  int subcell[2];
+
+  cell_to_subpage (s, cell, subcell);
+  return find_overflow (s->subpage, subcell[H], subcell[V]);
+}
+
+/* Given CELL, a table_cell within S->page, inserts a render_overflow for that
+   cell in S->subpage (which must not already exist).  Initializes the new
+   render_overflow's 'overflow' member from the overflow for CELL in S->page,
+   if there is one.
+
+   CELL must actually intersect the region of S->page that is being selected
+   by render_page_select() or the results will not make any sense. */
+static struct render_overflow *
+insert_overflow (struct render_page_selection *s,
+                 const struct table_cell *cell)
+{
+  const struct render_overflow *old;
+  struct render_overflow *of;
+
+  of = xzalloc (sizeof *of);
+  cell_to_subpage (s, cell, of->d);
+  hmap_insert (&s->subpage->overflows, &of->node,
+               hash_overflow (of->d[H], of->d[V]));
+
+  old = find_overflow (s->page, cell->d[H][0], cell->d[V][0]);
+  if (old != NULL)
+    memcpy (of->overflow, old->overflow, sizeof of->overflow);
+
+  return of;
+}
+
diff --git a/src/output/render.h b/src/output/render.h
new file mode 100644 (file)
index 0000000..cfba52e
--- /dev/null
@@ -0,0 +1,115 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_RENDER_H
+#define OUTPUT_RENDER_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <output/table-provider.h>
+
+struct table;
+
+enum render_line_style
+  {
+    RENDER_LINE_NONE,           /* No line. */
+    RENDER_LINE_SINGLE,         /* Single line. */
+    RENDER_LINE_DOUBLE,         /* Double line. */
+    RENDER_N_LINES
+  };
+
+struct render_params
+  {
+    /* Measures CELL's width.  Stores in *MIN_WIDTH the minimum width required
+       to avoid splitting a single word across multiple lines (normally, this
+       is the width of the longest word in the cell) and in *MAX_WIDTH the
+       minimum width required to avoid line breaks other than at new-lines. */
+    void (*measure_cell_width) (void *aux, const struct table_cell *cell,
+                                int *min_width, int *max_width);
+
+    /* Returns the height required to render CELL given a width of WIDTH. */
+    int (*measure_cell_height) (void *aux, const struct table_cell *cell,
+                                int width);
+
+    /* Draws a generalized intersection of lines in the rectangle whose
+       top-left corner is (BB[TABLE_HORZ][0], BB[TABLE_VERT][0]) and whose
+       bottom-right corner is (BB[TABLE_HORZ][1], BB[TABLE_VERT][1]).
+
+       STYLES is interpreted this way:
+
+       STYLES[TABLE_HORZ][0]: style of line from top of BB to its center.
+       STYLES[TABLE_HORZ][1]: style of line from bottom of BB to its center.
+       STYLES[TABLE_VERT][0]: style of line from left of BB to its center.
+       STYLES[TABLE_VERT][1]: style of line from right of BB to its center. */
+    void (*draw_line) (void *aux, int bb[TABLE_N_AXES][2],
+                       enum render_line_style styles[TABLE_N_AXES][2]);
+
+    /* Draws CELL within bounding box BB.  CLIP is the same as BB (the common
+       case) or a subregion enclosed by BB.  In the latter case only the part
+       of the cell that lies within CLIP should actually be drawn, although BB
+       should used to determine the layout of the cell. */
+    void (*draw_cell) (void *aux, const struct table_cell *cell,
+                       int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]);
+
+    /* Auxiliary data passed to each of the above functions. */
+    void *aux;
+
+    /* Page size to try to fit the rendering into.  Some tables will, of
+       course, overflow this size. */
+    int size[TABLE_N_AXES];
+
+    /* Nominal size of a character in the most common font:
+       font_size[TABLE_HORZ]: Em width.
+       font_size[TABLE_VERT]: Line spacing. */
+    int font_size[TABLE_N_AXES];
+
+    /* Width of different kinds of lines. */
+    int line_widths[TABLE_N_AXES][RENDER_N_LINES];
+  };
+\f
+/* A "page" of content that is ready to be rendered.
+
+   A page's size is not limited to the size passed in as part of render_params.
+   Use render_break (see below) to break a too-big render_page into smaller
+   render_pages that will fit in the available space. */
+struct render_page *render_page_create (const struct render_params *,
+                                        const struct table *);
+
+struct render_page *render_page_ref (const struct render_page *);
+void render_page_unref (struct render_page *);
+
+int render_page_get_size (const struct render_page *, enum table_axis);
+void render_page_draw (const struct render_page *);
+\f
+/* An iterator for breaking render_pages into smaller chunks. */
+struct render_break
+  {
+    struct render_page *page;   /* Page being broken up. */
+    enum table_axis axis;       /* Axis along which 'page' is being broken. */
+    int cell;                   /* Next cell. */
+    int pixel;                  /* Pixel offset within 'cell' (usually 0). */
+    int hw;                     /* Width of headers of 'page' along 'axis'. */
+  };
+
+void render_break_init (struct render_break *, struct render_page *,
+                        enum table_axis);
+void render_break_destroy (struct render_break *);
+
+bool render_break_has_next (const struct render_break *);
+int render_break_next_size (const struct render_break *);
+struct render_page *render_break_next (struct render_break *, int size);
+
+#endif /* output/render.h */
diff --git a/src/output/tab.c b/src/output/tab.c
new file mode 100644 (file)
index 0000000..058cb97
--- /dev/null
@@ -0,0 +1,765 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2006, 2009 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/tab.h>
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <data/data-out.h>
+#include <data/format.h>
+#include <data/settings.h>
+#include <data/value.h>
+#include <data/dictionary.h>
+#include <libpspp/assertion.h>
+#include <libpspp/compiler.h>
+#include <libpspp/misc.h>
+#include <libpspp/pool.h>
+#include <output/driver.h>
+#include <output/table-item.h>
+#include <output/table-provider.h>
+#include <output/text-item.h>
+
+#include "error.h"
+#include "minmax.h"
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+\f
+/* Set in the options field of cells that  */
+#define TAB_JOIN (1u << TAB_FIRST_AVAILABLE)
+
+/* Joined cell. */
+struct tab_joined_cell
+  {
+    int d[TABLE_N_AXES][2];     /* Table region, same as struct table_cell. */
+    char *contents;
+  };
+
+static const struct table_class tab_table_class;
+
+/* 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 *
+tab_create (int nc, int nr)
+{
+  struct tab_table *t;
+
+  t = pool_create_container (struct tab_table, container);
+  table_init (&t->table, &tab_table_class);
+  table_set_nc (&t->table, nc);
+  table_set_nr (&t->table, nr);
+
+  t->title = NULL;
+  t->cf = nc;
+  t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
+  t->ct = pool_malloc (t->container, nr * nc);
+  memset (t->ct, 0, nc * nr);
+
+  t->rh = pool_nmalloc (t->container, nc, nr + 1);
+  memset (t->rh, 0, nc * (nr + 1));
+
+  t->rv = pool_nmalloc (t->container, nr, nc + 1);
+  memset (t->rv, TAL_GAP, nr * (nc + 1));
+
+  t->col_ofs = t->row_ofs = 0;
+
+  return t;
+}
+
+/* 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)
+{
+  assert (t != NULL);
+  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;
+
+  assert (t != NULL);
+  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 char *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);
+         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_realloc (t->container, t->ct, nr * nc);
+
+      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_GAP,
+                  (nr - tab_nr (t)) * (nc + 1));
+       }
+    }
+
+  memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)));
+  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
+   multiple pages. */
+void
+tab_headers (struct tab_table *table, int l, int r, int t, int b)
+{
+  table_set_hl (&table->table, l);
+  table_set_hr (&table->table, r);
+  table_set_ht (&table->table, t);
+  table_set_hb (&table->table, b);
+}
+\f
+/* Rules. */
+
+/* Draws a vertical line to the left of cells at horizontal position X
+   from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
+void
+tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
+{
+  assert (t != NULL);
+
+#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))
+    {
+      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));
+      return;
+    }
+#endif
+
+  x += t->col_ofs;
+  y1 += t->row_ofs;
+  y2 += t->row_ofs;
+
+  assert (x >= 0);
+  assert (x <= tab_nc (t));
+  assert (y1 >= 0);
+  assert (y2 >= y1);
+  assert (y2 <= tab_nr (t));
+
+  if (style != -1)
+    {
+      int y;
+      for (y = y1; y <= y2; y++)
+        t->rv[x + (t->cf + 1) * y] = style;
+    }
+}
+
+/* Draws a horizontal line above cells at vertical position Y from X1
+   to X2 inclusive in style STYLE, if style is not -1. */
+void
+tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
+{
+  assert (t != NULL);
+
+  x1 += t->col_ofs;
+  x2 += t->col_ofs;
+  y += t->row_ofs;
+
+  assert (y >= 0);
+  assert (y <= tab_nr (t));
+  assert (x2 >= x1 );
+  assert (x1 >= 0 );
+  assert (x2 < tab_nc (t));
+
+  if (style != -1)
+    {
+      int x;
+      for (x = x1; x <= x2; x++)
+        t->rh[x + t->cf * y] = style;
+    }
+}
+
+/* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
+   lines of style F_H and vertical lines of style F_V.  Fills the
+   interior of the box with horizontal lines of style I_H and vertical
+   lines of style I_V.  Any of the line styles may be -1 to avoid
+   drawing those lines.  This is distinct from 0, which draws a null
+   line. */
+void
+tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
+        int x1, int y1, int x2, int y2)
+{
+  assert (t != NULL);
+
+#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))
+    {
+      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));
+      NOT_REACHED ();
+    }
+#endif
+
+  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);
+  assert (y1 >= 0);
+  assert (x2 < tab_nc (t));
+  assert (y2 < tab_nr (t));
+
+  if (f_h != -1)
+    {
+      int x;
+      for (x = x1; x <= x2; x++)
+        {
+          t->rh[x + t->cf * y1] = f_h;
+          t->rh[x + t->cf * (y2 + 1)] = f_h;
+        }
+    }
+  if (f_v != -1)
+    {
+      int y;
+      for (y = y1; y <= y2; y++)
+        {
+          t->rv[x1 + (t->cf + 1) * y] = f_v;
+          t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
+        }
+    }
+
+  if (i_h != -1)
+    {
+      int y;
+
+      for (y = y1 + 1; y <= y2; y++)
+       {
+         int x;
+
+          for (x = x1; x <= x2; x++)
+            t->rh[x + t->cf * y] = i_h;
+       }
+    }
+  if (i_v != -1)
+    {
+      int x;
+
+      for (x = x1 + 1; x <= x2; x++)
+       {
+         int y;
+
+          for (y = y1; y <= y2; y++)
+            t->rv[x + (t->cf + 1) * y] = 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 char opt,
+          const union value *v, const struct dictionary *dict, 
+          const struct fmt_spec *f)
+{
+  char *contents;
+
+  assert (table != NULL && v != NULL && f != NULL);
+#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;
+    }
+#endif
+
+  contents = data_out_pool (v, dict_get_encoding (dict), f, 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
+   with NDEC decimal places. */
+void
+tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
+          double val, int w, int d)
+{
+  struct fmt_spec f;
+  union value double_value;
+  char *s;
+
+  assert (c >= 0);
+  assert (c < tab_nc (table));
+  assert (r >= 0);
+  assert (r < tab_nr (table));
+
+  f = fmt_for_output (FMT_F, w, d);
+
+#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_fixed(): 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;
+    }
+#endif
+
+  double_value.f = val;
+  s = data_out_pool (&double_value, LEGACY_NATIVE, &f, table->container);
+
+  table->cc[c + r * table->cf] = s + strspn (s, " ");
+  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 char opt,
+          double val, const struct fmt_spec *fmt)
+{
+  union value double_value ;
+  char *s;
+
+  assert (table != NULL);
+
+  assert (c >= 0);
+  assert (c < tab_nc (table));
+  assert (r >= 0);
+  assert (r < tab_nr (table));
+
+  if ( fmt == NULL)
+    fmt = settings_get_format ();
+
+  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;
+    }
+#endif
+
+  double_value.f = val;
+  s = data_out_pool (&double_value, LEGACY_NATIVE, 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)
+{
+  assert (c >= 0 );
+  assert (r >= 0 );
+  assert (c < tab_nc (table));
+  assert (r < tab_nr (table));
+
+#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_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));
+      return;
+    }
+#endif
+
+  table->cc[c + r * table->cf] = text;
+  table->ct[c + r * table->cf] = opt;
+}
+
+/* Sets cell (C,R) in TABLE, with options OPT, to have text value
+   TEXT. */
+void
+tab_text (struct tab_table *table, int c, int r, unsigned opt,
+          const char *text)
+{
+  do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
+}
+
+/* Sets cell (C,R) in TABLE, with options OPT, to have text value
+   FORMAT, which is formatted as if passed to printf. */
+void
+tab_text_format (struct tab_table *table, int c, int r, unsigned opt,
+                 const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  do_tab_text (table, c, r, opt,
+               pool_vasprintf (table->container, format, args));
+  va_end (args);
+}
+
+static void
+do_tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
+                   unsigned opt, char *text)
+{
+  struct tab_joined_cell *j;
+
+  assert (x1 + table->col_ofs >= 0);
+  assert (y1 + table->row_ofs >= 0);
+  assert (y2 >= y1);
+  assert (x2 >= x1);
+  assert (y2 + table->row_ofs < tab_nr (table));
+  assert (x2 + table->col_ofs < 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 < y2 || y2 + table->row_ofs >= 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));
+      return;
+    }
+#endif
+
+  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->contents = text;
+
+  opt |= TAB_JOIN;
+
+  {
+    void **cc = &table->cc[x1 + y1 * table->cf];
+    unsigned char *ct = &table->ct[x1 + y1 * table->cf];
+    const int ofs = table->cf - (x2 - x1);
+
+    int y;
+
+    for (y = y1; y < y2; y++)
+      {
+       int x;
+
+       for (x = x1; x < x2; x++)
+         {
+           *cc++ = j;
+           *ct++ = opt;
+         }
+
+       cc += ofs;
+       ct += ofs;
+      }
+  }
+}
+
+/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
+   options OPT to have text value TEXT. */
+void
+tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
+                unsigned opt, const char *text)
+{
+  do_tab_joint_text (table, x1, y1, x2, y2, opt,
+                     pool_strdup (table->container, text));
+}
+
+/* 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;
+
+  va_start (args, format);
+  do_tab_joint_text (table, x1, y1, x2, y2, opt,
+                     pool_vasprintf (table->container, format, args));
+  va_end (args);
+}
+
+bool
+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);
+}
+
+/* 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));
+}
+\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;
+
+  assert (t != NULL);
+#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 ();
+    }
+#endif
+
+  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)
+{
+  assert (t != NULL);
+  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.
+
+   This function is obsolete.  Please do not add new uses of it.  Instead, use
+   a text_item (see output/text-item.h). */
+void
+tab_output_text (int options, const char *string)
+{
+  enum text_item_type type = (options & TAB_EMPH ? TEXT_ITEM_SUBHEAD
+                              : options & TAB_FIX ? TEXT_ITEM_MONOSPACE
+                              : TEXT_ITEM_PARAGRAPH);
+  text_item_submit (text_item_create (type, string));
+}
+
+/* Same as tab_output_text(), but FORMAT is passed through printf-like
+   formatting before output. */
+void
+tab_output_text_format (int options, const char *format, ...)
+{
+  va_list args;
+  char *text;
+
+  va_start (args, format);
+  text = xvasprintf (format, args);
+  va_end (args);
+
+  tab_output_text (options, text);
+
+  free (text);
+}
+\f
+/* Table class implementation. */
+
+static void
+tab_destroy (struct table *table)
+{
+  struct tab_table *t = tab_cast (table);
+  pool_destroy (t->container);
+}
+
+static void
+tab_get_cell (const struct table *table, int x, int y, struct table_cell *cell)
+{
+  const struct tab_table *t = tab_cast (table);
+  int index = x + y * t->cf;
+  unsigned char opt = t->ct[index];
+  const void *content = t->cc[index];
+
+  cell->options = opt;
+  if (opt & TAB_JOIN)
+    {
+      const struct tab_joined_cell *jc = content;
+      cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
+      cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
+      cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
+      cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
+      cell->contents = jc->contents;
+    }
+  else
+    {
+      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->contents = content != NULL ? content : "";
+    }
+  cell->destructor = NULL;
+}
+
+static int
+tab_get_rule (const struct table *table, enum table_axis axis, int x, int y)
+{
+  const struct tab_table *t = tab_cast (table);
+  return (axis == TABLE_VERT
+          ? t->rh[x + t->cf * y]
+          : t->rv[x + (t->cf + 1) * y]);
+}
+
+static const struct table_class tab_table_class =
+  {
+    tab_destroy,
+    tab_get_cell,
+    tab_get_rule,
+    NULL,                       /* paste */
+    NULL,                       /* select */
+  };
+
+struct tab_table *
+tab_cast (const struct table *table)
+{
+  assert (table->class == &tab_table_class);
+  return UP_CAST (table, struct tab_table, table);
+}
diff --git a/src/output/tab.h b/src/output/tab.h
new file mode 100644 (file)
index 0000000..db38b6b
--- /dev/null
@@ -0,0 +1,150 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997, 1998, 1999, 2000, 2009 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_TAB_H
+#define OUTPUT_TAB_H
+
+/* Simple table class.
+
+   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.  The title (or caption, actually) is a property of the
+         table_item (see output/table-item.h) in which a table is embedded,
+         not a property 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>
+
+/* A table. */
+struct tab_table
+  {
+    struct table table;
+    struct pool *container;
+
+    /* Table title, or a null pointer if no title has been set.
+
+       The table title is properly part of struct table_item, not struc*/
+    char *title;
+    int cf;                    /* Column factor for indexing purposes. */
+
+    /* Table contents.
+
+       Each array element in cc[] is ordinarily a "char *" pointer to a
+       string.  If TAB_JOIN (defined in tab.c) is set in ct[] for the element,
+       however, it is a joined cell and the corresponding element of cc[]
+       points to a struct tab_joined_cell. */
+    void **cc;                  /* Cell contents; void *[nr][nc]. */
+    unsigned char *ct;         /* Cell types; unsigned char[nr][nc]. */
+
+    /* Rules. */
+    unsigned char *rh;         /* Horiz rules; unsigned char[nr+1][nc]. */
+    unsigned char *rv;         /* Vert rules; unsigned char[nr][nc+1]. */
+
+    /* X and Y offsets. */
+    int col_ofs, row_ofs;
+  };
+
+struct tab_table *tab_cast (const struct table *);
+
+/* Number of rows or columns in TABLE. */
+static inline int tab_nr (const struct tab_table *table)
+        { return table_nr (&table->table); }
+static inline int tab_nc (const struct tab_table *table)
+        { return table_nc (&table->table); }
+
+/* Number of left/right/top/bottom header columns/rows in TABLE. */
+static inline int tab_l (const struct tab_table *table)
+        { return table_hl (&table->table); }
+static inline int tab_r (const struct tab_table *table)
+        { return table_hr (&table->table); }
+static inline int tab_t (const struct tab_table *table)
+        { return table_ht (&table->table); }
+static inline int tab_b (const struct tab_table *table)
+        { return table_hb (&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_submit (struct tab_table *);
+
+/* Rules. */
+void tab_hline (struct tab_table *, int style, int x1, int x2, int y);
+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. */
+
+/* Cells. */
+struct fmt_spec;
+struct dictionary;
+union value;
+void tab_value (struct tab_table *, int c, int r, unsigned char opt,
+               const union value *, const struct dictionary *dict,
+               const struct fmt_spec *);
+
+void tab_fixed (struct tab_table *, int c, int r, unsigned char opt,
+               double v, int w, int d);
+
+void tab_double (struct tab_table *, int c, int r, unsigned char opt,
+               double v, const struct fmt_spec *);
+
+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 *, ...)
+     PRINTF_FORMAT (5, 6);
+
+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);
+
+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 *, ...)
+     PRINTF_FORMAT (2, 3);
+
+#endif /* output/tab.h */
+
diff --git a/src/output/table-casereader.c b/src/output/table-casereader.c
new file mode 100644 (file)
index 0000000..4a1452c
--- /dev/null
@@ -0,0 +1,155 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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->class == &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;
+
+  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->options = TAB_RIGHT;
+  if (tc->heading != NULL)
+    {
+      if (y == 0)
+        {
+          s = xstrdup (tc->heading);
+          cell->contents = 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->contents = 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 table_casereader *tc = table_casereader_cast (t);
+  return axis == TABLE_VERT && tc->heading != NULL && y == 1 ? TAL_1 : 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) */
+  };
diff --git a/src/output/table-item.c b/src/output/table-item.c
new file mode 100644 (file)
index 0000000..b709273
--- /dev/null
@@ -0,0 +1,92 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <assert.h>
+
+#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
+#include <output/driver.h>
+#include <output/output-item-provider.h>
+#include <output/table-item.h>
+
+#include "gl/xalloc.h"
+
+/* Initializes ITEM as a table item for rendering TABLE.  The new table item
+   initially has the specified CAPTION, which may be NULL if no caption is yet
+   available.  The caller retains ownership of CAPTION. */
+struct table_item *
+table_item_create (struct table *table, const char *caption)
+{
+  struct table_item *item = xmalloc (sizeof *item);
+  output_item_init (&item->output_item, &table_item_class);
+  item->table = table;
+  item->caption = caption != NULL ? xstrdup (caption) : NULL;
+  return item;
+}
+
+/* Returns the table contained by TABLE_ITEM.  The caller must not modify or
+   unref the returned table. */
+const struct table *
+table_item_get_table (const struct table_item *table_item)
+{
+  return table_item->table;
+}
+
+/* Returns ITEM's caption, which is a null pointer if no caption has been
+   set. */
+const char *
+table_item_get_caption (const struct table_item *item)
+{
+  return item->caption;
+}
+
+/* Sets ITEM's caption to CAPTION, replacing any previous caption.  Specify
+   NULL for CAPTION to clear any caption from ITEM.  The caller retains
+   ownership of CAPTION.
+
+   This function may only be used on a table_item that is unshared. */
+void
+table_item_set_caption (struct table_item *item, const char *caption)
+{
+  assert (!table_item_is_shared (item));
+  free (item->caption);
+  item->caption = caption != NULL ? xstrdup (caption) : NULL;
+}
+
+/* Submits TABLE_ITEM to the configured output drivers, and transfers ownership
+   to the output subsystem. */
+void
+table_item_submit (struct table_item *table_item)
+{
+  output_submit (&table_item->output_item);
+}
+\f
+static void
+table_item_destroy (struct output_item *output_item)
+{
+  struct table_item *item = to_table_item (output_item);
+  free (item->caption);
+  table_unref (item->table);
+}
+
+const struct output_item_class table_item_class =
+  {
+    table_item_destroy,
+  };
diff --git a/src/output/table-item.h b/src/output/table-item.h
new file mode 100644 (file)
index 0000000..01e9899
--- /dev/null
@@ -0,0 +1,103 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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_TABLE_ITEM_H
+#define OUTPUT_TABLE_ITEM_H 1
+
+/* Table items.
+
+   A table item is a subclass of an output item (see output-item.h) that
+   contains a table (see table.h) and some formatting properties (currently
+   just a caption). */
+
+#include <libpspp/compiler.h>
+#include <output/output-item.h>
+
+/* A table item.
+
+   The members of struct table_item should not be accessed directly.  Use one
+   of the accessor functions defined below. */
+struct table_item
+  {
+    struct output_item output_item; /* Superclass. */
+    struct table *table;        /* The table to be rendered. */
+    char *caption;              /* May be null if there is no caption. */
+  };
+
+struct table_item *table_item_create (struct table *, const char *caption);
+
+const struct table *table_item_get_table (const struct table_item *);
+
+const char *table_item_get_caption (const struct table_item *);
+void table_item_set_caption (struct table_item *, const char *);
+\f
+/* This boilerplate for table_item, a subclass of output_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct output_item_class table_item_class;
+
+/* Returns true if SUPER is a table_item, otherwise false. */
+static inline bool
+is_table_item (const struct output_item *super)
+{
+  return super->class == &table_item_class;
+}
+
+/* Returns SUPER converted to table_item.  SUPER must be a table_item, as
+   reported by is_table_item. */
+static inline struct table_item *
+to_table_item (const struct output_item *super)
+{
+  assert (is_table_item (super));
+  return UP_CAST (super, struct table_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+table_item_super (const struct table_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct table_item *
+table_item_ref (const struct table_item *instance)
+{
+  return to_table_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+table_item_unref (struct table_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+table_item_is_shared (const struct table_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void table_item_submit (struct table_item *);
+\f
+#endif /* output/table-item.h */
diff --git a/src/output/table-paste.c b/src/output/table-paste.c
new file mode 100644 (file)
index 0000000..102b514
--- /dev/null
@@ -0,0 +1,317 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <libpspp/assertion.h>
+#include <libpspp/tower.h>
+#include <output/table-provider.h>
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+struct paste_subtable
+  {
+    struct tower_node node;
+    struct table *table;
+  };
+
+static struct paste_subtable *
+paste_subtable_cast (struct tower_node *node)
+{
+  return tower_data (node, struct paste_subtable, node);
+}
+
+struct table_paste
+  {
+    struct table table;
+    struct tower subtables;
+    enum table_axis orientation;
+  };
+
+static const struct table_class table_paste_class;
+
+static struct table_paste *
+table_paste_cast (const struct table *table)
+{
+  assert (table->class == &table_paste_class);
+  return UP_CAST (table, struct table_paste, table);
+}
+
+static bool
+is_table_paste (const struct table *table, int orientation)
+{
+  return (table->class == &table_paste_class
+          && table_paste_cast (table)->orientation == orientation);
+}
+
+static struct paste_subtable *
+paste_subtable_lookup (struct table_paste *tp, unsigned long int offset,
+                       unsigned long int *start)
+{
+  return paste_subtable_cast (tower_lookup (&tp->subtables, offset, start));
+}
+
+/* This must be called *before* adding TABLE to TP, otherwise the test for
+   whether TP is empty will not have the correct effect. */
+static void
+table_paste_increase_size (struct table_paste *tp,
+                           const struct table *table)
+{
+  int o = tp->orientation;
+  int h0, h1;
+
+  tp->table.n[o] += table->n[o];
+  tp->table.n[!o] = MAX (tp->table.n[!o], table->n[!o]);
+
+  h0 = table->h[!o][0];
+  h1 = table->h[!o][1];
+  if (tower_is_empty (&tp->subtables))
+    {
+      tp->table.h[!o][0] = h0;
+      tp->table.h[!o][1] = h1;
+    }
+  else
+    {
+      tp->table.h[!o][0] = MIN (tp->table.h[!o][0], h0);
+
+      /* XXX this is not quite right */
+      tp->table.h[!o][1] = MIN (tp->table.h[!o][1], h1);
+    }
+}
+
+static void
+reassess_headers (struct table_paste *tp)
+{
+  int o = tp->orientation;
+  if (tower_is_empty (&tp->subtables))
+    tp->table.h[o][0] = tp->table.h[o][1] = 0;
+  else
+    {
+      struct paste_subtable *h0, *h1;
+
+      h0 = paste_subtable_cast (tower_first (&tp->subtables));
+      tp->table.h[o][0] = h0->table->h[o][0];
+
+      h1 = paste_subtable_cast (tower_last (&tp->subtables));
+      tp->table.h[o][1] = h1->table->h[o][1];
+    }
+}
+
+static void
+table_paste_insert_subtable (struct table_paste *tp,
+                             struct table *table,
+                             struct tower_node *under)
+{
+  struct paste_subtable *subtable;
+
+  subtable = xmalloc (sizeof *subtable);
+  table_paste_increase_size (tp, table);
+  tower_insert (&tp->subtables, table->n[tp->orientation],
+                &subtable->node, under);
+  subtable->table = table;
+  reassess_headers (tp);
+}
+
+/* Takes ownership of A and B and returns a table that consists of tables A and
+   B "pasted together", that is, a table whose size is the sum of the sizes of
+   A and B along the axis specified by ORIENTATION.  A and B should have the
+   same size along the axis opposite ORIENTATION; the handling of tables that
+   have different sizes along that axis may vary.
+
+   The rules at the seam between A and B are combined.  The exact way in which
+   they are combined is unspecified, but the method of table_rule_combine() is
+   typical.
+
+   If A or B is null, returns the other argument. */
+struct table *
+table_paste (struct table *a, struct table *b, enum table_axis orientation)
+{
+  struct table_paste *tp;
+
+  /* Handle nulls. */
+  if (a == NULL)
+    return b;
+  if (b == NULL)
+    return a;
+
+  /* Handle tables that know how to paste themselves. */
+  if (!table_is_shared (a) && !table_is_shared (b) && a != b)
+    {
+      if (a->class->paste != NULL)
+        {
+          struct table *new = a->class->paste (a, b, orientation);
+          if (new != NULL)
+            return new;
+        }
+      if (b->class->paste != NULL && a->class != b->class)
+        {
+          struct table *new = b->class->paste (a, b, orientation);
+          if (new != NULL)
+            return new;
+        }
+    }
+
+  /* Create new table_paste and insert A and B into it. */
+  tp = xmalloc (sizeof *tp);
+  table_init (&tp->table, &table_paste_class);
+  tower_init (&tp->subtables);
+  tp->orientation = orientation;
+  table_paste_insert_subtable (tp, a, NULL);
+  table_paste_insert_subtable (tp, b, NULL);
+  return &tp->table;
+}
+
+/* Shorthand for table_paste (left, right, TABLE_HORZ). */
+struct table *
+table_hpaste (struct table *left, struct table *right)
+{
+  return table_paste (left, right, TABLE_HORZ);
+}
+
+/* Shorthand for table_paste (left, right, TABLE_VERT). */
+struct table *
+table_vpaste (struct table *left, struct table *right)
+{
+  return table_paste (left, right, TABLE_VERT);
+}
+
+static void
+table_paste_destroy (struct table *t)
+{
+  struct table_paste *tp = table_paste_cast (t);
+  struct tower_node *node, *next;
+
+  for (node = tower_first (&tp->subtables); node != NULL; node = next)
+    {
+      struct paste_subtable *ps = paste_subtable_cast (node);
+      table_unref (ps->table);
+      next = tower_delete (&tp->subtables, node);
+      free (node);
+    }
+  free (tp);
+}
+
+static void
+table_paste_get_cell (const struct table *t, int x, int y,
+                      struct table_cell *cell)
+{
+  struct table_paste *tp = table_paste_cast (t);
+  struct paste_subtable *ps;
+  unsigned long int start;
+  int d[TABLE_N_AXES];
+
+  d[TABLE_HORZ] = x;
+  d[TABLE_VERT] = y;
+  ps = paste_subtable_lookup (tp, d[tp->orientation], &start);
+  d[tp->orientation] -= start;
+  table_get_cell (ps->table, d[TABLE_HORZ], d[TABLE_VERT], cell);
+  cell->d[tp->orientation][0] += start;
+  cell->d[tp->orientation][1] += start;
+}
+
+static int
+table_paste_get_rule (const struct table *t,
+                      enum table_axis axis, int x, int y)
+{
+  struct table_paste *tp = table_paste_cast (t);
+  int h = tp->orientation == TABLE_HORZ ? x : y;
+  int k = tp->orientation == TABLE_HORZ ? y : x;
+  struct paste_subtable *ps;
+  unsigned long int start;
+
+  if (tp->orientation == axis)
+    {
+      int r;
+
+      ps = paste_subtable_lookup (tp, h == 0 ? 0 : h - 1, &start);
+      if (tp->orientation == TABLE_HORZ) /* XXX */
+        r = table_get_rule (ps->table, axis, h - start, k);
+      else
+        r = table_get_rule (ps->table, axis, k, h - start);
+      if (h == start + tower_node_get_size (&ps->node))
+        {
+          struct tower_node *ps2_ = tower_next (&tp->subtables, &ps->node);
+          if (ps2_ != NULL)
+            {
+              struct paste_subtable *ps2 = paste_subtable_cast (ps2_);
+              int r2;
+
+              if (tp->orientation == TABLE_HORZ) /* XXX */
+                r2 = table_get_rule (ps2->table, axis, 0, k);
+              else
+                r2 = table_get_rule (ps2->table, axis, k, 0);
+              return table_rule_combine (r, r2);
+            }
+        }
+      return r;
+    }
+  else
+    {
+      ps = paste_subtable_lookup (tp, h, &start);
+      if (tp->orientation == TABLE_HORZ) /* XXX */
+        return table_get_rule (ps->table, axis, h - start, k);
+      else
+        return table_get_rule (ps->table, axis, k, h - start);
+    }
+}
+
+static struct table *
+table_paste_paste (struct table *a, struct table *b,
+                   enum table_axis orientation)
+{
+  struct table_paste *ta, *tb;
+
+  ta = is_table_paste (a, orientation) ? table_paste_cast (a) : NULL;
+  tb = is_table_paste (b, orientation) ? table_paste_cast (b) : NULL;
+
+  if (ta != NULL)
+    {
+      if (tb != NULL)
+        {
+          /* Append all of B's subtables onto A, then destroy B. */
+          table_paste_increase_size (ta, b);
+          tower_splice (&ta->subtables, NULL,
+                        &tb->subtables, tower_first (&tb->subtables), NULL);
+          table_unref (b);
+        }
+      else
+        {
+          /* Append B to A's stack of subtables. */
+          table_paste_insert_subtable (ta, b, NULL);
+        }
+      reassess_headers (ta);
+      return a;
+    }
+  else if (tb != NULL)
+    {
+      /* Insert A at the beginning of B's stack of subtables. */
+      table_paste_insert_subtable (tb, a, tower_first (&tb->subtables));
+      reassess_headers (tb);
+      return b;
+    }
+  else
+    return NULL;
+}
+
+static const struct table_class table_paste_class =
+  {
+    table_paste_destroy,
+    table_paste_get_cell,
+    table_paste_get_rule,
+    table_paste_paste,
+    NULL,                       /* select */
+  };
diff --git a/src/output/table-provider.h b/src/output/table-provider.h
new file mode 100644 (file)
index 0000000..6d1a415
--- /dev/null
@@ -0,0 +1,177 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997, 1998, 1999, 2000, 2009 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_TABLE_PROVIDER
+#define OUTPUT_TABLE_PROVIDER 1
+
+#include <output/table.h>
+
+/* A cell in a table. */
+struct table_cell
+  {
+    /* Occupied table region.
+
+       d[TABLE_HORZ][0] is the leftmost column.
+       d[TABLE_HORZ][1] is the rightmost column, plus 1.
+       d[TABLE_VERT][0] is the top row.
+       d[TABLE_VERT][1] is the bottom row, plus 1.
+
+       For an ordinary cell:
+           d[TABLE_HORZ][1] == d[TABLE_HORZ][0] + 1
+       and d[TABLE_VERT][1] == d[TABLE_VERT][0] + 1
+
+       For a joined cell:
+          d[TABLE_HORZ][1] > d[TABLE_HORZ][0] + 1
+       or d[TABLE_VERT][1] > d[TABLE_VERT][0] + 1
+       or both. */
+    int d[TABLE_N_AXES][2];
+
+    const char *contents;       /* Text string contents. */
+    unsigned int options;       /* TAB_* values. */
+
+    /* Called to free the cell's data, if nonnull. */
+    void (*destructor) (void *destructor_aux);
+    void *destructor_aux;
+  };
+
+void table_cell_free (struct table_cell *);
+
+/* Returns the number of columns that CELL spans.  This is 1 for an ordinary
+   cell and greater than one for a cell that joins multiple columns. */
+static inline int
+table_cell_colspan (const struct table_cell *cell)
+{
+  return cell->d[TABLE_HORZ][1] - cell->d[TABLE_HORZ][0];
+}
+
+/* Returns the number of rows that CELL spans.  This is 1 for an ordinary cell
+   and greater than one for a cell that joins multiple rows. */
+static inline int
+table_cell_rowspan (const struct table_cell *cell)
+{
+  return cell->d[TABLE_VERT][1] - cell->d[TABLE_VERT][0];
+}
+
+/* Returns true if CELL is a joined cell, that is, if it spans multiple rows
+   or columns.  Otherwise, returns false. */
+static inline bool
+table_cell_is_joined (const struct table_cell *cell)
+{
+  return table_cell_colspan (cell) > 1 || table_cell_rowspan (cell) > 1;
+}
+\f
+/* Declarations to allow defining table classes. */
+
+struct table_class
+  {
+    /* Frees TABLE.
+
+       The table class may assume that any cells that were retrieved by calling
+       the 'get_cell' function have been freed (by calling their destructors)
+       before this function is called. */
+    void (*destroy) (struct table *table);
+
+    /* Initializes CELL with the contents of the table cell at column X and row
+       Y within TABLE.  All members of CELL must be initialized, except that if
+       'destructor' is set to a null pointer, then 'destructor_aux' need not be
+       initialized.  The 'contents' member of CELL must be set to a nonnull
+       value.
+
+       The table class must allow any number of cells in the table to be
+       retrieved simultaneously; that is, TABLE must not assume that a given
+       cell will be freed before another one is retrieved using 'get_cell'.
+
+       The table class must allow joined cells to be retrieved, with identical
+       contents, using any (X,Y) location inside the cell.
+
+       The table class must not allow cells to overlap.
+
+       The table class should not allow a joined cell to cross the border
+       between header rows/columns and the interior of the table.  That is, a
+       joined cell should be entirely within headers rows and columns or
+       entirely outside them.
+
+       The table class may assume that CELL will be freed before TABLE is
+       destroyed. */
+    void (*get_cell) (const struct table *table, int x, int y,
+                      struct table_cell *cell);
+
+    /* Returns one of the TAL_* enumeration constants (declared in
+       output/table.h) representing a rule running alongside one of the cells
+       in TABLE.
+
+       See table_get_rule() in table.c for a detailed explanation of the
+       meaning of AXIS and X and Y, including a diagram. */
+    int (*get_rule) (const struct table *table,
+                     enum table_axis axis, int x, int y);
+
+    /* This function is optional and most table classes will not implement it.
+
+       If provided, this function must take ownership of A and B and return a
+       table that consists of tables A and B "pasted together", that is, a
+       table whose size is the sum of the sizes of A and B along the axis
+       specified by ORIENTATION.  A and B will ordinarily have the same size
+       along the axis opposite ORIENTATION; no particular handling of tables
+       that have different sizes along that axis is required.
+
+       The handling of rules at the seam between A and B is not specified, but
+       table_rule_combine() is one reasonable way to do it.
+
+       Called only if neither A and B is shared (as returned by
+       table_is_shared()).
+
+       Called if A or B or both is of the class defined by this table class.
+       That is, the implementation must be prepared to deal with the case where
+       A or B is not the ordinarily expected table class.
+
+       This function may return a null pointer if it cannot implement the paste
+       operation, in which case the caller will use a fallback
+       implementation.
+
+       This function is used to implement table_paste(). */
+    struct table *(*paste) (struct table *a, struct table *b,
+                            enum table_axis orientation);
+
+    /* This function is optional and most table classes will not implement it.
+
+       If provided, this function must take ownership of TABLE and return a new
+       table whose contents are the TABLE's rows RECT[TABLE_VERT][0] through
+       RECT[TABLE_VERT][1], exclusive, and the TABLE's columns
+       RECT[TABLE_HORZ][0] through RECT[TABLE_HORZ][1].
+
+       Called only if TABLE is not shared (as returned by table_is_shared()).p
+
+       This function may return a null pointer if it cannot implement the
+       select operation, in which case the caller will use a fallback
+       implementation.
+
+       This function is used to implement table_select(). */
+    struct table *(*select) (struct table *table, int rect[TABLE_N_AXES][2]);
+  };
+
+void table_init (struct table *, const struct table_class *);
+
+/* Table class implementations can call these functions or just set the
+   table's n[] and h[][] members directly. */
+void table_set_nc (struct table *, int nc);
+void table_set_nr (struct table *, int nr);
+\f
+/* For use primarily by output drivers. */
+
+void table_get_cell (const struct table *, int x, int y, struct table_cell *);
+int table_get_rule (const struct table *, enum table_axis, int x, int y);
+
+#endif /* output/table-provider.h */
diff --git a/src/output/table-select.c b/src/output/table-select.c
new file mode 100644 (file)
index 0000000..1c2956a
--- /dev/null
@@ -0,0 +1,236 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <libpspp/assertion.h>
+#include <libpspp/cast.h>
+#include <output/table-provider.h>
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+struct table_select
+  {
+    struct table table;
+    struct table *subtable;
+    int ofs[2];
+  };
+
+static const struct table_class table_select_class;
+
+static struct table_select *
+table_select_cast (const struct table *table)
+{
+  assert (table->class == &table_select_class);
+  return UP_CAST (table, struct table_select, table);
+}
+
+/* Takes ownership of SUBTABLE and returns a new table whose contents are the
+   rectangular subregion of SUBTABLE that contains rows RECT[TABLE_VERT][0]
+   through RECT[TABLE_VERT][1], exclusive, and columns RECT[TABLE_HORZ][0]
+   through RECT[TABLE_HORZ][1]. */
+struct table *
+table_select (struct table *subtable, int rect[TABLE_N_AXES][2])
+{
+  struct table_select *ts;
+  int axis;
+
+  if (rect[TABLE_HORZ][0] == 0
+      && rect[TABLE_HORZ][1] == subtable->n[TABLE_HORZ]
+      && rect[TABLE_VERT][0] == 0
+      && rect[TABLE_VERT][1] == subtable->n[TABLE_VERT])
+    return subtable;
+
+  if (!table_is_shared (subtable) && subtable->class->select != NULL)
+    {
+      struct table *selected = subtable->class->select (subtable, rect);
+      if (selected != NULL)
+        return selected;
+    }
+
+  ts = xmalloc (sizeof *ts);
+  table_init (&ts->table, &table_select_class);
+  ts->subtable = subtable;
+  for (axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      int h1;
+      ts->ofs[axis] = rect[axis][0];
+      ts->table.n[axis] = rect[axis][1] - rect[axis][0];
+      if (subtable->h[axis][0] > rect[axis][0])
+        ts->table.h[axis][0] = subtable->h[axis][0] - rect[axis][0];
+      h1 = subtable->n[axis] - subtable->h[axis][1];
+      if (h1 < rect[axis][1])
+        ts->table.h[axis][1] = rect[axis][1] - h1;
+    }
+  return &ts->table;
+}
+
+/* Takes ownership of TABLE and returns a new table whose contents are:
+
+        - If AXIS is TABLE_HORZ, columns Z0 through Z1 (exclusive) of SUBTABLE.
+          If ADD_HEADERS is true, the returned table also includes any header
+          columns in SUBTABLE.
+
+        - If AXIS is TABLE_VERT, rows Z0 through Z1 (exclusive) of SUBTABLE.
+          If ADD_HEADERS is true, the returned table also includes any header
+          rows in SUBTABLE. */
+struct table *
+table_select_slice (struct table *subtable, enum table_axis axis,
+                    int z0, int z1, bool add_headers)
+{
+  struct table *table;
+  int rect[TABLE_N_AXES][2];
+
+  if (add_headers)
+    {
+      if (z0 == subtable->h[axis][0] && z1 == subtable->h[axis][1])
+        return subtable;
+
+      if (subtable->h[axis][0])
+        table_ref (subtable);
+      if (subtable->h[axis][1])
+        table_ref (subtable);
+    }
+  else
+    {
+      if (z0 == 0 && z1 == subtable->n[axis])
+        return subtable;
+    }
+
+  rect[TABLE_HORZ][0] = 0;
+  rect[TABLE_VERT][0] = 0;
+  rect[TABLE_HORZ][1] = subtable->n[TABLE_HORZ];
+  rect[TABLE_VERT][1] = subtable->n[TABLE_VERT];
+  rect[axis][0] = z0;
+  rect[axis][1] = z1;
+  table = table_select (subtable, rect);
+
+  if (add_headers)
+    {
+      if (subtable->h[axis][0])
+        table = table_paste (
+          table_select_slice (subtable, axis, 0, subtable->h[axis][0],
+                              false),
+          table, axis);
+
+      if (subtable->h[axis][1])
+        table = table_paste (
+          table,
+          table_select_slice (subtable, axis,
+                              subtable->n[axis] - subtable->h[axis][1],
+                              subtable->n[axis], false),
+          axis);
+    }
+
+  return table;
+}
+
+/* Takes ownership of TABLE and returns a new table whose contents are columns
+   X0 through X1 (exclusive) of SUBTABLE.  If ADD_HEADERS is true, the
+   returned table also includes any header columns in SUBTABLE. */
+struct table *
+table_select_columns (struct table *subtable, int x0, int x1,
+                      bool add_headers)
+{
+  return table_select_slice (subtable, TABLE_HORZ, x0, x1, add_headers);
+}
+
+/* Takes ownership of TABLE and returns a new table whose contents are rows Y0
+   through Y1 (exclusive) of SUBTABLE.  If ADD_HEADERS is true, the returned
+   table also includes any header rows in SUBTABLE. */
+struct table *
+table_select_rows (struct table *subtable, int y0, int y1,
+                   bool add_headers)
+{
+  return table_select_slice (subtable, TABLE_VERT, y0, y1, add_headers);
+}
+
+static void
+table_select_destroy (struct table *ti)
+{
+  struct table_select *ts = table_select_cast (ti);
+  table_unref (ts->subtable);
+  free (ts);
+}
+
+static void
+table_select_get_cell (const struct table *ti, int x, int y,
+                       struct table_cell *cell)
+{
+  struct table_select *ts = table_select_cast (ti);
+  int axis;
+
+  table_get_cell (ts->subtable,
+                  x + ts->ofs[TABLE_HORZ],
+                  y + ts->ofs[TABLE_VERT], cell);
+
+  for (axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      int *d = cell->d[axis];
+      int ofs = ts->ofs[axis];
+
+      d[0] = MAX (d[0] - ofs, 0);
+      d[1] = MIN (d[1] - ofs, ti->n[axis]);
+    }
+}
+
+static int
+table_select_get_rule (const struct table *ti,
+                       enum table_axis axis,
+                       int x, int y)
+{
+  struct table_select *ts = table_select_cast (ti);
+  return table_get_rule (ts->subtable, axis,
+                         x + ts->ofs[TABLE_HORZ],
+                         y + ts->ofs[TABLE_VERT]);
+}
+
+static struct table *
+table_select_select (struct table *ti, int rect[TABLE_N_AXES][2])
+{
+  struct table_select *ts = table_select_cast (ti);
+  int axis;
+
+  for (axis = 0; axis < TABLE_N_AXES; axis++)
+    {
+      int h1;
+
+      if (ts->table.h[axis][0] > rect[axis][0])
+        ts->table.h[axis][0] = ts->table.h[axis][0] - rect[axis][0];
+      else
+        ts->table.h[axis][0] = 0;
+
+      h1 = ts->table.n[axis] - ts->table.h[axis][1];
+      if (h1 < rect[axis][1])
+        ts->table.h[axis][1] = rect[axis][1] - h1;
+      else
+        ts->table.h[axis][1] = 0;
+
+      ts->ofs[axis] += rect[axis][0];
+      ts->table.n[axis] = rect[axis][1] - rect[axis][0];
+    }
+  return ti;
+}
+
+static const struct table_class table_select_class =
+  {
+    table_select_destroy,
+    table_select_get_cell,
+    table_select_get_rule,
+    NULL,                       /* paste */
+    table_select_select,
+  };
diff --git a/src/output/table-transpose.c b/src/output/table-transpose.c
new file mode 100644 (file)
index 0000000..5980194
--- /dev/null
@@ -0,0 +1,119 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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 <libpspp/assertion.h>
+#include <libpspp/cast.h>
+#include <output/table-provider.h>
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+struct table_transpose
+  {
+    struct table table;
+    struct table *subtable;
+  };
+
+static const struct table_class table_transpose_class;
+
+static struct table_transpose *
+table_transpose_cast (const struct table *table)
+{
+  assert (table->class == &table_transpose_class);
+  return UP_CAST (table, struct table_transpose, table);
+}
+
+/* Takes ownership of SUBTABLE and returns a new table whose contents are
+   SUBTABLE with rows and columns transposed. */
+struct table *
+table_transpose (struct table *subtable)
+{
+  if (subtable->n[TABLE_HORZ] == subtable->n[TABLE_VERT]
+      && subtable->n[TABLE_HORZ] <= 1)
+    return subtable;
+  else if (subtable->class == &table_transpose_class)
+    {
+      struct table_transpose *tt = table_transpose_cast (subtable);
+      struct table *table = table_ref (tt->subtable);
+      table_unref (subtable);
+      return table;
+    }
+  else
+    {
+      struct table_transpose *tt;
+      int axis;
+
+      tt = xmalloc (sizeof *tt);
+      table_init (&tt->table, &table_transpose_class);
+      tt->subtable = subtable;
+
+      for (axis = 0; axis < TABLE_N_AXES; axis++)
+        {
+          tt->table.n[axis] = subtable->n[!axis];
+          tt->table.h[axis][0] = subtable->h[!axis][0];
+          tt->table.h[axis][1] = subtable->h[!axis][1];
+        }
+      return &tt->table;
+    }
+}
+
+static void
+table_transpose_destroy (struct table *ti)
+{
+  struct table_transpose *tt = table_transpose_cast (ti);
+  table_unref (tt->subtable);
+  free (tt);
+}
+
+static void
+swap (int *x, int *y)
+{
+  int t = *x;
+  *x = *y;
+  *y = t;
+}
+
+static void
+table_transpose_get_cell (const struct table *ti, int x, int y,
+                          struct table_cell *cell)
+{
+  struct table_transpose *tt = table_transpose_cast (ti);
+  int i;
+
+  table_get_cell (tt->subtable, y, x, cell);
+  for (i = 0; i < 2; i++)
+    swap (&cell->d[TABLE_HORZ][i], &cell->d[TABLE_VERT][i]);
+}
+
+static int
+table_transpose_get_rule (const struct table *ti,
+                          enum table_axis axis,
+                          int x, int y)
+{
+  struct table_transpose *tt = table_transpose_cast (ti);
+  return table_get_rule (tt->subtable, !axis, y, x);
+}
+
+static const struct table_class table_transpose_class =
+  {
+    table_transpose_destroy,
+    table_transpose_get_cell,
+    table_transpose_get_rule,
+    NULL,                       /* paste */
+    NULL,                       /* select */
+  };
index 72edf17f08b7f6e9e0dec91ad8b56f5b9e87b88b..696931ae50980147be4212dd1af477a73c2448d1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009 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
 
 #include <config.h>
 
-#include "table.h"
+#include <output/table.h>
+#include <output/table-provider.h>
 
-#include <ctype.h>
-#include <stdarg.h>
-#include <limits.h>
+#include <assert.h>
 #include <stdlib.h>
 
-#include "output.h"
-#include "manager.h"
-
-#include <data/data-out.h>
-#include <data/format.h>
-#include <data/value.h>
-#include <data/dictionary.h>
-#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
 #include <libpspp/compiler.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-
-#include <data/settings.h>
-
-#include "minmax.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-\f
-const struct som_table_class tab_table_class;
-static char *command_name;
-
-/* Returns the font to use for a cell with the given OPTIONS. */
-static enum outp_font
-options_to_font (unsigned options)
-{
-  return (options & TAB_FIX ? OUTP_FIXED
-          : options & TAB_EMPH ? OUTP_EMPHASIS
-          : OUTP_PROPORTIONAL);
-}
-
-/* Creates a table with NC columns and NR rows. */
-struct tab_table *
-tab_create (int nc, int nr, int reallocable UNUSED)
-{
-  struct tab_table *t;
-
-  t = pool_create_container (struct tab_table, container);
-  t->col_style = TAB_COL_NONE;
-  t->col_group = 0;
-  t->title = NULL;
-  t->flags = SOMF_NONE;
-  t->nr = nr;
-  t->nc = t->cf = nc;
-  t->l = t->r = t->t = t->b = 0;
-
-  t->cc = pool_nmalloc (t->container, nr * nc, sizeof *t->cc);
-  t->ct = pool_malloc (t->container, nr * nc);
-  memset (t->ct, TAB_EMPTY, nc * nr);
 
-  t->rh = pool_nmalloc (t->container, nc, nr + 1);
-  memset (t->rh, 0, nc * (nr + 1));
+#include "gl/xalloc.h"
 
-  t->rv = pool_nmalloc (t->container, nr, nc + 1);
-  memset (t->rv, UCHAR_MAX, nr * (nc + 1));
-
-  t->dim = NULL;
-  t->w = t->h = NULL;
-  t->col_ofs = t->row_ofs = 0;
-
-  return t;
-}
-
-/* Destroys table T. */
-void
-tab_destroy (struct tab_table *t)
-{
-  assert (t != NULL);
-  free (t->title);
-  pool_destroy (t->container);
-}
-
-/* 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. */
-void
-tab_resize (struct tab_table *t, int nc, int nr)
+/* Increases TABLE's reference count, indicating that it has an additional
+   owner.  An table that is shared among multiple owners must not be
+   modified. */
+struct table *
+table_ref (const struct table *table_)
 {
-  assert (t != NULL);
-  if (nc != -1)
-    {
-      assert (nc + t->col_ofs <= t->cf);
-      t->nc = nc + t->col_ofs;
-    }
-  if (nr != -1)
-    {
-      assert (nr + t->row_ofs <= t->nr);
-      t->nr = nr + t->row_ofs;
-    }
+  struct table *table = CONST_CAST (struct table *, table_);
+  table->ref_cnt++;
+  return table;
 }
 
-/* Changes either or both dimensions of a table.  Consider using the
-   above routine instead if it won't waste a lot of space.
-
-   Changing the number of columns in a table is particularly expensive
-   in space and time.  Avoid doing such.  FIXME: In fact, transferring
-   of rules isn't even implemented yet. */
+/* Decreases TABLE's reference count, indicating that it has one fewer owner.
+   If TABLE no longer has any owners, it is freed. */
 void
-tab_realloc (struct tab_table *t, int nc, int nr)
+table_unref (struct table *table)
 {
-  int ro, co;
-
-  assert (t != NULL);
-  ro = t->row_ofs;
-  co = t->col_ofs;
-  if (ro || co)
-    tab_offset (t, 0, 0);
-
-  if (nc == -1)
-    nc = t->nc;
-  if (nr == -1)
-    nr = t->nr;
-
-  assert (nc == t->nc);
-
-  if (nc > t->cf)
+  if (table != NULL)
     {
-      int mr1 = MIN (nr, t->nr);
-      int mc1 = MIN (nc, t->nc);
-
-      struct substring *new_cc;
-      unsigned char *new_ct;
-      int r;
-
-      new_cc = pool_nmalloc (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 * t->nc], mc1 * sizeof *t->cc);
-         memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
-         memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
-       }
-      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 != t->nr)
-    {
-      t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
-      t->ct = pool_realloc (t->container, t->ct, nr * nc);
-
-      t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
-      t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
-
-      if (nr > t->nr)
-       {
-         memset (&t->rh[nc * (t->nr + 1)], TAL_0, (nr - t->nr) * nc);
-         memset (&t->rv[(nc + 1) * t->nr], UCHAR_MAX,
-                  (nr - t->nr) * (nc + 1));
-       }
-    }
-
-  memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
-
-  t->nr = nr;
-  t->nc = 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
-   multiple pages. */
-void
-tab_headers (struct tab_table *table, int l, int r, int t, int b)
-{
-  assert (table != NULL);
-  assert (l < table->nc);
-  assert (r < table->nc);
-  assert (t < table->nr);
-  assert (b < table->nr);
-
-
-  table->l = l;
-  table->r = r;
-  table->t = t;
-  table->b = b;
-}
-
-/* Set up table T so that, when it is an appropriate size, it will be
-   displayed across the page in columns.
-
-   STYLE is a TAB_COL_* constant.  GROUP is the number of rows to take
-   as a unit. */
-void
-tab_columns (struct tab_table *t, int style, int group)
-{
-  assert (t != NULL);
-  t->col_style = style;
-  t->col_group = group;
-}
-\f
-/* Rules. */
-
-/* Draws a vertical line to the left of cells at horizontal position X
-   from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
-void
-tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
-{
-  assert (t != NULL);
-
-#if DEBUGGING
-  if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
-      || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
-      || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
-    {
-      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,
-             t->nc, t->nr);
-      return;
-    }
-#endif
-
-  x += t->col_ofs;
-  y1 += t->row_ofs;
-  y2 += t->row_ofs;
-
-  assert (x  > 0);
-  assert (x  < t->nc);
-  assert (y1 >= 0);
-  assert (y2 >= y1);
-  assert (y2 <=  t->nr);
-
-  if (style != -1)
-    {
-      int y;
-      for (y = y1; y <= y2; y++)
-        t->rv[x + (t->cf + 1) * y] = style;
-    }
-}
-
-/* Draws a horizontal line above cells at vertical position Y from X1
-   to X2 inclusive in style STYLE, if style is not -1. */
-void
-tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
-{
-  assert (t != NULL);
-
-  x1 += t->col_ofs;
-  x2 += t->col_ofs;
-  y += t->row_ofs;
-
-  assert (y >= 0);
-  assert (y <= t->nr);
-  assert (x2 >= x1 );
-  assert (x1 >= 0 );
-  assert (x2 < t->nc);
-
-  if (style != -1)
-    {
-      int x;
-      for (x = x1; x <= x2; x++)
-        t->rh[x + t->cf * y] = style;
-    }
-}
-
-/* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
-   lines of style F_H and vertical lines of style F_V.  Fills the
-   interior of the box with horizontal lines of style I_H and vertical
-   lines of style I_V.  Any of the line styles may be -1 to avoid
-   drawing those lines.  This is distinct from 0, which draws a null
-   line. */
-void
-tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
-        int x1, int y1, int x2, int y2)
-{
-  assert (t != NULL);
-
-#if DEBUGGING
-  if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
-      || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
-      || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
-      || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
-    {
-      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,
-             t->nc, t->nr);
-      NOT_REACHED ();
-    }
-#endif
-
-  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);
-  assert (y1 >= 0);
-  assert (x2 < t->nc);
-  assert (y2 < t->nr);
-
-  if (f_h != -1)
-    {
-      int x;
-      for (x = x1; x <= x2; x++)
-        {
-          t->rh[x + t->cf * y1] = f_h;
-          t->rh[x + t->cf * (y2 + 1)] = f_h;
-        }
-    }
-  if (f_v != -1)
-    {
-      int y;
-      for (y = y1; y <= y2; y++)
-        {
-          t->rv[x1 + (t->cf + 1) * y] = f_v;
-          t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
-        }
-    }
-
-  if (i_h != -1)
-    {
-      int y;
-
-      for (y = y1 + 1; y <= y2; y++)
-       {
-         int x;
-
-          for (x = x1; x <= x2; x++)
-            t->rh[x + t->cf * y] = i_h;
-       }
-    }
-  if (i_v != -1)
-    {
-      int x;
-
-      for (x = x1 + 1; x <= x2; x++)
-       {
-         int y;
-
-          for (y = y1; y <= y2; y++)
-            t->rv[x + (t->cf + 1) * y] = i_v;
-       }
+      assert (table->ref_cnt > 0);
+      if (--table->ref_cnt == 0)
+        table->class->destroy (table);
     }
 }
 
-/* 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;
-
-  assert (t != NULL && title != NULL);
-  va_start (args, title);
-  t->title = xvasprintf (title, args);
-  va_end (args);
-}
-
-/* Set DIM_FUNC as the dimension function for table T. */
-void
-tab_dim (struct tab_table *t, tab_dim_func *dim_func, void *aux)
-{
-  assert (t != NULL && t->dim == NULL);
-  t->dim = dim_func;
-  t->dim_aux = aux;
-}
-
-/* Returns the natural width of column C in table T for driver D, that
-   is, the smallest width necessary to display all its cells without
-   wrapping.  The width will be no larger than the page width minus
-   left and right rule widths. */
-int
-tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
-{
-  int width;
-
-  assert (t != NULL && c >= 0 && c < t->nc);
-  {
-    int r;
-
-    for (width = r = 0; r < t->nr; r++)
-      {
-       struct outp_text text;
-       unsigned char opt = t->ct[c + r * t->cf];
-        int w;
-
-       if (opt & (TAB_JOIN | TAB_EMPTY))
-         continue;
-
-       text.string = t->cc[c + r * t->cf];
-       text.justification = OUTP_LEFT;
-        text.font = options_to_font (opt);
-        text.h = text.v = INT_MAX;
-
-       d->class->text_metrics (d, &text, &w, NULL);
-       if (w > width)
-         width = w;
-      }
-  }
-
-  if (width == 0)
-    {
-      /* FIXME: This is an ugly kluge to compensate for the fact
-         that we don't let joined cells contribute to column
-         widths. */
-      width = d->prop_em_width * 8;
-    }
-
-  {
-    const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
-
-    if (width > clamp)
-      width = clamp;
-  }
-
-  return width;
-}
-
-/* Returns the natural height of row R in table T for driver D, that
-   is, the minimum height necessary to display the information in the
-   cell at the widths set for each column. */
-int
-tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
-{
-  int height;
-
-  assert (t != NULL && r >= 0 && r < t->nr);
-
-  {
-    int c;
-
-    for (height = d->font_height, c = 0; c < t->nc; c++)
-      {
-       struct outp_text text;
-       unsigned char opt = t->ct[c + r * t->cf];
-        int h;
-
-       if (opt & (TAB_JOIN | TAB_EMPTY))
-         continue;
-
-       text.string = t->cc[c + r * t->cf];
-        text.justification = OUTP_LEFT;
-        text.font = options_to_font (opt);
-       text.h = t->w[c];
-        text.v = INT_MAX;
-       d->class->text_metrics (d, &text, NULL, &h);
-
-       if (h > height)
-         height = h;
-      }
-  }
-
-  return height;
-}
-
-/* Callback function to set all columns and rows to their natural
-   dimensions.  Not really meant to be called directly.  */
-void
-tab_natural_dimensions (struct tab_table *t, struct outp_driver *d,
-                        void *aux UNUSED)
-{
-  int i;
-
-  assert (t != NULL);
-
-  for (i = 0; i < t->nc; i++)
-    t->w[i] = tab_natural_width (t, d, i);
-
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = tab_natural_height (t, d, i);
-}
-
-\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 char opt,
-          const union value *v, const struct dictionary *dict, 
-          const struct fmt_spec *f)
-{
-  char *contents;
-
-  assert (table != NULL && v != NULL && f != NULL);
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= table->nc
-      || r + table->row_ofs >= table->nr)
-    {
-      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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  contents = data_out_pool (v, dict_get_encoding (dict), f, table->container);
-
-  table->cc[c + r * table->cf] = ss_cstr (contents);
-  table->ct[c + r * table->cf] = opt;
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
-   with NDEC decimal places. */
-void
-tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
-          double val, int w, int d)
-{
-  char *s, *cp;
-
-  struct fmt_spec f;
-  union value double_value;
-
-  assert (table != NULL && w <= 40);
-
-  assert (c >= 0);
-  assert (c < table->nc);
-  assert (r >= 0);
-  assert (r < table->nr);
-
-  f = fmt_for_output (FMT_F, w, d);
-
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= table->nc
-      || r + table->row_ofs >= table->nr)
-    {
-      printf ("tab_fixed(): 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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  double_value.f = val;
-  s = data_out_pool (&double_value, LEGACY_NATIVE, &f, table->container);
-
-  cp = s;
-  while (isspace ((unsigned char) *cp) && cp < &s[w])
-    cp++;
-  f.w = w - (cp - s);
-
-  table->cc[c + r * table->cf] = ss_buffer (cp, f.w);
-  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 char opt,
-          double val, const struct fmt_spec *fmt)
-{
-  struct substring ss;
-  union value double_value ;
-
-  assert (table != NULL);
-
-  assert (c >= 0);
-  assert (c < table->nc);
-  assert (r >= 0);
-  assert (r < table->nr);
-
-  if ( fmt == NULL)
-    fmt = settings_get_format ();
-
-  fmt_check_output (fmt);
-
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= table->nc
-      || r + table->row_ofs >= table->nr)
-    {
-      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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  double_value.f = val;
-  ss = ss_cstr (data_out_pool (&double_value, LEGACY_NATIVE, fmt, table->container));
-
-  ss_ltrim (&ss, ss_cstr (" "));
-
-  table->cc[c + r * table->cf] = ss;
-  table->ct[c + r * table->cf] = opt;
-}
-
-
-static void
-do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
-{
-  assert (c >= 0);
-  assert (r >= 0);
-  assert (c < table->nc);
-  assert (r < table->nr);
-
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= table->nc
-      || r + table->row_ofs >= table->nr)
-    {
-      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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  table->cc[c + r * table->cf] = ss_cstr (text);
-  table->ct[c + r * table->cf] = opt;
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have text value
-   TEXT. */
-void
-tab_text (struct tab_table *table, int c, int r, unsigned opt,
-          const char *text)
+/* Returns true if TABLE has more than one owner.  A table item that is shared
+   among multiple owners must not be modified. */
+bool
+table_is_shared (const struct table *table)
 {
-  do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
+  return table->ref_cnt > 1;
 }
 
-/* Sets cell (C,R) in TABLE, with options OPT, to have text value
-   FORMAT, which is formatted as if passed to printf. */
+/* Sets the number of left header columns in TABLE to HL. */
 void
-tab_text_format (struct tab_table *table, int c, int r, unsigned opt,
-                 const char *format, ...)
+table_set_hl (struct table *table, int hl)
 {
-  va_list args;
-
-  va_start (args, format);
-  do_tab_text (table, c, r, opt,
-               pool_vasprintf (table->container, format, args));
-  va_end (args);
-}
-
-static void
-do_tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
-                   unsigned opt, char *text)
-{
-  struct tab_joined_cell *j;
-
-  assert (x1 + table->col_ofs >= 0);
-  assert (y1 + table->row_ofs >= 0);
-  assert (y2 >= y1);
-  assert (x2 >= x1);
-  assert (y2 + table->row_ofs < table->nr);
-  assert (x2 + table->col_ofs < table->nc);
-
-#if DEBUGGING
-  if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
-      || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
-      || x2 < x1 || x2 + table->col_ofs >= table->nc
-      || y2 < y2 || y2 + table->row_ofs >= table->nr)
-    {
-      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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
-
-  j = pool_alloc (table->container, sizeof *j);
-  j->hit = 0;
-  j->x1 = x1 + table->col_ofs;
-  j->y1 = y1 + table->row_ofs;
-  j->x2 = ++x2 + table->col_ofs;
-  j->y2 = ++y2 + table->row_ofs;
-  j->contents = ss_cstr (text);
-
-  opt |= TAB_JOIN;
-
-  {
-    struct substring *cc = &table->cc[x1 + y1 * table->cf];
-    unsigned char *ct = &table->ct[x1 + y1 * table->cf];
-    const int ofs = table->cf - (x2 - x1);
-
-    int y;
-
-    for (y = y1; y < y2; y++)
-      {
-       int x;
-
-       for (x = x1; x < x2; x++)
-         {
-           *cc++ = ss_buffer ((char *) j, 0);
-           *ct++ = opt;
-         }
-
-       cc += ofs;
-       ct += ofs;
-      }
-  }
+  assert (!table_is_shared (table));
+  table->h[TABLE_HORZ][0] = hl;
 }
 
-/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
-   options OPT to have text value TEXT. */
+/* Sets the number of right header columns in TABLE to HR. */
 void
-tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
-                unsigned opt, const char *text)
+table_set_hr (struct table *table, int hr)
 {
-  do_tab_joint_text (table, x1, y1, x2, y2, opt,
-                     pool_strdup (table->container, text));
+  assert (!table_is_shared (table));
+  table->h[TABLE_HORZ][1] = hr;
 }
 
-/* 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. */
+/* Sets the number of top header rows in TABLE to HT. */
 void
-tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, int y2,
-                       unsigned opt, const char *format, ...)
+table_set_ht (struct table *table, int ht)
 {
-  va_list args;
-
-  va_start (args, format);
-  do_tab_joint_text (table, x1, y1, x2, y2, opt,
-                     pool_vasprintf (table->container, format, args));
-  va_end (args);
+  assert (!table_is_shared (table));
+  table->h[TABLE_VERT][0] = ht;
 }
 
-/* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
+/* Sets the number of top header rows in TABLE to HB. */
 void
-tab_raw (struct tab_table *table, int c, int r, unsigned opt,
-        struct substring *string)
+table_set_hb (struct table *table, int hb)
 {
-  assert (table != NULL && string != NULL);
-
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= table->nc
-      || r + table->row_ofs >= table->nr)
-    {
-      printf ("tab_raw(): 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,
-             table->nc, table->nr);
-      return;
-    }
-#endif
-
-  table->cc[c + r * table->cf] = *string;
-  table->ct[c + r * table->cf] = opt;
+  assert (!table_is_shared (table));
+  table->h[TABLE_VERT][1] = hb;
 }
 \f
-/* Miscellaneous. */
-
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-nowrap_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  t->w[0] = tab_natural_width (t, d, 0);
-  t->h[0] = d->font_height;
-}
-
-/* Sets the widths of all the columns and heights of all the rows in
-   table T for driver D. */
-static void
-wrap_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
-{
-  t->w[0] = tab_natural_width (t, d, 0);
-  t->h[0] = tab_natural_height (t, d, 0);
-}
-
-static void
-do_tab_output_text (struct tab_table *t, int options, char *text)
-{
-  do_tab_text (t, 0, 0, options, text);
-  tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
-  tab_dim (t, options & TAT_NOWRAP ? nowrap_dim : wrap_dim, NULL);
-  tab_submit (t);
-}
+/* Initializes TABLE as a table of the specified CLASS, initially with a
+   reference count of 1.
 
-/* Outputs TEXT as a table with a single cell having cell options
-   OPTIONS, which is a combination of the TAB_* and TAT_*
-   constants.  */
-void
-tab_output_text (int options, const char *text)
-{
-  struct tab_table *table = tab_create (1, 1, 0);
-  do_tab_output_text (table, options, pool_strdup (table->container, text));
-}
+   TABLE initially has 0 rows and columns and no headers.  The table
+   implementation should update the numbers of rows and columns.  The table
+   implementation (or its client) may update the header rows and columns.
 
-/* Outputs FORMAT as a table with a single cell having cell
-   options OPTIONS, which is a combination of the TAB_* and TAT_*
-   constants.  FORMAT is formatted as if it was passed through
-   printf. */
+   A table is an abstract class, that is, a plain struct table is not useful on
+   its own.  Thus, this function is normally called from the initialization
+   function of some subclass of table. */
 void
-tab_output_text_format (int options, const char *format, ...)
+table_init (struct table *table, const struct table_class *class)
 {
-  struct tab_table *table;
-  va_list args;
-
-  table = tab_create (1, 1, 0);
-
-  va_start (args, format);
-  do_tab_output_text (table, options,
-                      pool_vasprintf (table->container, format, args));
-  va_end (args);
+  table->class = class;
+  table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
+  table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
+  table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
+  table->ref_cnt = 1;
 }
 
-/* Set table flags to FLAGS. */
+/* Sets the number of columns in TABLE to NC. */
 void
-tab_flags (struct tab_table *t, unsigned flags)
+table_set_nc (struct table *table, int nc)
 {
-  assert (t != NULL);
-  t->flags = flags;
+  assert (!table_is_shared (table));
+  table->n[TABLE_HORZ] = nc;
 }
 
-/* Easy, type-safe way to submit a tab table to som. */
+/* Sets the number of rows in TABLE to NR. */
 void
-tab_submit (struct tab_table *t)
+table_set_nr (struct table *table, int nr)
 {
-  struct som_entity s;
-
-  assert (t != NULL);
-  s.class = &tab_table_class;
-  s.ext = t;
-  s.type = SOM_TABLE;
-  som_submit (&s);
-  tab_destroy (t);
+  assert (!table_is_shared (table));
+  table->n[TABLE_VERT] = nr;
 }
 \f
-/* Editing. */
+/* Initializes CELL with the contents of the table cell at column X and row Y
+   within TABLE.  When CELL is no longer needed, the caller is responsible for
+   freeing it by calling table_cell_free(CELL).
 
-/* Set table row and column offsets for all functions that affect
-   cells or rules. */
+   The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
 void
-tab_offset (struct tab_table *t, int col, int row)
+table_get_cell (const struct table *table, int x, int y,
+                struct table_cell *cell)
 {
-  int diff = 0;
-
-  assert (t != NULL);
-#if DEBUGGING
-  if (row < -1 || row > t->nr)
-    {
-      printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
-      NOT_REACHED ();
-    }
-  if (col < -1 || col > t->nc)
-    {
-      printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
-      NOT_REACHED ();
-    }
-#endif
-
-  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;
+  assert (x >= 0 && x < table->n[TABLE_HORZ]);
+  assert (y >= 0 && y < table->n[TABLE_VERT]);
+  table->class->get_cell (table, x, y, cell);
 }
 
-/* Increment the row offset by one. If the table is too small,
-   increase its size. */
+/* Frees CELL, which should have been initialized by calling
+   table_get_cell(). */
 void
-tab_next_row (struct tab_table *t)
+table_cell_free (struct table_cell *cell)
+{
+  if (cell->destructor != NULL)
+    cell->destructor (cell->destructor_aux);
+}
+
+/* Returns one of the TAL_* enumeration constants (declared in output/table.h)
+   representing a rule running alongside one of the cells in TABLE.
+
+   Suppose NC is the number of columns in TABLE and NR is the number of rows.
+   Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR.  If (X,Y) =
+   (0,0), the return value is the rule that runs vertically on the left side of
+   cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
+   cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
+   cell (NC-1,0).
+
+   The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
+   within a 7x7 table.  The '|' characters at the intersection of the X labels
+   and Y labels show the rule whose style would be returned by calling
+   table_get_rule with those X and Y values:
+
+                           0  1  2  3  4  5  6  7
+                           +--+--+--+--+--+--+--+
+                         0 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         1 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         2 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         3 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         4 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         5 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+                         6 |  |  |  |  |  |  |  |
+                           +--+--+--+--+--+--+--+
+
+   Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR.  If
+   (X,Y) = (0,0), the return value is the rule that runs horizontally above
+   the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
+   between that cell and cell (0,1); and so on, up to (0,NR), which runs
+   horizontally below cell (0,NR-1). */
+int
+table_get_rule (const struct table *table, enum table_axis axis, int x, int y)
 {
-  assert (t != NULL);
-  t->cc += t->cf;
-  t->ct += t->cf;
-  if (++t->row_ofs >= t->nr)
-    tab_realloc (t, -1, t->nr * 4 / 3);
+  assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
+  assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
+  return table->class->get_rule (table, axis, x, y);
 }
 \f
-static struct tab_table *t;
-static struct outp_driver *d;
-static int tab_hit;
-
-/* Set the current table to TABLE. */
-static void
-tabi_table (struct som_entity *table)
-{
-  assert (table != NULL);
-  assert (table->type == SOM_TABLE);
-
-  t = table->ext;
-  tab_offset (t, 0, 0);
-
-  assert (t->w == NULL && t->h == NULL);
-  t->w = pool_nalloc (t->container, t->nc, sizeof *t->w);
-  t->h = pool_nalloc (t->container, t->nr, sizeof *t->h);
-  t->hrh = pool_nmalloc (t->container, t->nr + 1, sizeof *t->hrh);
-  t->wrv = pool_nmalloc (t->container, t->nc + 1, sizeof *t->wrv);
-}
-
-/* Returns the line style to use for spacing purposes for a rule
-   of the given TYPE. */
-static enum outp_line_style
-rule_to_spacing_type (unsigned char type)
-{
-  switch (type)
-    {
-    case TAL_0:
-      return OUTP_L_NONE;
-    case TAL_GAP:
-    case TAL_1:
-      return OUTP_L_SINGLE;
-    case TAL_2:
-      return OUTP_L_DOUBLE;
-    default:
-      NOT_REACHED ();
-    }
-}
-
-/* Set the current output device to DRIVER. */
-static void
-tabi_driver (struct outp_driver *driver)
-{
-  int c, r;
-  int i;
-
-  assert (driver != NULL);
-  d = driver;
-
-  /* Figure out sizes of rules. */
-  for (r = 0; r <= t->nr; r++)
-    {
-      int width = 0;
-      for (c = 0; c < t->nc; c++)
-        {
-          unsigned char rh = t->rh[c + r * t->cf];
-          int w = driver->horiz_line_width[rule_to_spacing_type (rh)];
-          if (w > width)
-            width = w;
-        }
-      t->hrh[r] = width;
-    }
-
-  for (c = 0; c <= t->nc; c++)
-    {
-      int width = 0;
-      for (r = 0; r < t->nr; r++)
-        {
-          unsigned char *rv = &t->rv[c + r * (t->cf + 1)];
-          int w;
-          if (*rv == UCHAR_MAX)
-            *rv = c != 0 && c != t->nc ? TAL_GAP : TAL_0;
-          w = driver->vert_line_width[rule_to_spacing_type (*rv)];
-          if (w > width)
-            width = w;
-        }
-      t->wrv[c] = width;
-    }
-
-#if DEBUGGING
-  for (i = 0; i < t->nr; i++)
-    t->h[i] = -1;
-  for (i = 0; i < t->nc; i++)
-    t->w[i] = -1;
-#endif
-
-  assert (t->dim != NULL);
-  t->dim (t, d, t->dim_aux);
-
-#if DEBUGGING
+struct table_unshared
   {
-    int error = 0;
-
-    for (i = 0; i < t->nr; i++)
-      {
-       if (t->h[i] == -1)
-         {
-           printf ("Table row %d height not initialized.\n", i);
-           error = 1;
-         }
-       assert (t->h[i] > 0);
-      }
-
-    for (i = 0; i < t->nc; i++)
-      {
-       if (t->w[i] == -1)
-         {
-           printf ("Table column %d width not initialized.\n", i);
-           error = 1;
-         }
-       assert (t->w[i] > 0);
-      }
-  }
-#endif
-
-  /* Add up header sizes. */
-  for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
-    t->wl += t->w[i] + t->wrv[i + 1];
-  for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
-    t->ht += t->h[i] + t->hrh[i + 1];
-  for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
-    t->wr += t->w[i] + t->wrv[i + 1];
-  for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
-    t->hb += t->h[i] + t->hrh[i + 1];
-
-  /* Title. */
-  if (!(t->flags & SOMF_NO_TITLE))
-    t->ht += d->font_height;
-}
-
-/* Return the number of columns and rows in the table into N_COLUMNS
-   and N_ROWS, respectively. */
-static void
-tabi_count (int *n_columns, int *n_rows)
-{
-  assert (n_columns != NULL && n_rows != NULL);
-  *n_columns = t->nc;
-  *n_rows = t->nr;
-}
-
-static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
-
-/* Return the horizontal and vertical size of the entire table,
-   including headers, for the current output device, into HORIZ and
-   VERT. */
-static void
-tabi_area (int *horiz, int *vert)
-{
-  assert (horiz != NULL && vert != NULL);
+    struct table table;
+    struct table *subtable;
+  };
 
-  {
-    int w, c;
+static const struct table_class table_unshared_class;
 
-    for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
-        c < t->nc - t->r; c++)
-      w += t->w[c] + t->wrv[c];
-    *horiz = w;
-  }
+/* Takes ownership of TABLE and returns a table with the same contents but
+   which is guaranteed not to be shared (as returned by table_is_shared()).
 
-  {
-    int h, r;
-    for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
-        r < t->nr - t->b; r++)
-      h += t->h[r] + t->hrh[r];
-    *vert = h;
-  }
-}
+   If TABLE is unshared, just returns TABLE.
 
-/* Return the column style for this table into STYLE. */
-static void
-tabi_columns (int *style)
-{
-  assert (style != NULL);
-  *style = t->col_style;
-}
-
-/* Return the number of header rows/columns on the left, right, top,
-   and bottom sides into HL, HR, HT, and HB, respectively. */
-static void
-tabi_headers (int *hl, int *hr, int *ht, int *hb)
+   The only real use for this function is to create a copy of TABLE in which
+   the headers can be adjusted, which is a pretty specialized use case. */
+struct table *
+table_unshare (struct table *table)
 {
-  assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
-  *hl = t->l;
-  *hr = t->r;
-  *ht = t->t;
-  *hb = t->b;
-}
-
-/* Determines the number of rows or columns (including appropriate
-   headers), depending on CUMTYPE, that will fit into the space
-   specified.  Takes rows/columns starting at index START and attempts
-   to fill up available space MAX.  Returns in END the index of the
-   last row/column plus one; returns in ACTUAL the actual amount of
-   space the selected rows/columns (including appropriate headers)
-   filled. */
-static void
-tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
-{
-  int n;
-  int *d;
-  int *r;
-  int total;
-
-  assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
-  if (cumtype == SOM_ROWS)
-    {
-      assert (start >= 0 && start < t->nr);
-      n = t->nr - t->b;
-      d = &t->h[start];
-      r = &t->hrh[start + 1];
-      total = t->ht + t->hb;
-    }
+  if (!table_is_shared (table))
+    return table;
   else
     {
-      assert (start >= 0 && start < t->nc);
-      n = t->nc - t->r;
-      d = &t->w[start];
-      r = &t->wrv[start + 1];
-      total = t->wl + t->wr;
-    }
-
-  total += *d++;
-  if (total > max)
-    {
-      if (end)
-       *end = start;
-      if (actual)
-       *actual = 0;
-      return;
+      struct table_unshared *tiu = xmalloc (sizeof *tiu);
+      table_init (&tiu->table, &table_unshared_class);
+      table_set_nc (&tiu->table, table_nc (table));
+      table_set_nr (&tiu->table, table_nr (table));
+      table_set_hl (&tiu->table, table_hl (table));
+      table_set_hr (&tiu->table, table_hr (table));
+      table_set_ht (&tiu->table, table_ht (table));
+      table_set_hb (&tiu->table, table_hb (table));
+      tiu->subtable = table;
+      return &tiu->table;
     }
-
-  {
-    int x;
-
-    for (x = start + 1; x < n; x++)
-      {
-       int amt = *d++ + *r++;
-
-       total += amt;
-       if (total > max)
-         {
-           total -= amt;
-           break;
-         }
-      }
-
-    if (end)
-      *end = x;
-
-    if (actual)
-      *actual = total;
-  }
-}
-
-/* Return flags set for the current table into FLAGS. */
-static void
-tabi_flags (unsigned *flags)
-{
-  assert (flags != NULL);
-  *flags = t->flags;
 }
 
-/* Returns true if the table will fit in the given page WIDTH,
-   false otherwise. */
-static bool
-tabi_fits_width (int width)
+static struct table_unshared *
+table_unshared_cast (const struct table *table)
 {
-  int i;
-
-  for (i = t->l; i < t->nc - t->r; i++)
-    if (t->wl + t->wr + t->w[i] > width)
-      return false;
-
-  return true;
+  assert (table->class == &table_unshared_class);
+  return UP_CAST (table, struct table_unshared, table);
 }
 
-/* Returns true if the table will fit in the given page LENGTH,
-   false otherwise. */
-static bool
-tabi_fits_length (int length)
-{
-  int i;
-
-  for (i = t->t; i < t->nr - t->b; i++)
-    if (t->ht + t->hb + t->h[i] > length)
-      return false;
-
-  return true;
-}
-
-/* Sets the number of header rows/columns on the left, right, top,
-   and bottom sides to HL, HR, HT, and HB, respectively. */
 static void
-tabi_set_headers (int hl, int hr, int ht, int hb)
+table_unshared_destroy (struct table *tiu_)
 {
-  t->l = hl;
-  t->r = hr;
-  t->t = ht;
-  t->b = hb;
+  struct table_unshared *tiu = table_unshared_cast (tiu_);
+  table_unref (tiu->subtable);
+  free (tiu);
 }
 
-/* Render title for current table, with major index X and minor index
-   Y.  Y may be zero, or X and Y may be zero, but X should be nonzero
-   if Y is nonzero. */
 static void
-tabi_title (int x, int y)
+table_unshared_get_cell (const struct table *tiu_, int x, int y,
+                              struct table_cell *cell)
 {
-  char buf[1024];
-  char *cp;
-
-  if (t->flags & SOMF_NO_TITLE)
-    return;
-
-  cp = spprintf (buf, "%d.%d", table_num, subtable_num);
-  if (x && y)
-    cp = spprintf (cp, "(%d:%d)", x, y);
-  else if (x)
-    cp = spprintf (cp, "(%d)", x);
-  if (command_name != NULL)
-    cp = spprintf (cp, " %s", command_name);
-  cp = stpcpy (cp, ".  ");
-  if (t->title != NULL)
-    {
-      size_t length = strlen (t->title);
-      memcpy (cp, t->title, length);
-      cp += length;
-    }
-  *cp = 0;
-
-  {
-    struct outp_text text;
-
-    text.font = OUTP_PROPORTIONAL;
-    text.justification = OUTP_LEFT;
-    text.string = ss_buffer (buf, cp - buf);
-    text.h = d->width;
-    text.v = d->font_height;
-    text.x = 0;
-    text.y = d->cp_y;
-    d->class->text_draw (d, &text);
-  }
+  struct table_unshared *tiu = table_unshared_cast (tiu_);
+  table_get_cell (tiu->subtable, x, y, cell);
 }
 
-static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
-
-/* Renders columns C0...C1, plus headers, of rows R0...R1,
-   at the given vertical position Y.
-   C0 and C1 count vertical rules as columns,
-   but R0 and R1 do not count horizontal rules as rows.
-   Returns the vertical position after rendering. */
 static int
-render_rows (int y, int c0, int c1, int r0, int r1)
+table_unshared_get_rule (const struct table *tiu_,
+                              enum table_axis axis, int x, int y)
 {
-  int r;
-  for (r = r0; r < r1; r++)
-    {
-      int x = d->cp_x;
-      x = render_strip (x, y, r, 0, t->l * 2 + 1, r0, r1);
-      x = render_strip (x, y, r, c0 * 2 + 1, c1 * 2, r0, r1);
-      x = render_strip (x, y, r, (t->nc - t->r) * 2, t->nc * 2 + 1, r0, r1);
-      y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
-    }
-  return y;
+  struct table_unshared *tiu = table_unshared_cast (tiu_);
+  return table_get_rule (tiu->subtable, axis, x, y);
 }
 
-/* Draws table region (C0,R0)-(C1,R1), plus headers, at the
-   current position on the current output device.  */
-static void
-tabi_render (int c0, int r0, int c1, int r1)
-{
-  int y;
-
-  tab_hit++;
-
-  y = d->cp_y;
-  if (!(t->flags & SOMF_NO_TITLE))
-    y += d->font_height;
-
-  y = render_rows (y, c0, c1, 0, t->t * 2 + 1);
-  y = render_rows (y, c0, c1, r0 * 2 + 1, r1 * 2);
-  y = render_rows (y, c0, c1, (t->nr - t->b) * 2, t->nr * 2 + 1);
-}
-
-const struct som_table_class tab_table_class =
+static const struct table_class table_unshared_class =
   {
-    tabi_table,
-    tabi_driver,
-
-    tabi_count,
-    tabi_area,
-    NULL,
-    NULL,
-    tabi_columns,
-    NULL,
-    tabi_headers,
-    NULL,
-    tabi_cumulate,
-    tabi_flags,
-    tabi_fits_width,
-    tabi_fits_length,
-
-    NULL,
-    NULL,
-    tabi_set_headers,
-
-    tabi_title,
-    tabi_render,
+    table_unshared_destroy,
+    table_unshared_get_cell,
+    table_unshared_get_rule,
+    NULL,                       /* paste */
+    NULL,                       /* select */
   };
 \f
-static enum outp_justification
-translate_justification (unsigned int opt)
-{
-  switch (opt & TAB_ALIGN_MASK)
-    {
-    case TAB_RIGHT:
-      return OUTP_RIGHT;
-    case TAB_LEFT:
-      return OUTP_LEFT;
-    case TAB_CENTER:
-      return OUTP_CENTER;
-    default:
-      NOT_REACHED ();
-    }
-}
-
-/* Returns the line style to use for drawing a rule of the given
-   TYPE. */
-static enum outp_line_style
-rule_to_draw_type (unsigned char type)
-{
-  switch (type)
-    {
-    case TAL_0:
-    case TAL_GAP:
-      return OUTP_L_NONE;
-    case TAL_1:
-      return OUTP_L_SINGLE;
-    case TAL_2:
-      return OUTP_L_DOUBLE;
-    default:
-      NOT_REACHED ();
-    }
-}
+struct table_string
+  {
+    struct table table;
+    char *string;
+    unsigned int options;
+  };
 
-/* Returns the horizontal rule at the given column and row. */
-static int
-get_hrule (int c, int r)
-{
-  return t->rh[c + r * t->cf];
-}
+static const struct table_class table_string_class;
 
-/* Returns the vertical rule at the given column and row. */
-static int
-get_vrule (int c, int r)
+/* Returns a table that contains a single cell, whose contents are S with
+   options OPTIONS (a combination of TAB_* values).  */
+struct table *
+table_from_string (unsigned int options, const char *s)
 {
-  return t->rv[c + r * (t->cf + 1)];
+  struct table_string *ts = xmalloc (sizeof *ts);
+  table_init (&ts->table, &table_string_class);
+  ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
+  ts->string = xstrdup (s);
+  ts->options = options;
+  return &ts->table;
 }
 
-/* Renders the horizontal rule at the given column and row
-   at (X,Y) on the page. */
-static void
-render_horz_rule (int x, int y, int c, int r)
+static struct table_string *
+table_string_cast (const struct table *table)
 {
-  enum outp_line_style style = rule_to_draw_type (get_hrule (c, r));
-  if (style != OUTP_L_NONE)
-    d->class->line (d, x, y, x + t->w[c], y + t->hrh[r],
-                    OUTP_L_NONE, style, OUTP_L_NONE, style);
+  assert (table->class == &table_string_class);
+  return UP_CAST (table, struct table_string, table);
 }
 
-/* Renders the vertical rule at the given column and row
-   at (X,Y) on the page. */
 static void
-render_vert_rule (int x, int y, int c, int r)
+table_string_destroy (struct table *ts_)
 {
-  enum outp_line_style style = rule_to_draw_type (get_vrule (c, r));
-  if (style != OUTP_L_NONE)
-    d->class->line (d, x, y, x + t->wrv[c], y + t->h[r],
-                    style, OUTP_L_NONE, style, OUTP_L_NONE);
+  struct table_string *ts = table_string_cast (ts_);
+  free (ts->string);
+  free (ts);
 }
 
-/* Renders the rule intersection at the given column and row
-   at (X,Y) on the page. */
 static void
-render_rule_intersection (int x, int y, int c, int r)
+table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
+                       struct table_cell *cell)
 {
-  /* Bounds of intersection. */
-  int x0 = x;
-  int y0 = y;
-  int x1 = x + t->wrv[c];
-  int y1 = y + t->hrh[r];
-
-  /* Lines on each side of intersection. */
-  int top = r > 0 ? get_vrule (c, r - 1) : TAL_0;
-  int left = c > 0 ? get_hrule (c - 1, r) : TAL_0;
-  int bottom = r < t->nr ? get_vrule (c, r) : TAL_0;
-  int right = c < t->nc ? get_hrule (c, r) : TAL_0;
-
-  /* Output style for each line. */
-  enum outp_line_style o_top = rule_to_draw_type (top);
-  enum outp_line_style o_left = rule_to_draw_type (left);
-  enum outp_line_style o_bottom = rule_to_draw_type (bottom);
-  enum outp_line_style o_right = rule_to_draw_type (right);
-
-  if (o_top != OUTP_L_NONE || o_left != OUTP_L_NONE
-      || o_bottom != OUTP_L_NONE || o_right != OUTP_L_NONE)
-    d->class->line (d, x0, y0, x1, y1, o_top, o_left, o_bottom, o_right);
+  struct table_string *ts = table_string_cast (ts_);
+  cell->d[TABLE_HORZ][0] = 0;
+  cell->d[TABLE_HORZ][1] = 1;
+  cell->d[TABLE_VERT][0] = 0;
+  cell->d[TABLE_VERT][1] = 1;
+  cell->contents = ts->string;
+  cell->options = ts->options;
+  cell->destructor = NULL;
 }
 
-/* Returns the width of columns C1...C2 exclusive,
-   including interior but not exterior rules. */
-static int
-strip_width (int c1, int c2)
-{
-  int width = 0;
-  int c;
-
-  for (c = c1; c < c2; c++)
-    width += t->w[c] + t->wrv[c + 1];
-  if (c1 < c2)
-    width -= t->wrv[c2];
-  return width;
-}
 
-/* Returns the height of rows R1...R2 exclusive,
-   including interior but not exterior rules. */
 static int
-strip_height (int r1, int r2)
+table_string_get_rule (const struct table *ts UNUSED,
+                       enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
 {
-  int height = 0;
-  int r;
-
-  for (r = r1; r < r2; r++)
-    height += t->h[r] + t->hrh[r + 1];
-  if (r1 < r2)
-    height -= t->hrh[r2];
-  return height;
+  return TAL_0;
 }
 
-/* Renders the cell at the given column and row at (X,Y) on the
-   page.  Also renders joined cells that extend as far to the
-   right as C1 and as far down as R1. */
-static void
-render_cell (int x, int y, int c, int r, int c1, int r1)
-{
-  const int index = c + (r * t->cf);
-  unsigned char type = t->ct[index];
-  struct substring *content = &t->cc[index];
-
-  if (!(type & TAB_JOIN))
-    {
-      if (!(type & TAB_EMPTY))
-        {
-          struct outp_text text;
-          text.font = options_to_font (type);
-          text.justification = translate_justification (type);
-          text.string = *content;
-          text.h = t->w[c];
-          text.v = t->h[r];
-          text.x = x;
-          text.y = y;
-          d->class->text_draw (d, &text);
-        }
-    }
-  else
-    {
-      struct tab_joined_cell *j
-        = (struct tab_joined_cell *) ss_data (*content);
-
-      if (j->hit != tab_hit)
-        {
-          j->hit = tab_hit;
-
-          if (j->x1 == c && j->y1 == r)
-            {
-              struct outp_text text;
-              text.font = options_to_font (type);
-              text.justification = translate_justification (type);
-              text.string = j->contents;
-              text.x = x;
-              text.y = y;
-              text.h = strip_width (j->x1, MIN (j->x2, c1));
-              text.v = strip_height (j->y1, MIN (j->y2, r1));
-              d->class->text_draw (d, &text);
-            }
-        }
-    }
-}
-
-/* Render contiguous strip consisting of columns C0...C1, exclusive,
-   on row R, at (X,Y).  Returns X position after rendering.
-   Also renders joined cells that extend beyond that strip,
-   cropping them to lie within rendering region (C0,R0)-(C1,R1).
-   C0 and C1 count vertical rules as columns.
-   R counts horizontal rules as rows, but R0 and R1 do not. */
-static int
-render_strip (int x, int y, int r, int c0, int c1, int r0 UNUSED, int r1)
-{
-  int c;
-
-  for (c = c0; c < c1; c++)
-    if (c & 1)
-      {
-        if (r & 1)
-          render_cell (x, y, c / 2, r / 2, c1 / 2, r1);
-        else
-          render_horz_rule (x, y, c / 2, r / 2);
-        x += t->w[c / 2];
-      }
-    else
-      {
-        if (r & 1)
-          render_vert_rule (x, y, c / 2, r / 2);
-        else
-          render_rule_intersection (x, y, c / 2, r / 2);
-        x += t->wrv[c / 2];
-      }
-
-  return x;
-}
-
-/* Sets COMMAND_NAME as the name of the current command,
-   for embedding in output. */
-void
-tab_set_command_name (const char *command_name_)
-{
-  free (command_name);
-  command_name = command_name_ ? xstrdup (command_name_) : NULL;
-}
+static const struct table_class table_string_class =
+  {
+    table_string_destroy,
+    table_string_get_cell,
+    table_string_get_rule,
+    NULL,                       /* paste */
+    NULL,                       /* select */
+  };
index 1748c24c855e71ec8c0212dac76d00662db76f67..06427ac32b75bac0d91670840c3a10c4307b8484 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2009 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
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-#if !tab_h
-#define tab_h 1
+#ifndef OUTPUT_TABLE_H
+#define OUTPUT_TABLE_H 1
 
-#include <limits.h>
-#include <libpspp/str.h>
+/* Tables.
 
-/* Cell options. */
-enum
-  {
-    TAB_NONE = 0,
+.  A table is a rectangular grid of cells.  Cells can be joined to form larger
+   cells.  Rows and columns can be separated by rules of various types.  Rows
+   at the top and bottom of a table and columns at the left and right edges of
+   a table can be designated as headers, which means that if the table must be
+   broken across more than one page, those rows or columns are repeated on each
+   page.
 
-    TAB_ALIGN_MASK = 03,       /* Alignment mask. */
-    TAB_RIGHT = 00,            /* Right justify. */
-    TAB_LEFT = 01,             /* Left justify. */
-    TAB_CENTER = 02,           /* Center. */
+   Every table is an instance of a particular table class that is responsible
+   for keeping track of cell data.  By far the most common table class is
+   struct tab_table (see output/tab.h).  This header also declares some other
+   kinds of table classes, near the end of the file.
 
-    /* Cell types. */
-    TAB_JOIN = 004,            /* Joined cell. */
-    TAB_EMPTY = 010,           /* Empty cell. */
+   A table is not itself an output_item, and thus a table cannot by itself be
+   used for output, but they can be embedded inside struct table_item (see
+   table-item.h) for that purpose. */
 
-    /* Flags. */
-    TAB_EMPH = 020,             /* Emphasize cell contents. */
-    TAB_FIX = 040,              /* Use fixed font. */
-  };
+#include <stdbool.h>
+#include <stddef.h>
 
-/* Line styles. */
-enum
-  {
-    TAL_0 = 0,                 /* No line. */
-    TAL_1 = 1,                 /* Single line. */
-    TAL_2 = 2,                 /* Double line. */
-    TAL_GAP = 3,                /* Spacing but no line. */
-    TAL_COUNT,                 /* Number of line styles. */
-  };
+struct casereader;
+struct fmt_spec;
+struct variable;
 
-/* Column styles.  Must correspond to SOM_COL_*. */
+/* Properties of a table cell. */
 enum
   {
-    TAB_COL_NONE,                      /* No columns. */
-    TAB_COL_DOWN                       /* Columns down first. */
-  };
+    TAB_NONE = 0,
 
-/* Joined cell. */
-struct tab_joined_cell
-  {
-    int x1, y1;
-    int x2, y2;
-    int hit;
-    struct substring contents;
-  };
+    /* Alignment of cell contents. */
+    TAB_RIGHT      = 0 << 0,    /* Right justify. */
+    TAB_LEFT       = 1 << 0,    /* Left justify. */
+    TAB_CENTER     = 2 << 0,    /* Centered. */
+    TAB_ALIGNMENT  = 3 << 0,   /* Alignment mask. */
 
-struct outp_driver;
-struct tab_table;
-typedef void tab_dim_func (struct tab_table *, struct outp_driver *,
-                           void *aux);
+    /* These flags may be combined with any alignment. */
+    TAB_EMPH       = 1 << 2,    /* Emphasize cell contents. */
+    TAB_FIX        = 1 << 3,    /* Use fixed font. */
 
-/* A table. */
-struct tab_table
-  {
-    struct pool *container;
-
-    /* Contents. */
-    int col_style;             /* Columns: One of TAB_COL_*. */
-    int col_group;             /* Number of rows per column group. */
-    char *title;                /* Table title. */
-    unsigned flags;            /* SOMF_*. */
-    int nc, nr;                        /* Number of columns, rows. */
-    int cf;                    /* Column factor for indexing purposes. */
-    int l, r, t, b;            /* Number of header rows on each side. */
-    struct substring *cc;      /* Cell contents; substring *[nr][nc]. */
-    unsigned char *ct;         /* Cell types; unsigned char[nr][nc]. */
-    unsigned char *rh;         /* Horiz rules; unsigned char[nr+1][nc]. */
-    unsigned char *rv;         /* Vert rules; unsigned char[nr][nc+1]. */
-    tab_dim_func *dim;         /* Calculates cell widths and heights. */
-    void *dim_aux;              /* Auxiliary data for dim function. */
-
-    /* Calculated during output. */
-    int *w;                    /* Column widths; [nc]. */
-    int *h;                    /* Row heights; [nr]. */
-    int *hrh;                  /* Heights of horizontal rules; [nr+1]. */
-    int *wrv;                  /* Widths of vertical rules; [nc+1]. */
-    int wl, wr, ht, hb;                /* Width/height of header rows/columns. */
-
-    /* Editing info. */
-    int col_ofs, row_ofs;      /* X and Y offsets. */
+    /* Bits with values (1 << TAB_FIRST_AVAILABLE) and higher are
+       not used, so they are available for subclasses to use as
+       they wish. */
+    TAB_FIRST_AVAILABLE = 4
   };
 
-/* Number of rows in TABLE. */
-#define tab_nr(TABLE) ((TABLE)->nr)
-
-/* Number of columns in TABLE. */
-#define tab_nc(TABLE) ((TABLE)->nc)
-
-/* Number of left header columns in TABLE. */
-#define tab_l(TABLE) ((TABLE)->l)
-
-/* Number of right header columns in TABLE. */
-#define tab_r(TABLE) ((TABLE)->r)
-
-/* Number of top header rows in TABLE. */
-#define tab_t(TABLE) ((TABLE)->t)
-
-/* Number of bottom header rows in TABLE. */
-#define tab_b(TABLE) ((TABLE)->b)
-
-/* Tables. */
-struct tab_table *tab_create (int nc, int nr, int reallocable);
-void tab_destroy (struct tab_table *);
-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_columns (struct tab_table *, int style, int group);
-void tab_title (struct tab_table *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-void tab_flags (struct tab_table *, unsigned);
-void tab_submit (struct tab_table *);
-
-/* Dimensioning. */
-tab_dim_func tab_natural_dimensions;
-int tab_natural_width (struct tab_table *t, struct outp_driver *d, int c);
-int tab_natural_height (struct tab_table *t, struct outp_driver *d, int r);
-void tab_dim (struct tab_table *, tab_dim_func *, void *aux);
-
-/* Rules. */
-void tab_hline (struct tab_table *, int style, int x1, int x2, int y);
-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);
-
-/* Text options, passed in the `opt' argument. */
+/* Styles for the rules around table cells. */
 enum
   {
-    TAT_NONE = 0,              /* No options. */
-    TAT_TITLE = 0x0200 | TAB_EMPH, /* Title attributes. */
-    TAT_NOWRAP = 0x0800         /* No text wrap (tab_output_text() only). */
+    TAL_0,                     /* No line. */
+    TAL_GAP,                    /* Spacing but no line. */
+    TAL_1,                     /* Single line. */
+    TAL_2,                     /* Double line. */
+    N_LINES
   };
 
-/* Cells. */
-struct fmt_spec;
-struct dictionary;
-union value;
-void tab_value (struct tab_table *, int c, int r, unsigned char opt,
-               const union value *, const struct dictionary *dict,
-               const struct fmt_spec *);
+/* Given line styles A and B (each one of the TAL_* enumeration constants
+   above), returns a line style that "combines" them, that is, that gives a
+   reasonable line style choice for a rule for different reasons should have
+   both styles A and B.
+
+   Used especially for pasting tables together (see table_paste()). */
+static inline int table_rule_combine (int a, int b)
+{
+  return a > b ? a : b;
+}
 
-void tab_fixed (struct tab_table *, int c, int r, unsigned char opt,
-               double v, int w, int d);
+/* A table axis.
 
-void tab_double (struct tab_table *, int c, int r, unsigned char opt,
-               double v, const struct fmt_spec *);
+   Many table-related declarations use 2-element arrays in place of "x" and "y"
+   variables.  This reduces code duplication significantly, because much table
+   code has treat rows and columns the same way.
 
-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 *, ...)
-     PRINTF_FORMAT (5, 6);
+   A lot of code that uses these enumerations assumes that the two values are 0
+   and 1, so don't change them to other values. */
+enum table_axis
+  {
+    TABLE_HORZ,
+    TABLE_VERT,
+    TABLE_N_AXES
+  };
 
-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);
+/* A table. */
+struct table
+  {
+    const struct table_class *class;
 
-/* Cell low-level access. */
-#define tab_alloc(TABLE, AMT) pool_alloc ((TABLE)->container, (AMT))
-void tab_raw (struct tab_table *, int c, int r, unsigned opt,
-             struct substring *);
+    /* Table size.
 
-/* Editing. */
-void tab_offset (struct tab_table *, int col, int row);
-void tab_next_row (struct tab_table *);
+       n[TABLE_HORZ]: Number of columns.
+       n[TABLE_VERT]: Number of rows. */
+    int n[TABLE_N_AXES];
 
-/* Current row/column offset. */
-#define tab_row(TABLE) ((TABLE)->row_ofs)
-#define tab_col(TABLE) ((TABLE)->col_ofs)
+    /* Table headers.
 
-/* Simple output. */
-void tab_output_text (int options, const char *string);
-void tab_output_text_format (int options, const char *, ...)
-     PRINTF_FORMAT (2, 3);
+       Rows at the top and bottom of a table and columns at the left and right
+       edges of a table can be designated as headers.  If the table must be
+       broken across more than one page for output, headers rows and columns
+       are repeated on each page.
 
-/* Embedding the command name in the output. */
-void tab_set_command_name (const char *);
+       h[TABLE_HORZ][0]: Left header columns.
+       h[TABLE_HORZ][1]: Right header columns.
+       h[TABLE_VERT][0]: Top header rows.
+       h[TABLE_VERT][1]: Bottom header rows. */
+    int h[TABLE_N_AXES][2];
 
-#endif /* tab_h */
+    /* Reference count.  A table may be shared between multiple owners,
+       indicated by a reference count greater than 1.  When this is the case,
+       the table must not be modified. */
+    int ref_cnt;
+  };
 
+/* Reference counting. */
+struct table *table_ref (const struct table *);
+void table_unref (struct table *);
+bool table_is_shared (const struct table *);
+struct table *table_unshare (struct table *);
+
+/* Returns the number of columns or rows, respectively, in T. */
+static inline int table_nc (const struct table *t)
+        { return t->n[TABLE_HORZ]; }
+static inline int table_nr (const struct table *t)
+        { return t->n[TABLE_VERT]; }
+
+/* Returns the number of left, right, top, or bottom headers, respectively, in
+   T.  */
+static inline int table_hl (const struct table *t)
+        { return t->h[TABLE_HORZ][0]; }
+static inline int table_hr (const struct table *t)
+        { return t->h[TABLE_HORZ][1]; }
+static inline int table_ht (const struct table *t)
+        { return t->h[TABLE_VERT][0]; }
+static inline int table_hb (const struct table *t)
+        { return t->h[TABLE_VERT][1]; }
+
+/* Set headers. */
+void table_set_hl (struct table *, int hl);
+void table_set_hr (struct table *, int hr);
+void table_set_ht (struct table *, int ht);
+void table_set_hb (struct table *, int hb);
+\f
+/* Table classes. */
+
+/* Simple kinds of tables. */
+struct table *table_from_string (unsigned int options, 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 *,
+                           enum table_axis orientation);
+struct table *table_hpaste (struct table *left, struct table *right);
+struct table *table_vpaste (struct table *top, struct table *bottom);
+
+/* Taking subsets of tables. */
+struct table *table_select (struct table *, int rect[TABLE_N_AXES][2]);
+struct table *table_select_slice (struct table *, enum table_axis,
+                                  int z0, int z1, bool add_headers);
+struct table *table_select_columns (struct table *,
+                                    int x0, int x1, bool add_headers);
+struct table *table_select_rows (struct table *,
+                                 int y0, int y1, bool add_headers);
+
+/* Miscellaneous table operations. */
+struct table *table_transpose (struct table *);
+
+#endif /* output/table.h */
diff --git a/src/output/text-item.c b/src/output/text-item.c
new file mode 100644 (file)
index 0000000..16588ae
--- /dev/null
@@ -0,0 +1,102 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 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/text-item.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <libpspp/cast.h>
+#include <output/driver.h>
+#include <output/output-item-provider.h>
+
+#include "xalloc.h"
+#include "xvasprintf.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static struct text_item *
+allocate_text_item (enum text_item_type type, char *text)
+{
+  struct text_item *item = xmalloc (sizeof *item);
+  output_item_init (&item->output_item, &text_item_class);
+  item->text = text;
+  item->type = type;
+  return item;
+}
+
+/* Creates and returns a new text item containing a copy of TEXT and the
+   specified TYPE.  The caller retains ownership of TEXT. */
+struct text_item *
+text_item_create (enum text_item_type type, const char *text)
+{
+  return allocate_text_item (type, xstrdup (text));
+}
+
+/* Creates and returns a new text item containing a copy of FORMAT, which is
+   formatted as if by printf(), and the specified TYPE.  The caller retains
+   ownership of FORMAT. */
+struct text_item *
+text_item_create_format (enum text_item_type type, const char *format, ...)
+{
+  struct text_item *item;
+  va_list args;
+
+  va_start (args, format);
+  item = allocate_text_item (type, xvasprintf (format, args));
+  va_end (args);
+
+  return item;
+}
+
+/* Returns ITEM's type. */
+enum text_item_type
+text_item_get_type (const struct text_item *item)
+{
+  return item->type;
+}
+
+/* Returns ITEM's text, which the caller may not modify or free. */
+const char *
+text_item_get_text (const struct text_item *item)
+{
+  return item->text;
+}
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+   the output subsystem. */
+void
+text_item_submit (struct text_item *item)
+{
+  output_submit (&item->output_item);
+}
+\f
+static void
+text_item_destroy (struct output_item *output_item)
+{
+  struct text_item *item = to_text_item (output_item);
+  free (item->text);
+  free (item);
+}
+
+const struct output_item_class text_item_class =
+  {
+    text_item_destroy,
+  };
diff --git a/src/output/text-item.h b/src/output/text-item.h
new file mode 100644 (file)
index 0000000..b62e7dc
--- /dev/null
@@ -0,0 +1,133 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009 Free Sonftware 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_TEXT_ITEM_H
+#define OUTPUT_TEXT_ITEM_H 1
+
+/* Text items.
+
+   A text item is a subclass of an output item (see
+   output/output-item.h).
+
+   A text item is just a text string. */
+
+#include <stdbool.h>
+#include <libpspp/compiler.h>
+#include <output/output-item.h>
+
+enum text_item_type
+  {
+    /* Each PSPP command is bracketed between a pair of these text items.  The
+       text item's string is the full name of the command.  The syntax text
+       items associated with the command, as well as all output produced
+       directly by the command, are contained within the pair.  There is no
+       nesting. */
+    TEXT_ITEM_COMMAND_OPEN,     /* Command starting. */
+    TEXT_ITEM_COMMAND_CLOSE,    /* Command completed. */
+
+    /* Headings. */
+    TEXT_ITEM_TITLE,            /* TITLE command. */
+    TEXT_ITEM_SUBTITLE,         /* SUBTITLE command. */
+    TEXT_ITEM_SUBHEAD,          /* Heading within a command's output.*/
+
+    /* Syntax. */
+    TEXT_ITEM_SYNTAX,           /* A single line of PSPP syntax. */
+    TEXT_ITEM_COMMENT,          /* COMMENT command. */
+    TEXT_ITEM_ECHO,             /* ECHO command. */
+
+    /* Ordinary text. */
+    TEXT_ITEM_PARAGRAPH,        /* Normal paragraph of text. */
+    TEXT_ITEM_MONOSPACE,        /* Paragraph of monospaced text. */
+
+    /* Spacing.  Some output drivers that are not based on lines and pages
+       (e.g. CSV, HTML) may ignore these. */
+    TEXT_ITEM_BLANK_LINE,       /* Blank line. */
+    TEXT_ITEM_EJECT_PAGE        /* Eject page. */
+  };
+
+/* A text item. */
+struct text_item
+  {
+    struct output_item output_item;
+    char *text;                 /* The content. */
+    enum text_item_type type;   /* Type. */
+  };
+
+struct text_item *text_item_create (enum text_item_type, const char *text);
+struct text_item *text_item_create_format (enum text_item_type,
+                                           const char *format, ...)
+  PRINTF_FORMAT (2, 3);
+
+enum text_item_type text_item_get_type (const struct text_item *);
+const char *text_item_get_text (const struct text_item *);
+\f
+/* This boilerplate for text_item, a subclass of output_item, was
+   autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include <libpspp/cast.h>
+
+extern const struct output_item_class text_item_class;
+
+/* Returns true if SUPER is a text_item, otherwise false. */
+static inline bool
+is_text_item (const struct output_item *super)
+{
+  return super->class == &text_item_class;
+}
+
+/* Returns SUPER converted to text_item.  SUPER must be a text_item, as
+   reported by is_text_item. */
+static inline struct text_item *
+to_text_item (const struct output_item *super)
+{
+  assert (is_text_item (super));
+  return UP_CAST (super, struct text_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+text_item_super (const struct text_item *instance)
+{
+  return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct text_item *
+text_item_ref (const struct text_item *instance)
+{
+  return to_text_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+   the reference count is now zero. */
+static inline void
+text_item_unref (struct text_item *instance)
+{
+  output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+   false otherwise. */
+static inline bool
+text_item_is_shared (const struct text_item *instance)
+{
+  return output_item_is_shared (&instance->output_item);
+}
+
+void text_item_submit (struct text_item *);
+\f
+#endif /* output/text-item.h */
index c21b681d1f289f980e8bbcd274c2743726c73275..124380cf48199167ccca16457cdc14cfa5df1d48 100644 (file)
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
 include $(top_srcdir)/src/ui/terminal/automake.mk
-if WITHGUI
+if HAVE_GUI
 include $(top_srcdir)/src/ui/gui/automake.mk
 endif
 
@@ -9,7 +9,6 @@ endif
 noinst_LTLIBRARIES += src/ui/libuicommon.la
 
 src_ui_libuicommon_la_SOURCES = \
-       src/ui/command-line.c src/ui/command-line.h \
        src/ui/debugger.c src/ui/debugger.h \
        src/ui/source-init-opts.c src/ui/source-init-opts.h \
        src/ui/syntax-gen.c src/ui/syntax-gen.h
diff --git a/src/ui/command-line.c b/src/ui/command-line.c
deleted file mode 100644 (file)
index 46dddd4..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
-
-   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 "command-line.h"
-#include <argp.h>
-#include <gl/xalloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libpspp/compiler.h>
-#include <assert.h>
-
-
-struct clp_child
-{
-  void *aux;
-};
-
-struct command_line_processor
-{
-  struct argp master_parser;
-
-  struct clp_child *child_lookup_table;
-  struct argp_child *children;
-  int n_children;
-
-  const char *doc;
-  const char *args_doc;
-
-  void *aux;
-};
-
-
-/* Convenience function for use in parsing functions.
-   Returns the object for this parser */
-struct command_line_processor *
-get_subject (struct argp_state *state)
-{
-  const struct argp *root = state->root_argp;
-
-  const struct argp_child *children = root->children;
-
-  return  (struct command_line_processor *) children[0].argp;
-}
-
-
-/* Create a command line processor.
-   DOC is typically the name of the program and short description.
-   ARGS_DOC is a short description of the non option arguments.
-   AUX is an arbitrary pointer.
- */
-struct command_line_processor *
-command_line_processor_create (const char *doc, const char *args_doc, void *aux)
-{
-  struct command_line_processor *clp = xzalloc (sizeof (*clp));
-
-  clp->children = NULL;
-  clp->child_lookup_table = NULL;
-
-  clp->doc = doc;
-  clp->args_doc = args_doc;
-  clp->aux = aux;
-
-  return clp;
-}
-
-/* Destroy a command line processor */
-void
-command_line_processor_destroy (struct command_line_processor *clp)
-{
-  free (clp->children);
-  free (clp->child_lookup_table);
-  free (clp);
-}
-
-
-/* Add a CHILD to the processor CLP, with the doc string DOC.
-   AUX is an auxilliary pointer, specific to CHILD.
-   If AUX is not known or not needed then it may be set to NULL
-*/
-void
-command_line_processor_add_options (struct command_line_processor *clp, const struct argp *child,
-                              const char *doc, void *aux)
-{
-  clp->n_children++;
-
-  clp->children = xrealloc (clp->children, (clp->n_children + 1) * sizeof (*clp->children));
-  memset (&clp->children[clp->n_children - 1], 0, sizeof (*clp->children));
-
-  clp->child_lookup_table = xrealloc (clp->child_lookup_table,
-                                     clp->n_children * sizeof (*clp->child_lookup_table));
-
-  clp->child_lookup_table [clp->n_children - 1].aux = aux;
-
-  clp->children [clp->n_children - 1].argp = child;
-  clp->children [clp->n_children - 1].header = doc;
-  clp->children [clp->n_children].argp = NULL;
-}
-
-
-/* Set the aux paramter for CHILD in CLP to AUX.
-   Any previous value will be overwritten.
- */
-void
-command_line_processor_replace_aux (struct command_line_processor *clp, const struct argp *child, void *aux)
-{
-  int i;
-  for (i = 0 ; i < clp->n_children; ++i )
-    {
-      if (child->options == clp->children[i].argp->options)
-       {
-         clp->child_lookup_table[i].aux = aux;
-         break;
-       }
-    }
-  assert (i < clp->n_children);
-}
-
-
-static error_t
-top_level_parser (int key UNUSED, char *arg UNUSED, struct argp_state *state)
-{
-  int i;
-  struct command_line_processor *clp = state->input;
-
-  if ( key == ARGP_KEY_INIT)
-    {
-
-      for (i = 0;  i < clp->n_children ; ++i)
-       {
-         state->child_inputs[i] = clp->child_lookup_table[i].aux;
-       }
-    }
-
-  return ARGP_ERR_UNKNOWN;
-}
-
-
-/* Parse the command line specified by (ARGC, ARGV) using CLP */
-void
-command_line_processor_parse (struct command_line_processor *clp, int argc, char **argv)
-{
-  clp->master_parser.parser = top_level_parser;
-  clp->master_parser.args_doc = clp->args_doc;
-
-  clp->master_parser.doc = clp->doc;
-
-  clp->master_parser.children = clp->children;
-
-  argp_parse (&clp->master_parser, argc, argv, 0, 0, clp);
-}
-
diff --git a/src/ui/command-line.h b/src/ui/command-line.h
deleted file mode 100644 (file)
index 98edbea..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
-
-   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 SRC_UI_COMMAND_LINE_H
-#define SRC_UI_COMMAND_LINE_H
-
-#include <argp.h>
-
-struct command_line_processor;
-
-struct command_line_processor * get_subject (struct argp_state *state);
-
-struct command_line_processor *command_line_processor_create (const char *, const char *, void *);
-
-void command_line_processor_add_options (struct command_line_processor *cla, const struct argp *child, const char *doc, void *aux);
-
-void command_line_processor_replace_aux (struct command_line_processor *cla, const struct argp *child, void *aux);
-
-void command_line_processor_destroy (struct command_line_processor *);
-
-void command_line_processor_parse (struct command_line_processor *, int argc, char **argv);
-
-#endif
index 0a827a3a489876cba70598abcf2ee7fbc946a576..a9b6f2123caa9573c35824858ddef552ed3bbb89 100644 (file)
@@ -26,6 +26,7 @@ src_ui_gui_psppire_LDADD = \
        src/libpspp.la \
        src/libpspp-core.la \
        $(GTK_LIBS) \
+       $(CAIRO_LIBS) \
        $(LIBINTL)
 
 src_ui_gui_psppiredir = $(pkgdatadir)
@@ -61,7 +62,6 @@ UI_FILES = \
        src/ui/gui/factor.ui \
        src/ui/gui/find.ui \
        src/ui/gui/frequencies.ui \
-       src/ui/gui/message-dialog.ui \
        src/ui/gui/oneway.ui \
        src/ui/gui/psppire.ui \
        src/ui/gui/rank.ui \
@@ -143,8 +143,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/helper.c \
        src/ui/gui/helper.h \
        src/ui/gui/main.c \
-       src/ui/gui/message-dialog.c \
-       src/ui/gui/message-dialog.h \
        src/ui/gui/missing-val-dialog.c \
        src/ui/gui/missing-val-dialog.h \
         src/ui/gui/oneway-anova-dialog.c \
index 9336f7ce3d4dbe318fb8ed5fbdd5a890e3be57ed..6ccb5a534deca402d8e879dd2f3f6376a13e30e3 100644 (file)
@@ -23,7 +23,7 @@
 #include <libpspp/getl.h>
 #include <language/lexer/lexer.h>
 #include <language/command.h>
-#include <output/manager.h>
+#include <output/driver.h>
 #include "psppire-output-window.h"
 
 extern struct dataset *the_dataset;
@@ -102,9 +102,7 @@ execute_syntax (struct getl_interface *sss)
   if (!lazy_casereader_destroy (reader, lazy_serial))
     psppire_data_store_set_reader (the_data_store, reader);
 
-  som_flush ();
-
-  psppire_output_window_reload ();
+  output_flush ();
 
   return retval;
 }
index d72116069884cf3a21a199a7615b8e400a8657b5..ca0c3b5f4a9bb20b378792db2c7f1664a5d44b46 100644 (file)
@@ -34,6 +34,7 @@ which match particular strings */
 #include <ctype.h>
 #include <sys/types.h>
 #include <regex.h>
+#include <libpspp/cast.h>
 #include <libpspp/message.h>
 
 #include <gtk/gtk.h>
@@ -566,7 +567,8 @@ regexp_label_compare (const struct comparator *cmptr,
 static void
 regexp_destroy (struct comparator *cmptr)
 {
-  struct regexp_comparator *rec = (struct regexp_comparator *) cmptr;
+  struct regexp_comparator *rec
+    = UP_CAST (cmptr, struct regexp_comparator, parent);
 
   regfree (&rec->re);
 }
@@ -574,7 +576,8 @@ regexp_destroy (struct comparator *cmptr)
 static void
 cmptr_value_destroy (struct comparator *cmptr)
 {
-  struct value_comparator *vc = (struct value_comparator *) cmptr;
+  struct value_comparator *vc
+    = UP_CAST (cmptr, struct value_comparator, parent);
   value_destroy (&vc->pattern, var_get_width (cmptr->var));
 }
 
@@ -583,7 +586,7 @@ static struct comparator *
 value_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target)
 {
   struct value_comparator *vc = xzalloc (sizeof (*vc));
-  struct comparator *cmptr = (struct comparator *) vc;
+  struct comparator *cmptr = &vc->parent;
 
   cmptr->flags = 0;
   cmptr->var = var;
@@ -602,7 +605,7 @@ string_comparator_create (const struct variable *var, const PsppireDict *dict,
                          enum string_cmp_flags flags)
 {
   struct string_comparator *ssc = xzalloc (sizeof (*ssc));
-  struct comparator *cmptr = (struct comparator *) ssc;
+  struct comparator *cmptr = &ssc->parent;
 
   cmptr->flags = flags;
   cmptr->var = var;
@@ -625,7 +628,7 @@ regexp_comparator_create (const struct variable *var, const PsppireDict *dict, c
 {
   int code;
   struct regexp_comparator *rec = xzalloc (sizeof (*rec));
-  struct comparator *cmptr = (struct comparator *) rec;
+  struct comparator *cmptr = &rec->parent;
 
   cmptr->flags = flags;
   cmptr->var = var;
index 3e53f1ecb2e2ece73aa5d3a60d4d4fc8a0a4e206..377f17a7f6f77dae93e73a59e02fd31a95f5ae15 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <glib.h>
 #include "helper.h"
-#include "message-dialog.h"
 #include <data/format.h>
 #include <data/data-in.h>
 #include <data/data-out.h>
index 05cc421b3ede67e4f08ef4ded3c10b0f065c5ec9..517d74affdafe7b7b903bb1d8057f593fa326bdd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2010  Free Software Foundation
 
    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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <gl/xalloc.h>
+
+#include "ui/gui/psppire.h"
+
 #include <gtk/gtk.h>
-#include "psppire.h"
-#include "progname.h"
 #include <stdlib.h>
-#include <argp.h>
-#include <gl/relocatable.h>
-#include <ui/command-line.h>
-#include <ui/source-init-opts.h>
 
-#include <libpspp/version.h>
-#include <libpspp/copyleft.h>
+#include "libpspp/argv-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/getl.h"
+#include "libpspp/version.h"
+#include "libpspp/copyleft.h"
+#include "ui/source-init-opts.h"
+
+#include "gl/progname.h"
+#include "gl/relocatable.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-const char *argp_program_version = version;
-const char *argp_program_bug_address = PACKAGE_BUGREPORT;
-
 \f
 /* Arguments to be interpreted before the X server gets initialised */
 
-static const struct argp_option startup_options [] =
+enum
   {
-    {"no-splash",  'q',  0,  0,  N_("Don't show the splash screen"), 0 },
-    { 0, 0, 0, 0, 0, 0 }
+    OPT_NO_SPLASH,
+    N_STARTUP_OPTIONS
   };
 
-static error_t
-parse_startup_opts (int key, char *arg, struct argp_state *state)
+static const struct argv_option startup_options[N_STARTUP_OPTIONS] =
+  {
+    {"no-splash", 'q', no_argument, OPT_NO_SPLASH}
+  };
+
+static void
+startup_option_callback (int id, void *show_splash_)
 {
-  gboolean *showsplash = state->input;
+  gboolean *show_splash = show_splash_;
 
-  switch (key)
+  switch (id)
     {
-    case 'q':
-      *showsplash = FALSE;
+    case OPT_NO_SPLASH:
+      *show_splash = FALSE;
       break;
+
     default:
-      return ARGP_ERR_UNKNOWN;
+      NOT_REACHED ();
     }
-  return 0;
 }
-
-static const struct argp startup_argp = {startup_options, parse_startup_opts, 0, 0, 0, 0, 0};
-
 \f
-
 static GtkWidget *
 create_splash_window (void)
 {
@@ -108,10 +110,9 @@ quit_one_loop (gpointer data)
 
 struct initialisation_parameters
 {
-  int argc;
-  char **argv;
+  struct source_stream *ss;
+  const char *data_file;
   GtkWidget *splash_window;
-  struct command_line_processor *clp;
 };
 
 
@@ -119,7 +120,7 @@ static gboolean
 run_inner_loop (gpointer data)
 {
   struct initialisation_parameters *ip = data;
-  initialize (ip->clp, ip->argc, ip->argv);
+  initialize (ip->ss, ip->data_file);
 
   g_timeout_add (500, hide_splash_window, ip->splash_window);
 
@@ -144,10 +145,10 @@ static GMemVTable vtable =
 int
 main (int argc, char *argv[])
 {
-  struct command_line_processor *clp ;
   struct initialisation_parameters init_p;
   gboolean show_splash = TRUE;
-
+  struct argv_parser *parser;
+  struct source_stream *ss;
   const gchar *vers;
 
   set_program_name (argv[0]);
@@ -170,21 +171,22 @@ main (int argc, char *argv[])
       g_warning (vers);
     }
 
-  clp = command_line_processor_create (_("PSPPIRE --- A user interface for PSPP"), "[ DATA-FILE ]", 0);
-
-  command_line_processor_add_options (clp, &startup_argp, _("Miscellaneous options:"),  &show_splash);
-  command_line_processor_add_options (clp, &post_init_argp,
-                                     _("Options affecting syntax and behavior:"),  NULL);
-  command_line_processor_add_options (clp, &non_option_argp, NULL, NULL);
-
-  command_line_processor_parse (clp, argc, argv);
-
+  /* Let GDK remove any options that it owns. */
   gdk_init (&argc, &argv);
 
+  /* Parse our own options. */
+  ss = create_source_stream ();
+  parser = argv_parser_create ();
+  argv_parser_add_options (parser, startup_options, N_STARTUP_OPTIONS,
+                           startup_option_callback, &show_splash);
+  source_init_register_argv_parser (parser, ss);
+  if (!argv_parser_run (parser, argc, argv))
+    exit (EXIT_FAILURE);
+  argv_parser_destroy (parser);
+
   init_p.splash_window = create_splash_window ();
-  init_p.argc = argc;
-  init_p.argv = argv;
-  init_p.clp = clp;
+  init_p.ss = ss;
+  init_p.data_file = optind < argc ? argv[optind] : NULL;
 
   if ( show_splash )
     gtk_widget_show (init_p.splash_window);
diff --git a/src/ui/gui/message-dialog.c b/src/ui/gui/message-dialog.c
deleted file mode 100644 (file)
index 7513295..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005 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 <stdio.h>
-#include <stdarg.h>
-
-#include <config.h>
-#include <gettext.h>
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
-
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/msg-locator.h>
-#include "message-dialog.h"
-#include "progname.h"
-
-
-#include <gtk/gtk.h>
-#include <glib.h>
-
-#include "helper.h"
-
-static void enqueue_msg (const struct msg *m);
-static gboolean popup_messages (gpointer);
-
-#define MAX_EARLY_MESSAGES 100
-static GQueue *early_queue;
-
-static unsigned long dropped_messages;
-
-#define MAX_LATE_MESSAGES 10
-static GQueue *late_queue;
-
-static int error_cnt, warning_cnt, note_cnt;
-
-static GtkBuilder *message_xml;
-static GtkWidget *message_dialog;
-
-void
-message_dialog_init (struct source_stream *ss)
-{
-  early_queue = g_queue_new ();
-  dropped_messages = 0;
-  late_queue = g_queue_new ();
-  error_cnt = warning_cnt = note_cnt = 0;
-  msg_init (ss, enqueue_msg);
-  message_xml = builder_new ("message-dialog.ui");
-  message_dialog = get_widget_assert (message_xml, "message-dialog");
-
-  GTK_WIDGET_SET_FLAGS (get_widget_assert (message_xml, "close-button"),
-                       GTK_CAN_DEFAULT);
-
-}
-
-void
-message_dialog_done (void)
-{
-  msg_done ();
-  g_queue_free (early_queue);
-  dropped_messages = 0;
-  g_queue_free (late_queue);
-  gtk_widget_destroy (message_dialog);
-  g_object_unref (message_xml);
-}
-
-static void
-format_message (struct msg *m, struct string *msg)
-{
-  const char *label;
-
-  if (m->where.file_name)
-    ds_put_format (msg, "%s:", m->where.file_name);
-  if (m->where.line_number != -1)
-    ds_put_format (msg, "%d:", m->where.line_number);
-  if (m->where.file_name || m->where.line_number != -1)
-    ds_put_char (msg, ' ');
-
-  switch (m->severity)
-    {
-    case MSG_ERROR:
-      switch (m->category)
-       {
-       case MSG_SYNTAX:
-         label = _("syntax error");
-         break;
-
-       case MSG_DATA:
-         label = _("data file error");
-         break;
-
-       case MSG_GENERAL:
-       default:
-         label = _("PSPP error");
-         break;
-       }
-      break;
-    case MSG_WARNING:
-      switch (m->category)
-       {
-       case MSG_SYNTAX:
-         label = _("syntax warning");
-          break;
-
-       case MSG_DATA:
-         label = _("data file warning");
-         break;
-
-       case MSG_GENERAL:
-        default:
-         label = _("PSPP warning");
-          break;
-        }
-      break;
-    case MSG_NOTE:
-    default:
-      switch (m->category)
-        {
-        case MSG_SYNTAX:
-         label = _("syntax information");
-          break;
-
-        case MSG_DATA:
-         label = _("data file information");
-          break;
-
-        case MSG_GENERAL:
-        default:
-         label = _("PSPP information");
-         break;
-       }
-      break;
-    }
-  ds_put_format (msg, "%s: %s\n", label, m->text);
-  msg_destroy (m);
-}
-
-static void
-enqueue_msg (const struct msg *msg)
-{
-  struct msg *m = msg_dup (msg);
-
-  switch (m->severity)
-    {
-    case MSG_ERROR:
-      error_cnt++;
-      break;
-    case MSG_WARNING:
-      warning_cnt++;
-      break;
-    case MSG_NOTE:
-      note_cnt++;
-      break;
-    }
-
-  if (g_queue_get_length (early_queue) < MAX_EARLY_MESSAGES)
-    {
-      if (g_queue_is_empty (early_queue))
-        g_idle_add (popup_messages, NULL);
-      g_queue_push_tail (early_queue, m);
-    }
-  else
-    {
-      if (g_queue_get_length (late_queue) >= MAX_LATE_MESSAGES)
-        {
-          struct msg *m = g_queue_pop_head (late_queue);
-          msg_destroy (m);
-          dropped_messages++;
-        }
-      g_queue_push_tail (late_queue, m);
-    }
-}
-
-static gboolean
-popup_messages (gpointer unused UNUSED)
-{
-  GtkTextBuffer *text_buffer;
-  GtkTextIter end;
-  GtkTextView *text_view;
-  GtkLabel *label;
-  struct string lead = DS_EMPTY_INITIALIZER;
-  struct string msg = DS_EMPTY_INITIALIZER;
-  int message_cnt;
-
-  gdk_threads_enter ();
-
-  /* Set up the dialog. */
-  if (message_xml == NULL || message_dialog == NULL)
-    goto use_fallback;
-
-  /* If a pointer grab is in effect, then the combination of that, and
-     a modal dialog box, will cause an impossible situation.
-     So don't pop it up just yet.
-  */
-  if ( gdk_display_pointer_is_grabbed (gtk_widget_get_display (message_dialog)))
-    {
-      ds_destroy (&lead);
-      ds_destroy (&msg);
-      gdk_threads_leave ();
-      return TRUE;
-    }
-
-  /* Compose the lead-in. */
-  message_cnt = error_cnt + warning_cnt + note_cnt;
-  if (dropped_messages == 0)
-    ds_put_format (
-      &lead,
-      ngettext ("The PSPP processing engine reported the following message:",
-                "The PSPP processing engine reported the following messages:",
-                message_cnt));
-  else
-    {
-      ds_put_format (
-        &lead,
-        ngettext ("The PSPP processing engine reported %d message.",
-                  "The PSPP processing engine reported %d messages.",
-                  message_cnt),
-        message_cnt);
-      ds_put_cstr (&lead, "  ");
-      ds_put_format (
-        &lead,
-        ngettext ("%d of these messages are displayed below.",
-                  "%d of these messages are displayed below.",
-                  MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES),
-        MAX_EARLY_MESSAGES + MAX_LATE_MESSAGES);
-    }
-
-
-  /* Compose the messages. */
-  while (!g_queue_is_empty (early_queue))
-    format_message (g_queue_pop_head (early_queue), &msg);
-  if (dropped_messages)
-    {
-      ds_put_format (&msg, "...\nOmitting %lu messages\n...\n",
-                     dropped_messages);
-      dropped_messages = 0;
-    }
-  while (!g_queue_is_empty (late_queue))
-    format_message (g_queue_pop_head (late_queue), &msg);
-
-  text_buffer = gtk_text_buffer_new (NULL);
-  gtk_text_buffer_get_end_iter (text_buffer, &end);
-  gtk_text_buffer_insert (text_buffer, &end, ds_data (&msg), ds_length (&msg));
-
-  label = GTK_LABEL (get_widget_assert (message_xml, "lead-in"));
-  if (label == NULL)
-    goto use_fallback;
-  gtk_label_set_text (label, ds_cstr (&lead));
-
-  text_view = GTK_TEXT_VIEW (get_widget_assert (message_xml, "message"));
-  if (text_view == NULL)
-    goto use_fallback;
-  gtk_text_view_set_buffer (text_view, text_buffer);
-
-  gtk_widget_grab_default (get_widget_assert (message_xml, "close-button"));
-  gtk_widget_grab_focus (get_widget_assert (message_xml, "close-button"));
-  gtk_dialog_run ( GTK_DIALOG (message_dialog));
-  gtk_widget_hide (message_dialog);
-
-  ds_destroy (&lead);
-  ds_destroy (&msg);
-
-  gdk_threads_leave ();
-  return FALSE;
-
-use_fallback:
-  g_warning ("Could not create message dialog.  "
-             "Is PSPPIRE properly installed?");
-  fputs (ds_cstr (&msg), stderr);
-  ds_destroy (&lead);
-  ds_destroy (&msg);
-  gdk_threads_leave ();
-  return FALSE;
-}
-
diff --git a/src/ui/gui/message-dialog.h b/src/ui/gui/message-dialog.h
deleted file mode 100644 (file)
index 45eeca6..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004,2005  Free Software Foundation
-
-   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 ERROR_DIALOG_H
-#define ERROR_DIALOG_H
-
-#include <libpspp/message.h>
-
-struct source_stream ;
-
-void message_dialog_init (struct source_stream *);
-void message_dialog_done (void);
-
-#endif
diff --git a/src/ui/gui/message-dialog.ui b/src/ui/gui/message-dialog.ui
deleted file mode 100644 (file)
index 540a390..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0"?>
-<interface>
-  <!-- interface-requires gtk+ 2.12 -->
-  <!-- interface-naming-policy project-wide -->
-  <object class="GtkDialog" id="message-dialog">
-    <property name="width_request">600</property>
-    <property name="height_request">350</property>
-    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-    <property name="border_width">12</property>
-    <property name="title" translatable="yes">Messages Reported</property>
-    <property name="modal">True</property>
-    <property name="window_position">center-on-parent</property>
-    <property name="type_hint">dialog</property>
-    <property name="has_separator">False</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
-        <property name="visible">True</property>
-        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">24</property>
-        <child>
-          <object class="GtkHBox" id="hbox1">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="spacing">12</property>
-            <child>
-              <object class="GtkImage" id="image1">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="yalign">0</property>
-                <property name="stock">gtk-dialog-info</property>
-                <property name="icon-size">6</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkVBox" id="vbox1">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkLabel" id="lead-in">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">The PSPP processor reported # errors.  The first # and last # are shown below:</property>
-                    <property name="wrap">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow1">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="hscrollbar_policy">automatic</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">etched-in</property>
-                    <child>
-                      <object class="GtkTextView" id="message">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="editable">False</property>
-                        <property name="wrap_mode">word</property>
-                        <property name="left_margin">6</property>
-                        <property name="right_margin">6</property>
-                        <property name="cursor_visible">False</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="close-button">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="0">close-button</action-widget>
-    </action-widgets>
-  </object>
-</interface>
index 0b709ee4cadee9fc91a8cb53bdc5a05324612169..dfc2663f7893e0a06b89a22d77b8cd0cd6b98bb2 100644 (file)
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.2.0 on Sat Aug 11 17:19:54 2007 by john@marilyn-->
+<?xml version="1.0"?>
 <glade-interface>
+  <!-- interface-requires gtk+ 2.16 -->
+  <!-- interface-naming-policy toplevel-contextual -->
   <widget class="GtkWindow" id="output-viewer-window">
     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
     <property name="default_width">600</property>
@@ -16,7 +16,6 @@
             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
             <child>
               <widget class="GtkMenuItem" id="menuitem1">
-                <property name="visible">False</property>
                 <property name="sensitive">False</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <property name="label" translatable="yes">_File</property>
                     <property name="visible">True</property>
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
-                      <widget class="GtkImageMenuItem" id="file_save">
+                      <widget class="GtkMenuItem" id="file_export">
                         <property name="visible">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">gtk-save</property>
+                        <property name="label" translatable="yes">_Export</property>
                         <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkImageMenuItem" id="file_save-as">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">gtk-save-as</property>
-                        <property name="use_underline">True</property>
-                        <property name="use_stock">True</property>
                       </widget>
                     </child>
                   </widget>
@@ -49,7 +38,6 @@
             </child>
             <child>
               <widget class="GtkMenuItem" id="menuitem2">
-                <property name="visible">False</property>
                 <property name="sensitive">False</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                 <property name="label" translatable="yes">_Edit</property>
@@ -60,9 +48,9 @@
                     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                     <child>
                       <widget class="GtkImageMenuItem" id="imagemenuitem7">
+                        <property name="label">gtk-copy</property>
                         <property name="visible">True</property>
                         <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">gtk-copy</property>
                         <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                       </widget>
           </widget>
           <packing>
             <property name="expand">False</property>
+            <property name="position">0</property>
           </packing>
         </child>
         <child>
-          <widget class="GtkScrolledWindow" id="scrolledwindow1">
+          <widget class="GtkHPaned" id="hpaned1">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
-            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-            <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
-            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+            <property name="position">112</property>
+            <property name="position_set">True</property>
             <child>
-              <widget class="GtkTextView" id="output-viewer-textview">
+              <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">automatic</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <child>
+                  <widget class="GtkTreeView" id="overview">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="headers_visible">False</property>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="resize">False</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkScrolledWindow" id="scrolledwindow1">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="editable">False</property>
-                <property name="left_margin">5</property>
+                <property name="hscrollbar_policy">automatic</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <child>
+                  <widget class="GtkLayout" id="output">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                </child>
               </widget>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
             </child>
           </widget>
           <packing>
index 9e2190b2909e181475309ed1c58e10b3ce304872..bc31022a5d7056876007cb9b95a6f1fa1e2fa48a 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+
+#include "ui/gui/psppire-dict.h"
+
 #include <string.h>
 #include <stdlib.h>
-
 #include <gtk/gtk.h>
-#include <ui/gui/psppire-marshal.h>
-
-#include "psppire-var-ptr.h"
-#include "psppire-dict.h"
-#include <data/dictionary.h>
-#include <data/missing-values.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <libpspp/i18n.h>
-
-#include "helper.h"
-#include "message-dialog.h"
 
+#include "data/dictionary.h"
+#include "data/missing-values.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-marshal.h"
+#include "ui/gui/psppire-var-ptr.h"
 
 enum  {
   BACKEND_CHANGED,
index b0eff950c7e5e6b466b70edda79e9faf40702a8b..ebf29c01a3ca41c3a58f9d456fee644fb8679919 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010  Free Software Foundation
 
    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
 #include <gtk/gtkbox.h>
 #include "helper.h"
 
+#include <libpspp/cast.h>
 #include <libpspp/message.h>
+#include <libpspp/string-map.h>
+#include <output/cairo.h>
+#include <output/chart-item.h>
+#include <output/driver-provider.h>
+#include <output/output-item.h>
+#include <output/table-item.h>
+#include <output/text-item.h>
+#include <output/tab.h>
 #include <stdlib.h>
 
 #include "about.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-
+enum
+  {
+    COL_TITLE,                  /* Table title. */
+    COL_Y,                      /* Y position of top of title. */
+    N_COLS
+  };
 
 static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer);
 static void psppire_output_window_base_init     (PsppireOutputWindowClass *class);
@@ -84,10 +98,29 @@ psppire_output_window_finalize (GObject *object)
 }
 
 
+static void
+psppire_output_window_dispose (GObject *obj)
+{
+  PsppireOutputWindow *viewer = PSPPIRE_OUTPUT_WINDOW (obj);
+  size_t i;
+
+  for (i = 0; i < viewer->n_items; i++)
+    output_item_unref (viewer->items[i]);
+  free (viewer->items);
+  viewer->items = NULL;
+  viewer->n_items = viewer->allocated_items = 0;
+
+  /* Chain up to the parent class */
+  G_OBJECT_CLASS (parent_class)->dispose (obj);
+}
+
 static void
 psppire_output_window_class_init (PsppireOutputWindowClass *class)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
   parent_class = g_type_class_peek_parent (class);
+  object_class->dispose = psppire_output_window_dispose;
 }
 
 
@@ -106,13 +139,186 @@ psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
                                     gpointer class_data)
 {
 }
+\f
+/* Output driver class. */
 
+struct psppire_output_driver
+  {
+    struct output_driver driver;
+    PsppireOutputWindow *viewer;
+    struct xr_driver *xr;
+  };
 
-\f
+static struct output_driver_class psppire_output_class;
+
+static struct psppire_output_driver *
+psppire_output_cast (struct output_driver *driver)
+{
+  assert (driver->class == &psppire_output_class);
+  return UP_CAST (driver, struct psppire_output_driver, driver);
+}
+
+static gboolean
+expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+  struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering");
+  cairo_t *cr;
+
+  cr = gdk_cairo_create (widget->window);
+  xr_rendering_draw (r, cr);
+  cairo_destroy (cr);
+
+  return TRUE;
+}
 
-static PsppireOutputWindow *the_output_viewer = NULL;
+static void
+psppire_output_submit (struct output_driver *this,
+                       const struct output_item *item)
+{
+  struct psppire_output_driver *pod = psppire_output_cast (this);
+  PsppireOutputWindow *viewer;
+  GtkWidget *drawing_area;
+  struct xr_rendering *r;
+  struct string title;
+  GtkTreeStore *store;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+  cairo_t *cr;
+  int tw, th;
+
+  if (pod->viewer == NULL)
+    {
+      pod->viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
+      gtk_widget_show_all (GTK_WIDGET (pod->viewer));
+      pod->viewer->driver = pod;
+    }
+  viewer = pod->viewer;
 
+  if (viewer->n_items >= viewer->allocated_items)
+    viewer->items = x2nrealloc (viewer->items, &viewer->allocated_items,
+                                sizeof *viewer->items);
+  viewer->items[viewer->n_items++] = output_item_ref (item);
 
+  if (is_text_item (item))
+    {
+      const struct text_item *text_item = to_text_item (item);
+      enum text_item_type type = text_item_get_type (text_item);
+      const char *text = text_item_get_text (text_item);
+
+      if (type == TEXT_ITEM_COMMAND_CLOSE)
+        {
+          viewer->in_command = false;
+          return;
+        }
+      else if (text[0] == '\0')
+        return;
+    }
+
+  cr = gdk_cairo_create (GTK_WIDGET (pod->viewer)->window);
+  if (pod->xr == NULL)
+    pod->xr = xr_create_driver (cr);
+
+  r = xr_rendering_create (pod->xr, item, cr);
+  if (r == NULL)
+    goto done;
+
+  xr_rendering_measure (r, &tw, &th);
+
+  drawing_area = gtk_drawing_area_new ();
+  gtk_widget_modify_bg (
+    GTK_WIDGET (drawing_area), GTK_STATE_NORMAL,
+    &gtk_widget_get_style (drawing_area)->base[GTK_STATE_NORMAL]);
+  g_object_set_data (G_OBJECT (drawing_area), "rendering", r);
+  gtk_widget_set_size_request (drawing_area, tw, th);
+  gtk_layout_put (pod->viewer->output, drawing_area, 0, pod->viewer->y);
+  gtk_widget_show (drawing_area);
+  g_signal_connect (G_OBJECT (drawing_area), "expose_event",
+                     G_CALLBACK (expose_event_callback), NULL);
+
+  if (!is_text_item (item)
+      || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
+      || !viewer->in_command)
+    {
+      store = GTK_TREE_STORE (gtk_tree_view_get_model (viewer->overview));
+
+      ds_init_empty (&title);
+      if (is_text_item (item)
+          && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
+        {
+          gtk_tree_store_append (store, &iter, NULL);
+          viewer->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
+          viewer->in_command = true;
+        }
+      else
+        {
+          GtkTreeIter *p = viewer->in_command ? &viewer->cur_command : NULL;
+          gtk_tree_store_append (store, &iter, p);
+        }
+
+      ds_clear (&title);
+      if (is_text_item (item))
+        ds_put_cstr (&title, text_item_get_text (to_text_item (item)));
+      else if (is_table_item (item))
+        {
+          const char *caption = table_item_get_caption (to_table_item (item));
+          if (caption != NULL)
+            ds_put_format (&title, "Table: %s", caption);
+          else
+            ds_put_cstr (&title, "Table");
+        }
+      else if (is_chart_item (item))
+        {
+          const char *s = chart_item_get_title (to_chart_item (item));
+          if (s != NULL)
+            ds_put_format (&title, "Chart: %s", s);
+          else
+            ds_put_cstr (&title, "Chart");
+        }
+      gtk_tree_store_set (store, &iter,
+                          COL_TITLE, ds_cstr (&title),
+                          COL_Y, viewer->y,
+                          -1);
+      ds_destroy (&title);
+
+      path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
+      gtk_tree_view_expand_row (viewer->overview, path, TRUE);
+      gtk_tree_path_free (path);
+    }
+
+  if (pod->viewer->max_width < tw)
+    pod->viewer->max_width = tw;
+  pod->viewer->y += th;
+
+  gtk_layout_set_size (pod->viewer->output,
+                       pod->viewer->max_width, pod->viewer->y);
+
+  gtk_window_set_urgency_hint (GTK_WINDOW (pod->viewer), TRUE);
+
+done:
+  cairo_destroy (cr);
+}
+
+static struct output_driver_class psppire_output_class =
+  {
+    "PSPPIRE",                  /* name */
+    NULL,                       /* destroy */
+    psppire_output_submit,      /* submit */
+    NULL,                       /* flush */
+  };
+
+void
+psppire_output_window_setup (void)
+{
+  struct psppire_output_driver *pod;
+  struct output_driver *d;
+
+  pod = xzalloc (sizeof *pod);
+  d = &pod->driver;
+  output_driver_init (d, &psppire_output_class, "PSPPIRE",
+                      SETTINGS_DEVICE_UNFILTERED);
+  output_driver_register (d);
+}
+\f
 int viewer_length = 16;
 int viewer_width = 59;
 
@@ -125,9 +331,7 @@ on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
 
   gtk_widget_destroy (GTK_WIDGET (ow));
 
-  the_output_viewer = NULL;
-
-  unlink (output_file_name());
+  ow->driver->viewer = NULL;
 
   return FALSE;
 }
@@ -139,99 +343,198 @@ cancel_urgency (GtkWindow *window,  gpointer data)
 {
   gtk_window_set_urgency_hint (window, FALSE);
 }
-/* Sets width and length according to the new size
-   of the output window */
+
 static void
-on_textview_resize (GtkWidget     *widget,
-                   GtkAllocation *allocation,
-                   gpointer       user_data)
+on_row_activate (GtkTreeView *overview,
+                 GtkTreePath *path,
+                 GtkTreeViewColumn *column,
+                 PsppireOutputWindow *window)
 {
-  PangoContext * context ;
-  PangoLayout *layout ;
-  PangoRectangle logical;
-  GtkStyle *style;
-  gint right_margin, left_margin;
-  GtkTextView *text_view = GTK_TEXT_VIEW (widget);
-
-  context = gtk_widget_create_pango_context (widget);
-  layout = pango_layout_new (context);
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  GtkAdjustment *vadj;
+  GValue value = {0};
+  double y, min, max;
+
+  model = gtk_tree_view_get_model (overview);
+  if (!gtk_tree_model_get_iter (model, &iter, path))
+    return;
+
+  gtk_tree_model_get_value (model, &iter, COL_Y, &value);
+  y = g_value_get_long (&value);
+  g_value_unset (&value);
+
+  vadj = gtk_layout_get_vadjustment (window->output);
+  min = vadj->lower;
+  max = vadj->upper - vadj->page_size;
+  if (y < min)
+    y = min;
+  else if (y > max)
+    y = max;
+  gtk_adjustment_set_value (vadj, y);
+}
 
-  style = gtk_widget_get_style (widget);
+static GtkFileFilter *
+add_filter (GtkFileChooser *chooser, const char *name, const char *pattern)
+{
+  GtkFileFilter *filter = gtk_file_filter_new ();
+  g_object_ref_sink (G_OBJECT (filter));
+  gtk_file_filter_set_name (filter, name);
+  gtk_file_filter_add_pattern (filter, pattern);
+  gtk_file_chooser_add_filter (chooser, filter);
+  return filter;
+}
 
-  pango_layout_set_font_description (layout, style->font_desc);
+static void
+export_output (PsppireOutputWindow *window, struct string_map *options,
+               const char *format)
+{
+  struct output_driver *driver;
+  size_t i;
 
-  /* Find the width of one character.  We can use any character, because
-     the textview has a monospaced font */
-  pango_layout_set_text (layout, "M", 1);
+  string_map_insert (options, "format", format);
+  driver = output_driver_create (options);
+  if (driver == NULL)
+    return;
 
-  pango_layout_get_extents (layout,  NULL, &logical);
+  for (i = 0; i < window->n_items; i++)
+    driver->class->submit (driver, window->items[i]);
+  output_driver_destroy (driver);
+}
 
-  left_margin = gtk_text_view_get_left_margin (text_view);
-  right_margin = gtk_text_view_get_right_margin (text_view);
+static void
+psppire_output_window_export (PsppireOutputWindow *window)
+{
+  gint response;
+
+  GtkFileFilter *pdf_filter;
+  GtkFileFilter *html_filter;
+  GtkFileFilter *odt_filter;
+  GtkFileFilter *txt_filter;
+  GtkFileFilter *ps_filter;
+  GtkFileFilter *csv_filter;
+  GtkFileChooser *chooser;
+  GtkWidget *dialog;
+
+  dialog = gtk_file_chooser_dialog_new (_("Export Output"),
+                                        GTK_WINDOW (window),
+                                        GTK_FILE_CHOOSER_ACTION_SAVE,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_SAVE,   GTK_RESPONSE_ACCEPT,
+                                        NULL);
+  chooser = GTK_FILE_CHOOSER (dialog);
+
+  pdf_filter = add_filter (chooser, _("PDF Files (*.pdf)"), "*.pdf");
+  html_filter = add_filter (chooser, _("HTML Files (*.html)"), "*.html");
+  odt_filter = add_filter (chooser, _("OpenDocument Files (*.odt)"), "*.odt");
+  txt_filter = add_filter (chooser, _("Text Files (*.txt)"), "*.txt");
+  ps_filter = add_filter (chooser, _("PostScript Files (*.ps)"), "*.ps");
+  csv_filter = add_filter (chooser, _("Comma-Separated Value Files (*.csv)"),
+                           "*.csv");
+
+  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
+  gtk_file_chooser_set_filter (chooser, pdf_filter);
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if ( response == GTK_RESPONSE_ACCEPT )
+    {
+      char *filename = gtk_file_chooser_get_filename (chooser);
+      GtkFileFilter *filter = gtk_file_chooser_get_filter (chooser);
+      struct string_map options;
+
+      g_return_if_fail (filename);
+      g_return_if_fail (filter);
+
+      string_map_init (&options);
+      string_map_insert (&options, "output-file", filename);
+      if (filter == pdf_filter)
+        {
+          string_map_insert (&options, "output-type", "pdf");
+          export_output (window, &options, "cairo");
+        }
+      else if (filter == html_filter)
+        export_output (window, &options, "html");
+      else if (filter == odt_filter)
+        export_output (window, &options, "odf");
+      else if (filter == txt_filter)
+        {
+          string_map_insert (&options, "headers", "false");
+          string_map_insert (&options, "paginate", "false");
+          string_map_insert (&options, "squeeze", "true");
+          string_map_insert (&options, "emphasis", "none");
+          string_map_insert (&options, "chart-type", "none");
+          string_map_insert (&options, "top-margin", "0");
+          string_map_insert (&options, "bottom-margin", "0");
+          export_output (window, &options, "ascii");
+        }
+      else if (filter == ps_filter)
+        {
+          string_map_insert (&options, "output-type", "ps");
+          export_output (window, &options, "cairo");
+        }
+      else if (filter == csv_filter)
+        export_output (window, &options, "csv");
+      else
+        g_return_if_reached ();
+
+      free (filename);
+    }
 
-  viewer_length = allocation->height / PANGO_PIXELS (logical.height);
-  viewer_width = (allocation->width - right_margin - left_margin)
-    / PANGO_PIXELS (logical.width);
+  g_object_unref (G_OBJECT (pdf_filter));
+  g_object_unref (G_OBJECT (html_filter));
+  g_object_unref (G_OBJECT (txt_filter));
+  g_object_unref (G_OBJECT (ps_filter));
+  g_object_unref (G_OBJECT (csv_filter));
 
-  g_object_unref (G_OBJECT (layout));
-  g_object_unref (G_OBJECT (context));
+  gtk_widget_destroy (dialog);
 }
 
-
 static void
 psppire_output_window_init (PsppireOutputWindow *window)
 {
-  GtkBuilder *xml = builder_new ("output-viewer.ui");
-
-  GtkWidget *box = gtk_vbox_new (FALSE, 0);
-
-  GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  GtkBuilder *xml;
 
-  GtkWidget *menubar = get_widget_assert (xml, "menubar1");
+  xml = builder_new ("output-viewer.ui");
 
-  window->textview = get_widget_assert (xml, "output-viewer-textview");
+  gtk_widget_reparent (get_widget_assert (xml, "vbox1"), GTK_WIDGET (window));
 
+  window->output = GTK_LAYOUT (get_widget_assert (xml, "output"));
+  window->y = 0;
 
-  gtk_container_add (GTK_CONTAINER (window), box);
+  window->overview = GTK_TREE_VIEW (get_widget_assert (xml, "overview"));
+  gtk_tree_view_set_model (window->overview,
+                           GTK_TREE_MODEL (gtk_tree_store_new (
+                                             N_COLS,
+                                             G_TYPE_STRING, /* COL_TITLE */
+                                             G_TYPE_LONG))); /* COL_Y */
 
+  window->in_command = false;
 
-  g_object_ref (menubar);
-  gtk_widget_unparent (menubar);
+  window->items = NULL;
+  window->n_items = window->allocated_items = 0;
 
-  g_object_ref (sw);
-  gtk_widget_unparent (sw);
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_append_column (GTK_TREE_VIEW (window->overview), column);
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_add_attribute (column, renderer, "text", COL_TITLE);
 
+  g_signal_connect (GTK_TREE_VIEW (window->overview),
+                    "row-activated", G_CALLBACK (on_row_activate), window);
 
-  gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
-  gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
-
-
-  gtk_widget_show_all (box);
+  gtk_widget_modify_bg (GTK_WIDGET (window->output), GTK_STATE_NORMAL,
+                        &gtk_widget_get_style (GTK_WIDGET (window->output))->base[GTK_STATE_NORMAL]);
 
   connect_help (xml);
 
-  window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
-
   g_signal_connect (window,
                    "focus-in-event",
                    G_CALLBACK (cancel_urgency),
                    NULL);
 
-  {
-    /* Output uses ascii characters for tabular material.
-       So we need a monospaced font otherwise it'll look silly */
-    PangoFontDescription *font_desc =
-      pango_font_description_from_string ("monospace");
-
-    gtk_widget_modify_font (window->textview, font_desc);
-    pango_font_description_free (font_desc);
-  }
-
-  g_signal_connect (window->textview, "size-allocate",
-                   G_CALLBACK (on_textview_resize), NULL);
-
-  window->fp = NULL;
-
   g_signal_connect (get_action_assert (xml,"help_about"),
                    "activate",
                    G_CALLBACK (about_new),
@@ -254,6 +557,9 @@ psppire_output_window_init (PsppireOutputWindow *window)
       GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar1/windows_menuitem/windows_minimise-all")->parent);
   }
 
+  g_signal_connect_swapped (get_action_assert (xml, "file_export"), "activate",
+                            G_CALLBACK (psppire_output_window_export), window);
+
   g_object_unref (xml);
 
   g_signal_connect (window, "delete-event",
@@ -269,108 +575,3 @@ psppire_output_window_new (void)
                                   "description", _("Output Viewer"),
                                   NULL));
 }
-
-static void reload_viewer (PsppireOutputWindow *ow);
-
-void
-psppire_output_window_reload (void)
-{
-  struct stat buf;
-
-  /* If there is no output, then don't do anything */
-  if (0 != stat (output_file_name(), &buf))
-    return ;
-
-  if ( NULL == the_output_viewer )
-    {
-      the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
-      gtk_widget_show (GTK_WIDGET (the_output_viewer));
-    }
-
-  reload_viewer (the_output_viewer);
-
-}
-
-
-static void
-reload_viewer (PsppireOutputWindow *ow)
-{
-  GtkTextIter end_iter;
-  GtkTextMark *mark ;
-
-  char *line = NULL;
-
-  gboolean chars_inserted = FALSE;
-
-  gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
-
-  line = xrealloc (line, sizeof (char) * (viewer_width + 1));
-
-  mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
-
-#ifdef __CYGWIN__
-  /*
-    Apparently Windoze is not capabale of writing to a file whilst
-    another (or the same) process is reading from it.   Therefore, we
-    must close the file after reading it, and clear the entire buffer
-    before writing to it.
-    This will be slower for large buffers, but should work
-    (in so far as anything ever works on windows).
-  */
-  {
-    GtkTextIter start_iter;
-    FILE *fp = fopen (output_file_name(), "r");
-    if ( !fp)
-      {
-       g_critical ("Cannot open %s\n", output_file_name());
-       return;
-      }
-
-    /* Delete all the entire buffer */
-    gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
-    gtk_text_buffer_delete (ow->buffer, &start_iter, &end_iter);
-
-
-    gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
-    /* Read in the next lot of text */
-    while (fgets (line, viewer_width + 1, fp) != NULL)
-      {
-       chars_inserted = TRUE;
-       gtk_text_buffer_insert (ow->buffer, &start_iter, line, -1);
-      }
-
-    fclose (fp);
-  }
-#else
-  {
-    if ( ow->fp == NULL)
-      {
-       ow->fp = fopen (output_file_name(), "r");
-       if ( ow->fp == NULL)
-         {
-           g_critical ("Cannot open %s\n", output_file_name());
-           return;
-         }
-      }
-
-    /* Read in the next lot of text */
-    while (fgets (line, viewer_width + 1, ow->fp) != NULL)
-      {
-       chars_inserted = TRUE;
-       gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
-      }
-  }
-#endif
-
-  /* Scroll to where the start of this lot of text begins */
-  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
-                               mark,
-                               0.1, TRUE, 0.0, 0.0);
-
-
-  if ( chars_inserted )
-    gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);
-}
-
-
-
index d11eca618d84c9c18c86e5dc7bd184b6f9771a75..95deed93fec542dbd9bb8ee891fb4c2a289f6260 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2009  Free Software Foundation
 
    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
@@ -31,10 +31,6 @@ extern int viewer_length;
 extern int viewer_width ;
 
 
-#define OUTPUT_FILE_NAME "psppire.txt"
-
-
-
 G_BEGIN_DECLS
 
 #define PSPPIRE_OUTPUT_WINDOW_TYPE            (psppire_output_window_get_type ())
@@ -56,9 +52,17 @@ struct _PsppireOutputWindow
   PsppireWindow parent;
 
   /* <private> */
-  GtkTextBuffer *buffer;  /* The buffer which contains the text */
-  GtkWidget *textview ;
-  FILE *fp;               /* The file it's viewing */
+  struct psppire_output_driver *driver;
+  GtkLayout *output;
+  int max_width;
+  int y;
+
+  GtkTreeView *overview;
+  GtkTreeIter cur_command;
+  bool in_command;
+
+  struct output_item **items;
+  size_t n_items, allocated_items;
 };
 
 struct _PsppireOutputWindowClass
@@ -70,9 +74,7 @@ struct _PsppireOutputWindowClass
 GType      psppire_output_window_get_type        (void);
 GtkWidget* psppire_output_window_new             (void);
 
-
-void psppire_output_window_reload (void);
-
+void psppire_output_window_setup (void);
 
 G_END_DECLS
 
index 8491851383f4405805bbf71d0a35d5e172500b29..e61269164046cfaa6792f2ece2b390d2d23bc3b9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006, 2009  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009, 2010  Free Software Foundation
 
    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
 
 #include <config.h>
 
-#include <libpspp/i18n.h>
+#include "ui/gui/psppire.h"
+
 #include <assert.h>
-#include <libintl.h>
 #include <gsl/gsl_errno.h>
-
-#include <xalloc.h>
-#include <argp.h>
-#include <ui/command-line.h>
-#include "relocatable.h"
-
-#include "psppire-data-window.h"
-#include "psppire.h"
-#include "widgets.h"
-
-#include <libpspp/getl.h>
-#include <unistd.h>
-#include <data/casereader.h>
-#include <data/datasheet.h>
-#include <data/file-handle-def.h>
-#include <data/settings.h>
-#include <data/file-name.h>
-#include <data/procedure.h>
-#include <libpspp/getl.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/version.h>
-#include <output/output.h>
-#include <output/journal.h>
-#include <language/syntax-string-source.h>
-
 #include <gtk/gtk.h>
-#include "psppire-dict.h"
-#include "dict-display.h"
-#include "psppire-selector.h"
-#include "psppire-var-view.h"
-#include "psppire-var-store.h"
-#include "psppire-data-store.h"
-#include "executor.h"
-#include "message-dialog.h"
-#include <ui/syntax-gen.h>
-
-#include "psppire-window-register.h"
-#include "psppire-output-window.h"
-
-#include <data/sys-file-reader.h>
-#include <data/por-file-reader.h>
+#include <libintl.h>
+#include <unistd.h>
 
-#include <ui/source-init-opts.h>
+#include "data/casereader.h"
+#include "data/datasheet.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/por-file-reader.h"
+#include "data/procedure.h"
+#include "data/settings.h"
+#include "data/sys-file-reader.h"
+#include "language/lexer/lexer.h"
+#include "language/syntax-string-source.h"
+#include "libpspp/getl.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "output/driver.h"
+#include "output/journal.h"
+#include "output/message-item.h"
+#include "ui/gui/dict-display.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dict.h"
+#include "ui/gui/psppire-output-window.h"
+#include "ui/gui/psppire-selector.h"
+#include "ui/gui/psppire-var-store.h"
+#include "ui/gui/psppire-var-view.h"
+#include "ui/gui/psppire-window-register.h"
+#include "ui/gui/psppire.h"
+#include "ui/gui/widgets.h"
+#include "ui/source-init-opts.h"
+#include "ui/syntax-gen.h"
+
+#include "gl/xalloc.h"
+#include "gl/relocatable.h"
 
 GtkRecentManager *the_recent_mgr = 0;
 PsppireDataStore *the_data_store = 0;
@@ -75,6 +70,9 @@ struct dataset * the_dataset = NULL;
 
 static GtkWidget *the_data_window;
 
+static void handle_msg (const struct msg *);
+static void load_data_file (const char *);
+
 static void
 replace_casereader (struct casereader *s)
 {
@@ -88,7 +86,7 @@ replace_casereader (struct casereader *s)
 
 
 void
-initialize (struct command_line_processor *clp, int argc, char **argv)
+initialize (struct source_stream *ss, const char *data_file)
 {
   PsppireDict *dictionary = 0;
 
@@ -97,19 +95,13 @@ initialize (struct command_line_processor *clp, int argc, char **argv)
   preregister_widgets ();
 
   gsl_set_error_handler_off ();
-  fn_init ();
-  outp_init ();
   settings_init (&viewer_width, &viewer_length);
   fh_init ();
-  the_source_stream =
-    create_source_stream (
-                         fn_getenv_default ("STAT_INCLUDE_PATH", include_path)
-                         );
 
   the_dataset = create_dataset ();
 
-
-  message_dialog_init (the_source_stream);
+  the_source_stream = ss;
+  msg_init (ss, handle_msg);
 
   dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
 
@@ -123,25 +115,7 @@ initialize (struct command_line_processor *clp, int argc, char **argv)
 
   create_icon_factory ();
 
-  {
-    const char *filename = output_file_name ();
-
-    struct string config_string;
-
-    ds_init_empty (&config_string);
-
-    ds_put_format (&config_string,
-                  "gui:ascii:screen:squeeze=on headers=off top-margin=0 "
-                  "bottom-margin=0 paginate=off length=auto width=auto "
-                  "emphasis=none "
-                  "output-file=\"%s\" append=yes", filename);
-
-    outp_configure_driver_line (ds_ss (&config_string));
-
-    unlink (filename);
-
-    ds_destroy (&config_string);
-  }
+  psppire_output_window_setup ();
 
   journal_enable ();
   textdomain (PACKAGE);
@@ -154,11 +128,8 @@ initialize (struct command_line_processor *clp, int argc, char **argv)
   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
 
   the_data_window = psppire_data_window_new ();
-
-  command_line_processor_replace_aux (clp, &post_init_argp, the_source_stream);
-  command_line_processor_replace_aux (clp, &non_option_argp, the_source_stream);
-
-  command_line_processor_parse (clp, argc, argv);
+  if (data_file != NULL)
+    load_data_file (data_file);
 
   execute_syntax (create_syntax_string_source (""));
 
@@ -170,9 +141,8 @@ void
 de_initialize (void)
 {
   destroy_source_stream (the_source_stream);
-  message_dialog_done ();
   settings_done ();
-  outp_done ();
+  output_close ();
   i18n_done ();
 }
 
@@ -267,94 +237,67 @@ create_icon_factory (void)
 
   gtk_icon_factory_add_default (factory);
 }
-
 \f
-
-static error_t
-parse_non_options (int key, char *arg, struct argp_state *state)
+static void
+load_data_file (const char *arg)
 {
-  struct source_stream *ss = state->input;
-
-  if ( NULL == ss )
-    return 0;
-
-  switch (key)
+  gchar *filename = NULL;
+  gchar *utf8 = NULL;
+  const gchar *local_encoding = NULL;
+  gsize written = -1;
+  const gboolean local_is_utf8 = g_get_charset (&local_encoding);
+
+  /* There seems to be no Glib function to convert from local encoding
+     to filename encoding.  Therefore it has to be done in two steps:
+     the intermediate encoding is UTF8.
+
+     Either step could fail.  However, in many cases the file can still
+     be loaded even if the conversion fails. So in those cases, after showing
+     a warning, we simply copy the locally encoded filename to the destination
+     and hope for the best.
+  */
+
+  if ( local_is_utf8)
     {
-    case ARGP_KEY_ARG:
-      {
-       gchar *filename = NULL;
-       gchar *utf8 = NULL;
-       const gchar *local_encoding = NULL;
-       gsize written = -1;
-       const gboolean local_is_utf8 = g_get_charset (&local_encoding);
-
-       /* There seems to be no Glib function to convert from local encoding
-          to filename encoding.  Therefore it has to be done in two steps:
-          the intermediate encoding is UTF8.
-
-          Either step could fail.  However, in many cases the file can still
-          be loaded even if the conversion fails. So in those cases, after showing
-          a warning, we simply copy the locally encoded filename to the destination
-          and hope for the best.
-       */
-
-       if ( local_is_utf8)
-         {
-           utf8 = xstrdup (arg);
-         }
-       else
-         {
-           GError *err = NULL;
-           utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
-           if ( NULL == utf8)
-             {
-               g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
-                          local_encoding,
-                          err->message);
-               g_clear_error (&err);
-             }
-         }
-
-       if ( NULL != utf8)
-         {
-           GError *err = NULL;
-           filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
-           if ( NULL == filename)
-             {
-               g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
-                          err->message);
-               g_clear_error (&err);
-             }
-         }
-
-       g_free (utf8);
-
-       if ( filename == NULL)
-         filename = xstrdup (arg);
-
-       psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
-
-       g_free (filename);
-       break;
-      }
-    default:
-      return ARGP_ERR_UNKNOWN;
+      utf8 = xstrdup (arg);
+    }
+  else
+    {
+      GError *err = NULL;
+      utf8 = g_locale_to_utf8 (arg, -1, NULL, &written, &err);
+      if ( NULL == utf8)
+        {
+          g_warning ("Cannot convert filename from local encoding \"%s\" to UTF-8: %s",
+                     local_encoding,
+                     err->message);
+          g_clear_error (&err);
+        }
     }
-  return 0;
-}
 
+  if ( NULL != utf8)
+    {
+      GError *err = NULL;
+      filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
+      if ( NULL == filename)
+        {
+          g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
+                     err->message);
+          g_clear_error (&err);
+        }
+    }
 
-const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};
+  g_free (utf8);
 
+  if ( filename == NULL)
+    filename = xstrdup (arg);
 
-const char *
-output_file_name (void)
-{
-  const char *dir = default_output_path ();
-  static char *filename = NULL;
+  psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
 
-  if ( NULL == filename )
-    filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME);
+  g_free (filename);
+}
 
-  return filename;
+static void
+handle_msg (const struct msg *m)
+{
+  message_item_submit (message_item_create (m));
 }
index 27a633f2ecf35c57cd30dc01ac85aa4a61db28a9..ee747ef90606b200b195d9fa497ce239457fe58d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006, 2009  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009, 2010  Free Software Foundation
 
    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
 #ifndef PSPPIRE_H
 #define PSPPIRE_H
 
-#include <argp.h>
+struct source_stream;
 
-struct command_line_processor ;
-extern const struct argp non_option_argp ;
-
-void initialize (struct command_line_processor *, int argc, char **argv);
+void initialize (struct source_stream *, const char *data_file);
 void de_initialize (void);
 
 void psppire_quit (void);
index 214370513b7369087344f60c636f450704f3b7a7..6ec866c93a11d7997f2de2fd66583b040e5b06b3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006  Free Software Foundation
+   Copyright (C) 2006, 2009  Free Software Foundation
 
    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
@@ -19,6 +19,7 @@
 
 #include <libpspp/getl.h>
 #include <libpspp/compiler.h>
+#include <libpspp/cast.h>
 #include <libpspp/str.h>
 
 #include <stdlib.h>
@@ -72,7 +73,8 @@ read_line_from_buffer (struct getl_interface *i,
   gchar *text;
   GtkTextIter next_line;
 
-  struct syntax_editor_source *ses = (struct syntax_editor_source *) i;
+  struct syntax_editor_source *ses
+    = UP_CAST (i, struct syntax_editor_source, parent);
 
   if ( gtk_text_iter_compare (&ses->i, &ses->end) >= 0)
     return false;
@@ -124,5 +126,5 @@ create_syntax_editor_source (GtkTextBuffer *buffer,
   ses->parent.location = location;
 
 
-  return (struct getl_interface *) ses;
+  return &ses->parent;
 }
index 14eacabfadddb5842e81f444855233b0e903ec03..5f43ff498f10a6c4910a53bec9fc5bfda82a87fb 100644 (file)
@@ -324,7 +324,7 @@ on_remove (GtkWidget *w, gpointer data)
   struct val_labs_dialog *dialog = data;
 
   union value value;
-  const struct val_lab *vl;
+  struct val_lab *vl;
 
   get_selected_tuple (dialog, &value, NULL);
   vl = val_labs_lookup (dialog->labs, &value);
index 43ae5c629ac1098998c480a09175af95bd457326..c91a9fef1a8956c4bd856d58fa26fd998194df69 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010  Free Software Foundation
 
    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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <argp.h>
+
 #include "source-init-opts.h"
+
 #include <stdbool.h>
-#include <xalloc.h>
-#include <string.h>
-#include <output/output.h>
-#include <data/file-name.h>
-#include <libpspp/getl.h>
-#include <language/syntax-file.h>
 #include <stdlib.h>
-#include <libpspp/llx.h>
-#include <data/por-file-reader.h>
-#include <data/sys-file-reader.h>
-#include <libpspp/message.h>
-#include <ui/syntax-gen.h>
-#include <language/syntax-string-source.h>
-#include <data/file-name.h>
-#include <data/settings.h>
+#include <string.h>
+
+#include "data/file-name.h"
+#include "data/por-file-reader.h"
+#include "data/settings.h"
+#include "data/sys-file-reader.h"
+#include "language/syntax-file.h"
+#include "language/syntax-string-source.h"
+#include "libpspp/assertion.h"
+#include "libpspp/argv-parser.h"
+#include "libpspp/getl.h"
+#include "libpspp/llx.h"
+#include "libpspp/message.h"
+#include "ui/syntax-gen.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-static const struct argp_option post_init_options [] = {
-  {"algorithm", 'a', "{compatible|enhanced}", 0, N_("set to `compatible' if you want output calculated from broken algorithms"), 0},
-  {"include", 'I', "DIR", 0, N_("Append DIR to include path"), 0},
-  {"no-include", 'I', 0, 0, N_("Clear include path"), 0},
-  {"no-statrc", 'r', 0, 0, N_("Disable execution of .pspp/rc at startup"), 0},
-  {"config-dir", 'B', "DIR", 0, N_("Set configuration directory to DIR"), 0},
-  {"safer", 's', 0, 0,  N_("Don't allow some unsafe operations"), 0},
-  {"syntax", 'x', "{compatible|enhanced}", 0, N_("Set to `compatible' if you want only to accept SPSS compatible syntax"), 0},
-  { 0, 0, 0, 0, 0, 0 }
-};
-
-static error_t
-parse_post_init_opts (int key, char *arg, struct argp_state *state)
-{
-  struct source_init
+enum
   {
-    bool process_statrc;
+    OPT_ALGORITHM,
+    OPT_INCLUDE,
+    OPT_NO_INCLUDE,
+    OPT_SAFER,
+    OPT_SYNTAX,
+    N_SOURCE_INIT_OPTIONS
   };
 
-  struct source_init *sip = state->hook;
-
-  struct source_stream *ss = state->input;
+static const struct argv_option source_init_options[N_SOURCE_INIT_OPTIONS] =
+  {
+    {"algorithm", 'a', required_argument, OPT_ALGORITHM},
+    {"include", 'I', required_argument, OPT_INCLUDE},
+    {"no-include", 0, no_argument, OPT_NO_INCLUDE},
+    {"safer", 's', no_argument, OPT_SAFER},
+    {"syntax", 'x', required_argument, OPT_SYNTAX},
+  };
 
-  if ( state->input == NULL)
-    return 0;
+static void
+source_init_option_callback (int id, void *ss_)
+{
+  struct source_stream *ss = ss_;
 
-  switch (key)
+  switch (id)
     {
-    case ARGP_KEY_INIT:
-      state->hook = sip = xzalloc (sizeof (struct source_init));
-      sip->process_statrc = true;
-      break;
-    case ARGP_KEY_FINI:
-      free (sip);
-      break;
-    case  'a':
-      if ( 0 == strcmp (arg, "compatible") )
+    case OPT_ALGORITHM:
+      if (!strcmp (optarg, "compatible"))
        settings_set_algorithm (COMPATIBLE);
-      else if ( 0 == strcmp (arg, "enhanced"))
+      else if (!strcmp (optarg, "enhanced"))
        settings_set_algorithm (ENHANCED);
       else
-       {
-         argp_failure (state, 1, 0, _("Algorithm must be either \"compatible\" or \"enhanced\"."));
-       }
-      break;
-    case 'B':
-      config_path = arg;
+        error (1, 0,
+               _("Algorithm must be either \"compatible\" or \"enhanced\"."));
       break;
-    case 'I':
-      if (arg == NULL || !strcmp (arg, "-"))
+
+    case OPT_INCLUDE:
+      if (!strcmp (optarg, "-"))
        getl_clear_include_path (ss);
       else
-       getl_add_include_dir (ss, arg);
+       getl_add_include_dir (ss, optarg);
       break;
-    case 'r':
-      sip->process_statrc = false;
-      break;
-    case ARGP_KEY_SUCCESS:
-      if (sip->process_statrc)
-       {
-         char *pspprc_fn = fn_search_path ("rc", config_path);
-         if (pspprc_fn != NULL)
-           {
-             getl_append_source (ss,
-                                 create_syntax_file_source (pspprc_fn),
-                                 GETL_BATCH,
-                                 ERRMODE_CONTINUE
-                                 );
-
-             free (pspprc_fn);
-           }
-       }
+
+    case OPT_NO_INCLUDE:
+      getl_clear_include_path (ss);
       break;
-    case 's':
+
+    case OPT_SAFER:
       settings_set_safer_mode ();
       break;
-    case 'x':
-      if ( 0 == strcmp (arg, "compatible") )
+
+    case OPT_SYNTAX:
+      if (!strcmp (optarg, "compatible") )
        settings_set_syntax (COMPATIBLE);
-      else if ( 0 == strcmp (arg, "enhanced"))
+      else if (!strcmp (optarg, "enhanced"))
        settings_set_syntax (ENHANCED);
       else
-       {
-         argp_failure (state, 1, 0, _("Syntax must be either \"compatible\" or \"enhanced\"."));
-       }
+        error (1, 0,
+               _("Syntax must be either \"compatible\" or \"enhanced\"."));
       break;
+
     default:
-      return ARGP_ERR_UNKNOWN;
+      NOT_REACHED ();
     }
-
-  return 0;
 }
 
-const struct argp post_init_argp =
-  {post_init_options, parse_post_init_opts, 0, 0, 0, 0, 0};
-
+void
+source_init_register_argv_parser (struct argv_parser *ap,
+                                  struct source_stream *ss)
+{
+  argv_parser_add_options (ap, source_init_options, N_SOURCE_INIT_OPTIONS,
+                           source_init_option_callback, ss);
+}
index 874935313ae2554daf9dc6de3ce65ddbbfca52e1..cfd87f3fa0322266114d346b850b73332dfd42bf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010  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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
-#ifndef SOURCE_INIT_OPTS
-#define SOURCE_INIT_OPTS
+#ifndef UI_SOURCE_INIT_OPTS
+#define UI_SOURCE_INIT_OPTS
 
-extern const struct argp post_init_argp;
+struct argv_parser;
+struct source_stream;
 
-#endif
+void source_init_register_argv_parser (struct argv_parser *,
+                                       struct source_stream *);
 
+#endif /* ui/source/source-init-opts.h */
index 9cde11c9110641e1c6f39fa1aa4de959865cb74b..81b896dc878839d44590f9e3205ebc53d5e07fb0 100644 (file)
@@ -25,6 +25,7 @@ src_ui_terminal_pspp_LDADD = \
        src/ui/libuicommon.la \
        src/libpspp.la \
        src/libpspp-core.la \
+       $(CAIRO_LIBS) \
        $(NCURSES_LIBS) \
        $(LIBICONV) \
        $(LIBINTL) $(LIBREADLINE)
index 7ad162fca6d40b746a0155d891d8e08784e2e4df..02be4f78c0e777f1e93df1719fc7fc0ed48f13f2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 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
 #include <ieeefp.h>
 #endif
 
-
-#include <libpspp/i18n.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <libpspp/getl.h>
-#include <data/file-name.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <gsl/gsl_errno.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/prompt.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/version.h>
-#include <math/random.h>
-#include <output/output.h>
-#include <ui/debugger.h>
-#include <ui/terminal/msg-ui.h>
-#include <ui/terminal/read-line.h>
-#include <ui/terminal/terminal.h>
-#include <ui/terminal/terminal-opts.h>
-#include <ui/command-line.h>
-#include <ui/source-init-opts.h>
-
-#include "fatal-signal.h"
-#include "progname.h"
-#include "relocatable.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/procedure.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "gsl/gsl_errno.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/prompt.h"
+#include "libpspp/argv-parser.h"
+#include "libpspp/compiler.h"
+#include "libpspp/getl.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "math/random.h"
+#include "output/driver.h"
+#include "ui/debugger.h"
+#include "ui/source-init-opts.h"
+#include "ui/terminal/msg-ui.h"
+#include "ui/terminal/read-line.h"
+#include "ui/terminal/terminal-opts.h"
+#include "ui/terminal/terminal.h"
+
+#include "gl/fatal-signal.h"
+#include "gl/progname.h"
+#include "gl/relocatable.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -76,15 +75,14 @@ static struct dataset * the_dataset = NULL;
 static struct lexer *the_lexer;
 static struct source_stream *the_source_stream ;
 
-const char *argp_program_version = version;
-const char *argp_program_bug_address = PACKAGE_BUGREPORT;
-
 /* Program entry point. */
 int
 main (int argc, char **argv)
 {
   int *view_width_p, *view_length_p;
-  struct command_line_processor *clp;
+  struct terminal_opts *terminal_opts;
+  struct argv_parser *parser;
+
   set_program_name (argv[0]);
 
   signal (SIGABRT, bug_handler);
@@ -96,13 +94,8 @@ main (int argc, char **argv)
   fpu_init ();
   gsl_set_error_handler_off ();
 
-  outp_init ();
-  fn_init ();
   fh_init ();
-  the_source_stream =
-    create_source_stream (
-                         fn_getenv_default ("STAT_INCLUDE_PATH", include_path)
-                         );
+  the_source_stream = create_source_stream ();
   prompt_init ();
   readln_initialize ();
   terminal_init (&view_width_p, &view_length_p);
@@ -111,38 +104,16 @@ main (int argc, char **argv)
 
   the_dataset = create_dataset ();
 
-
-
-  clp = command_line_processor_create (_("PSPP --- A program for statistical analysis"),
-                                      _("FILE1, FILE2 ... FILEn"), NULL);
-
-  command_line_processor_add_options (clp, &io_argp,
-                                     _("Options affecting input and output locations:"), the_source_stream);
-
-  command_line_processor_add_options (clp, &test_argp,
-                                     _("Diagnostic options:"), the_source_stream);
-
-  command_line_processor_add_options (clp, &post_init_argp,
-                                     _("Options affecting syntax and behavior:"), the_source_stream);
-
-  command_line_processor_parse (clp, argc, argv);
+  parser = argv_parser_create ();
+  terminal_opts = terminal_opts_init (parser, the_source_stream);
+  source_init_register_argv_parser (parser, the_source_stream);
+  if (!argv_parser_run (parser, argc, argv))
+    exit (EXIT_FAILURE);
+  terminal_opts_done (terminal_opts, argc, argv);
+  argv_parser_destroy (parser);
 
   msg_ui_init (the_source_stream);
 
-  if (!settings_get_testing_mode ())
-    {
-      outp_read_devices ();
-    }
-  else
-    {
-      outp_configure_driver_line
-       (
-        ss_cstr ("raw-ascii:ascii:listing:width=9999 length=9999 "
-                 "output-file=\"pspp.list\" emphasis=none "
-                 "headers=off paginate=off squeeze=on "
-                 "top-margin=0 bottom-margin=0"));
-    }
-
   the_lexer = lex_create (the_source_stream);
 
   for (;;)
@@ -158,13 +129,13 @@ main (int argc, char **argv)
                     "a cascade of dependent command failures."));
          getl_abort_noninteractive (the_source_stream);
        }
-      else
-       check_msg_count (the_source_stream);
+      else if (msg_ui_too_many_errors ())
+        getl_abort_noninteractive (the_source_stream);
     }
 
 
   clean_up ();
-  return any_errors ();
+  return msg_ui_any_errors ();
 }
 \f
 
@@ -219,7 +190,7 @@ clean_up (void)
       destroy_source_stream (the_source_stream);
       prompt_done ();
       readln_uninitialize ();
-      outp_done ();
+      output_close ();
       msg_ui_done ();
       i18n_done ();
     }
index 682d753d8fbd36200f68e33677c239e5ef5b6c17..c657f096f3c16d9679f3bfafff44fa57017d2994 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010 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
 
 #include <config.h>
 
-#include "msg-ui.h"
+#include "ui/terminal/msg-ui.h"
 
-#include "unilbrk.h"
-#include "localcharset.h"
-
-#include <libpspp/msg-locator.h>
-#include <libpspp/getl.h>
-#include <data/settings.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <output/journal.h>
-#include <output/output.h>
-#include <output/table.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "data/settings.h"
+#include "libpspp/getl.h"
+#include "libpspp/message.h"
+#include "libpspp/msg-locator.h"
+#include "libpspp/str.h"
+#include "output/journal.h"
+#include "output/driver.h"
+#include "output/tab.h"
+#include "output/message-item.h"
+
+#include "gl/unilbrk.h"
+#include "gl/localcharset.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-/* Number of errors, warnings reported. */
-static int error_count;
-static int warning_count;
-static const char *error_file;
+/* Number of messages reported, by severity level. */
+static int counts[MSG_N_SEVERITIES];
 
-static void handle_msg (const struct msg *);
+/* True after the maximum number of errors or warnings has been exceeded. */
+static bool too_many_errors;
 
-static FILE *msg_file ;
+/* True after the maximum number of notes has been exceeded. */
+static bool too_many_notes;
 
-void
-msg_ui_set_error_file (const char *filename)
-{
-  error_file = filename;
-}
+static void handle_msg (const struct msg *);
 
 void
 msg_ui_init (struct source_stream *ss)
 {
-  msg_file = stdout;
-
-  if ( error_file )
-    {
-      msg_file = fopen (error_file, "a");
-      if ( NULL == msg_file )
-       {
-         int err = errno;
-         printf ( _("Cannot open %s (%s). "
-                    "Writing errors to stdout instead.\n"),
-                  error_file, strerror(err) );
-         msg_file = stdout;
-       }
-    }
   msg_init (ss, handle_msg);
 }
 
@@ -78,198 +63,80 @@ msg_ui_done (void)
 {
   msg_done ();
   msg_locator_done ();
-
-  if ( msg_file ) /* FIXME: do we really want to close stdout ?? */
-    fclose (msg_file);
 }
 
 /* Checks whether we've had so many errors that it's time to quit
    processing this syntax file. */
-void
-check_msg_count (struct source_stream *ss)
+bool
+msg_ui_too_many_errors (void)
 {
-  if (!getl_is_interactive (ss))
-    {
-      if (settings_get_errorbreak () && error_count)
-        msg (MN, _("Terminating execution of syntax file due to error."));
-      else if (error_count > settings_get_mxerrs () )
-        msg (MN, _("Errors (%d) exceeds limit (%d)."),
-             error_count, settings_get_mxerrs ());
-      else if (error_count + warning_count > settings_get_mxwarns () )
-        msg (MN, _("Warnings (%d) exceed limit (%d)."),
-             error_count + warning_count, settings_get_mxwarns () );
-      else
-        return;
-
-      getl_abort_noninteractive (ss);
-    }
+  return too_many_errors;
 }
 
 void
-reset_msg_count (void)
+msg_ui_reset_counts (void)
 {
-  error_count = warning_count = 0;
+  int i;
+
+  for (i = 0; i < MSG_N_SEVERITIES; i++)
+    counts[i] = 0;
+  too_many_errors = false;
+  too_many_notes = false;
 }
 
 bool
-any_errors (void)
+msg_ui_any_errors (void)
 {
-  return error_count > 0;
+  return counts[MSG_S_ERROR] > 0;
 }
-\f
-typedef void write_line_func (int indent, struct substring line, void *aux);
-static void dump_message (char *msg, unsigned width, unsigned indent,
-                          write_line_func *, void *aux);
-static write_line_func write_stream;
-static write_line_func write_journal;
 
 static void
-handle_msg (const struct msg *m)
+submit_note (char *s)
 {
-  struct category
-    {
-      bool show_command_name;   /* Show command name with error? */
-      bool show_file_location;  /* Show syntax file location? */
-    };
-
-  static const struct category categories[] =
-    {
-      {false, false},           /* MSG_GENERAL. */
-      {true, true},             /* MSG_SYNTAX. */
-      {false, true},            /* MSG_DATA. */
-    };
-
-  struct severity
-    {
-      const char *name;         /* How to identify this severity. */
-      int *count;               /* Number of msgs with this severity so far. */
-    };
-
-  static struct severity severities[] =
-    {
-      {N_("error"), &error_count},          /* MSG_ERROR. */
-      {N_("warning"), &warning_count},      /* MSG_WARNING. */
-      {NULL, NULL},                         /* MSG_NOTE. */
-    };
-
-  const struct category *category = &categories[m->category];
-  const struct severity *severity = &severities[m->severity];
-  struct string string = DS_EMPTY_INITIALIZER;
-
-  if (category->show_file_location && m->where.file_name)
-    {
-      ds_put_format (&string, "%s:", m->where.file_name);
-      if (m->where.line_number != -1)
-       ds_put_format (&string, "%d:", m->where.line_number);
-      ds_put_char (&string, ' ');
-    }
-
-  if (severity->name != NULL)
-    ds_put_format (&string, "%s: ", gettext (severity->name));
-
-  if (severity->count != NULL)
-    ++*severity->count;
-
-  if (category->show_command_name && msg_get_command_name () != NULL)
-    ds_put_format (&string, "%s: ", msg_get_command_name ());
-
-  ds_put_cstr (&string, m->text);
-
-  if (msg_file != stdout || settings_get_error_routing_to_terminal ())
-    dump_message (ds_cstr (&string),
-                  isatty (fileno (msg_file)) ? settings_get_viewwidth () : INT_MAX, 8,
-                  write_stream, msg_file);
-
-  dump_message (ds_cstr (&string), 78, 0, write_journal, NULL);
-
-  if (settings_get_error_routing_to_listing ())
-    {
-      /* Disable screen output devices, because the error should
-         already have been reported to the screen with the
-         dump_message call above. */
-      outp_enable_device (false, OUTP_DEV_SCREEN);
-      tab_output_text (TAB_LEFT, ds_cstr (&string));
-      outp_enable_device (true, OUTP_DEV_SCREEN);
-    }
-
-  ds_destroy (&string);
+  struct msg m;
+
+  m.category = MSG_C_GENERAL;
+  m.severity = MSG_S_NOTE;
+  m.where.file_name = NULL;
+  m.where.line_number = -1;
+  m.text = s;
+  message_item_submit (message_item_create (&m));
+  free (s);
 }
 
-/* Divides MSG into lines of WIDTH width for the first line and
-   WIDTH - INDENT width for each succeeding line, and writes the
-   lines by calling DUMP_LINE for each line, passing AUX as
-   auxiliary data. */
 static void
-dump_message (char *msg, unsigned width, unsigned indent,
-              write_line_func *dump_line, void *aux)
+handle_msg (const struct msg *m)
 {
-  size_t length = strlen (msg);
-  char *string, *breaks;
-  int line_indent;
-  size_t line_start, i;
-
-  /* Allocate temporary buffers.
-     If we can't get memory for them, then just dump the whole
-     message. */
-  string = strdup (msg);
-  breaks = malloc (length);
-  if (string == NULL || breaks == NULL)
-    {
-      free (string);
-      free (breaks);
-      dump_line (0, ss_cstr (msg), aux);
-      return;
-    }
-
-  /* Break into lines. */
-  if (indent > width / 3)
-    indent = width / 3;
-  ulc_width_linebreaks (string, length,
-                        width - indent, -indent, 0,
-                        NULL, locale_charset (), breaks);
+  int n_msgs, max_msgs;
 
-  /* Write out lines. */
-  line_start = 0;
-  line_indent = 0;
-  for (i = 0; i < length; i++)
-    if (breaks[i] == UC_BREAK_POSSIBLE || breaks[i] == UC_BREAK_MANDATORY)
-      {
-        dump_line (line_indent,
-                   ss_buffer (string + line_start, i - line_start), aux);
-        line_indent = indent;
+  if (too_many_errors || (too_many_notes && m->severity == MSG_S_NOTE))
+    return;
 
-        /* UC_BREAK_POSSIBLE means that a line break can be
-           inserted, and that the character should be included
-           in the next line.
-           UC_BREAK_MANDATORY means that this character is a line
-           break, so it should not be included in the next line. */
-        line_start = i + (breaks[i] == UC_BREAK_MANDATORY);
-      }
-  if (line_start < length)
-    dump_line (line_indent,
-               ss_buffer (string + line_start, length - line_start), aux);
-
-  free (string);
-  free (breaks);
-}
+  message_item_submit (message_item_create (m));
 
-/* Write LINE_INDENT spaces, LINE, then a new-line to STREAM. */
-static void
-write_stream (int line_indent, struct substring line, void *stream_)
-{
-  FILE *stream = stream_;
-  int i;
-  for (i = 0; i < line_indent; i++)
-    putc (' ', stream);
-  fwrite (ss_data (line), 1, ss_length (line), stream);
-  putc ('\n', stream);
-}
-
-/* Writes LINE to the journal. */
-static void
-write_journal (int line_indent UNUSED, struct substring line, void *unused UNUSED)
-{
-  char *s = xstrndup (ss_data (line), ss_length (line));
-  journal_write (true, s);
-  free (s);
+  counts[m->severity]++;
+  max_msgs = settings_get_max_messages (m->severity);
+  n_msgs = counts[m->severity];
+  if (m->severity == MSG_S_WARNING)
+    n_msgs += counts[MSG_S_ERROR];
+  if (n_msgs > max_msgs)
+    {
+      if (m->severity == MSG_S_NOTE)
+        {
+          too_many_notes = true;
+          submit_note (xasprintf (_("Notes (%d) exceed limit (%d).  "
+                                    "Suppressing further notes."),
+                                  n_msgs, max_msgs));
+        }
+      else
+        {
+          too_many_errors = true;
+          if (m->severity == MSG_S_WARNING)
+            submit_note (xasprintf (_("Warnings (%d) exceed limit (%d)."),
+                                    n_msgs, max_msgs));
+          else
+            submit_note (xasprintf (_("Errors (%d) exceed limit (%d)."),
+                                    n_msgs, max_msgs));
+        }
+    }
 }
index aa49e730e012d681db53f25dfdf35e2deeb39795..2c08a8822aa4f9948da02f8b13f466882dca76d1 100644 (file)
 #define MSG_UI_H 1
 
 #include <stdbool.h>
+#include <stdio.h>
 
-struct source_stream ;
+struct source_stream;
 
-void msg_ui_set_error_file (const char *filename);
+void msg_ui_set_error_file (FILE *);
 void msg_ui_init (struct source_stream *);
 void msg_ui_done (void);
-void check_msg_count (struct source_stream *);
-void reset_msg_count (void);
-bool any_errors (void);
+bool msg_ui_too_many_errors (void);
+void msg_ui_reset_counts (void);
+bool msg_ui_any_errors (void);
 
 #endif /* msg-ui.h */
index 7b23f38d2f359b58ecec1635970904d732edad5c..0fa145c98ac502edb7f29f25e471a2ca6ee885b7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009 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
 #include <data/file-name.h>
 #include <data/settings.h>
 #include <language/command.h>
+#include <libpspp/cast.h>
 #include <libpspp/message.h>
 #include <libpspp/str.h>
 #include <libpspp/version.h>
 #include <language/prompt.h>
 #include <output/journal.h>
-#include <output/manager.h>
+#include <output/driver.h>
 #include <ui/terminal/terminal.h>
 
 #include "xalloc.h"
@@ -107,8 +108,7 @@ static bool
 read_interactive (struct getl_interface *s,
                   struct string *line)
 {
-  struct readln_source *is  =
-    (struct readln_source *) s ;
+  struct readln_source *is  = UP_CAST (s, struct readln_source, parent);
 
   return is->interactive_func (line, prompt_get_style ());
 }
@@ -151,12 +151,11 @@ readln_read (struct string *line, enum prompt_style style)
 
   assert (initialised);
 
-  reset_msg_count ();
+  msg_ui_reset_counts ();
 
   welcome ();
 
-  if (style == PROMPT_FIRST)
-    som_flush ();
+  output_flush ();
 
 #if HAVE_READLINE
   rl_attempted_completion_function = (style == PROMPT_FIRST
@@ -215,7 +214,7 @@ create_readln_source (void)
   rlns->parent.read = read_interactive;
   rlns->parent.close = readln_close;
 
-  return (struct getl_interface *) rlns;
+  return &rlns->parent;
 }
 
 
index d2ddc6eeffa2b611f9d524d5b13fb8453d4dcb9e..a0f6072b521b65698ee4d0c6bb33fee8da2f4b4e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010  Free Software Foundation
 
    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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <argp.h>
+
+#include "terminal-opts.h"
+
 #include <stdbool.h>
 #include <xalloc.h>
 #include <stdlib.h>
-#include <data/settings.h>
-#include <output/output.h>
-#include "msg-ui.h"
-#include <ui/command-line.h>
-#include <libpspp/verbose-msg.h>
-#include <libpspp/llx.h>
-#include <data/file-name.h>
-#include "terminal-opts.h"
-#include <libpspp/getl.h>
-#include <language/syntax-file.h>
-#include "read-line.h"
+#include <unistd.h>
+
+#include "data/settings.h"
+#include "data/file-name.h"
+#include "language/syntax-file.h"
+#include "libpspp/argv-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/getl.h"
+#include "libpspp/llx.h"
+#include "libpspp/str.h"
+#include "libpspp/string-array.h"
+#include "libpspp/string-map.h"
+#include "libpspp/string-set.h"
+#include "libpspp/version.h"
+#include "output/driver.h"
+#include "output/driver-provider.h"
+#include "output/msglog.h"
+#include "ui/terminal/msg-ui.h"
+#include "ui/terminal/read-line.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+#include "gl/version-etc.h"
+#include "gl/xmemdup0.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+struct terminal_opts
+  {
+    struct source_stream *source_stream;
+    enum syntax_mode syntax_mode;
+    struct string_map options;  /* Output driver options. */
+    bool has_output_driver;
+    bool has_terminal_driver;
+    bool has_error_file;
+    bool process_statrc;
+  };
 
-static const struct argp_option test_options [] =
+enum
   {
-    {"verbose", 'v', 0, 0, N_("Increase diagnostic verbosity level"), 0},
-    {"testing-mode", 'T', 0, OPTION_HIDDEN, 0, 0},
+    OPT_TESTING_MODE,
+    OPT_ERROR_FILE,
+    OPT_OUTPUT,
+    OPT_OUTPUT_OPTION,
+    OPT_INTERACTIVE,
+    OPT_NO_STATRC,
+    OPT_HELP,
+    OPT_VERSION,
+    N_TERMINAL_OPTIONS
+  };
 
-    { 0, 0, 0, 0, 0, 0 }
+static struct argv_option terminal_argv_options[N_TERMINAL_OPTIONS] =
+  {
+    {"testing-mode", 0, no_argument, OPT_TESTING_MODE},
+    {"error-file", 'e', required_argument, OPT_ERROR_FILE},
+    {"output", 'o', required_argument, OPT_OUTPUT},
+    {NULL, 'O', required_argument, OPT_OUTPUT_OPTION},
+    {"interactive", 'i', no_argument, OPT_INTERACTIVE},
+    {"no-statrc", 'r', no_argument, OPT_NO_STATRC},
+    {"help", 'h', no_argument, OPT_HELP},
+    {"version", 'V', no_argument, OPT_VERSION},
   };
 
-static error_t
-parse_test_opts (int key, char *arg, struct argp_state *state)
+static void
+register_output_driver (struct terminal_opts *to)
 {
-  switch (key)
+  if (!string_map_is_empty (&to->options))
     {
-    case 'T':
-      settings_set_testing_mode (true);
-      break;
-    case 'v':
-      verbose_increment_level ();
-      break;
-    default:
-      return ARGP_ERR_UNKNOWN;
+      struct output_driver *driver;
+
+      driver = output_driver_create (&to->options);
+      if (driver != NULL)
+        {
+          output_driver_register (driver);
+
+          to->has_output_driver = true;
+          if (driver->device_type == SETTINGS_DEVICE_TERMINAL)
+            to->has_terminal_driver = true;
+        }
+      string_map_clear (&to->options);
     }
-
-  return 0;
 }
 
-static const struct argp_option io_options [] =
-  {
-    {"error-file", 'e', "FILE", 0,
-     N_("Send error messages to FILE (appended)"), 0},
-
-    {"device", 'o', "DEVICE", 0,
-     N_("Select output driver DEVICE and disable defaults"), 0},
-
-    {"list", 'l', 0, 0,
-     N_("Print a list of known driver classes, then exit"), 0},
+static void
+parse_output_option (struct terminal_opts *to, const char *option)
+{
+  const char *equals;
+  char *key, *value;
 
-    {"interactive", 'i', 0, 0, N_("Start an interactive session"), 0},
+  equals = strchr (option, '=');
+  if (equals == NULL)
+    {
+      error (0, 0, _("%s: output option missing `='"), option);
+      return;
+    }
 
-    { 0, 0, 0, 0, 0, 0 }
-  };
+  key = xmemdup0 (option, equals - option);
+  if (string_map_contains (&to->options, key))
+    {
+      error (0, 0, _("%s: output option %s specified more than twice"), key);
+      free (key);
+      return;
+    }
 
+  value = xmemdup0 (equals + 1, strlen (equals + 1));
+  string_map_insert_nocopy (&to->options, key, value);
+}
 
-static error_t
-parse_io_opts (int key, char *arg, struct argp_state *state)
+static char *
+get_supported_formats (void)
 {
-  struct source_init
-  {
-    struct llx_list file_list;
-    bool cleared_device_defaults;
-    bool interactive;
-  };
-
-  struct fn_element {
-    struct ll ll;
-    const char *fn;
-  };
+  const struct string_set_node *node;
+  struct string_array format_array;
+  struct string_set format_set;
+  char *format_string;
+  const char *format;
+  size_t i;
+
+  /* Get supported formats as unordered set. */
+  string_set_init (&format_set);
+  output_get_supported_formats (&format_set);
+
+  /* Converted supported formats to sorted array. */
+  string_array_init (&format_array);
+  STRING_SET_FOR_EACH (format, node, &format_set)
+    string_array_append (&format_array, format);
+  string_array_sort (&format_array);
+  string_set_destroy (&format_set);
+
+  /* Converted supported formats to string. */
+  format_string = string_array_join (&format_array, " ");
+  string_array_destroy (&format_array);
+  return format_string;
+}
 
-  struct source_init *sip = state->hook;
+static char *
+get_default_include_path (void)
+{
+  struct source_stream *ss;
+  struct string dst;
+  char **path;
+  size_t i;
+
+  ss = create_source_stream ();
+  path = getl_include_path (ss);
+  ds_init_empty (&dst);
+  for (i = 0; path[i] != NULL; i++)
+    ds_put_format (&dst, " %s", path[i]);
+  destroy_source_stream (ss);
+
+  return ds_steal_cstr (&dst);
+}
 
-  struct source_stream *ss = state->input;
+static void
+usage (void)
+{
+  char *supported_formats = get_supported_formats ();
+  char *default_include_path = get_default_include_path ();
+
+  printf ("\
+PSPP, a program for statistical analysis of sample data.\n\
+Usage: %s [OPTION]... FILE...\n\
+\n\
+Arguments to long options also apply to equivalent short options.\n\
+\n\
+Output options:\n\
+  -o, --output=FILE         output to FILE, default format from FILE's name\n\
+  -O format=FORMAT          override format for previous -o\n\
+  -O OPTION=VALUE           set output option to customize previous -o\n\
+  -O device={terminal|listing}  override device type for previous -o\n\
+  -e, --error-file=FILE     append errors, warnings, and notes to FILE\n\
+Supported output formats: %s\n\
+\n\
+Language options:\n\
+  -I, --include=DIR         append DIR to search path\n\
+  -I-, --no-include         clear search path\n\
+  -r, --no-statrc           disable running rc file at startup\n\
+  -a, --algorithm={compatible|enhanced}\n\
+                            set to `compatible' if you want output\n\
+                            calculated from broken algorithms\n\
+  -x, --syntax={compatible|enhanced}\n\
+                            set to `compatible' to disable PSPP extensions\n\
+  -i, --interactive         interpret syntax in interactive mode\n\
+  -s, --safer               don't allow some unsafe operations\n\
+Default search path:%s\n\
+\n\
+Informative output:\n\
+  -h, --help                display this help and exit\n\
+  -V, --version             output version information and exit\n\
+\n\
+Non-option arguments are interpreted as syntax files to execute.\n",
+          program_name, supported_formats, default_include_path);
+
+  free (supported_formats);
+  free (default_include_path);
+
+  emit_bug_reporting_address ();
+  exit (EXIT_SUCCESS);
+}
 
-  struct command_line_processor *clp = get_subject (state);
+static void
+terminal_option_callback (int id, void *to_)
+{
+  struct terminal_opts *to = to_;
 
-  switch (key)
+  switch (id)
     {
-    case ARGP_KEY_INIT:
-      state->hook = sip = xzalloc (sizeof (struct source_init));
-      llx_init (&sip->file_list);
-      break;
-    case ARGP_KEY_ARG:
-      if (strchr (arg, '='))
-       outp_configure_macro (arg);
-      else
-       {
-         llx_push_tail (&sip->file_list, arg, &llx_malloc_mgr);
-       }
-      break;
-    case ARGP_KEY_SUCCESS:
-      {
-      struct llx *llx = llx_null (&sip->file_list);
-      while ((llx = llx_next (llx)) != llx_null (&sip->file_list))
-       {
-         const char *fn = llx_data (llx);
-         /* Assume it's a syntax file */
-         getl_append_source (ss,
-                             create_syntax_file_source (fn),
-                             GETL_BATCH,
-                             ERRMODE_CONTINUE
-                             );
-
-       }
-
-      if (sip->interactive || llx_is_empty (&sip->file_list))
-       {
-         getl_append_source (ss, create_readln_source (),
-                             GETL_INTERACTIVE,
-                             ERRMODE_CONTINUE
-                             );
-
-         if (!sip->cleared_device_defaults)
-           outp_configure_add ("interactive");
-       }
-      }
+    case OPT_TESTING_MODE:
+      settings_set_testing_mode (true);
       break;
-    case ARGP_KEY_FINI:
-      free (sip);
+
+    case OPT_ERROR_FILE:
+      if (!strcmp (optarg, "none") || msglog_create (optarg))
+        to->has_error_file = true;
       break;
-    case 'e':
-      msg_ui_set_error_file (arg);
+
+    case OPT_OUTPUT:
+      register_output_driver (to);
+      string_map_insert (&to->options, "output-file", optarg);
       break;
-    case 'i':
-      sip->interactive = true;
+
+    case OPT_OUTPUT_OPTION:
+      parse_output_option (to, optarg);
       break;
-    case 'l':
-      outp_list_classes ();
+
+    case OPT_INTERACTIVE:
+      to->syntax_mode = GETL_INTERACTIVE;
       break;
-    case 'o':
-      if (! sip->cleared_device_defaults)
-       {
-         outp_configure_clear ();
-         sip->cleared_device_defaults = true;
-       }
-      outp_configure_add (arg);
+
+    case OPT_NO_STATRC:
+      to->process_statrc = false;
       break;
+
+    case OPT_HELP:
+      usage ();
+      exit (EXIT_SUCCESS);
+
+    case OPT_VERSION:
+      version_etc (stdout, "pspp", PACKAGE_NAME, PACKAGE_VERSION,
+                   "Ben Pfaff", "John Darrington", "Jason Stover",
+                   (char *) NULL);
+      exit (EXIT_SUCCESS);
+
     default:
-      return ARGP_ERR_UNKNOWN;
+      NOT_REACHED ();
     }
-
-  return 0;
 }
 
-const struct argp io_argp =  {io_options, parse_io_opts, 0, 0, 0, 0, 0};
-const struct argp test_argp =  {test_options, parse_test_opts, 0, 0, 0, 0, 0};
-
-#if 0
-static const struct argp_child children [] =
-  {
-    {&io_argp, 0, N_("Options affecting input and output locations:"), 0},
-    {&test_argp, 0, N_("Diagnostic options:"), 0},
-    {0, 0, 0, 0}
-  };
+struct terminal_opts *
+terminal_opts_init (struct argv_parser *ap, struct source_stream *ss)
+{
+  struct terminal_opts *to;
+
+  to = xmalloc (sizeof *to);
+  to->source_stream = ss;
+  to->syntax_mode = GETL_BATCH;
+  string_map_init (&to->options);
+  to->has_output_driver = false;
+  to->has_error_file = false;
+  to->process_statrc = true;
+
+  argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS,
+                           terminal_option_callback, to);
+  return to;
+}
 
+static void
+add_syntax_file (struct terminal_opts *to, const char *file_name)
+{
+  if (!strcmp (file_name, "-") && isatty (STDIN_FILENO))
+    getl_append_source (to->source_stream, create_readln_source (),
+                        GETL_INTERACTIVE, ERRMODE_CONTINUE);
+  else
+    getl_append_source (to->source_stream,
+                        create_syntax_file_source (file_name),
+                        to->syntax_mode, ERRMODE_CONTINUE);
+}
 
-static error_t
-propagate_aux (int key, char *arg, struct argp_state *state)
+void
+terminal_opts_done (struct terminal_opts *to, int argc, char *argv[])
 {
-  if ( key == ARGP_KEY_INIT)
+  if (to->process_statrc)
+    {
+      char *rc = fn_search_path ("rc", getl_include_path (to->source_stream));
+      if (rc != NULL)
+        {
+          getl_append_source (to->source_stream,
+                              create_syntax_file_source (rc), GETL_BATCH,
+                              ERRMODE_CONTINUE);
+          free (rc);
+        }
+    }
+
+  if (optind < argc)
     {
       int i;
-      for (i = 0 ; i < sizeof (children) / sizeof (children[0]) - 1 ; ++i)
-       state->child_inputs[i] = state->input;
+
+      for (i = optind; i < argc; i++)
+        add_syntax_file (to, argv[i]);
     }
+  else
+    add_syntax_file (to, "-");
 
-  return ARGP_ERR_UNKNOWN;
-}
+  register_output_driver (to);
+  if (!to->has_output_driver)
+    {
+      string_map_insert (&to->options, "output-file", "-");
+      string_map_insert (&to->options, "format", "txt");
+      register_output_driver (to);
+    }
 
-const struct argp terminal_argp =  {NULL, propagate_aux, 0, 0, children, 0, 0};
+  if (to->has_terminal_driver && !to->has_error_file)
+    msglog_create ("-");
 
-#endif
+  string_map_destroy (&to->options);
+  free (to);
+}
index e5d032d18efcc156d28e2c7b3a613993affdc20d..12251123db3623b71cf65d5745bada2ddc78eb43 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010  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
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
-#ifndef TERMINAL_OPTS
-#define TERMINAL_OPTS
+#ifndef UI_TERMINAL_TERMINAL_OPTS_H
+#define UI_TERMINAL_TERMINAL_OPTS_H 1
 
-extern const struct argp io_argp ;
-extern const struct argp test_argp ;
+struct argv_parser;
+struct source_stream;
+struct terminal_opts;
 
-extern const struct argp terminal_argp;
-
-#endif
+struct terminal_opts *terminal_opts_init (struct argv_parser *,
+                                          struct source_stream *);
+void terminal_opts_done (struct terminal_opts *, int argc, char *argv[]);
 
+#endif /* ui/terminal/terminal-opts.h */
index 282522db0342d8750454b3dc162493b5fc709cc8..8174e64562800e55a632a7c48f789d18013920b1 100644 (file)
@@ -1,2 +1,3 @@
 Makefile
 Makefile.in
+/testsuite
diff --git a/tests/atlocal.in b/tests/atlocal.in
new file mode 100644 (file)
index 0000000..97e1ae3
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- shell-script -*-
+PERL='@PERL@'
+CHARSETALIASDIR="$abs_top_builddir/gl"
+export CHARSETALIASDIR
index 8a974a32f7033545d91cd075b8c879180a7c7eed..dcfbf2335df87f99560823510504d3f20b9a0e71 100644 (file)
@@ -194,6 +194,8 @@ nodist_TESTS = \
        tests/libpspp/range-set-test \
        tests/libpspp/sparse-array-test \
        tests/libpspp/str-test \
+       tests/libpspp/string-map-test \
+       tests/libpspp/string-set-test \
        tests/libpspp/tower-test
 
 TESTS = $(dist_TESTS) $(nodist_TESTS)
@@ -202,7 +204,8 @@ check_PROGRAMS += \
        $(nodist_TESTS) \
        tests/data/datasheet-test \
        tests/formats/inexactify \
-       tests/libpspp/sparse-xarray-test
+       tests/libpspp/sparse-xarray-test \
+       tests/output/render-test
 
 tests_data_datasheet_test_SOURCES = \
        tests/data/datasheet-test.c
@@ -288,6 +291,23 @@ tests_libpspp_str_test_SOURCES = \
        tests/libpspp/str-test.c
 tests_libpspp_str_test_LDADD = src/libpspp/libpspp.la gl/libgl.la $(LIBINTL) 
 
+tests_libpspp_string_map_test_SOURCES = \
+       src/libpspp/hash-functions.c \
+       src/libpspp/hmap.c \
+       src/libpspp/string-map.c \
+       src/libpspp/string-set.c \
+       tests/libpspp/string-map-test.c
+tests_libpspp_string_map_test_LDADD = gl/libgl.la $(LIBINTL)
+tests_libpspp_string_map_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
+
+tests_libpspp_string_set_test_SOURCES = \
+       src/libpspp/hash-functions.c \
+       src/libpspp/hmap.c \
+       src/libpspp/string-set.c \
+       tests/libpspp/string-set-test.c
+tests_libpspp_string_set_test_LDADD = gl/libgl.la $(LIBINTL)
+tests_libpspp_string_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
+
 tests_libpspp_tower_test_SOURCES = \
        src/libpspp/abt.c \
        src/libpspp/abt.h \
@@ -333,6 +353,15 @@ tests_dissect_sysfile_SOURCES = \
 tests_dissect_sysfile_LDADD = gl/libgl.la $(LIBINTL) 
 tests_dissect_sysfile_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\"
 
+check_PROGRAMS += tests/output/render-test
+tests_output_render_test_SOURCES = tests/output/render-test.c
+tests_output_render_test_LDADD = \
+       src/libpspp.la \
+       src/libpspp-core.la \
+       $(CAIRO_LIBS) \
+       $(LIBICONV) \
+       $(LIBINTL)
+
 EXTRA_DIST += \
        $(dist_TESTS) \
         tests/Book1.gnm.unzipped \
@@ -340,9 +369,6 @@ EXTRA_DIST += \
        tests/no_case_size.sav \
        tests/coverage.sh tests/test_template \
        tests/v13.sav tests/v14.sav \
-       tests/bugs/computebug.stat tests/bugs/computebug.out \
-       tests/bugs/recode-copy-bug-1.stat tests/bugs/recode-copy-bug-2.stat \
-       tests/bugs/recode-copy-bug-1.out tests/bugs/recode-copy-bug-2.out \
        tests/expressions/randist/beta.out \
        tests/expressions/randist/cauchy.out \
        tests/expressions/randist/chisq.out \
@@ -382,3 +408,43 @@ check-for-export-var-val:
 DIST_HOOKS += check-for-export-var-val
 
 EXTRA_DIST += tests/OChangeLog
+\f
+# Autotest testsuite
+
+EXTRA_DIST += \
+       $(TESTSUITE_AT) \
+       $(TESTSUITE) \
+       tests/atlocal.in \
+       $(srcdir)/package.m4 \
+       $(TESTSUITE)
+TESTSUITE_AT = \
+       tests/testsuite.at \
+       tests/output/render.at
+TESTSUITE = $(srcdir)/tests/testsuite
+DISTCLEANFILES += tests/atconfig tests/atlocal $(TESTSUITE)
+
+CHECK_LOCAL += tests_check
+tests_check: tests/atconfig tests/atlocal $(TESTSUITE)
+       $(SHELL) '$(TESTSUITE)' -C tests AUTOTEST_PATH=tests/output $(TESTSUITEFLAGS)
+
+CLEAN_LOCAL += tests_clean
+tests_clean:
+       test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' -C tests --clean
+
+AUTOM4TE = $(SHELL) $(srcdir)/missing --run autom4te
+AUTOTEST = $(AUTOM4TE) --language=autotest
+$(TESTSUITE): package.m4 $(TESTSUITE_AT)
+       $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
+       mv $@.tmp $@
+
+# The `:;' works around a Bash 3.2 bug when the output is not writeable.
+$(srcdir)/package.m4: $(top_srcdir)/configure.ac
+       :;{ \
+         echo '# Signature of the current package.' && \
+         echo 'm4_define([AT_PACKAGE_NAME],      [$(PACKAGE_NAME)])' && \
+         echo 'm4_define([AT_PACKAGE_TARNAME],   [$(PACKAGE_TARNAME)])' && \
+         echo 'm4_define([AT_PACKAGE_VERSION],   [$(PACKAGE_VERSION)])' && \
+         echo 'm4_define([AT_PACKAGE_STRING],    [$(PACKAGE_STRING)])' && \
+         echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])' && \
+         echo 'm4_define([AT_PACKAGE_URL],       [$(PACKAGE_URL)])'; \
+       } >'$(srcdir)/package.m4'
index 0b006780f319de5ac506e877543c2e25be7d94da..98bd8dcfe33b4d0de93afd57ed1823d9f26d1a2f 100755 (executable)
@@ -74,22 +74,20 @@ LIST /x y.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|X       |F8.2  |
-|Y       |A25   |
-+--------+------+
-        X                         Y
---------- -------------------------
-    87.34 bar                       
-    87.50 foo                       
+activity="compare output"
+diff $TEMPDIR/pspp.csv - << EOF | cat -E
+Table: Reading free-form data from INLINE.
+Variable,Format
+X,F8.2
+Y,A25
+
+Table: Data List
+X,Y
+87.34,bar                      
+87.50,foo                      
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 43fd9f8c47a13bca00092282932b59ccab028016..449e90e949856a489e939cf1900308d3b177ad47 100755 (executable)
@@ -76,7 +76,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 # So this will have a non zero error status.
 # But it shouldn't crash!
 activity="run_program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 
index ae60e79ce41070610af46e0a78699a1033dba78d..e3adb6ef377d55e2f82b309de06e5c95bb0ea590 100755 (executable)
@@ -73,7 +73,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index b0da13bbf3a0af4075e27f87e4ba1ee51e2c2585..c400e2e905cc9246d7eb3bf42dd960e9b4fd11d2 100755 (executable)
@@ -84,7 +84,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="appending to data"
@@ -93,7 +93,7 @@ $PERL -e 'for ($i=0; $i<25000; $i++) { print "AB04\nAB12\n" };' >> $TEMPDIR/larg
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 3c9365dfce520d6ea7c4cf7154a59c0fa90a343b..9cc3ad93075e15721c2087bd881dbf93f7d833cf 100755 (executable)
@@ -75,7 +75,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 011c344d059ed8a406995bd3e5123ebc065e71e9..17f4fedf64c62560750f3995c89c0ca890147dc3 100755 (executable)
@@ -72,7 +72,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 342f9bc08ab95eeeb7531e97087c4206d678372a..f28762d19495c4048722ab0363beb8593028e26a 100755 (executable)
@@ -63,7 +63,7 @@ COMMENT this is a comment at end of file.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail; fi
 
 pass;
index 71f9eab48d329ed0e2ab8673d48c7578c50ffd3a..d8c838888e747d873e7218315705359921c531f7 100755 (executable)
@@ -74,7 +74,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 # Make sure the file really was compressed
index 0d4a313e26edbb451e38e3dc45c065f558c4cd98..2417cca92bc423873eb795e6d661ba406ac0ed7b 100755 (executable)
@@ -70,7 +70,7 @@ SAVE outfile='$TEMPDIR/temp.sav'.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail; fi
 
 
index b0baf4f09cd4272c5e77c773032cd852f75d75c4..5bb132143755b36a7d19ab1e182a26eb86d14099 100755 (executable)
@@ -74,24 +74,21 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run prog"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' pspp.list
-diff -b pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+----------------+------+
-|    Variable    |Format|
-#================#======#
-|longVariablename|F8.0  |
-|x               |F8.0  |
-+----------------+------+
-longVariablename        x
----------------- -------- 
-           99.00     2.00
-           97.00     4.00
+diff pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+longVariablename,F8.0
+x,F8.0
+
+Table: Data List
+longVariablename,x
+99.00,2.00
+97.00,4.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 83aeae048acfe9ca5fce21a4ab84d8492ef901d8..455ec39d09599e022119e1b34d550673084a2b13 100755 (executable)
@@ -72,7 +72,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/compute-sum.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/compute-sum.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
diff --git a/tests/bugs/computebug.out b/tests/bugs/computebug.out
deleted file mode 100644 (file)
index 61fc7d0..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |A161  |
-|B       |A3    |
-+--------+------+
-                                                                                                                                                                A   B
------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---
-ABC                                                                                                                                                               def 
-GHI                                                                                                                                                               jkl 
index dfa5990a759cc416209552e6ba60b4f1eb6379cd..4ba6a9d1a375486fa55df15d60f4c1569aa17d84 100755 (executable)
@@ -53,24 +53,42 @@ pass()
 }
 
 mkdir -p $TEMPDIR
-
-activity="copy file"
-cp $top_srcdir/tests/bugs/computebug.stat $TEMPDIR
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="chdir"
 cd $TEMPDIR
 if [ $? -ne 0 ] ; then no_result ; fi
 
+activity="create input"
+cat > $TESTFILE <<EOF
+DATA LIST LIST
+ /A (A161)
+ B (A3).
+
+BEGIN DATA
+abc   def
+ghi   jkl
+END DATA.
+
+COMPUTE A=upcase(A).
+EXECUTE.
+LIST.
+EOF
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/computebug.stat
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list $top_srcdir/tests/bugs/computebug.out
-diff -b -w $TEMPDIR/pspp.list $top_srcdir/tests/bugs/computebug.out
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,A161
+B,A3
+
+Table: Data List
+A,B
+ABC                                                                                                                                                              ,def
+GHI                                                                                                                                                              ,jkl
+EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
diff --git a/tests/bugs/computebug.stat b/tests/bugs/computebug.stat
deleted file mode 100644 (file)
index e308301..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-DATA LIST LIST
- /A (A161)
- B (A3).
-
-BEGIN DATA
-abc   def
-ghi   jkl
-END DATA.
-
-COMPUTE A=upcase(A).
-EXECUTE.
-LIST.
-
-
index 4454319c709420bb47181ef010698499a87bdb20..5bebfed5c7d77f269303e4ec6d771cbd4b016795 100755 (executable)
@@ -70,46 +70,35 @@ CROSSTABS VARIABLES X (1,7) Y (1,7) /TABLES X BY Y.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |F8.0  |
-|B       |F8.0  |
-|X       |F8.0  |
-|Y       |F8.0  |
-+--------+------+
-2.1 CROSSTABS.  Summary.
-#===============#=====================================================#
-#               #                        Cases                        #
-#               #-----------------+-----------------+-----------------#
-#               #      Valid      |     Missing     |      Total      #
-#               #--------+--------+--------+--------+--------+--------#
-#               #       N| Percent|       N| Percent|       N| Percent#
-#---------------#--------+--------+--------+--------+--------+--------#
-#X * Y          #       1|  100.0%|       0|    0.0%|       1|  100.0%#
-#===============#========#========#========#========#========#========#
-2.2 CROSSTABS.  X * Y [count].
-#===============#==============================================================#========#
-#               #                               Y                              |        #
-#               #--------+--------+--------+--------+--------+--------+--------+        #
-#              X#    1.00|    2.00|    3.00|    4.00|    5.00|    6.00|    7.00|  Total #
-#---------------#--------+--------+--------+--------+--------+--------+--------+--------#
-#           1.00#      .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|      .0|     1.0#
-#           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|      .0|     1.0#
-#===============#========#========#========#========#========#========#========#========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,F8.0
+B,F8.0
+X,F8.0
+Y,F8.0
+
+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,.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,.0,1.0
+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,.0,1.0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index b0db128a1c54e01947a704fdacb7bb6f24d59d19..d283516153c71ccbb1fa81980580d4166c4c50a3 100755 (executable)
@@ -75,43 +75,32 @@ CROSSTABS /TABLES = x BY y.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|y       |A18   |
-+--------+------+
-$TEMPDIR/crosstabs-crash2.sh.sps:4: warning: BEGIN DATA: Missing value(s) for all variables from x onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/crosstabs-crash2.sh.sps:6: warning: BEGIN DATA: Missing value(s) for all variables from x onward.  These will be filled with the system-missing value or blanks, as appropriate.
-2.1 CROSSTABS.  Summary.
-#===============#=====================================================#
-#               #                        Cases                        #
-#               #-----------------+-----------------+-----------------#
-#               #      Valid      |     Missing     |      Total      #
-#               #--------+--------+--------+--------+--------+--------#
-#               #       N| Percent|       N| Percent|       N| Percent#
-#---------------#--------+--------+--------+--------+--------+--------#
-#x * y          #       4|   66.7%|       2|   33.3%|       6|  100.0%#
-#===============#========#========#========#========#========#========#
-2.2 CROSSTABS.  x * y [count].
-#===============#===================================#========#
-#               #                 y                 |        #
-#               #--------+--------+--------+--------+        #
-#              x#     one|   three|     two|    zero|  Total #
-#               #unity   |lots    |duality |none    |        #
-#               #        |        |        |        |        #
-#---------------#--------+--------+--------+--------+--------#
-#           1.00#     1.0|      .0|      .0|     1.0|     2.0#
-#           2.00#      .0|      .0|     1.0|      .0|     1.0#
-#           3.00#      .0|     1.0|      .0|      .0|     1.0#
-#Total          #     1.0|     1.0|     1.0|     1.0|     4.0#
-#===============#========#========#========#========#========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,F8.0
+y,A18
+
+"$TEMPDIR/crosstabs-crash2.sh.sps:4: warning: BEGIN DATA: Missing value(s) for all variables from x onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/crosstabs-crash2.sh.sps:6: warning: BEGIN DATA: Missing value(s) for all variables from x onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+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.0,.0,.0,1.0,2.0
+2.00,.0,.0,1.0,.0,1.0
+3.00,.0,1.0,.0,.0,1.0
+Total,1.0,1.0,1.0,1.0,4.0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 3ef691f376b672facb32463112c4ac9d86337f74..6f02a5087ae4f9fdcabe2072814a4d6765142d02 100755 (executable)
@@ -84,7 +84,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/ct.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/ct.stat
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 3e6629985913517b6645e951c927e87968b99c20..bfb6f6857689c492c1ff7e83065941c62cb5ae19 100755 (executable)
@@ -76,56 +76,36 @@ CROSSTABS
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|y       |F8.0  |
-+--------+------+
-2.1 CROSSTABS.  Summary.
-#===============#=====================================================#
-#               #                        Cases                        #
-#               #-----------------+-----------------+-----------------#
-#               #      Valid      |     Missing     |      Total      #
-#               #--------+--------+--------+--------+--------+--------#
-#               #       N| Percent|       N| Percent|       N| Percent#
-#---------------#--------+--------+--------+--------+--------+--------#
-#x * y          #       4|  100.0%|       0|    0.0%|       4|  100.0%#
-#===============#========#========#========#========#========#========#
-2.2 CROSSTABS.  x * y [count].
-#===============#=================#========#
-#               #        y        |        #
-#               #--------+--------+        #
-#              x#    1.00|    2.00|  Total #
-#---------------#--------+--------+--------#
-#           2.00#      .0|     1.0|     1.0#
-#           3.00#     1.0|      .0|     1.0#
-#           4.00#     1.0|     1.0|     2.0#
-#Total          #     2.0|     2.0|     4.0#
-#===============#========#========#========#
-2.3 CROSSTABS.  Chi-square tests.
-#===============#========#========#========#
-#Statistic      #   Value|      df|  Asymp.#
-#               #        |        |    Sig.#
-#               #        |        |(2-sided#
-#               #        |        |       )#
-#---------------#--------+--------+--------#
-#Pearson        #    2.00|       2|     .37#
-#Chi-Square     #        |        |        #
-#Likelihood     #    2.77|       2|     .25#
-#Ratio          #        |        |        #
-#Linear-by-Linea#     .27|       1|     .60#
-#r Association  #        |        |        #
-#N of Valid     #       4|        |        #
-#Cases          #        |        |        #
-#===============#========#========#========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,F8.0
+y,F8.0
+
+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,.0,1.0,1.0
+3.00,1.0,.0,1.0
+4.00,1.0,1.0,2.0
+Total,2.0,2.0,4.0
+
+Table: Chi-square tests.
+Statistic,Value,df,Asymp. Sig. (2-sided)
+Pearson Chi-Square,2.00,2,.37
+Likelihood Ratio,2.77,2,.25
+Linear-by-Linear Association,.27,1,.60
+N of Valid Cases,4,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 26de22b2390a61b4eb0ddae36ea429bf344582dc..624f5a5ba69da7f8fade089dc597ee68be2a8bb6 100755 (executable)
@@ -74,7 +74,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #This must fail
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE
 if [ $? -ne 1 ] ; then fail ; fi
 
 
index dfdcbfdc60f2da20c2fe29075cc452bafd2372e4..15ba9e2cb51321c7b55017ed6ae081655822b08c 100755 (executable)
@@ -67,7 +67,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #This must fail
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TEMPDIR/ct.stat 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TEMPDIR/ct.stat 
 if [ $? -ne 1 ] ; then fail ; fi
 
 pass;
index ca958cd1ea6eabf09a81504637e998522f908bea..c579cf36b3c626b6ab3061da5c4618560626cbe1 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 cd $TEMPDIR
 
 activity="run data"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/ff.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/ff.stat
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index b96b2feab28075dbe117f3a25763d6e3373a21f0..ddc2e7a62fe7421dd9b47ac11bd2feba98395dfe 100755 (executable)
@@ -71,7 +71,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 # Must not crash.
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/repeat.stat 
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/repeat.stat 
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 49ce086c592d07a44bccf306cef5d20443ff18e7..dd4449d80dbd5ed2f4f67fdb89b9800e6f166833 100755 (executable)
@@ -73,7 +73,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass
index 6cd172fde54abab2387bee19c804881774a27787..03c51c6fe90cb50f662f97dda43a02f4fe2724ad 100755 (executable)
@@ -73,7 +73,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 01fe8f9a3288e88489801976bbbb4c37dbd72190..32f0e99fc4e117806f8d0e75b9d3810e582bf394 100755 (executable)
@@ -74,7 +74,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 6093c343901f21f391040c83c4ad9fb7417e672f..2afc044f90c53c0ba1925eec6c92084bcfb449ce 100755 (executable)
@@ -75,7 +75,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 5e3edec3dadf176d60bfb12f0c0aab1aa9108e2a..86b382e65bd47e47c64e0b16f5387fa8ba41f9f9 100755 (executable)
@@ -74,7 +74,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 2> /dev/null
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 2> /dev/null
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 2cd6c14a6a00d930722149a77d5fc5da0d86fe7e..2ea650c88166f2e8d414edd358d077895dcb83b9 100755 (executable)
@@ -78,40 +78,28 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|y       |F8.0  |
-+--------+------+
-2.1 EXAMINE.  Case Processing Summary
-#=#===============================#
-# #             Cases             #
-# #----------+----------+---------#
-# #   Valid  |  Missing |  Total  #
-# #-+--------+-+--------+-+-------#
-# #N| Percent|N| Percent|N|Percent#
-#=#=#========#=#========#=#=======#
-#x#6|85.7143%|1|14.2857%|7|   100%#
-#=#=#========#=#========#=#=======#
-2.2 EXAMINE.  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%#
-#==========#=#========#=#========#=#=======#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,F8.0
+y,F8.0
+
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x,6,85.7143%,1,14.2857%,7,100%
+
+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%
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -138,7 +126,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index b5c44b54ace8e19c741c0df1b6f9b7a5e883bef1..f6c2f002f2fa47c1d0837d6ba2f83edf134bc244 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
index d047b76758a332ff398ab56ecc5d65c2d4f80c19..88e539c159d2d2374b5682d387ef403e6ce3f570 100755 (executable)
@@ -68,7 +68,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 # We use the stdinput here, because the bug seems to manifest itself only in 
 # interactive mode.
 activity="run program"
-cat $TESTFILE | $SUPERVISOR $PSPP --testing-mode  > /dev/null
-if [ $? -ne 0 ] ; then fail ; fi
+cat $TESTFILE | $SUPERVISOR $PSPP -o pspp.csv  > /dev/null
+if [ $? -ne 1 ] ; then fail ; fi
 
 pass
index 2cc6cfc5a3e26ec7f0b8d24a629fb75728e4f2d5..aa76a8c0c723294f7ac5b9b7c6dfde17eadc89e0 100755 (executable)
@@ -87,35 +87,35 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-LOCATION   EDITOR    SHELL     FREQ
- -------- -------- -------- --------
-     1.00     1.00     1.00     2.00 
-     1.00     1.00     2.00    30.00 
-     1.00     2.00     1.00     8.00 
-     1.00     2.00     2.00    20.00 
-     2.00     1.00     1.00     2.00 
-     2.00     1.00     2.00    22.00 
-     2.00     2.00     1.00     1.00 
-     2.00     2.00     2.00     3.00 
-LOCATION   EDITOR    SHELL     FREQ
- -------- -------- -------- --------
-     1.00     1.00     1.00     2.00 
-     1.00     1.00     2.00    30.00 
-     1.00     2.00     1.00     8.00 
-     1.00     2.00     2.00    20.00 
-     2.00     1.00     1.00     2.00 
-     2.00     1.00     2.00    22.00 
-     2.00     2.00     1.00     1.00 
-     2.00     2.00     2.00     3.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+LOCATION,EDITOR,SHELL,FREQ
+1.00,1.00,1.00,2.00
+1.00,1.00,2.00,30.00
+1.00,2.00,1.00,8.00
+1.00,2.00,2.00,20.00
+2.00,1.00,1.00,2.00
+2.00,1.00,2.00,22.00
+2.00,2.00,1.00,1.00
+2.00,2.00,2.00,3.00
+
+Table: Data List
+LOCATION,EDITOR,SHELL,FREQ
+1.00,1.00,1.00,2.00
+1.00,1.00,2.00,30.00
+1.00,2.00,1.00,8.00
+1.00,2.00,2.00,20.00
+2.00,1.00,1.00,2.00
+2.00,1.00,2.00,22.00
+2.00,2.00,1.00,1.00
+2.00,2.00,2.00,3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 789fe32c74766ade1f606d060375ce049ba50858..3417601ae41ab1808613fbe1beefd4f5e4453e93 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 cd $TEMPDIR
 
 activity="run data"
-$SUPERVISOR $PSPP -o html $TESTFILE
+$SUPERVISOR $PSPP -o pspp.html $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 4f07d30281e5173da39d667bd64efab363560e68..9882d0da7017df854f3218f64268939137bfdac2 100755 (executable)
@@ -80,7 +80,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 # So this will have a non zero error status.
 # But it shouldn't crash!
 activity="run_program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 
index 600ca729457745f6c77fec0ba64acd124db73fb7..947e782b9ce705e0db260920f45d9174f0507f83 100755 (executable)
@@ -73,7 +73,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 # The above syntax is invalid, so this program should fail to parse
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 
@@ -92,7 +92,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 # The above syntax is invalid, so this program should fail to parse
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE
 if [ $? -ne 1 ] ; then fail ; fi
 
 
index f64674ded977c02b35b080e4ac00d8bb68247c74..dce41774962eca44cabe26e17629f582e57807f9 100755 (executable)
@@ -73,19 +73,19 @@ EOF
     if [ $? -ne 0 ] ; then no_result ; fi
 
     activity="run PSPP ($mode)"
-    $SUPERVISOR $PSPP --testing-mode $TESTFILE
+    $SUPERVISOR $PSPP -o pspp.csv $TESTFILE
     if [ $? -ne 0 ] ; then no_result ; fi
 
 
     activity="compare output ($mode)"
-    perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-    diff -u -b  -w $TEMPDIR/pspp.list - << EOF
- a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
--- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 
- x  y  z  a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w
--- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-24 25 26  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
+    diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
+
+Table: Data List
+x,y,z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w
+24,25,26,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
 EOF
     if [ $? -ne 0 ] ; then fail ; fi
 done
index 73bce147237c8dd1d60ca98babc529096ddd7cea..e848639cdfad46eaaa72a694b4d0dd9b2c7d2db4 100755 (executable)
@@ -74,7 +74,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run_program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index e89ecadf81d1030ba1d1268f2a817d1ecd52a012..296952ce01724a294fe8842782b09c125bc44082 100755 (executable)
@@ -78,7 +78,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index dd95c2c0772f9a404fb2e30a7dfd2d4bac5d8602..25b0dcfbaa1518d9ce1fa1c10c349a756855aeac 100755 (executable)
@@ -78,24 +78,21 @@ FINISH.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|w       |F8.0  |
-|x       |F8.0  |
-|y       |F8.0  |
-+--------+------+
-       x        y        j
--------- -------- --------
-    5.00     6.00    55.00 
-    2.00     3.00    55.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+w,F8.0
+x,F8.0
+y,F8.0
+
+Table: Data List
+x,y,j
+5.00,6.00,55.00
+2.00,3.00,55.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 5272063094049e75f1513c7c8b2538bafb020f93..1ec496eb7b9d1efa1a336160d07d59ba5789561f 100755 (executable)
@@ -78,25 +78,19 @@ DESCRIPTIVES
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|ID      |F8.0  |
-|ABC     |F8.0  |
-+--------+------+
-2.1 DESCRIPTIVES.  Valid cases = 6; cases with missing value(s) = 0.
-+--------#-+----+-------+-------+-------+
-|Variable#N|Mean|Std Dev|Minimum|Maximum|
-#========#=#====#=======#=======#=======#
-|ABC     #6|3.00|    .84|   2.00|   4.00|
-+--------#-+----+-------+-------+-------+
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+ID,F8.0
+ABC,F8.0
+
+Table: Valid cases = 6; cases with missing value(s) = 0.
+Variable,N,Mean,Std Dev,Minimum,Maximum
+ABC,6,3.00,.84,2.00,4.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index d9f3e59cb5ce81d0ad33c56ba807be4e3117b5b5..27795114aaabda7e048e4a6c00644991d30a65c4 100755 (executable)
@@ -77,7 +77,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check and save copy of output files"
@@ -103,7 +103,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-{ $SUPERVISOR $PSPP --testing-mode $TESTFILE -e /dev/null; } >/dev/null 2>&1
+{ $SUPERVISOR $PSPP -o pspp.csv $TESTFILE -e /dev/null; } >/dev/null 2>&1
 # PSPP should have terminated with a signal.  POSIX requires that the exit
 # status of a process terminated by a signal be greater than 128.
 if [ $? -le 128 ] ; then no_result ; fi
@@ -142,7 +142,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE -e /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE -e /dev/null
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check for remaining temporary files"
@@ -162,33 +162,34 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 4"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE -e /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE -e /dev/null
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b pspp.list - << EOF
-       X        Y
--------- --------
-    1.00     2.00
-    2.00     3.00
-    3.00     4.00
-    4.00     5.00
-    5.00     6.00
-X        Y
-- --------
-1     3.00
-2     4.00
-3     5.00
-4     6.00
-5     7.00
-X        Y
-- --------
-1     4.00
-2     5.00
-3     6.00
-4     7.00
-5     8.00
+diff -c pspp.csv - << EOF
+Table: Data List
+X,Y
+1.00,2.00
+2.00,3.00
+3.00,4.00
+4.00,5.00
+5.00,6.00
+
+Table: Data List
+X,Y
+1,3.00
+2,4.00
+3,5.00
+4,6.00
+5,7.00
+
+Table: Data List
+X,Y
+1,4.00
+2,5.00
+3,6.00
+4,7.00
+5,8.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 2bac4413014e0d57e0bb084cf0953ae4e0916511..8089a21acae3808c60b66eaabe6b5a8aec218995 100755 (executable)
@@ -84,11 +84,10 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check that foo2.out was created"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
 diff -b foo2.out - << EOF
  1
  2
index 657e53834933b31f147b64cc75015659c3755eeb..0296de0d1b34217edb0017f371f339333c1fef9b 100755 (executable)
@@ -85,7 +85,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 22b215660708b355e9780b563080a0caec5fab0c..0b66ddb19e0738eb8cc5cec7de07254a21f83376 100755 (executable)
@@ -70,7 +70,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 
index e423f3e8b4c6318241adc54718902d22a1697b41..7d931d460ba19a02d43bad73d6724548d10fba4a 100755 (executable)
@@ -75,35 +75,35 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-      R1
---------
-     7.71 
-     2.99 
-      .21 
-     4.95 
-     6.34 
-     4.43 
-     7.49 
-     8.32 
-     4.99 
-     5.83 
-     2.25 
-      .25 
-     1.98 
-     7.09 
-     7.61 
-     2.66 
-     1.69 
-     2.64 
-      .88 
-     1.50 
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -b  -w $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+R1
+7.71
+2.99
+.21
+4.95
+6.34
+4.43
+7.49
+8.32
+4.99
+5.83
+2.25
+.25
+1.98
+7.09
+7.61
+2.66
+1.69
+2.64
+.88
+1.50
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
diff --git a/tests/bugs/recode-copy-bug-1.out b/tests/bugs/recode-copy-bug-1.out
deleted file mode 100644 (file)
index 659eba5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |A1    |
-|B       |A1    |
-+--------+------+
-A B
-- -
-3 2 
-2 3 
-1 4 
diff --git a/tests/bugs/recode-copy-bug-1.stat b/tests/bugs/recode-copy-bug-1.stat
deleted file mode 100644 (file)
index c493a15..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-TITLE 'Test for regression of recode COPY bug'
-
-DATA LIST LIST
- /A (A1)
- B (A1).
-
-BEGIN DATA
-1     2
-2     3
-3     4
-END DATA.
-
-** Clearly, the else=copy is superfluous here
-RECODE A ("1"="3") ("3"="1") (ELSE=COPY).
-EXECUTE.
-LIST.
-
diff --git a/tests/bugs/recode-copy-bug-2.out b/tests/bugs/recode-copy-bug-2.out
deleted file mode 100644 (file)
index 50899a8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |A1    |
-|B       |A1    |
-+--------+------+
-A B A1
-- - --
-1 2  3 
-2 3  2 
-3 4  1 
diff --git a/tests/bugs/recode-copy-bug-2.stat b/tests/bugs/recode-copy-bug-2.stat
deleted file mode 100644 (file)
index 95873d7..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-DATA LIST LIST
- /A (A1)
- B (A1).
-
-BEGIN DATA
-1     2
-2     3
-3     4
-END DATA.
-
-STRING A1 (A1).
-RECODE A ("1"="3") ("3"="1") (ELSE=COPY) INTO a1.
-EXECUTE.
-LIST.
-
-
index 912590a34c0869d6260a107a5483f4002c7f0167..6e6ac06eb3b9b266e7650623b23251fde5daf028 100755 (executable)
@@ -53,39 +53,88 @@ pass()
 }
 
 mkdir -p $TEMPDIR
-
-activity="copy template 1" 
-cp $top_srcdir/tests/bugs/recode-copy-bug-1.stat $TEMPDIR
+cd $TEMPDIR
 if [ $? -ne 0 ] ; then no_result ; fi
 
-activity="copy template 2" 
-cp $top_srcdir/tests/bugs/recode-copy-bug-2.stat $TEMPDIR
+activity="create syntax 1"
+cat > recode-copy-bug-1.stat <<EOF
+TITLE 'Test for regression of recode COPY bug'
+
+DATA LIST LIST
+ /A (A1)
+ B (A1).
+
+BEGIN DATA
+1     2
+2     3
+3     4
+END DATA.
+
+** Clearly, the else=copy is superfluous here
+RECODE A ("1"="3") ("3"="1") (ELSE=COPY).
+EXECUTE.
+LIST.
+EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-activity="chdir"
-cd $TEMPDIR
+activity="create syntax 2" 
+cat > recode-copy-bug-2.stat <<EOF
+DATA LIST LIST
+ /A (A1)
+ B (A1).
+
+BEGIN DATA
+1     2
+2     3
+3     4
+END DATA.
+
+STRING A1 (A1).
+RECODE A ("1"="3") ("3"="1") (ELSE=COPY) INTO a1.
+EXECUTE.
+LIST.
+EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/recode-copy-bug-1.stat
+$SUPERVISOR $PSPP -o pspp.csv recode-copy-bug-1.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
-
 activity="compare output 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list $top_srcdir/tests/bugs/recode-copy-bug-1.out
-diff -b -w $TEMPDIR/pspp.list $top_srcdir/tests/bugs/recode-copy-bug-1.out
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Title: Test for regression of recode COPY bug
+
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,A1
+B,A1
+
+Table: Data List
+A,B
+3,2
+2,3
+1,4
+EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/recode-copy-bug-2.stat
+$SUPERVISOR $PSPP -o pspp.csv recode-copy-bug-2.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
-
 activity="compare output 2"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list $top_srcdir/tests/bugs/recode-copy-bug-2.out
-diff -b -w $TEMPDIR/pspp.list $top_srcdir/tests/bugs/recode-copy-bug-2.out
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,A1
+B,A1
+
+Table: Data List
+A,B,A1
+1,2,3
+2,3,2
+3,4,1
+EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 826d5dc4d898cff3983404316b677d5fc84259f7..b0961302ff3b474ae7798293c2e47a563a3df209 100755 (executable)
@@ -69,17 +69,17 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-       a
---------
-    1.00
-    2.00
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -b  -w $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+a
+1.00
+2.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index dedfc6c834a8f20129ba3766e9cbbdc19c55acf8..b6cddb2a4113de8302a24159f961fc06d3fea9b1 100755 (executable)
@@ -59,7 +59,7 @@ mkdir -p $TEMPDIR
 cd $TEMPDIR
 
 activity="sending SIGINT to pspp"
-echo 'host kill -INT $PPID' | $PSPP --testing-mode > /dev/null 2> $TEMPDIR/stderr1
+echo 'host kill -INT $PPID' | $PSPP -o pspp.csv > /dev/null 2> $TEMPDIR/stderr1
 if [ $? -ne 0 ] ; then no_result ; fi
 
 # SIGINT should have caused a clean shutdown
@@ -68,7 +68,7 @@ activity="checking for absence of error messages 1"
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="sending SIGSEGV to pspp"
-echo 'host kill -SEGV $PPID' | $PSPP --testing-mode > /dev/null 2> $TEMPDIR/stderr2
+echo 'host kill -SEGV $PPID' | $PSPP -o pspp.csv > /dev/null 2> $TEMPDIR/stderr2
 if [ $? -eq 0 ] ; then no_result ; fi
 
 # SIGSEGV should have caused an error message
index 5565d31ad4b5faf6ca12db873d1d933e7fb72c12..205a7d4c7514d968a3a6cee91ecccbbbdaa0f9f9 100755 (executable)
@@ -82,43 +82,33 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|ID      |F8.0  |
-|INDEP   |A1    |
-|DEP1    |F8.0  |
-|DEP2    |F8.0  |
-+--------+------+
-2.1 T-TEST.  Group Statistics
-#==========#=#====#==============#=========#
-#     INDEP|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#
-#==========#=#====#==============#=========#
-2.2 T-TEST.  Independent Samples Test
-#===============================#========#============================================================================#
-#                               #Levene's|                        t-test for Equality of Means                        #
-#                               #---+----+-----+----+---------------+---------------+---------------------+-----------#
-#                               #   |    |     |    |               |               |                     |    95%    #
-#                               #   |    |     |    |               |               |                     +-----+-----#
-#                               # F |Sig.|  t  | df |Sig. (2-tailed)|Mean Difference|Std. Error Difference|Lower|Upper#
-#===============================#===#====#=====#====#===============#===============#=====================#=====#=====#
-#DEP1Equal variances assumed    #.00|1.00|-4.47|8.00|            .00|          -2.00|                  .45|-3.03| -.97#
-#    Equal variances not assumed#   |    |-4.47|8.00|            .00|          -2.00|                  .45|-3.03| -.97#
-#DEP2Equal variances assumed    #.00|1.00| 4.47|8.00|            .00|           2.00|                  .45|  .97| 3.03#
-#    Equal variances not assumed#   |    | 4.47|8.00|            .00|           2.00|                  .45|  .97| 3.03#
-#===============================#===#====#=====#====#===============#===============#=====================#=====#=====#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+ID,F8.0
+INDEP,A1
+DEP1,F8.0
+DEP2,F8.0
+
+Table: Group Statistics
+,INDEP,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
+DEP1,Equal variances assumed,.00,1.00,-4.47,8.00,.00,-2.00,.45,-3.03,-.97
+,Equal variances not assumed,,,-4.47,8.00,.00,-2.00,.45,-3.03,-.97
+DEP2,Equal variances assumed,.00,1.00,4.47,8.00,.00,2.00,.45,.97,3.03
+,Equal variances not assumed,,,4.47,8.00,.00,2.00,.45,.97,3.03
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index c49103a88292fe1f5fc1ad051c08151b72669fb3..0fdac2afcfee2065729b53140d49c1b763bdbf79 100755 (executable)
@@ -81,7 +81,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 #invert  v
 if [ $? -eq 0 ] ; then fail ; fi
 
index c54bba3cf541a1ce7c738487e88ec6db09bb7a1e..5504e6cc46fcab384954b550f2492d405d4fa307 100755 (executable)
@@ -79,38 +79,28 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|gv      |A8    |
-+--------+------+
-2.1 T-TEST.  Group Statistics
-#==========#=#====#==============#=========#
-#     gv   |N|Mean|Std. Deviation|S.E. Mean#
-#==========#=#====#==============#=========#
-#x One     |5|2.60|           .55|      .24#
-#  Two     |3|3.50|           .50|      .29#
-#==========#=#====#==============#=========#
-2.2 T-TEST.  Independent Samples Test
-#============================#=========#============================================================================#
-#                            # Levene's|                        t-test for Equality of Means                        #
-#                            #----+----+-----+----+---------------+---------------+---------------------+-----------#
-#                            #    |    |     |    |               |               |                     |    95%    #
-#                            #    |    |     |    |               |               |                     +-----+-----#
-#                            #  F |Sig.|  t  | df |Sig. (2-tailed)|Mean Difference|Std. Error Difference|Lower|Upper#
-#============================#====#====#=====#====#===============#===============#=====================#=====#=====#
-#xEqual variances assumed    #1.13| .33|-2.32|6.00|            .06|           -.90|                  .38|-1.83|  .03#
-# Equal variances not assumed#    |    |-2.38|4.70|            .07|           -.90|                  .38|-1.89|  .09#
-#============================#====#====#=====#====#===============#===============#=====================#=====#=====#
+diff -c $TEMPDIR/pspp.csv - << EOF
+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
+
+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
+x,Equal variances assumed,1.13,.33,-2.32,6.00,.06,-.90,.38,-1.83,.03
+,Equal variances not assumed,,,-2.38,4.70,.07,-.90,.38,-1.89,.09
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index a9a311b7cc63290d4377f2c49e7208cbf741586e..47b096425ce42d0a642e69af513d59366387b1f3 100755 (executable)
@@ -73,43 +73,31 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |F8.0  |
-|B       |F8.0  |
-+--------+------+
-2.1 T-TEST.  Paired Sample Statistics
-#========#=====#=#==============#=========#
-#        # Mean|N|Std. Deviation|S.E. Mean#
-#========#=====#=#==============#=========#
-#Pair 0 A#4.333|3|         5.774|    3.333#
-#       B#1.333|3|          .577|     .333#
-#========#=====#=#==============#=========#
-2.2 T-TEST.  Paired Samples Correlations
-#======#=====#=#===========#====#
-#      |     #N|Correlation|Sig.#
-#======#=====#=#===========#====#
-#Pair 0|A & B#3|      1.000|.000#
-#======#=====#=#===========#====#
-2.3 T-TEST.  Paired Samples Test
-#===========#==================================================#=====#==#===============#
-#           #                Paired Differences                |     |  |               #
-#           #-----+--------------+---------------+-------------+     |  |               #
-#           #     |              |               |     95%     |     |  |               #
-#           #     |              |               +------+------+     |  |               #
-#           # Mean|Std. Deviation|Std. Error Mean| Lower| Upper|  t  |df|Sig. (2-tailed)#
-#===========#=====#==============#===============#======#======#=====#==#===============#
-#Pair 0A - B#3.000|         5.196|          3.000|-9.908|15.908|1.000| 2|           .423#
-#===========#=====#==============#===============#======#======#=====#==#===============#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,F8.0
+B,F8.0
+
+Table: Paired Sample Statistics
+,,Mean,N,Std. Deviation,S.E. Mean
+Pair 0,A,4.333,3,5.774,3.333
+,B,1.333,3,.577,.333
+
+Table: Paired Samples Correlations
+,,N,Correlation,Sig.
+Pair 0,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)
+Pair 0,A - B,3.000,5.196,3.000,-9.908,15.908,1.000,2,.423
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 92dc3fb02b057f8215dd2907e8e340732b4521a1..3413a51ffb7ba9f57635114022764f907e1e5777 100755 (executable)
@@ -75,11 +75,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/first.list
+cp $TEMPDIR/pspp.csv $TEMPDIR/first.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -103,8 +103,8 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list $TEMPDIR/first.list
-diff -b $TEMPDIR/pspp.list $TEMPDIR/first.list
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv $TEMPDIR/first.csv
+diff -b $TEMPDIR/pspp.csv $TEMPDIR/first.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index e8c43ebca02d3c890ccb676a1c5df86714d8db7f..e4940c080de376a41f660a150982c5d95ac0f813 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #The syntax was invalid.  Therefore pspp must return non zero.
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 pass;
index 6168f4bb86fa6149a72062c363e848ff8485798b..2027c0a3a02f1ce7170176aeefb0cf3bb9728aa7 100755 (executable)
@@ -83,37 +83,29 @@ FINISH
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|SEX     |A1    |
-|X       |F8.0  |
-+--------+------+
-2.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+---------------+-----+
-|N       Valid  |    4|
-|        Missing|    0|
-|Mean           |19.25|
-|Std Dev        | 8.81|
-|Minimum        |12.00|
-|Maximum        |31.00|
-+---------------+-----+
+diff -c $TEMPDIR/pspp.csv - << EOF
+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,
+
+N,Valid,4
+,Missing,0
+Mean,,19.25
+Std Dev,,8.81
+Minimum,,12.00
+Maximum,,31.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 8ffa86115999566dbca7c821aca16e67cb2aa793..96856d5a51c37c3194176853d2b85e1233619201 100755 (executable)
@@ -80,29 +80,29 @@ list.
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-       X
---------
-    6.00 
-    7.00 
-    8.00 
-    9.00 
-       X
---------
-    1.00 
-    2.00 
-    3.00 
-    4.00 
-    5.00 
-    6.00 
-    7.00 
-    8.00 
-    9.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X
+6.00
+7.00
+8.00
+9.00
+
+Table: Data List
+X
+1.00
+2.00
+3.00
+4.00
+5.00
+6.00
+7.00
+8.00
+9.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 774b6230b6a68e7d0f3a2f9bf5e2237aa24bbcf1..3f3a40adcf4fa1ca414d3cdb92f180b30fff31ce 100755 (executable)
@@ -81,12 +81,12 @@ chmod u-w $TEMPDIR
 # on a single PSPP invocation, except that charts are only supported for
 # a single driver at a time, and we'd prefer to test chart support for
 # all of our driver types.
-for driver in list-ascii list-ps html; do
+for file in pspp.csv pspp.html pspp.odt pspp.pdf pspp.txt; do
     # PSPP will fail to create the output file.  Currently this doesn't cause
     # PSPP's exit status to be nonzero, although this is arguably incorrect.
     # At any rate, PSPP should not crash.
-    activity="run pspp with $driver driver"
-    $SUPERVISOR $PSPP -o $driver test.pspp >/dev/null 2>&1
+    activity="run pspp with $file driver"
+    $SUPERVISOR $PSPP -o $file test.pspp >/dev/null 2>&1
     if [ $? -ne 0 ] ; then fail ; fi
 done
 
index 7388caaa2466f296c2b0dcf5b588accf33c40a07..d552041e8980bbf3d96bc0ef299c8106e7ce00c5 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass
index 4d57f661e79511acfb522e2ddd2f0590a91814d4..1f07ca6d37adc88cab27c0fbea2b2ab90f6832c1 100755 (executable)
@@ -77,7 +77,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #Invalid syntax --- return value is non zero.
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 pass;
index 48232f2e4828303d4b0862754b73375478ff5f03..d2b164bf4f0a06ebcd69efa0d374eb761211f226 100755 (executable)
@@ -84,52 +84,52 @@ cat > b.data <<EOF
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-cat > concatenate.out <<EOF
-A B C D INA INB
-- - - - --- ---
-1 a B     1   0
-8 a M     1   0
-3 a E     1   0
-5 a G     1   0
-0 a A     1   0
-5 a H     1   0
-6 a I     1   0
-7 a J     1   0
-2 a D     1   0
-7 a K     1   0
-1 a C     1   0
-7 a L     1   0
-4 a F     1   0
-1 b   N   0   1
-3 b   O   0   1
-4 b   P   0   1
-6 b   Q   0   1
-7 b   R   0   1
-9 b   S   0   1
+cat > concatenate.csv <<EOF
+Table: Data List
+A,B,C,D,INA,INB
+1,a,B,,1,0
+8,a,M,,1,0
+3,a,E,,1,0
+5,a,G,,1,0
+0,a,A,,1,0
+5,a,H,,1,0
+6,a,I,,1,0
+7,a,J,,1,0
+2,a,D,,1,0
+7,a,K,,1,0
+1,a,C,,1,0
+7,a,L,,1,0
+4,a,F,,1,0
+1,b,,N,0,1
+3,b,,O,0,1
+4,b,,P,0,1
+6,b,,Q,0,1
+7,b,,R,0,1
+9,b,,S,0,1
 EOF
 
-cat > interleave.out <<EOF
-A B C D INA INB FIRST LAST
-- - - - --- --- ----- ----
-0 a A     1   0     1   1
-1 a B     1   0            1    0
-1 a C     1   0            0    0
-1 b   N   0   1            0    1
-2 a D     1   0            1    1
-3 a E     1   0            1    0
-3 b   O   0   1            0    1
-4 a F     1   0            1    0
-4 b   P   0   1            0    1
-5 a G     1   0            1    0
-5 a H     1   0            0    1
-6 a I     1   0            1    0
-6 b   Q   0   1            0    1
-7 a J     1   0            1    0
-7 a K     1   0            0    0
-7 a L     1   0            0    0
-7 b   R   0   1            0    1
-8 a M     1   0            1    1
-9 b   S   0   1            1    1
+cat > interleave.csv <<EOF
+Table: Data List
+A,B,C,D,INA,INB,FIRST,LAST
+0,a,A,,1,0,1,1
+1,a,B,,1,0,1,0
+1,a,C,,1,0,0,0
+1,b,,N,0,1,0,1
+2,a,D,,1,0,1,1
+3,a,E,,1,0,1,0
+3,b,,O,0,1,0,1
+4,a,F,,1,0,1,0
+4,b,,P,0,1,0,1
+5,a,G,,1,0,1,0
+5,a,H,,1,0,0,1
+6,a,I,,1,0,1,0
+6,b,,Q,0,1,0,1
+7,a,J,,1,0,1,0
+7,a,K,,1,0,0,0
+7,a,L,,1,0,0,0
+7,b,,R,0,1,0,1
+8,a,M,,1,0,1,1
+9,b,,S,0,1,1,1
 EOF
 
 # Test ADD FILES.
@@ -186,13 +186,13 @@ EOF
        if [ $? -ne 0 ] ; then no_result ; fi
 
        activity="run $name.pspp"
-       $SUPERVISOR $PSPP --testing-mode $name.pspp 
+       $SUPERVISOR $PSPP -o pspp.csv $name.pspp 
        if [ $? -ne 0 ] ; then no_result ; fi
 
        activity="check $name output"
-       perl -pi -e 's/^\s*$//g' pspp.list
-       perl -pi -e 's/^\s*$//g' $type.out
-       diff -u -b -w pspp.list $type.out
+       perl -pi -e 's/^\s*$//g' pspp.csv
+       perl -pi -e 's/^\s*$//g' $type.csv
+       diff -u -b -w pspp.csv $type.csv
        if [ $? -ne 0 ] ; then fail ; fi
     done
 done
index 63abc6f3b003ac093ee59434736522d9d64d27c8..ba51161c6a16b6375ca140249d8ed04e387f396c 100755 (executable)
@@ -155,32 +155,39 @@ cat > agg-skel.pspp <<EOF
 EOF
 
 activity="expected output (itemwise missing) create"
-cat > agg-itemwise.out <<EOF
+cat > agg-itemwise.csv <<EOF
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
-G        N       NI      NU     NUI NFGT2 NFGT2I SFGT2 SFGT2I NFIN23 NFIN23I SFIN23 SFIN23I NFLT2 NFLT2I SFLT2 SFLT2I NFIRST NFIRSTI SFIRST SFIRSTI NFOUT23 NFOUT23I SFOUT23 SFOUT23I NLAST NLASTI SLAST SLASTI NMAX NMAXI SMAX SMAXI    NMEAN   NMEANI NMIN NMINI SMIN SMINI       NN      NNI       SN      SNI   NNMISS  NNMISSI   SNMISS  SNMISSI     NNU    NNUI     SNU    SNUI NNUMISS NNUMISSI SNUMISS SNUMISSI NPGT2 NPGT2I SPGT2 SPGT2I NPIN23 NPIN23I SPIN23 SPIN23I NPLT2 NPLT2I SPLT2 SPLT2I NPOUT23 NPOUT23I SPOUT23 SPOUT23I  NMEDIAN NMEDIANI      NSD     NSDI     NSUM    NSUMI
-- -------- -------- ------- ------- ----- ------ ----- ------ ------ ------- ------ ------- ----- ------ ----- ------ ------ ------- ------ ------- ------- -------- ------- -------- ----- ------ ----- ------ ---- ----- ---- ----- -------- -------- ---- ----- ---- ----- -------- -------- -------- -------- -------- -------- -------- -------- ------- ------- ------- ------- ------- -------- ------- -------- ----- ------ ----- ------ ------ ------- ------ ------- ----- ------ ----- ------ ------- -------- ------- -------- -------- -------- -------- -------- -------- --------
-1     7.00     7.00       6       6  .333   .429  .333   .429   .333    .286   .333    .286  .500   .429  .500   .429      0       0      0       0    .667     .714    .667     .714     5      5     5      5    5     5    5     5     2.00     2.29    0     0    0     0     6.00     7.00     6.00     7.00     1.00      .00     1.00      .00       5       6       5       6       1        0       1        0  33.3   42.9  33.3   42.9   33.3    28.6   33.3    28.6  50.0   42.9  50.0   42.9    66.7     71.4    66.7     71.4     1.50     2.00     1.79     1.80    12.00    16.00 
-2     5.00     5.00       4       4 1.000  1.000 1.000  1.000   .000    .000   .000    .000  .000   .000  .000   .000      6       6      6       4   1.000    1.000   1.000    1.000     8      8     8      8    8     8    8     8     7.00     7.00    6     6    6     4     3.00     3.00     3.00     5.00     2.00     2.00     2.00      .00       3       3       3       4       1        1       1        0 100.0  100.0 100.0  100.0     .0      .0     .0      .0    .0     .0    .0     .0   100.0    100.0   100.0    100.0     7.00     7.00     1.00     1.00    21.00    21.00 
-3     2.00     2.00       1       1  .000   .000  .000   .000   .000    .000   .000    .000 1.000  1.000 1.000  1.000      1       1      1       1   1.000    1.000   1.000    1.000     1      1     1      1    1     1    1     1     1.00     1.00    1     1    1     1     2.00     2.00     2.00     2.00      .00      .00      .00      .00       1       1       1       1       0        0       0        0    .0     .0    .0     .0     .0      .0     .0      .0 100.0  100.0 100.0  100.0   100.0    100.0   100.0    100.0     1.00     1.00      .00      .00     2.00     2.00 
-4     1.00     1.00       1       1  .      .     .     1.000   .       .      .       .000  .      .     .      .000      .       .              4    .        .       .       1.000     .      .            4    .     .          4      .        .      .     .          4      .00      .00      .00     1.00     1.00     1.00     1.00      .00       0       0       0       1       1        1       1        0    .      .     .   100.0     .       .      .       .0    .      .     .      .0      .        .       .     100.0      NaN      NaN      .        .        .        .   
 
+Table: Data List
+G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT2I,SFLT2,SFLT2I,NFIRST,NFIRSTI,SFIRST,SFIRSTI,NFOUT23,NFOUT23I,SFOUT23,SFOUT23I,NLAST,NLASTI,SLAST,SLASTI,NMAX,NMAXI,SMAX,SMAXI,NMEAN,NMEANI,NMIN,NMINI,SMIN,SMINI,NN,NNI,SN,SNI,NNMISS,NNMISSI,SNMISS,SNMISSI,NNU,NNUI,SNU,SNUI,NNUMISS,NNUMISSI,SNUMISS,SNUMISSI,NPGT2,NPGT2I,SPGT2,SPGT2I,NPIN23,NPIN23I,SPIN23,SPIN23I,NPLT2,NPLT2I,SPLT2,SPLT2I,NPOUT23,NPOUT23I,SPOUT23,SPOUT23I,NMEDIAN,NMEDIANI,NSD,NSDI,NSUM,NSUMI
+1,7.00,7.00,6,6,.333,.429,.333,.429,.333,.286,.333,.286,.500,.429,.500,.429,0,0,0,0,.667,.714,.667,.714,5,5,5,5,5,5,5,5,2.00,2.29,0,0,0,0,6.00,7.00,6.00,7.00,1.00,.00,1.00,.00,5,6,5,6,1,0,1,0,33.3,42.9,33.3,42.9,33.3,28.6,33.3,28.6,50.0,42.9,50.0,42.9,66.7,71.4,66.7,71.4,1.50,2.00,1.79,1.80,12.00,16.00
+2,5.00,5.00,4,4,1.000,1.000,1.000,1.000,.000,.000,.000,.000,.000,.000,.000,.000,6,6,6,4,1.000,1.000,1.000,1.000,8,8,8,8,8,8,8,8,7.00,7.00,6,6,6,4,3.00,3.00,3.00,5.00,2.00,2.00,2.00,.00,3,3,3,4,1,1,1,0,100.0,100.0,100.0,100.0,.0,.0,.0,.0,.0,.0,.0,.0,100.0,100.0,100.0,100.0,7.00,7.00,1.00,1.00,21.00,21.00
+3,2.00,2.00,1,1,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000,1.000,1.000,1,1,1,1,1.000,1.000,1.000,1.000,1,1,1,1,1,1,1,1,1.00,1.00,1,1,1,1,2.00,2.00,2.00,2.00,.00,.00,.00,.00,1,1,1,1,0,0,0,0,.0,.0,.0,.0,.0,.0,.0,.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,1.00,1.00,.00,.00,2.00,2.00
+4,1.00,1.00,1,1,.   ,.   ,.   ,1.000,.   ,.   ,.   ,.000,.   ,.   ,.   ,.000,.,.,,4,.   ,.   ,.   ,1.000,.,.,,4,.,.,,4,.  ,.  ,.,.,,4,.00,.00,.00,1.00,1.00,1.00,1.00,.00,0,0,0,1,1,1,1,0,. ,. ,. ,100.0,. ,. ,. ,.0,. ,. ,. ,.0,. ,. ,. ,100.0,NaN,NaN,.  ,.  ,.  ,.  
 EOF
 
 activity="expected output (columnwise missing) create"
-cat > agg-columnwise.out <<EOF
+cat > agg-columnwise.csv <<EOF
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
+
 warning: AGGREGATE: The value arguments passed to the FOUT function are out-of-order.  They will be treated as if they had been specified in the correct order.
-G        N       NI      NU     NUI NFGT2 NFGT2I SFGT2 SFGT2I NFIN23 NFIN23I SFIN23 SFIN23I NFLT2 NFLT2I SFLT2 SFLT2I NFIRST NFIRSTI SFIRST SFIRSTI NFOUT23 NFOUT23I SFOUT23 SFOUT23I NLAST NLASTI SLAST SLASTI NMAX NMAXI SMAX SMAXI    NMEAN   NMEANI NMIN NMINI SMIN SMINI       NN      NNI       SN      SNI   NNMISS  NNMISSI   SNMISS  SNMISSI     NNU    NNUI     SNU    SNUI NNUMISS NNUMISSI SNUMISS SNUMISSI NPGT2 NPGT2I SPGT2 SPGT2I NPIN23 NPIN23I SPIN23 SPIN23I NPLT2 NPLT2I SPLT2 SPLT2I NPOUT23 NPOUT23I SPOUT23 SPOUT23I  NMEDIAN NMEDIANI      NSD     NSDI     NSUM    NSUMI
-- -------- -------- ------- ------- ----- ------ ----- ------ ------ ------- ------ ------- ----- ------ ----- ------ ------ ------- ------ ------- ------- -------- ------- -------- ----- ------ ----- ------ ---- ----- ---- ----- -------- -------- ---- ----- ---- ----- -------- -------- -------- -------- -------- -------- -------- -------- ------- ------- ------- ------- ------- -------- ------- -------- ----- ------ ----- ------ ------ ------- ------ ------- ----- ------ ----- ------ ------- -------- ------- -------- -------- -------- -------- -------- -------- --------
-1     7.00     7.00       6       6  .      .429  .      .429   .       .286   .       .286  .      .429  .      .429      .       0              0    .        .714    .        .714     .      5            5    .     5          5      .       2.29    .     0          0     6.00     7.00     6.00     7.00     1.00      .00     1.00      .00       5       6       5       6       1        0       1        0    .    42.9    .    42.9     .     28.6     .     28.6    .    42.9    .    42.9      .      71.4      .      71.4      .       2.00      .       1.80      .      16.00 
-2     5.00     5.00       4       4  .      .     .     1.000   .       .      .       .000  .      .     .      .000      .       .              4    .        .       .       1.000     .      .            8    .     .          8      .        .      .     .          4     3.00     3.00     3.00     5.00     2.00     2.00     2.00      .00       3       3       3       4       1        1       1        0    .      .     .   100.0     .       .      .       .0    .      .     .      .0      .        .       .     100.0      .        .        .        .        .        .   
-3     2.00     2.00       1       1  .000   .000  .000   .000   .000    .000   .000    .000 1.000  1.000 1.000  1.000      1       1      1       1   1.000    1.000   1.000    1.000     1      1     1      1    1     1    1     1     1.00     1.00    1     1    1     1     2.00     2.00     2.00     2.00      .00      .00      .00      .00       1       1       1       1       0        0       0        0    .0     .0    .0     .0     .0      .0     .0      .0 100.0  100.0 100.0  100.0   100.0    100.0   100.0    100.0     1.00     1.00      .00      .00     2.00     2.00 
-4     1.00     1.00       1       1  .      .     .     1.000   .       .      .       .000  .      .     .      .000      .       .              4    .        .       .       1.000     .      .            4    .     .          4      .        .      .     .          4      .00      .00      .00     1.00     1.00     1.00     1.00      .00       0       0       0       1       1        1       1        0    .      .     .   100.0     .       .      .       .0    .      .     .      .0      .        .       .     100.0      .        .        .        .        .        .   
+
+Table: Data List
+G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT2I,SFLT2,SFLT2I,NFIRST,NFIRSTI,SFIRST,SFIRSTI,NFOUT23,NFOUT23I,SFOUT23,SFOUT23I,NLAST,NLASTI,SLAST,SLASTI,NMAX,NMAXI,SMAX,SMAXI,NMEAN,NMEANI,NMIN,NMINI,SMIN,SMINI,NN,NNI,SN,SNI,NNMISS,NNMISSI,SNMISS,SNMISSI,NNU,NNUI,SNU,SNUI,NNUMISS,NNUMISSI,SNUMISS,SNUMISSI,NPGT2,NPGT2I,SPGT2,SPGT2I,NPIN23,NPIN23I,SPIN23,SPIN23I,NPLT2,NPLT2I,SPLT2,SPLT2I,NPOUT23,NPOUT23I,SPOUT23,SPOUT23I,NMEDIAN,NMEDIANI,NSD,NSDI,NSUM,NSUMI
+1,7.00,7.00,6,6,.   ,.429,.   ,.429,.   ,.286,.   ,.286,.   ,.429,.   ,.429,.,0,,0,.   ,.714,.   ,.714,.,5,,5,.,5,,5,.  ,2.29,.,0,,0,6.00,7.00,6.00,7.00,1.00,.00,1.00,.00,5,6,5,6,1,0,1,0,. ,42.9,. ,42.9,. ,28.6,. ,28.6,. ,42.9,. ,42.9,. ,71.4,. ,71.4,.  ,2.00,.  ,1.80,.  ,16.00
+2,5.00,5.00,4,4,.   ,.   ,.   ,1.000,.   ,.   ,.   ,.000,.   ,.   ,.   ,.000,.,.,,4,.   ,.   ,.   ,1.000,.,.,,8,.,.,,8,.  ,.  ,.,.,,4,3.00,3.00,3.00,5.00,2.00,2.00,2.00,.00,3,3,3,4,1,1,1,0,. ,. ,. ,100.0,. ,. ,. ,.0,. ,. ,. ,.0,. ,. ,. ,100.0,.  ,.  ,.  ,.  ,.  ,.  
+3,2.00,2.00,1,1,.000,.000,.000,.000,.000,.000,.000,.000,1.000,1.000,1.000,1.000,1,1,1,1,1.000,1.000,1.000,1.000,1,1,1,1,1,1,1,1,1.00,1.00,1,1,1,1,2.00,2.00,2.00,2.00,.00,.00,.00,.00,1,1,1,1,0,0,0,0,.0,.0,.0,.0,.0,.0,.0,.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,100.0,1.00,1.00,.00,.00,2.00,2.00
+4,1.00,1.00,1,1,.   ,.   ,.   ,1.000,.   ,.   ,.   ,.000,.   ,.   ,.   ,.000,.,.,,4,.   ,.   ,.   ,1.000,.,.,,4,.,.,,4,.  ,.  ,.,.,,4,.00,.00,.00,1.00,1.00,1.00,1.00,.00,0,0,0,1,1,1,1,0,. ,. ,. ,100.0,. ,. ,. ,.0,. ,. ,. ,.0,. ,. ,. ,100.0,.  ,.  ,.  ,.  ,.  ,.  
 EOF
 
 for outfile in scratch active external; do
@@ -221,12 +228,12 @@ for outfile in scratch active external; do
            if [ $? -ne 0 ] ; then no_result ; fi
            
            activity="run $name.pspp"
-           $SUPERVISOR $PSPP --testing-mode -e /dev/null $name.pspp 
+           $SUPERVISOR $PSPP -o pspp.csv -e /dev/null $name.pspp 
            if [ $? -ne 0 ] ; then no_result ; fi
 
            activity="check $name output"
-           perl -pi -e 's/^\s*$//g;s/^.*:\d+: //;' pspp.list agg-$missing.out
-           diff -b -w pspp.list agg-$missing.out
+           perl -pi -e 's/^.*:\d+: //;' pspp.csv
+           diff -c pspp.csv agg-$missing.csv
            if [ $? -ne 0 ] ; then fail ; fi
        done
     done
index d4d36e603a737ce4e64081fb174266e91314c390..d4dece6c47d89242e074b91e13201e6e4ca6444c 100755 (executable)
@@ -96,52 +96,37 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-1.1 DISPLAY.  
-+--------+-----------------+-----------------------------------+
-|Variable|Description      |                                   |
-#========#=================#===================================#
-|a       |Custom attributes|                                   |
-|        |ValidationRule[1]|a * b > 3                          |
-|        |ValidationRule[2]|a + b > 2                          |
-+--------+-----------------+-----------------------------------+
-|b       |Custom attributes|                                   |
-|        |ValidationRule[1]|a * b > 3                          |
-|        |ValidationRule[2]|a + b > 2                          |
-+--------+-----------------+-----------------------------------+
-|c       |Custom attributes|                                   |
-|        |QuestionWording  |X or Y?                            |
-+--------+-----------------+-----------------------------------+
-1.2 DISPLAY.  Custom data file attributes.
-+---------+---------------+
-|Attribute|Value          |
-#=========#===============#
-|array[1] |array element 1|
-|array[2] |array element 2|
-|key      |value          |
-+---------+---------------+
-2.1 DISPLAY.  
-+--------+---------------+-----------------------------------+
-|Variable|Description    |                                   |
-#========#===============#===================================#
-|b       |Custom attribut|s:                                 |
-|        |ValidationRule |a * b > 3                          |
-+--------+---------------+-----------------------------------+
-|c       |Custom attribut|s:                                 |
-|        |QuestionWording|X or Y?                            |
-+--------+---------------+-----------------------------------+
-2.2 DISPLAY.  Custom data file attributes.
-+---------+---------------+
-|Attribute|Value          |
-#=========#===============#
-|array    |array element 2|
-|key      |value          |
-+---------+---------------+
+diff -c $TEMPDIR/pspp.csv - << EOF
+Variable,Description,
+a,Custom attributes:,
+,ValidationRule[1],a * b > 3
+,ValidationRule[2],a + b > 2
+b,Custom attributes:,
+,ValidationRule[1],a * b > 3
+,ValidationRule[2],a + b > 2
+c,Custom attributes:,
+,QuestionWording,X or Y?
+
+Table: Custom data file attributes.
+Attribute,Value
+array[1],array element 1
+array[2],array element 2
+key,value
+
+Variable,Description,
+b,Custom attributes:,
+,ValidationRule,a * b > 3
+c,Custom attributes:,
+,QuestionWording,X or Y?
+
+Table: Custom data file attributes.
+Attribute,Value
+array,array element 2
+key,value
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index e956fcfa0403363b6ef61b9d7955855728185ff3..6aaf8722a37ef0b060d7e24934dc2fd39979cc5a 100755 (executable)
@@ -87,41 +87,39 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="test output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|X       |     1|  1-  5|A5    |
-|Y       |     1|  7-  7|F1.0  |
-+--------+------+-------+------+
-    X Y        A        B
------ - -------- --------
-lasdj 1     1.00     3.00 
-asdfk 0     3.00     4.00 
-asdfj 2     4.00     2.00 
-asdfj 1     4.00     3.00 
-asdfk 2     3.00     2.00 
-asdfj 9     4.00     1.00 
-lajks 9     2.00     1.00 
-asdfk 0     3.00     4.00 
-asdfk 1     3.00     3.00 
-    X Y        A        B        Z        W
------ - -------- -------- -------- --------
-lasdj 1     1.00     3.00      .00     1.00 
-asdfk 0     3.00     4.00      .00     1.00 
-asdfj 2     4.00     2.00     1.00     2.00 
-asdfj 1     4.00     3.00      .00     1.00 
-asdfk 2     3.00     2.00     1.00     2.00 
-asdfj 9     4.00     1.00     4.00     3.00 
-lajks 9     2.00     1.00     4.00     3.00 
-asdfk 0     3.00     4.00      .00     1.00 
-asdfk 1     3.00     3.00      .00     1.00 
+diff -b $TEMPDIR/pspp.csv - <<EOF
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+X,1,1-  5,A5
+Y,1,7-  7,F1.0
+
+Table: Data List
+X,Y,A,B
+lasdj,1,1.00,3.00
+asdfk,0,3.00,4.00
+asdfj,2,4.00,2.00
+asdfj,1,4.00,3.00
+asdfk,2,3.00,2.00
+asdfj,9,4.00,1.00
+lajks,9,2.00,1.00
+asdfk,0,3.00,4.00
+asdfk,1,3.00,3.00
+
+Table: Data List
+X,Y,A,B,Z,W
+lasdj,1,1.00,3.00,.00,1.00
+asdfk,0,3.00,4.00,.00,1.00
+asdfj,2,4.00,2.00,1.00,2.00
+asdfj,1,4.00,3.00,.00,1.00
+asdfk,2,3.00,2.00,1.00,2.00
+asdfj,9,4.00,1.00,4.00,3.00
+lajks,9,2.00,1.00,4.00,3.00
+asdfk,0,3.00,4.00,.00,1.00
+asdfk,1,3.00,3.00,.00,1.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 6d835015e7e3d6ade18ccbe7cf0b45caa957cc70..45752fc7a71ac46efe3fe3d445101745b1281d9c 100755 (executable)
@@ -86,40 +86,38 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare data"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - << foobar
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|A       |     1|  1-  1|F1.0  |
-|B       |     1|  2-  2|F1.0  |
-+--------+------+-------+------+
-A B
-- -
-1 2 
-3 4 
-5 6 
-7 8 
-9 0 
-2.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|A       |     1|  1-  1|F1.0  |
-|B       |     1|  2-  2|F1.0  |
-+--------+------+-------+------+
-A B
-- -
-0 9 
-8 7 
-6 5 
-4 3 
-2 1 
+diff -c $TEMPDIR/pspp.csv - << foobar
+Title: Test BEGIN DATA ... END DATA
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+A,1,1-  1,F1.0
+B,1,2-  2,F1.0
+
+Table: Data List
+A,B
+1,2
+3,4
+5,6
+7,8
+9,0
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+A,1,1-  1,F1.0
+B,1,2-  2,F1.0
+
+Table: Data List
+A,B
+0,9
+8,7
+6,5
+4,3
+2,1
 foobar
 if [ $? -ne 0 ] ; then fail ; fi
 
index 41e1963c170c1106ae024cdbf052be1dc9ab164b..8caa95c4908e4f296b6ce85d209cd8ee27332a21 100755 (executable)
@@ -138,7 +138,7 @@ foobar
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 # Like the above comments say ...
index d8fcb1cbbcb1893dfc8ff31c65d1be4b060b418f..06c1d24519c5bbbc2028dab5f98f97555bfef696 100755 (executable)
@@ -94,58 +94,43 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 CORRELATIONS.  Correlations
-#========================#=====#=====#=====#=====#
-#                        #foo  |bar  |wiz  |bang #
-#----+-------------------#-----+-----+-----+-----#
-#foo |Pearson Correlation#1.000| .802| .890|-.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#
-#    |Sig. (2-tailed)    # .017| .291|     | .505#
-#----+-------------------#-----+-----+-----+-----#
-#bang|Pearson Correlation#-.308| .118|-.344|1.000#
-#    |Sig. (2-tailed)    # .553| .824| .505|     #
-#====#===================#=====#=====#=====#=====#
-2.1 CORRELATIONS.  Correlations
-#=======================#=====#=====#
-#                       #bar  |wiz  #
-#---+-------------------#-----+-----#
-#bar|Pearson Correlation#1.000| .497#
-#   |Sig. (2-tailed)    #     | .210#
-#---+-------------------#-----+-----#
-#wiz|Pearson Correlation# .497|1.000#
-#   |Sig. (2-tailed)    # .210|     #
-#===#===================#=====#=====#
-3.1 CORRELATIONS.  Correlations
-#========================#=====#=====#=====#=====#
-#                        #foo  |bar  |wiz  |bang #
-#----+-------------------#-----+-----+-----+-----#
-#foo |Pearson Correlation#1.000| .805| .883|-.308#
-#    |Sig. (2-tailed)    #     | .029| .008| .553#
-#    |N                  #    7|    7|    7|    6#
-#----+-------------------#-----+-----+-----+-----#
-#bar |Pearson Correlation# .805|1.000| .497| .164#
-#    |Sig. (2-tailed)    # .029|     | .210| .725#
-#    |N                  #    7|    8|    8|    7#
-#----+-------------------#-----+-----+-----+-----#
-#wiz |Pearson Correlation# .883| .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#
-#====#===================#=====#=====#=====#=====#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Correlations
+,,foo,bar,wiz,bang
+foo,Pearson Correlation,1.000,.802,.890,-.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
+,Sig. (2-tailed),.017,.291,,.505
+bang,Pearson Correlation,-.308,.118,-.344,1.000
+,Sig. (2-tailed),.553,.824,.505,
+
+Table: Correlations
+,,bar,wiz
+bar,Pearson Correlation,1.000,.497
+,Sig. (2-tailed),,.210
+wiz,Pearson Correlation,.497,1.000
+,Sig. (2-tailed),.210,
+
+Table: Correlations
+,,foo,bar,wiz,bang
+foo,Pearson Correlation,1.000,.805,.883,-.308
+,Sig. (2-tailed),,.029,.008,.553
+,N,7,7,7,6
+bar,Pearson Correlation,.805,1.000,.497,.164
+,Sig. (2-tailed),.029,,.210,.725
+,N,7,8,8,7
+wiz,Pearson Correlation,.883,.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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -177,11 +162,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy results"
-cp $TEMPDIR/pspp.list $TEMPDIR/weighted
+cp $TEMPDIR/pspp.csv $TEMPDIR/weighted
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 3"
@@ -211,11 +196,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="Compare weighted and unweighted results"
-diff $TEMPDIR/pspp.list $TEMPDIR/weighted
+diff $TEMPDIR/pspp.csv $TEMPDIR/weighted
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass;
index 0813c428aa647d9bfc40dad03b4f60b7b4a818d7..bba7d06268a6cad26d0a9a5545164bef358ab124 100755 (executable)
@@ -80,29 +80,28 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="Run pspp 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|V1      |     1|  1-  2|A2    |
-|V2      |     1|  3-  4|A2    |
-+--------+------+-------+------+
-V1 V2        C
--- -- --------
-12 34      .00 
-32 1      1.00 
-2  13     1.00 
-41 21      .00 
-11 04      .00 
-03  4     1.00 
-01 93      .00 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Title: Test COUNT transformation
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+V1,1,1-  2,A2
+V2,1,3-  4,A2
+
+Table: Data List
+V1,V2,C
+12,34,.00
+32,1 ,1.00
+2 ,13,1.00
+41,21,.00
+11,04,.00
+03,4,1.00
+01,93,.00
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
@@ -128,27 +127,24 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="Run pspp 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|y       |F8.0  |
-+--------+------+
-       x        y        C
--------- -------- --------
-    1.00     2.00     1.00 
-    2.00     3.00     1.00 
-    4.00     5.00      .00 
-    2.00     2.00     2.00 
-    5.00     6.00      .00 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,F8.0
+y,F8.0
+
+Table: Data List
+x,y,C
+1.00,2.00,1.00
+2.00,3.00,1.00
+4.00,5.00,.00
+2.00,2.00,2.00
+5.00,6.00,.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 3f821199ff3e2d10f22627e6ce35c93ec7b1f157..13c2a683c61cd83ac90908ca47ae9d0aaff1f8a7 100755 (executable)
@@ -147,64 +147,65 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|A       |F8.0  |
-|B       |F8.0  |
-|C       |F8.0  |
-|D       |F8.0  |
-+--------+------+
-       A        B        C        D
--------- -------- -------- --------
-    1.00    23.00    45.00     2.03 
-    2.00    22.00    34.00    23.00 
-    3.00    34.00    34.00    34.00 
-       A        B        C        D
--------- -------- -------- --------
-     .       1.00     2.00     3.00 
-     .       4.00      .       5.00 
-    6.00     7.00     8.00     9.00 
-     .00     1.00      .        .   
-     .        .        .        .   
-    2.00     3.00     4.00     5.00 
-       A        B        C        D
--------- -------- -------- --------
-    1.00     2.00     3.00     4.00 
-    1.00     2.00     3.00      .   
-    1.00     2.00      .       4.00 
-    1.00     2.00      .        .   
-    1.00      .       3.00     4.00 
-    1.00      .       3.00      .   
-    1.00      .        .       4.00 
-    1.00      .        .        .   
-     .       2.00     3.00     4.00 
-     .       2.00     3.00      .   
-     .       2.00      .       4.00 
-     .       2.00      .        .   
-     .        .       3.00     4.00 
-     .        .       3.00      .   
-     .        .        .       4.00 
-     .        .        .        .   
-               start                  end count
--------------------- -------------------- -----
-          07/22/2007           10/06/2007   321
-          07/14/1789           08/26/1789     4
-          01/01/1972           12/31/1999   682
-x y
-- -
-1 2
-3 4
-5 6
-7 8
-9 0
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+A,F8.0
+B,F8.0
+C,F8.0
+D,F8.0
+
+Table: Data List
+A,B,C,D
+1.00,23.00,45.00,2.03
+2.00,22.00,34.00,23.00
+3.00,34.00,34.00,34.00
+
+Table: Data List
+A,B,C,D
+.  ,1.00,2.00,3.00
+.  ,4.00,.  ,5.00
+6.00,7.00,8.00,9.00
+.00,1.00,.  ,.  
+.  ,.  ,.  ,.  
+2.00,3.00,4.00,5.00
+
+Table: Data List
+A,B,C,D
+1.00,2.00,3.00,4.00
+1.00,2.00,3.00,.  
+1.00,2.00,.  ,4.00
+1.00,2.00,.  ,.  
+1.00,.  ,3.00,4.00
+1.00,.  ,3.00,.  
+1.00,.  ,.  ,4.00
+1.00,.  ,.  ,.  
+.  ,2.00,3.00,4.00
+.  ,2.00,3.00,.  
+.  ,2.00,.  ,4.00
+.  ,2.00,.  ,.  
+.  ,.  ,3.00,4.00
+.  ,.  ,3.00,.  
+.  ,.  ,.  ,4.00
+.  ,.  ,.  ,.  
+
+Table: Data List
+start,end,count
+07/22/2007,10/06/2007,321
+07/14/1789,08/26/1789,4
+01/01/1972,12/31/1999,682
+
+Table: Data List
+x,y
+1,2
+3,4
+5,6
+7,8
+9,0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 8cb6b824016542a45e54326d9f52091e05a1ce23..8d2dcdae12e21653ae49bf72d725a1731f8f7795 100755 (executable)
@@ -108,11 +108,10 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test1"
-$SUPERVISOR $PSPP --testing-mode test1.pspp
+$SUPERVISOR $PSPP -o pspp.csv test1.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test1 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
 diff -u $TEMPDIR/test1.out $TEMPDIR/test1.expected
 if [ $? -ne 0 ] ; then fail ; fi
 
index 0f395422f50180cb5b736f86ab9c37358e063c5d..8c68a8b9a7250566116ce154c4016da58dab106a 100755 (executable)
@@ -84,15 +84,15 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-a       h0       h1       h2       h3       v1       v2       v3       v4       v5       v6
-- -------- -------- -------- -------- -------- -------- -------- -------- -------- --------
-0     8.00     8.50     8.00     8.00     4.00     5.00     6.00     5.00     6.00     7.00 
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -b  $TEMPDIR/pspp.csv - <<EOF
+Table: Data List
+a,h0,h1,h2,h3,v1,v2,v3,v4,v5,v6
+0,8.00,8.50,8.00,8.00,4.00,5.00,6.00,5.00,6.00,7.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 491f79aa3bf4f96317b75769473c706bc8001509..4276661442bb1f2111f3f8b893bbffbe0620aa19 100755 (executable)
@@ -81,7 +81,7 @@ if [ ! -f $TEMPDIR/foobar ] ; then fail ; fi
 
 # This command must fail
 activity="run prog 1"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -eq 0 ] ; then fail ; fi
 
 
@@ -95,7 +95,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run prog 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 # foobar should now be gone
index 67dfed0a5757fa0d859d743e6a407ef26a3a10eb..71d7d27982f9d6e8ea72d776299dc8479bbf2a64 100755 (executable)
@@ -95,40 +95,31 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 EXAMINE.  Case Processing Summary
-#==#=======================================#
-#  #                 Cases                 #
-#  #-------------+-----------+-------------#
-#  #    Valid    |  Missing  |    Total    #
-#  #-----+-------+---+-------+-----+-------#
-#  #  N  |Percent| N |Percent|  N  |Percent#
-#==#=====#=======#===#=======#=====#=======#
-#V1#23.00|   100%|.00|     0%|23.00|   100%#
-#==#=====#=======#===#=======#=====#=======#
-1.2 EXAMINE.  Extreme Values
-#============#===========#=====#
-#            #Case Number|Value#
-#============#===========#=====#
-#V1 Highest 1#         21|20.00#
-#           2#         20|19.00#
-#           3#         19|18.00#
-#           4#         19|18.00#
-#           5#         18|17.00#
-#           6#         17|16.00#
-#  ----------#-----------+-----#
-#    Lowest 1#          1| 1.00#
-#           2#          2| 2.00#
-#           3#          3| 3.00#
-#           4#          3| 3.00#
-#           5#          4| 3.00#
-#           6#          5| 4.00#
-#============#===========#=====#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+V1,23.00,100%,.00,0%,23.00,100%
+
+Table: Extreme Values
+,,,Case Number,Value
+V1,Highest,1,21,20.00
+,,2,20,19.00
+,,3,19,18.00
+,,4,19,18.00
+,,5,18,17.00
+,,6,17,16.00
+,Lowest,1,1,1.00
+,,2,2,2.00
+,,3,3,3.00
+,,4,3,3.00
+,,5,4,3.00
+,,6,5,4.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 708e5342b27c1f5a9a722acc89023233a03b4fad..9cb0b9593277fd6b605d74f1b7036a50702bf946 100755 (executable)
@@ -88,114 +88,75 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|X       |F8.0  |
-+--------+------+
-2.1 EXAMINE.  Case Processing Summary
-#=#=============================#
-# #            Cases            #
-# #---------+---------+---------#
-# #  Valid  | Missing |  Total  #
-# #-+-------+-+-------+-+-------#
-# #N|Percent|N|Percent|N|Percent#
-#=#=#=======#=#=======#=#=======#
-#X#3|   100%|0|     0%|3|   100%#
-#=#=#=======#=#=======#=#=======#
-2.2 EXAMINE.  Percentiles
-#================#================================#
-#                #             Percentiles        #
-#                #---+---+----+----+----+----+----#
-#                # 5 | 10| 25 | 50 | 75 | 90 | 95 #
-#=#==============#===#===#====#====#====#====#====#
-#X|HAverage      #.40|.80|2.00|5.00|8.00|8.00|8.00#
-# |Tukey's Hinges#   |   |3.50|5.00|6.50|    |    #
-#=#==============#===#===#====#====#====#====#====#
-3.1 EXAMINE.  Case Processing Summary
-#=#=============================#
-# #            Cases            #
-# #---------+---------+---------#
-# #  Valid  | Missing |  Total  #
-# #-+-------+-+-------+-+-------#
-# #N|Percent|N|Percent|N|Percent#
-#=#=#=======#=#=======#=#=======#
-#X#3|   100%|0|     0%|3|   100%#
-#=#=#=======#=#=======#=#=======#
-3.2 EXAMINE.  Percentiles
-#==================#================================#
-#                  #             Percentiles        #
-#                  #---+---+----+----+----+----+----#
-#                  # 5 | 10| 25 | 50 | 75 | 90 | 95 #
-#=#================#===#===#====#====#====#====#====#
-#X|Weighted Average#.30|.60|1.50|3.50|5.75|7.10|7.55#
-# |Tukey's Hinges  #   |   |3.50|5.00|6.50|    |    #
-#=#================#===#===#====#====#====#====#====#
-4.1 EXAMINE.  Case Processing Summary
-#=#=============================#
-# #            Cases            #
-# #---------+---------+---------#
-# #  Valid  | Missing |  Total  #
-# #-+-------+-+-------+-+-------#
-# #N|Percent|N|Percent|N|Percent#
-#=#=#=======#=#=======#=#=======#
-#X#3|   100%|0|     0%|3|   100%#
-#=#=#=======#=#=======#=#=======#
-4.2 EXAMINE.  Percentiles
-#================#================================#
-#                #             Percentiles        #
-#                #---+---+----+----+----+----+----#
-#                # 5 | 10| 25 | 50 | 75 | 90 | 95 #
-#=#==============#===#===#====#====#====#====#====#
-#X|Rounded       #.00|.00|2.00|5.00|5.00|8.00|8.00#
-# |Tukey's Hinges#   |   |3.50|5.00|6.50|    |    #
-#=#==============#===#===#====#====#====#====#====#
-5.1 EXAMINE.  Case Processing Summary
-#=#=============================#
-# #            Cases            #
-# #---------+---------+---------#
-# #  Valid  | Missing |  Total  #
-# #-+-------+-+-------+-+-------#
-# #N|Percent|N|Percent|N|Percent#
-#=#=#=======#=#=======#=#=======#
-#X#3|   100%|0|     0%|3|   100%#
-#=#=#=======#=#=======#=#=======#
-5.2 EXAMINE.  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#
-# |Tukey's Hinges#    |    |3.50|5.00|6.50|    |    #
-#=#==============#====#====#====#====#====#====#====#
-6.1 EXAMINE.  Case Processing Summary
-#=#=============================#
-# #            Cases            #
-# #---------+---------+---------#
-# #  Valid  | Missing |  Total  #
-# #-+-------+-+-------+-+-------#
-# #N|Percent|N|Percent|N|Percent#
-#=#=#=======#=#=======#=#=======#
-#X#3|   100%|0|     0%|3|   100%#
-#=#=#=======#=#=======#=#=======#
-6.2 EXAMINE.  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#
-# |Tukey's Hinges          #    |    |3.50|5.00|6.50|    |    #
-#=#========================#====#====#====#====#====#====#====#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+X,F8.0
+
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+X,3,100%,0,0%,3,100%
+
+Table: Percentiles
+,,Percentiles,,,,,,
+,,5,10,25,50,75,90,95
+X,HAverage,.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%
+
+Table: Percentiles
+,,Percentiles,,,,,,
+,,5,10,25,50,75,90,95
+X,Weighted Average,.30,.60,1.50,3.50,5.75,7.10,7.55
+,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%
+
+Table: Percentiles
+,,Percentiles,,,,,,
+,,5,10,25,50,75,90,95
+X,Rounded,.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%
+
+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
+,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%
+
+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
+,Tukey's Hinges,,,3.50,5.00,6.50,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 11534385ce509ff3f8f5153aa6cb88c09b0cfd0e..1e5b0db0ee0b58a683e686f94dbe9bd6ea2d5839 100755 (executable)
@@ -98,166 +98,139 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 # NOTE:  In the following data: Only the extreme values have been checked
 # The descriptives have been blindly pasted.
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|QUALITY |F8.0  |
-|W       |F8.0  |
-|BRAND   |F8.0  |
-+--------+------+
-Case#  QUALITY        W    BRAND
------ -------- -------- --------
-    1     3.00     1.00     1.00 
-    2     2.00     2.00     1.00 
-    3     1.00     2.00     1.00 
-    4     1.00     1.00     1.00 
-    5     4.00     1.00     1.00 
-    6     4.00     1.00     1.00 
-    7     5.00     1.00     2.00 
-    8     2.00     1.00     2.00 
-    9     4.00     4.00     2.00 
-   10     2.00     1.00     2.00 
-   11     3.00     1.00     2.00 
-   12     7.00     1.00     3.00 
-   13     4.00     2.00     3.00 
-   14     5.00     3.00     3.00 
-   15     3.00     1.00     3.00 
-   16     6.00     1.00     3.00 
-2.1 EXAMINE.  Case Processing Summary
-#===============#=======================================#
-#               #                 Cases                 #
-#               #-------------+-----------+-------------#
-#               #    Valid    |  Missing  |    Total    #
-#               #-----+-------+---+-------+-----+-------#
-#               #  N  |Percent| N |Percent|  N  |Percent#
-#===============#=====#=======#===#=======#=====#=======#
-#Breaking Strain#24.00|   100%|.00|     0%|24.00|   100%#
-#===============#=====#=======#===#=======#=====#=======#
-2.2 EXAMINE.  Extreme Values
-#=========================#===========#=====#
-#                         #Case Number|Value#
-#=========================#===========#=====#
-#Breaking Strain Highest 1#         12| 7.00#
-#                        2#         16| 6.00#
-#                               3#          7| 5.00#
-#               ----------#-----------+-----#
-#                 Lowest 1#          3| 1.00#
-#                        2#          3| 1.00#
-#                        3#          4| 1.00#
-#=========================#===========#=====#
-2.3 EXAMINE.  Descriptives
-#============================================================#=========#==========#
-#                                                            #Statistic|Std. Error#
-#============================================================#=========#==========#
-#Breaking Strain Mean                                        #   3.54  |    .32   #
-#                95% Confidence Interval for Mean Lower Bound#   2.87  |          #
-#                                                 Upper Bound#   4.21  |          #
-#                5% Trimmed Mean                             #   3.50  |          #
-#                Median                                      #   4.00  |          #
-#                Variance                                    #   2.52  |          #
-#                Std. Deviation                              #   1.59  |          #
-#                Minimum                                     #   1.00  |          #
-#                Maximum                                     #   7.00  |          #
-#                Range                                       #   6.00  |          #
-#                Interquartile Range                         #   2.75  |          #
-#                Skewness                                    #   .06   |    .47   #
-#                Kurtosis                                    #   -.36  |    .92   #
-#============================================================#=========#==========#
-2.4 EXAMINE.  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%#
-#============================#====#=======#===#=======#====#=======#
-2.5 EXAMINE.  Extreme Values
-#======================================#===========#=====#
-#                Manufacturer          #Case Number|Value#
-#======================================#===========#=====#
-#Breaking Strain Aspeger      Highest 1#          5| 4.00#
-#                                     2#          6| 4.00#
-#                                     3#          1| 3.00#
-#                            ----------#-----------+-----#
-#                              Lowest 1#          3| 1.00#
-#                                     2#          3| 1.00#
-#                                     3#          4| 1.00#
-#               -----------------------#-----------+-----#
-#                Bloggs       Highest 1#          7| 5.00#
-#                                     2#          9| 4.00#
-#                                     3#          9| 4.00#
-#                            ----------#-----------+-----#
-#                              Lowest 1#          8| 2.00#
-#                                     2#         10| 2.00#
-#                                     3#         11| 3.00#
-#               -----------------------#-----------+-----#
-#                       Charlies     Highest 1#         12| 7.00#
-#                                     2#         16| 6.00#
-#                                     3#         14| 5.00#
-#                            ----------#-----------+-----#
-#                              Lowest 1#         15| 3.00#
-#                                     2#         13| 4.00#
-#                                     3#         13| 4.00#
-#======================================#===========#=====#
-2.6 EXAMINE.  Descriptives
-#=========================================================================#=========#==========#
-#                Manufacturer                                             #Statistic|Std. Error#
-#=========================================================================#=========#==========#
-#Breaking Strain Aspeger      Mean                                        #   2.25  |    .45   #
-#                             95% Confidence Interval for Mean Lower Bound#   1.18  |          #
-#                                                              Upper Bound#   3.32  |          #
-#                             5% Trimmed Mean                             #   2.22  |          #
-#                             Median                                      #   2.00  |          #
-#                             Variance                                    #   1.64  |          #
-#                             Std. Deviation                              #   1.28  |          #
-#                             Minimum                                     #   1.00  |          #
-#                             Maximum                                     #   4.00  |          #
-#                             Range                                       #   3.00  |          #
-#                             Interquartile Range                         #   2.75  |          #
-#                             Skewness                                    #   .47   |    .75   #
-#                             Kurtosis                                    #  -1.55  |   1.48   #
-#               ----------------------------------------------------------#---------+----------#
-#                Bloggs       Mean                                        #   3.50  |    .38   #
-#                             95% Confidence Interval for Mean Lower Bound#   2.61  |          #
-#                                                              Upper Bound#   4.39  |          #
-#                             5% Trimmed Mean                             #   3.50  |          #
-#                             Median                                      #   4.00  |          #
-#                             Variance                                    #   1.14  |          #
-#                             Std. Deviation                              #   1.07  |          #
-#                             Minimum                                     #   2.00  |          #
-#                             Maximum                                     #   5.00  |          #
-#                             Range                                       #   3.00  |          #
-#                             Interquartile Range                         #   1.75  |          #
-#                             Skewness                                    #   -.47  |    .75   #
-#                             Kurtosis                                    #   -.83  |   1.48   #
-#               ----------------------------------------------------------#---------+----------#
-#                Charlies     Mean                                        #   4.88  |    .44   #
-#                             95% Confidence Interval for Mean Lower Bound#   3.83  |          #
-#                                                              Upper Bound#   5.92  |          #
-#                             5% Trimmed Mean                             #   4.86  |          #
-#                             Median                                      #   5.00  |          #
-#                             Variance                                    #   1.55  |          #
-#                             Std. Deviation                              #   1.25  |          #
-#                             Minimum                                     #   3.00  |          #
-#                             Maximum                                     #   7.00  |          #
-#                             Range                                       #   4.00  |          #
-#                             Interquartile Range                         #   1.75  |          #
-#                             Skewness                                    #   .30   |    .75   #
-#                             Kurtosis                                    #   .15   |   1.48   #
-#=========================================================================#=========#==========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+QUALITY,F8.0
+W,F8.0
+BRAND,F8.0
+
+Table: Data List
+Case Number,QUALITY,W,BRAND
+1,3.00,1.00,1.00
+2,2.00,2.00,1.00
+3,1.00,2.00,1.00
+4,1.00,1.00,1.00
+5,4.00,1.00,1.00
+6,4.00,1.00,1.00
+7,5.00,1.00,2.00
+8,2.00,1.00,2.00
+9,4.00,4.00,2.00
+10,2.00,1.00,2.00
+11,3.00,1.00,2.00
+12,7.00,1.00,3.00
+13,4.00,2.00,3.00
+14,5.00,3.00,3.00
+15,3.00,1.00,3.00
+16,6.00,1.00,3.00
+
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+Breaking Strain,24.00,100%,.00,0%,24.00,100%
+
+Table: Extreme Values
+,,,Case Number,Value
+Breaking Strain,Highest,1,12,7.00
+,,2,16,6.00
+,,3,7,5.00
+,Lowest,1,3,1.00
+,,2,3,1.00
+,,3,4,1.00
+
+Table: Descriptives
+,,,Statistic,Std. Error
+Breaking Strain,Mean,,3.54,.32
+,95% Confidence Interval for Mean,Lower Bound,2.87,
+,,Upper Bound,4.21,
+,5% Trimmed Mean,,3.50,
+,Median,,4.00,
+,Variance,,2.52,
+,Std. Deviation,,1.59,
+,Minimum,,1.00,
+,Maximum,,7.00,
+,Range,,6.00,
+,Interquartile Range,,2.75,
+,Skewness,,.06,.47
+,Kurtosis,,-.36,.92
+
+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%
+
+Table: Extreme Values
+,Manufacturer,,,Case Number,Value
+Breaking Strain,Aspeger,Highest,1,5,4.00
+,,,2,6,4.00
+,,,3,1,3.00
+,,Lowest,1,3,1.00
+,,,2,3,1.00
+,,,3,4,1.00
+,Bloggs,Highest,1,7,5.00
+,,,2,9,4.00
+,,,3,9,4.00
+,,Lowest,1,8,2.00
+,,,2,10,2.00
+,,,3,11,3.00
+,Charlies,Highest,1,12,7.00
+,,,2,16,6.00
+,,,3,14,5.00
+,,Lowest,1,15,3.00
+,,,2,13,4.00
+,,,3,13,4.00
+
+Table: Descriptives
+,Manufacturer,,,Statistic,Std. Error
+Breaking Strain,Aspeger,Mean,,2.25,.45
+,,95% Confidence Interval for Mean,Lower Bound,1.18,
+,,,Upper Bound,3.32,
+,,5% Trimmed Mean,,2.22,
+,,Median,,2.00,
+,,Variance,,1.64,
+,,Std. Deviation,,1.28,
+,,Minimum,,1.00,
+,,Maximum,,4.00,
+,,Range,,3.00,
+,,Interquartile Range,,2.75,
+,,Skewness,,.47,.75
+,,Kurtosis,,-1.55,1.48
+,Bloggs,Mean,,3.50,.38
+,,95% Confidence Interval for Mean,Lower Bound,2.61,
+,,,Upper Bound,4.39,
+,,5% Trimmed Mean,,3.50,
+,,Median,,4.00,
+,,Variance,,1.14,
+,,Std. Deviation,,1.07,
+,,Minimum,,2.00,
+,,Maximum,,5.00,
+,,Range,,3.00,
+,,Interquartile Range,,1.75,
+,,Skewness,,-.47,.75
+,,Kurtosis,,-.83,1.48
+,Charlies,Mean,,4.88,.44
+,,95% Confidence Interval for Mean,Lower Bound,3.83,
+,,,Upper Bound,5.92,
+,,5% Trimmed Mean,,4.86,
+,,Median,,5.00,
+,,Variance,,1.55,
+,,Std. Deviation,,1.25,
+,,Minimum,,3.00,
+,,Maximum,,7.00,
+,,Range,,4.00,
+,,Interquartile Range,,1.75,
+,,Skewness,,.30,.75
+,,Kurtosis,,.15,1.48
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 3dfe52f10be98f1d213041303d85bac8fae4cff6..937f05f79e625d5a063293c9380d746f6d3daade 100755 (executable)
@@ -76,26 +76,22 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-diff  -b  $TEMPDIR/pspp.list - << EOF 
-1.1 DATA LIST.  Reading free-form data from myhandle.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-+--------+------+
-
-       x
---------
-    1.00 
-    2.00 
-    5.00 
-  109.00 
-
+diff -c $TEMPDIR/pspp.csv - << EOF 
+Table: Reading free-form data from myhandle.
+Variable,Format
+x,F8.0
+
+Table: Data List
+x
+1.00
+2.00
+5.00
+109.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index e6211b4d4b8090189628ddd8c11e6fcc4de98122..a275f2957bbe2207a8bbae73e8d81cfa6f8a07bb 100755 (executable)
@@ -119,54 +119,98 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 # We need to filter out the dates/times
 activity="date filter"
-grep -v '[Ee]ntered' $TEMPDIR/pspp.list > $TEMPDIR/pspp.filtered
+sed 's/(Entered [^)]*)/(Entered <date>)/' $TEMPDIR/pspp.csv > $TEMPDIR/pspp.filtered
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.filtered
-diff -b  $TEMPDIR/pspp.filtered - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|X       |     1|  1-  1|F1.0  |
-|Y       |     1|  2-  2|F1.0  |
-+--------+------+-------+------+
+diff -c $TEMPDIR/pspp.filtered - <<EOF
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+X,1,1-  1,F1.0
+Y,1,2-  2,F1.0
+
 Documents in the active file:
+
 document First line of a document
+
 Second line of a document
+
 The last line should end with a period: .
+
+(Entered <date>)
+
 File label:
+
 This is a test file label
+
 Documents in the active file:
+
 document First line of a document
+
 Second line of a document
+
 The last line should end with a period: .
+
+(Entered <date>)
+
 Line one
+
 Line two
+
+(Entered <date>)
+
 File label:
+
 This is a test file label
+
 Documents in the active file:
+
 document First line of a document
+
 Second line of a document
+
 The last line should end with a period: .
+
+(Entered <date>)
+
 Line one
+
 Line two
+
+(Entered <date>)
+
 document There should be another document now.
+
+(Entered <date>)
+
 Documents in the active file:
+
 document First line of a document
+
 Second line of a document
+
 The last line should end with a period: .
+
+(Entered <date>)
+
 Line one
+
 Line two
+
+(Entered <date>)
+
 document There should be another document now.
+
+(Entered <date>)
+
 File label:
+
 This is a test file label
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
index ec76fba9f099c08157cd123ec647a01df6c8450d..13704791e19dafa5aba16ea5f2fa5f590cc595e9 100755 (executable)
@@ -86,39 +86,40 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="check results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - << EOF
- X FILTER_$
--- --------
- 1     1.00 
- 3     1.00 
- 5     1.00 
- 7     1.00 
- 9     1.00 
- X FILTER_$
--- --------
- 1     1.00 
- 2      .00 
- 3     1.00 
- 4      .00 
- 5     1.00 
- 6      .00 
- 7     1.00 
- 8      .00 
- 9     1.00 
-10      .00 
- X FILTER_$
--- --------
- 2     1.00 
- 4     1.00 
- 6     1.00 
- 8     1.00 
-10     1.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X,FILTER_$
+1,1.00
+3,1.00
+5,1.00
+7,1.00
+9,1.00
+
+Table: Data List
+X,FILTER_$
+1,1.00
+2,.00
+3,1.00
+4,.00
+5,1.00
+6,.00
+7,1.00
+8,.00
+9,1.00
+10,.00
+
+Table: Data List
+X,FILTER_$
+2,1.00
+4,1.00
+6,1.00
+8,1.00
+10,1.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index a3e5caf2c896cc84ebad3058ad7bb59d775a398c..141a75cc4a641cdd8acb038c90828d4da4cb55c1 100755 (executable)
@@ -92,48 +92,51 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/flip.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/flip.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b  $TEMPDIR/pspp.list - << EOF
-N  A  B  C  D
-- -- -- -- --
-v  1  2  3  4 
-w  6  7  8  9 
-x 11 12 13 14 
-y 16 17 18 19 
-z 21 22 23 24 
-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 
-CASE_LBL        A        B        C        D
--------- -------- -------- -------- --------
-V            1.00     2.00     3.00     4.00 
-W            6.00     7.00     8.00     9.00 
-X           11.00    12.00    13.00    14.00 
-Y           16.00    17.00    18.00    19.00 
-Z           21.00    22.00    23.00    24.00 
-v1 v2 v3 v4 v5 v6 v7 v8 v9 v10
--- -- -- -- -- -- -- -- -- ---
- 1  2  3  4  5  6  7  8  9  10 
- 4  5  6  7  8  9 10 11 12  13 
-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 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+N,A,B,C,D
+v,1,2,3,4
+w,6,7,8,9
+x,11,12,13,14
+y,16,17,18,19
+z,21,22,23,24
+
+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
+
+Table: Data List
+CASE_LBL,A,B,C,D
+V       ,1.00,2.00,3.00,4.00
+W       ,6.00,7.00,8.00,9.00
+X       ,11.00,12.00,13.00,14.00
+Y       ,16.00,17.00,18.00,19.00
+Z       ,21.00,22.00,23.00,24.00
+
+Table: Data List
+v1,v2,v3,v4,v5,v6,v7,v8,v9,v10
+1,2,3,4,5,6,7,8,9,10
+4,5,6,7,8,9,10,11,12,13
+
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index c28c8dd478c9f6dc4dd04ea8ddd5dbb2ac27a069..c6cf630c039c5819d3d60f2c5a4886ad9dd8fb7c 100755 (executable)
@@ -87,125 +87,99 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output 1"
-diff $TEMPDIR/pspp.list - <<EOF
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|VAR001  |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|VAR002  |Format: A8                                 |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|VAR003  |Format: F8.2                               |       3|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-
-  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 
-
-2.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|V1      |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|V2      |Format: A8                                 |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|VAR001  |Format: F8.2                               |       3|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-
-      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 
-
-3.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|name    |Format: A8                                 |       1|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|id      |Format: F8.2                               |       2|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|height  |Format: F8.2                               |       3|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-
-    name       id   height
--------- -------- --------
-fred          .00    23.40 
-bert         1.00      .56 
-charlie      2.00      .   
-dick         3.00   -34.09 
-
-4.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|vone    |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|vtwo    |Format: F8.2                               |       2|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|vthree  |Format: A8                                 |       3|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|v4      |Format: F8.2                               |       4|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-
-    vone     vtwo   vthree       v4
--------- -------- -------- --------
-    1.00     3.00              5.00 
-    2.00     4.00              6.00 
-
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Variable,Description,,Position
+VAR001,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+VAR002,Format: A8,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+VAR003,Format: F8.2,,3
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+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
+
+Variable,Description,,Position
+V1,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+V2,Format: A8,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+VAR001,Format: F8.2,,3
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+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
+
+Variable,Description,,Position
+name,Format: A8,,1
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+id,Format: F8.2,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+height,Format: F8.2,,3
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+Table: Data List
+name,id,height
+fred    ,.00,23.40
+bert    ,1.00,.56
+charlie ,2.00,.  
+dick    ,3.00,-34.09
+
+Variable,Description,,Position
+vone,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+vtwo,Format: F8.2,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+vthree,Format: A8,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+v4,Format: F8.2,,4
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+Table: Data List
+vone,vtwo,vthree,v4
+1.00,3.00,,5.00
+2.00,4.00,,6.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -223,14 +197,14 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output 2"
-diff $TEMPDIR/pspp.list - <<EOF
-warning: Selected sheet or range of spreadsheet "$TEMPDIR/Book1.gnumeric" is empty.
-warning: Selected sheet or range of spreadsheet "$TEMPDIR/Book1.gnumeric" is empty.
+diff -c $TEMPDIR/pspp.csv - <<EOF
+"warning: Selected sheet or range of spreadsheet ""$TEMPDIR/Book1.gnumeric"" is empty."
 
+"warning: Selected sheet or range of spreadsheet ""$TEMPDIR/Book1.gnumeric"" is empty."
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 1d8afadaa815f2ece469e7d488845844540f8951..e15080ab92cbe43a4c2e711c0ebe55be11633334 100755 (executable)
@@ -202,131 +202,106 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << 'EOF'
-1.1 DISPLAY.  
-+---------------+-------------------------------------------+--------+
-|Variable       |Description                                |Position|
-#===============#===========================================#========#
-|bool           |Format: F8.2                               |       1|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|bytea          |Format: AHEX2                              |       2|
-|               |Measure: Nominal                           |        |
-|               |Display Alignment: Left                    |        |
-|               |Display Width: 1                           |        |
-+---------------+-------------------------------------------+--------+
-|char           |Format: A8                                 |       3|
-|               |Measure: Nominal                           |        |
-|               |Display Alignment: Left                    |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|int8           |Format: F8.2                               |       4|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|int2           |Format: F8.2                               |       5|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|int4           |Format: F8.2                               |       6|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|numeric        |Format: E40.6                              |       7|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|text           |Format: A16                                |       8|
-|               |Measure: Nominal                           |        |
-|               |Display Alignment: Left                    |        |
-|               |Display Width: 16                          |        |
-+---------------+-------------------------------------------+--------+
-|oid            |Format: F8.2                               |       9|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|float4         |Format: F8.2                               |      10|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|float8         |Format: F8.2                               |      11|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|money          |Format: DOLLAR8.2                          |      12|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|pbchar         |Format: A8                                 |      13|
-|               |Measure: Nominal                           |        |
-|               |Display Alignment: Left                    |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|varchar        |Format: A8                                 |      14|
-|               |Measure: Nominal                           |        |
-|               |Display Alignment: Left                    |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|date           |Format: DATE11                             |      15|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|time           |Format: TIME11.0                           |      16|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|timestamp      |Format: DATETIME22.0                       |      17|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|timestamptz    |Format: DATETIME22.0                       |      18|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|interval       |Format: DTIME13.0                          |      19|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|interval_months|Format: F3.0                               |      20|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|timetz         |Format: TIME11.0                           |      21|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-|timetz_zone    |Format: F8.2                               |      22|
-|               |Measure: Scale                             |        |
-|               |Display Alignment: Right                   |        |
-|               |Display Width: 8                           |        |
-+---------------+-------------------------------------------+--------+
-    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               .        .        .                                .                                 .        .        .        .                               .           .                      .                      .             .               .           .         .   
-    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 
+diff -c $TEMPDIR/pspp.csv - << 'EOF'
+Variable,Description,,Position
+bool,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+bytea,Format: AHEX2,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 1,,
+char,Format: A8,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+int8,Format: F8.2,,4
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+int2,Format: F8.2,,5
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+int4,Format: F8.2,,6
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+numeric,Format: E40.6,,7
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+text,Format: A16,,8
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 16,,
+oid,Format: F8.2,,9
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+float4,Format: F8.2,,10
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+float8,Format: F8.2,,11
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+money,Format: DOLLAR8.2,,12
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+pbchar,Format: A8,,13
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+varchar,Format: A8,,14
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+date,Format: DATE11,,15
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+time,Format: TIME11.0,,16
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+timestamp,Format: DATETIME22.0,,17
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+timestamptz,Format: DATETIME22.0,,18
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+interval,Format: DTIME13.0,,19
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+interval_months,Format: F3.0,,20
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+timetz,Format: TIME11.0,,21
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+timetz_zone,Format: F8.2,,22
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+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,,.  ,.  ,.  ,.          ,,.  ,.  ,.  ,.  ,,,.,.,.,.,.,.,.,.  
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -345,31 +320,24 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 2"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << 'EOF'
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|a       |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|b       |Format: DATE11                             |       2|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|c       |Format: E40.2                              |       3|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
+diff -c $TEMPDIR/pspp.csv - << 'EOF'
+Variable,Description,,Position
+a,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+b,Format: DATE11,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+c,Format: E40.2,,3
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -402,28 +370,28 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 3"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << 'EOF'
-       x     diff
--------- --------
-    1.00      .   
-    2.00     1.00 
-    3.00     1.00 
-    4.00     1.00 
-    5.00     1.00 
-    6.00     1.00 
-       x     diff
--------- --------
- 1000.00     1.00 
-  999.00     1.00 
-  998.00     1.00 
-  997.00     1.00 
-  996.00     1.00 
-  995.00     1.00 
+diff -c $TEMPDIR/pspp.csv - << 'EOF'
+Table: Data List
+x,diff
+1.00,.  
+2.00,1.00
+3.00,1.00
+4.00,1.00
+5.00,1.00
+6.00,1.00
+
+Table: Data List
+x,diff
+1000.00,1.00
+999.00,1.00
+998.00,1.00
+997.00,1.00
+996.00,1.00
+995.00,1.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -463,7 +431,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 4"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
index c601b50672bce576545f530392d815b59937af7e..3cc68499a32d66f55e9836fd18f3d4ba3819c115 100755 (executable)
@@ -132,36 +132,38 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test"
-$SUPERVISOR $PSPP --testing-mode test.pspp
+$SUPERVISOR $PSPP -o pspp.csv test.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<'EOF'
-            username                                 password        uid        gid                                    gecos                                     home                                    shell
--------------------- ---------------------------------------- ---------- ---------- ---------------------------------------- ---------------------------------------- ----------------------------------------
-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
-   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
-   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
-      name  age color   received  price height       type
----------- ---- ----- ---------- ------ ------ ----------
-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
+diff -c $TEMPDIR/pspp.csv - <<'EOF'
+Table: Data List
+username,password,uid,gid,gecos,home,shell
+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                                
+
+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
+
+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
+
+Table: Data List
+name,age,color,received,price,height,type
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 1c7b7cefca8e99ce9b4b3682ca37292769ca653e..54d6cf869301df4f9f718e73659f2772f4a81992 100755 (executable)
@@ -86,266 +86,269 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-       x
---------
-       1
-       2
-       3
-       4
-       5
-       6
-       7
-       8
-       9
-      10
-       x
---------
-       1
-       2
-       x
---------
-       1
-       2
-       3
-       4
-       5
-       6
-       7
-       8
-       9
-      10
-      11
-      12
-      13
-      14
-      15
-      16
-      17
-      18
-      19
-      20
-      21
-      22
-      23
-      24
-      25
-      26
-      27
-      28
-      29
-      30
-      31
-      32
-      33
-      34
-      35
-      36
-       x
---------
-       1
-       2
-       3
-       4
-       5
-       6
-       7
-       8
-       9
-      10
-      11
-      12
-      13
-      14
-      15
-      16
-      17
-      18
-      19
-      20
-      21
-      22
-      23
-      24
-      25
-      26
-      27
-      28
-      29
-      30
-      31
-      32
-      33
-      34
-      35
-      36
-      37
-      38
-      39
-      40
-      41
-      42
-      43
-      44
-      45
-      46
-      47
-      48
-      49
-      50
-      51
-      52
-      53
-      54
-      55
-      56
-      57
-      58
-      59
-      60
-      61
-      62
-      63
-      64
-      65
-      66
-      67
-      68
-      69
-      70
-      71
-      72
-      73
-      74
-      75
-      76
-      77
-      78
-      79
-      80
-      81
-      82
-      83
-      84
-      85
-      86
-      87
-      88
-      89
-      90
-      91
-      92
-      93
-      94
-      95
-      96
-       x
---------
-       1
-       2
-       3
-       4
-       5
-       6
-       7
-       8
-       9
-      10
-      11
-      12
-      13
-      14
-      15
-      16
-      17
-      18
-      19
-      20
-      21
-      22
-      23
-      24
-      25
-      26
-      27
-      28
-      29
-      30
-      31
-      32
-      33
-      34
-      35
-      36
-      37
-      38
-      39
-      40
-      41
-      42
-      43
-      44
-      45
-      46
-      47
-      48
-      49
-      50
-      51
-      52
-      53
-      54
-      55
-      56
-      57
-      58
-      59
-      60
-      61
-      62
-      63
-      64
-      65
-      66
-      67
-      68
-      69
-      70
-      71
-      72
-      73
-      74
-      75
-      76
-      77
-      78
-      79
-      80
-      81
-      82
-      83
-      84
-      85
-      86
-      87
-      88
-      89
-      90
-      91
-      92
-      93
-      94
-      95
-      96
-      97
-      98
-      99
-     100
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+x
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+
+Table: Data List
+x
+1
+2
+
+Table: Data List
+x
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+
+Table: Data List
+x
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+
+Table: Data List
+x
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 2bd0346b52f826eafe95b7e0cdca3fbcf03bb465..f0560495bb91c719606a3d517c60b7adc7579b9c 100755 (executable)
@@ -152,56 +152,59 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-       A        B        C        D
--------- -------- -------- --------
-    1.00    23.00    45.00     2.03
-    2.00    22.00    34.00    23.00
-    3.00    34.00    34.00    34.00
-       A        B        C        D
--------- -------- -------- --------
-     .       1.00     2.00     3.00
-     .       4.00      .       5.00
-    6.00     7.00      .       8.00
-    9.00      .00     1.00      .
-     .        .        .        .
-     .        .        .       2.00
-     .       3.00     4.00     5.00
-       A        B        C        D
--------- -------- -------- --------
-    1.00     2.00     3.00     4.00
-    1.00     2.00     3.00      .
-    1.00     2.00      .       4.00
-    1.00     2.00      .        .
-    1.00      .       3.00     4.00
-    1.00      .       3.00      .
-    1.00      .        .       4.00
-    1.00      .        .        .
-     .       2.00     3.00     4.00
-     .       2.00     3.00      .
-     .       2.00      .       4.00
-     .       2.00      .        .
-     .        .       3.00     4.00
-     .        .       3.00      .
-     .        .        .       4.00
-     .        .        .        .
-               start                  end count
--------------------- -------------------- -----
-          07/22/2007           10/06/2007   321
-          07/14/1789           08/26/1789     4
-          01/01/1972           12/31/1999   682
-x y
-- -
-1 2
-3 4
-5 6
-7 8
-9 0
+diff -b  $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+A,B,C,D
+1.00,23.00,45.00,2.03
+2.00,22.00,34.00,23.00
+3.00,34.00,34.00,34.00
+
+Table: Data List
+A,B,C,D
+.  ,1.00,2.00,3.00
+.  ,4.00,.  ,5.00
+6.00,7.00,.  ,8.00
+9.00,.00,1.00,.
+.  ,.  ,.  ,.
+.  ,.  ,.  ,2.00
+.  ,3.00,4.00,5.00
+
+Table: Data List
+A,B,C,D
+1.00,2.00,3.00,4.00
+1.00,2.00,3.00,.
+1.00,2.00,.  ,4.00
+1.00,2.00,.  ,.
+1.00,.  ,3.00,4.00
+1.00,.  ,3.00,.
+1.00,.  ,.  ,4.00
+1.00,.  ,.  ,.
+.  ,2.00,3.00,4.00
+.  ,2.00,3.00,.
+.  ,2.00,.  ,4.00
+.  ,2.00,.  ,.
+.  ,.  ,3.00,4.00
+.  ,.  ,3.00,.
+.  ,.  ,.  ,4.00
+.  ,.  ,.  ,.
+
+Table: Data List
+start,end,count
+07/22/2007,10/06/2007,321
+07/14/1789,08/26/1789,4
+01/01/1972,12/31/1999,682
+
+Table: Data List
+x,y
+1,2
+3,4
+5,6
+7,8
+9,0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 0cb178bf5776ade7e26ac28b5218f2eefd18e70f..b519d4695e03ebff38d17fdb7975a8643562bea0 100755 (executable)
@@ -74,17 +74,16 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-       X        Y
--------- --------
-    1.00     2.00 
-    3.00     .
-    5.00     6.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X,Y
+1.00,2.00
+3.00,.  
+5.00,6.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index a6e8c7784a2c1666793fe934fcd02eb58c808bc6..0740128667d633ab11316a3ebe47d56d3d4412ef 100755 (executable)
@@ -87,17 +87,16 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test1"
-$SUPERVISOR $PSPP --testing-mode test1.pspp
+$SUPERVISOR $PSPP -o pspp.csv test1.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test1 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-         X          Y
----------- ----------
-         1          4
-         2          5
-         3          6
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X,Y
+1,4
+2,5
+3,6
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -122,19 +121,19 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test2"
-$SUPERVISOR $PSPP --testing-mode test2.pspp
+$SUPERVISOR $PSPP -o pspp.csv test2.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test2 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-         X          Y
----------- ----------
-         1          4
-         2          5
-         3          6
-         .          7
-         .          8
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X,Y
+1,4
+2,5
+3,6
+.,7
+.,8
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -162,22 +161,22 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test3"
-$SUPERVISOR $PSPP --testing-mode test3.pspp
+$SUPERVISOR $PSPP -o pspp.csv test3.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test3 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-         X
-----------
-         1
-         2
-         3
-         4
-         5
-         6
-         7
-         8
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X
+1
+2
+3
+4
+5
+6
+7
+8
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -208,22 +207,22 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test4"
-$SUPERVISOR $PSPP --testing-mode test4.pspp
+$SUPERVISOR $PSPP -o pspp.csv test4.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test4 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-         X
-----------
-         1
-         2
-         3
-         4
-         5
-         6
-         7
-         8
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X
+1
+2
+3
+4
+5
+6
+7
+8
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -245,64 +244,64 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run test5"
-$SUPERVISOR $PSPP --testing-mode test5.pspp
+$SUPERVISOR $PSPP -o pspp.csv test5.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare test5 results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-Case#        X
------ --------
-    1     3.00
-    2     6.00
-    3     9.00
-    4    12.00
-    5    15.00
-    6    18.00
-    7    21.00
-    8    24.00
-    9    27.00
-   10    30.00
-   11    33.00
-   12    36.00
-   13    39.00
-   14    42.00
-   15    45.00
-   16    48.00
-   17    51.00
-   18    54.00
-   19    57.00
-   20    60.00
-   21    63.00
-   22    66.00
-   23    69.00
-   24    72.00
-   25    75.00
-   26    78.00
-   27    81.00
-   28    84.00
-   29    87.00
-   30    90.00
-   31    93.00
-   32    96.00
-   33    99.00
-   34   102.00
-   35   105.00
-   36   108.00
-   37   111.00
-   38   114.00
-   39   117.00
-   40   120.00
-   41   123.00
-   42   126.00
-   43   129.00
-   44   132.00
-   45   135.00
-   46   138.00
-   47   141.00
-   48   144.00
-   49   147.00
-   50   150.00
+perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.csv
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+Case Number,X
+1,3.00
+2,6.00
+3,9.00
+4,12.00
+5,15.00
+6,18.00
+7,21.00
+8,24.00
+9,27.00
+10,30.00
+11,33.00
+12,36.00
+13,39.00
+14,42.00
+15,45.00
+16,48.00
+17,51.00
+18,54.00
+19,57.00
+20,60.00
+21,63.00
+22,66.00
+23,69.00
+24,72.00
+25,75.00
+26,78.00
+27,81.00
+28,84.00
+29,87.00
+30,90.00
+31,93.00
+32,96.00
+33,99.00
+34,102.00
+35,105.00
+36,108.00
+37,111.00
+38,114.00
+39,117.00
+40,120.00
+41,123.00
+42,126.00
+43,129.00
+44,132.00
+45,135.00
+46,138.00
+47,141.00
+48,144.00
+49,147.00
+50,150.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index f80dc5fc4a0df3f1c4250ef32e0bf3bb45e7a524..0d8f1697aa36ee1fb6950dfcf4b94728f7fac10e 100755 (executable)
@@ -92,7 +92,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #This command should fail
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -eq 0 ] ; then fail ; fi
 
 
@@ -110,7 +110,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
@@ -158,7 +158,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 # This command should fail
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -eq 0 ] ; then fail ; fi
 
 activity="create wrapper 6"
@@ -174,7 +174,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 4"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
@@ -210,15 +210,16 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 5"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -ne 1 ] ; then no_result ; fi
 
 activity="examine output 1"
-diff $TEMPDIR/pspp.list - <<EOF
+diff -c $TEMPDIR/pspp.csv - <<EOF
 $TEMPDIR/foo.sps:10: error: DISPLAY: AKSDJ is not a variable name.
+
 warning: Error encountered while ERROR=STOP is effective.
-$TEMPDIR/foo.sps:10: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 
+$TEMPDIR/foo.sps:10: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -236,19 +237,18 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 6"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -ne 1 ] ; then no_result ; fi
 
 activity="examine output 2"
-diff $TEMPDIR/pspp.list - <<EOF
+diff $TEMPDIR/pspp.csv - <<EOF
 $TEMPDIR/foo.sps:10: error: DISPLAY: AKSDJ is not a variable name.
 
-       x
---------
-    1.00 
-    2.00 
-    3.00 
-
+Table: Data List
+x
+1.00
+2.00
+3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -268,7 +268,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 #This command should fail
 activity="run program 7"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE > /dev/null
 if [ $? -eq 0 ] ; then no_result ; fi
 
 pass;
index bc14e1a93dfc2a6b1b5ef1c7b733b5e31b82956b..e8c39dd2c9d0caa58868950bd4520cb10856a766 100755 (executable)
@@ -77,25 +77,22 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/lag.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/lag.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare result"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|W       |     1|  1-  1|F1.0  |
-+--------+------+-------+------+
-W        X        Y        Z
-- -------- -------- --------
-1      .        .        .   
-2     1.00      .        .   
-3     2.00     1.00     1.00 
-4     3.00     2.00     2.00 
-5     4.00     3.00     3.00 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+W,1,1-  1,F1.0
+
+Table: Data List
+W,X,Y,Z
+1,.  ,.  ,.  
+2,1.00,.  ,.  
+3,2.00,1.00,1.00
+4,3.00,2.00,2.00
+5,4.00,3.00,3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index ca03b5cad88ae341abd2eb833ad8bdc5ce4b2eea..14612b9075e903e4c032023d7d7ce85bfb55ea85 100755 (executable)
@@ -83,21 +83,20 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-       a        b        c
--------- -------- --------
-    1.00     2.00     3.00
-    4.00     5.00     6.00
-    7.00     8.00     9.00
-   10.00    11.00    12.00
-   13.00    14.00    15.00
-   16.00    17.00    18.00
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+a,b,c
+1.00,2.00,3.00
+4.00,5.00,6.00
+7.00,8.00,9.00
+10.00,11.00,12.00
+13.00,14.00,15.00
+16.00,17.00,18.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 504314a9601c1d977d405a48df05cddb71f281e0..7079fd4d290cf753fbfe3c787877d4d5a4ca9f57 100755 (executable)
@@ -66,7 +66,7 @@ data list file='$top_srcdir/tests/weighting.data'/AVAR 1-5 BVAR 6-10.
 weight by BVAR.
 list.
 *list /cases=from 5 to 20 by 2 /format numbered.
-list /format numbered weight.
+list /format numbered.
 
 *** Multiple lines.
 data list file='$top_srcdir/tests/list.data' notable /X000 to X126 1-127.
@@ -78,182 +78,182 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from "$top_srcdir/tests/weighting.data".
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|AVAR    |     1|  1-  5|F5.0  |
-|BVAR    |     1|  6- 10|F5.0  |
-+--------+------+-------+------+
- AVAR  BVAR
------ -----
-   18     1 
-   19     7 
-   20    26 
-   21    76 
-   22    57 
-   23    58 
-   24    38 
-   25    38 
-   26    30 
-   27    21 
-   28    23 
-   29    24 
-   30    23 
-   31    14 
-   32    21 
-   33    21 
-   34    14 
-   35    14 
-   36    17 
-   37    11 
-   38    16 
-   39    14 
-   40    15 
-   41    14 
-   42    14 
-   43     8 
-   44    15 
-   45    10 
-   46    12 
-   47    13 
-   48    13 
-   49     5 
-   50     5 
-   51     3 
-   52     7 
-   53     6 
-   54     2 
-   55     2 
-   56     2 
-   57     3 
-   58     1 
-   59     3 
-   61     1 
-   62     3 
-   63     1 
-   64     1 
-   65     2 
-   70     1 
-   78     1 
-   79     1 
-   80     1 
-   94     1 
-Case#  AVAR  BVAR
------ ----- -----
-    1    18     1 
-    2    19     7 
-    3    20    26 
-    4    21    76 
-    5    22    57 
-    6    23    58 
-    7    24    38 
-    8    25    38 
-    9    26    30 
-   10    27    21 
-   11    28    23 
-   12    29    24 
-   13    30    23 
-   14    31    14 
-   15    32    21 
-   16    33    21 
-   17    34    14 
-   18    35    14 
-   19    36    17 
-   20    37    11 
-   21    38    16 
-   22    39    14 
-   23    40    15 
-   24    41    14 
-   25    42    14 
-   26    43     8 
-   27    44    15 
-   28    45    10 
-   29    46    12 
-   30    47    13 
-   31    48    13 
-   32    49     5 
-   33    50     5 
-   34    51     3 
-   35    52     7 
-   36    53     6 
-   37    54     2 
-   38    55     2 
-   39    56     2 
-   40    57     3 
-   41    58     1 
-   42    59     3 
-   43    61     1 
-   44    62     3 
-   45    63     1 
-   46    64     1 
-   47    65     2 
-   48    70     1 
-   49    78     1 
-   50    79     1 
-   51    80     1 
-   52    94     1 
-X000 X001 X002 X003 X004 X005 X006 X007 X008 X009 X010 X011 X012 X013 X014 X015 X016 X017 X018 X019 X020 X021 X022 X023 X024 X025 X026 X027 X028 X029 X030
----- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-   7    6    7    5    3    2    4    6    6    3    4    8    5    1    3    7    8    9    0    7    3    4    8    3    1    0    6    4    0    9    1 
-   8    8    8    6    9    3    0    8    9    4    2    4    1    7    7    5    4    2    3    7    8    3    3    4    1    8    6    7    6    0    3 
-   4    9    2    6    1    1    5    0    7    9    0    9    1    8    7    1    5    2    7    2    6    4    2    7    8    5    2    2    4    2    4 
-   8    1    9    8    4    8    8    9    2    0    2    3    1    9    5    8    7    5    8    7    9    3    3    2    0    0    1    4    9    1    7 
-   4    5    2    7    7    7    8    9    8    7    0    9    5    6    3    7    2    9    8    4    5    5    4    1    5    1    6    6    5    0    6 
-   2    3    9    9    6    1    9    6    7    0    7    7    7    3    2    7    6    0    6    6    3    5    2    5    1    1    5    0    7    3    5 
-   1    6    6    7    7    9    9    6    9    1    2    6    6    4    7    6    9    9    4    4    0    4    7    4    3    9    8    9    2    3    7 
-   1    6    2    3    9    1    4    6    8    4    1    9    6    8    9    2    3    1    6    8    4    7    1    1    7    0    1    1    5    4    3 
-   3    6    8    1    3    9    3    2    3    3    7    6    0    1    2    9    4    8    9    1    1    3    1    2    1    8    2    9    5    9    9 
-   6    4    1    8    7    3    1    1    4    5    4    3    1    0    8    2    9    9    4    8    5    6    8    1    6    5    0    5    0    3    5 
-   2    2    8    4    5    3    4    0    8    3    7    4    9    5    0    7    7    1    6    6    5    1    0    8    6    4    2    9    0    7    1 
-   6    6    1    7    6    3    7    4    5    2    0    4    0    7    4    9    1    8    1    3    4    9    9    1    1    7    8    8    9    7    4 
-   9    8    6    5    7    1    3    5    8    2    6    8    6    6    1    2    0    0    7    2    2    2    0    1    0    7    8    2    6    8    2 
-   1    1    6    3    2    3    4    5    3    7    7    6    2    2    0    0    8    0    7    7    9    4    9    6    0    2    5    2    4    4    7 
-   9    9    8    1    6    6    3    6    3    7    5    6    3    8    3    3    3    0    0    0    3    5    4    2    6    1    3    6    7    0    2 
-   6    8    2    1    5    6    7    7    4    6    0    5    9    1    0    3    5    6    5    0    0    5    7    3    8    9    6    0    2    4    8 
-   0    9    5    2    7    7    4    9    5    2    6    7    5    2    6    1    5    4    5    9    5    5    2    8    0    8    0    5    3    4    0 
-   1    6    4    1    7    9    0    1    9    3    2    1    1    8    6    1    5    0    9    1    0    6    8    3    9    2    1    7    1    1    9 
-   3    7    6    3    1    8    2    8    7    1    5    8    0    1    7    4    7    8    9    3    2    8    8    3    7    1    9    4    9    6    8 
-   2    0    4    6    8    2    0    7    5    3    0    6    2    2    2    4    0    4    5    5    3    5    8    9    0    9    3    2    7    2    1 
-   7    9    7    0    6    2    0    0    9    1    9    4    0    3    8    5    9    2    8    7    6    2    6    3    2    7    6    4    6    1    8 
-   4    8    4    1    1    7    6    0    1    7    0    2    5    1    0    5    7    7    4    5    0    6    5    0    0    8    9    6    2    5    2 
-   6    9    4    9    9    7    3    7    9    7    9    9    0    9    5    6    2    9    1    0    7    2    1    5    8    1    2    3    8    8    7 
-   1    3    9    6    2    8    5    9    9    6    5    3    5    4    8    9    4    4    0    8    1    6    1    2    4    7    0    0    6    8    2 
-   0    7    0    0    4    8    9    5    2    4    3    5    8    2    0    8    3    5    8    6    9    7    3    4    9    4    5    0    0    3    6 
-X000 X001 X002 X003 X004 X005 X006 X007 X008 X009 X010 X011 X012 X013 X014 X015 X016 X017 X018 X019 X020 X021 X022 X023 X024 X025 X026 X027 X028 X029 X030 X031 X032 X033 X034 X035 X036 X037 X038 X039 X040 X041 X042 X043 X044 X045 X046 X047 X048 X049 X050 X051 X052 X053 X054 X055 X056 X057 X058 X059 X060 X061 X062 X063 X064 X065 X066 X067 X068 X069 X070 X071 X072 X073 X074 X075 X076 X077 X078 X079 X080 X081 X082 X083 X084 X085 X086 X087 X088 X089 X090 X091 X092 X093 X094 X095 X096 X097 X098 X099 X100 X101 X102 X103 X104 X105 X106 X107 X108 X109 X110 X111 X112 X113 X114 X115 X116 X117 X118 X119 X120 X121 X122 X123 X124 X125 X126
----- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
-   7    6    7    5    3    2    4    6    6    3    4    8    5    1    3    7    8    9    0    7    3    4    8    3    1    0    6    4    0    9    1    7    5    8    5    9    2    9    5    8    4    2    8    1    5    2    9    5    1    1    3    7    5    3    2    6    5    9    4    1    8    7    5    2    3    3    8    1    5    7    6    7    5    3    2    4    6    6    3    4    8    5    1    3    7    8    9    0    7    3    4    8    3    1    0    6    4    0    9    1    7    5    8    5    9    2    9    5    8    4    2    8    1    5    2    9    5    1    1    3    7    5    3    2    6    5    8 
-   8    8    8    6    9    3    0    8    9    4    2    4    1    7    7    5    4    2    3    7    8    3    3    4    1    8    6    7    6    0    3    6    8    1    4    7    5    5    8    6    9    0    0    2    7    9    7    3    1    0    2    2    6    6    8    7    4    1    6    8    4    5    5    5    0    6    7    1    4    8    8    8    6    9    3    0    8    9    4    2    4    1    7    7    5    4    2    3    7    8    3    3    4    1    8    6    7    6    0    3    6    8    1    4    7    5    5    8    6    9    0    0    2    7    9    7    3    1    0    2    2    6    6    8    7    4    6 
-   4    9    2    6    1    1    5    0    7    9    0    9    1    8    7    1    5    2    7    2    6    4    2    7    8    5    2    2    4    2    4    8    3    8    5    6    2    0    6    9    9    8    0    2    7    8    3    4    2    1    8    8    7    2    5    5    8    6    2    6    0    0    4    1    5    2    6    0    2    4    9    2    6    1    1    5    0    7    9    0    9    1    8    7    1    5    2    7    2    6    4    2    7    8    5    2    2    4    2    4    8    3    8    5    6    2    0    6    9    9    8    0    2    7    8    3    4    2    1    8    8    7    2    5    5    8    9 
-   8    1    9    8    4    8    8    9    2    0    2    3    1    9    5    8    7    5    8    7    9    3    3    2    0    0    1    4    9    1    7    7    3    6    8    9    6    8    8    0    1    3    3    2    2    1    0    1    6    0    8    8    4    4    0    6    4    0    2    3    6    2    6    5    7    2    7    0    0    8    1    9    8    4    8    8    9    2    0    2    3    1    9    5    8    7    5    8    7    9    3    3    2    0    0    1    4    9    1    7    7    3    6    8    9    6    8    8    0    1    3    3    2    2    1    0    1    6    0    8    8    4    4    0    6    4    1 
-   4    5    2    7    7    7    8    9    8    7    0    9    5    6    3    7    2    9    8    4    5    5    4    1    5    1    6    6    5    0    6    9    5    0    6    4    7    7    4    6    6    4    5    1    2    0    8    4    9    8    8    7    6    4    0    1    6    0    6    5    9    5    0    5    3    9    1    4    9    4    5    2    7    7    7    8    9    8    7    0    9    5    6    3    7    2    9    8    4    5    5    4    1    5    1    6    6    5    0    6    9    5    0    6    4    7    7    4    6    6    4    5    1    2    0    8    4    9    8    8    7    6    4    0    1    6    6 
-   2    3    9    9    6    1    9    6    7    0    7    7    7    3    2    7    6    0    6    6    3    5    2    5    1    1    5    0    7    3    5    1    8    6    0    5    9    1    1    8    1    8    6    9    1    0    8    8    0    4    6    5    1    9    0    3    2    8    1    9    6    2    4    6    8    9    6    7    5    2    3    9    9    6    1    9    6    7    0    7    7    7    3    2    7    6    0    6    6    3    5    2    5    1    1    5    0    7    3    5    1    8    6    0    5    9    1    1    8    1    8    6    9    1    0    8    8    0    4    6    5    1    9    0    3    2    5 
-   1    6    6    7    7    9    9    6    9    1    2    6    6    4    7    6    9    9    4    4    0    4    7    4    3    9    8    9    2    3    7    3    1    5    3    9    4    2    7    6    4    1    2    0    7    9    7    6    0    3    1    0    7    0    6    3    9    5    1    0    3    2    9    9    4    4    1    5    7    1    6    6    7    7    9    9    6    9    1    2    6    6    4    7    6    9    9    4    4    0    4    7    4    3    9    8    9    2    3    7    3    1    5    3    9    4    2    7    6    4    1    2    0    7    9    7    6    0    3    1    0    7    0    6    3    9    4 
-   1    6    2    3    9    1    4    6    8    4    1    9    6    8    9    2    3    1    6    8    4    7    1    1    7    0    1    1    5    4    3    6    2    7    1    1    9    5    9    7    9    0    8    5    9    9    7    4    0    5    2    5    2    4    6    1    6    4    1    9    1    5    0    8    0    1    3    2    0    1    6    2    3    9    1    4    6    8    4    1    9    6    8    9    2    3    1    6    8    4    7    1    1    7    0    1    1    5    4    3    6    2    7    1    1    9    5    9    7    9    0    8    5    9    9    7    4    0    5    2    5    2    4    6    1    6    8 
-   3    6    8    1    3    9    3    2    3    3    7    6    0    1    2    9    4    8    9    1    1    3    1    2    1    8    2    9    5    9    9    8    5    7    2    8    8    5    0    1    0    9    9    1    2    3    2    8    3    1    9    6    6    2    8    7    1    4    1    4    8    9    6    5    0    8    4    5    7    3    6    8    1    3    9    3    2    3    3    7    6    0    1    2    9    4    8    9    1    1    3    1    2    1    8    2    9    5    9    9    8    5    7    2    8    8    5    0    1    0    9    9    1    2    3    2    8    3    1    9    6    6    2    8    7    1    0 
-   6    4    1    8    7    3    1    1    4    5    4    3    1    0    8    2    9    9    4    8    5    6    8    1    6    5    0    5    0    3    5    9    9    7    9    8    2    0    9    6    7    3    2    1    5    0    3    5    9    7    5    4    5    4    7    2    9    9    6    1    8    4    8    7    8    8    5    3    0    6    4    1    8    7    3    1    1    4    5    4    3    1    0    8    2    9    9    4    8    5    6    8    1    6    5    0    5    0    3    5    9    9    7    9    8    2    0    9    6    7    3    2    1    5    0    3    5    9    7    5    4    5    4    7    2    9    7 
-   2    2    8    4    5    3    4    0    8    3    7    4    9    5    0    7    7    1    6    6    5    1    0    8    6    4    2    9    0    7    1    2    1    9    7    6    5    1    6    3    7    5    9    8    2    9    7    9    3    4    7    8    5    8    7    1    4    7    2    3    4    3    4    1    2    3    4    4    2    2    2    8    4    5    3    4    0    8    3    7    4    9    5    0    7    7    1    6    6    5    1    0    8    6    4    2    9    0    7    1    2    1    9    7    6    5    1    6    3    7    5    9    8    2    9    7    9    3    4    7    8    5    8    7    1    4    9 
-   6    6    1    7    6    3    7    4    5    2    0    4    0    7    4    9    1    8    1    3    4    9    9    1    1    7    8    8    9    7    4    7    5    7    5    2    2    4    6    9    6    6    4    8    3    8    8    6    7    9    0    1    0    1    4    1    8    2    4    8    6    6    9    7    5    7    2    9    5    6    6    1    7    6    3    7    4    5    2    0    4    0    7    4    9    1    8    1    3    4    9    9    1    1    7    8    8    9    7    4    7    5    7    5    2    2    4    6    9    6    6    4    8    3    8    8    6    7    9    0    1    0    1    4    1    8    5 
-   9    8    6    5    7    1    3    5    8    2    6    8    6    6    1    2    0    0    7    2    2    2    0    1    0    7    8    2    6    8    2    7    7    8    2    6    9    8    3    9    2    9    9    8    7    1    3    9    3    0    1    5    4    3    6    4    0    2    0    2    6    9    8    5    4    0    9    0    8    9    8    6    5    7    1    3    5    8    2    6    8    6    6    1    2    0    0    7    2    2    2    0    1    0    7    8    2    6    8    2    7    7    8    2    6    9    8    3    9    2    9    9    8    7    1    3    9    3    0    1    5    4    3    6    4    0    6 
-   1    1    6    3    2    3    4    5    3    7    7    6    2    2    0    0    8    0    7    7    9    4    9    6    0    2    5    2    4    4    7    7    7    3    0    9    8    4    4    3    3    4    0    7    6    2    8    4    4    7    3    4    3    5    0    3    7    8    7    5    0    4    4    0    9    0    2    9    5    1    1    6    3    2    3    4    5    3    7    7    6    2    2    0    0    8    0    7    7    9    4    9    6    0    2    5    2    4    4    7    7    7    3    0    9    8    4    4    3    3    4    0    7    6    2    8    4    4    7    3    4    3    5    0    3    7    7 
-   9    9    8    1    6    6    3    6    3    7    5    6    3    8    3    3    3    0    0    0    3    5    4    2    6    1    3    6    7    0    2    8    9    3    9    8    9    4    6    4    1    2    3    5    2    6    0    8    7    3    8    0    8    3    4    4    4    5    1    3    2    8    0    7    9    0    5    5    4    9    9    8    1    6    6    3    6    3    7    5    6    3    8    3    3    3    0    0    0    3    5    4    2    6    1    3    6    7    0    2    8    9    3    9    8    9    4    6    4    1    2    3    5    2    6    0    8    7    3    8    0    8    3    4    4    4    9 
-   6    8    2    1    5    6    7    7    4    6    0    5    9    1    0    3    5    6    5    0    0    5    7    3    8    9    6    0    2    4    8    8    4    2    1    9    8    9    9    5    5    9    0    6    0    2    2    8    8    7    0    0    4    7    6    2    8    2    3    0    7    1    1    0    2    9    1    6    8    6    8    2    1    5    6    7    7    4    6    0    5    9    1    0    3    5    6    5    0    0    5    7    3    8    9    6    0    2    4    8    8    4    2    1    9    8    9    9    5    5    9    0    6    0    2    2    8    8    7    0    0    4    7    6    2    8    4 
-   0    9    5    2    7    7    4    9    5    2    6    7    5    2    6    1    5    4    5    9    5    5    2    8    0    8    0    5    3    4    0    3    5    7    5    4    5    9    4    2    4    0    0    1    5    6    2    0    1    9    1    8    6    3    8    7    4    2    0    8    2    1    3    4    2    4    3    3    3    0    9    5    2    7    7    4    9    5    2    6    7    5    2    6    1    5    4    5    9    5    5    2    8    0    8    0    5    3    4    0    3    5    7    5    4    5    9    4    2    4    0    0    1    5    6    2    0    1    9    1    8    6    3    8    7    4    8 
-   1    6    4    1    7    9    0    1    9    3    2    1    1    8    6    1    5    0    9    1    0    6    8    3    9    2    1    7    1    1    9    4    9    6    8    6    5    8    7    7    1    1    8    4    0    6    5    7    9    6    1    9    4    9    2    6    1    4    7    4    4    1    1    4    8    6    9    0    2    1    6    4    1    7    9    0    1    9    3    2    1    1    8    6    1    5    0    9    1    0    6    8    3    9    2    1    7    1    1    9    4    9    6    8    6    5    8    7    7    1    1    8    4    0    6    5    7    9    6    1    9    4    9    2    6    1    5 
-   3    7    6    3    1    8    2    8    7    1    5    8    0    1    7    4    7    8    9    3    2    8    8    3    7    1    9    4    9    6    8    5    3    6    8    7    6    0    7    4    3    4    4    5    6    2    9    3    2    1    8    7    9    6    0    8    9    3    2    7    5    8    8    1    6    5    6    4    4    3    7    6    3    1    8    2    8    7    1    5    8    0    1    7    4    7    8    9    3    2    8    8    3    7    1    9    4    9    6    8    5    3    6    8    7    6    0    7    4    3    4    4    5    6    2    9    3    2    1    8    7    9    6    0    8    9    1 
-   2    0    4    6    8    2    0    7    5    3    0    6    2    2    2    4    0    4    5    5    3    5    8    9    0    9    3    2    7    2    1    1    3    7    8    1    9    8    0    7    3    3    3    7    5    7    1    7    1    9    2    6    4    2    5    4    4    2    9    7    3    4    3    9    4    2    6    7    9    2    0    4    6    8    2    0    7    5    3    0    6    2    2    2    4    0    4    5    5    3    5    8    9    0    9    3    2    7    2    1    1    3    7    8    1    9    8    0    7    3    3    3    7    5    7    1    7    1    9    2    6    4    2    5    4    4    1 
-   7    9    7    0    6    2    0    0    9    1    9    4    0    3    8    5    9    2    8    7    6    2    6    3    2    7    6    4    6    1    8    5    2    5    8    9    9    8    9    0    1    8    6    1    3    5    9    2    9    7    9    7    1    7    0    4    5    6    3    3    9    5    8    9    3    1    8    3    4    7    9    7    0    6    2    0    0    9    1    9    4    0    3    8    5    9    2    8    7    6    2    6    3    2    7    6    4    6    1    8    5    2    5    8    9    9    8    9    0    1    8    6    1    3    5    9    2    9    7    9    7    1    7    0    4    5    8 
-   4    8    4    1    1    7    6    0    1    7    0    2    5    1    0    5    7    7    4    5    0    6    5    0    0    8    9    6    2    5    2    7    5    7    0    7    6    6    9    0    3    9    2    0    3    4    6    0    1    2    8    3    8    3    4    0    4    8    3    0    8    8    4    3    6    3    2    6    4    4    8    4    1    1    7    6    0    1    7    0    2    5    1    0    5    7    7    4    5    0    6    5    0    0    8    9    6    2    5    2    7    5    7    0    7    6    6    9    0    3    9    2    0    3    4    6    0    1    2    8    3    8    3    4    0    4    5 
-   6    9    4    9    9    7    3    7    9    7    9    9    0    9    5    6    2    9    1    0    7    2    1    5    8    1    2    3    8    8    7    4    7    3    5    8    2    9    6    2    6    7    3    8    7    8    5    1    9    6    1    9    8    3    4    8    6    8    8    0    1    5    6    8    5    3    6    3    2    6    9    4    9    9    7    3    7    9    7    9    9    0    9    5    6    2    9    1    0    7    2    1    5    8    1    2    3    8    8    7    4    7    3    5    8    2    9    6    2    6    7    3    8    7    8    5    1    9    6    1    9    8    3    4    8    6    8 
-   1    3    9    6    2    8    5    9    9    6    5    3    5    4    8    9    4    4    0    8    1    6    1    2    4    7    0    0    6    8    2    9    3    3    8    7    4    3    6    5    1    2    8    7    8    6    8    2    3    8    2    4    7    5    8    1    3    3    4    6    1    1    5    6    6    4    9    7    2    1    3    9    6    2    8    5    9    9    6    5    3    5    4    8    9    4    4    0    8    1    6    1    2    4    7    0    0    6    8    2    9    3    3    8    7    4    3    6    5    1    2    8    7    8    6    8    2    3    8    2    4    7    5    8    1    3    8 
-   0    7    0    0    4    8    9    5    2    4    3    5    8    2    0    8    3    5    8    6    9    7    3    4    9    4    5    0    0    3    6    2    0    8    3    7    8    4    2    1    8    7    8    8    0    0    6    3    6    4    2    7    1    5    1    2    1    1    1    8    5    3    2    0    1    9    4    6    6    0    7    0    0    4    8    9    5    2    4    3    5    8    2    0    8    3    5    8    6    9    7    3    4    9    4    5    0    0    3    6    2    0    8    3    7    8    4    2    1    8    7    8    8    0    0    6    3    6    4    2    7    1    5    1    2    1    8 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+"Table: Reading 1 record from ""$top_srcdir/tests/weighting.data""."
+Variable,Record,Columns,Format
+AVAR,1,1-  5,F5.0
+BVAR,1,6- 10,F5.0
+
+Table: Data List
+AVAR,BVAR
+18,1
+19,7
+20,26
+21,76
+22,57
+23,58
+24,38
+25,38
+26,30
+27,21
+28,23
+29,24
+30,23
+31,14
+32,21
+33,21
+34,14
+35,14
+36,17
+37,11
+38,16
+39,14
+40,15
+41,14
+42,14
+43,8
+44,15
+45,10
+46,12
+47,13
+48,13
+49,5
+50,5
+51,3
+52,7
+53,6
+54,2
+55,2
+56,2
+57,3
+58,1
+59,3
+61,1
+62,3
+63,1
+64,1
+65,2
+70,1
+78,1
+79,1
+80,1
+94,1
+
+Table: Data List
+Case Number,AVAR,BVAR
+1,18,1
+2,19,7
+3,20,26
+4,21,76
+5,22,57
+6,23,58
+7,24,38
+8,25,38
+9,26,30
+10,27,21
+11,28,23
+12,29,24
+13,30,23
+14,31,14
+15,32,21
+16,33,21
+17,34,14
+18,35,14
+19,36,17
+20,37,11
+21,38,16
+22,39,14
+23,40,15
+24,41,14
+25,42,14
+26,43,8
+27,44,15
+28,45,10
+29,46,12
+30,47,13
+31,48,13
+32,49,5
+33,50,5
+34,51,3
+35,52,7
+36,53,6
+37,54,2
+38,55,2
+39,56,2
+40,57,3
+41,58,1
+42,59,3
+43,61,1
+44,62,3
+45,63,1
+46,64,1
+47,65,2
+48,70,1
+49,78,1
+50,79,1
+51,80,1
+52,94,1
+
+Table: Data List
+X000,X001,X002,X003,X004,X005,X006,X007,X008,X009,X010,X011,X012,X013,X014,X015,X016,X017,X018,X019,X020,X021,X022,X023,X024,X025,X026,X027,X028,X029,X030
+7,6,7,5,3,2,4,6,6,3,4,8,5,1,3,7,8,9,0,7,3,4,8,3,1,0,6,4,0,9,1
+8,8,8,6,9,3,0,8,9,4,2,4,1,7,7,5,4,2,3,7,8,3,3,4,1,8,6,7,6,0,3
+4,9,2,6,1,1,5,0,7,9,0,9,1,8,7,1,5,2,7,2,6,4,2,7,8,5,2,2,4,2,4
+8,1,9,8,4,8,8,9,2,0,2,3,1,9,5,8,7,5,8,7,9,3,3,2,0,0,1,4,9,1,7
+4,5,2,7,7,7,8,9,8,7,0,9,5,6,3,7,2,9,8,4,5,5,4,1,5,1,6,6,5,0,6
+2,3,9,9,6,1,9,6,7,0,7,7,7,3,2,7,6,0,6,6,3,5,2,5,1,1,5,0,7,3,5
+1,6,6,7,7,9,9,6,9,1,2,6,6,4,7,6,9,9,4,4,0,4,7,4,3,9,8,9,2,3,7
+1,6,2,3,9,1,4,6,8,4,1,9,6,8,9,2,3,1,6,8,4,7,1,1,7,0,1,1,5,4,3
+3,6,8,1,3,9,3,2,3,3,7,6,0,1,2,9,4,8,9,1,1,3,1,2,1,8,2,9,5,9,9
+6,4,1,8,7,3,1,1,4,5,4,3,1,0,8,2,9,9,4,8,5,6,8,1,6,5,0,5,0,3,5
+2,2,8,4,5,3,4,0,8,3,7,4,9,5,0,7,7,1,6,6,5,1,0,8,6,4,2,9,0,7,1
+6,6,1,7,6,3,7,4,5,2,0,4,0,7,4,9,1,8,1,3,4,9,9,1,1,7,8,8,9,7,4
+9,8,6,5,7,1,3,5,8,2,6,8,6,6,1,2,0,0,7,2,2,2,0,1,0,7,8,2,6,8,2
+1,1,6,3,2,3,4,5,3,7,7,6,2,2,0,0,8,0,7,7,9,4,9,6,0,2,5,2,4,4,7
+9,9,8,1,6,6,3,6,3,7,5,6,3,8,3,3,3,0,0,0,3,5,4,2,6,1,3,6,7,0,2
+6,8,2,1,5,6,7,7,4,6,0,5,9,1,0,3,5,6,5,0,0,5,7,3,8,9,6,0,2,4,8
+0,9,5,2,7,7,4,9,5,2,6,7,5,2,6,1,5,4,5,9,5,5,2,8,0,8,0,5,3,4,0
+1,6,4,1,7,9,0,1,9,3,2,1,1,8,6,1,5,0,9,1,0,6,8,3,9,2,1,7,1,1,9
+3,7,6,3,1,8,2,8,7,1,5,8,0,1,7,4,7,8,9,3,2,8,8,3,7,1,9,4,9,6,8
+2,0,4,6,8,2,0,7,5,3,0,6,2,2,2,4,0,4,5,5,3,5,8,9,0,9,3,2,7,2,1
+7,9,7,0,6,2,0,0,9,1,9,4,0,3,8,5,9,2,8,7,6,2,6,3,2,7,6,4,6,1,8
+4,8,4,1,1,7,6,0,1,7,0,2,5,1,0,5,7,7,4,5,0,6,5,0,0,8,9,6,2,5,2
+6,9,4,9,9,7,3,7,9,7,9,9,0,9,5,6,2,9,1,0,7,2,1,5,8,1,2,3,8,8,7
+1,3,9,6,2,8,5,9,9,6,5,3,5,4,8,9,4,4,0,8,1,6,1,2,4,7,0,0,6,8,2
+0,7,0,0,4,8,9,5,2,4,3,5,8,2,0,8,3,5,8,6,9,7,3,4,9,4,5,0,0,3,6
+
+Table: Data List
+X000,X001,X002,X003,X004,X005,X006,X007,X008,X009,X010,X011,X012,X013,X014,X015,X016,X017,X018,X019,X020,X021,X022,X023,X024,X025,X026,X027,X028,X029,X030,X031,X032,X033,X034,X035,X036,X037,X038,X039,X040,X041,X042,X043,X044,X045,X046,X047,X048,X049,X050,X051,X052,X053,X054,X055,X056,X057,X058,X059,X060,X061,X062,X063,X064,X065,X066,X067,X068,X069,X070,X071,X072,X073,X074,X075,X076,X077,X078,X079,X080,X081,X082,X083,X084,X085,X086,X087,X088,X089,X090,X091,X092,X093,X094,X095,X096,X097,X098,X099,X100,X101,X102,X103,X104,X105,X106,X107,X108,X109,X110,X111,X112,X113,X114,X115,X116,X117,X118,X119,X120,X121,X122,X123,X124,X125,X126
+7,6,7,5,3,2,4,6,6,3,4,8,5,1,3,7,8,9,0,7,3,4,8,3,1,0,6,4,0,9,1,7,5,8,5,9,2,9,5,8,4,2,8,1,5,2,9,5,1,1,3,7,5,3,2,6,5,9,4,1,8,7,5,2,3,3,8,1,5,7,6,7,5,3,2,4,6,6,3,4,8,5,1,3,7,8,9,0,7,3,4,8,3,1,0,6,4,0,9,1,7,5,8,5,9,2,9,5,8,4,2,8,1,5,2,9,5,1,1,3,7,5,3,2,6,5,8
+8,8,8,6,9,3,0,8,9,4,2,4,1,7,7,5,4,2,3,7,8,3,3,4,1,8,6,7,6,0,3,6,8,1,4,7,5,5,8,6,9,0,0,2,7,9,7,3,1,0,2,2,6,6,8,7,4,1,6,8,4,5,5,5,0,6,7,1,4,8,8,8,6,9,3,0,8,9,4,2,4,1,7,7,5,4,2,3,7,8,3,3,4,1,8,6,7,6,0,3,6,8,1,4,7,5,5,8,6,9,0,0,2,7,9,7,3,1,0,2,2,6,6,8,7,4,6
+4,9,2,6,1,1,5,0,7,9,0,9,1,8,7,1,5,2,7,2,6,4,2,7,8,5,2,2,4,2,4,8,3,8,5,6,2,0,6,9,9,8,0,2,7,8,3,4,2,1,8,8,7,2,5,5,8,6,2,6,0,0,4,1,5,2,6,0,2,4,9,2,6,1,1,5,0,7,9,0,9,1,8,7,1,5,2,7,2,6,4,2,7,8,5,2,2,4,2,4,8,3,8,5,6,2,0,6,9,9,8,0,2,7,8,3,4,2,1,8,8,7,2,5,5,8,9
+8,1,9,8,4,8,8,9,2,0,2,3,1,9,5,8,7,5,8,7,9,3,3,2,0,0,1,4,9,1,7,7,3,6,8,9,6,8,8,0,1,3,3,2,2,1,0,1,6,0,8,8,4,4,0,6,4,0,2,3,6,2,6,5,7,2,7,0,0,8,1,9,8,4,8,8,9,2,0,2,3,1,9,5,8,7,5,8,7,9,3,3,2,0,0,1,4,9,1,7,7,3,6,8,9,6,8,8,0,1,3,3,2,2,1,0,1,6,0,8,8,4,4,0,6,4,1
+4,5,2,7,7,7,8,9,8,7,0,9,5,6,3,7,2,9,8,4,5,5,4,1,5,1,6,6,5,0,6,9,5,0,6,4,7,7,4,6,6,4,5,1,2,0,8,4,9,8,8,7,6,4,0,1,6,0,6,5,9,5,0,5,3,9,1,4,9,4,5,2,7,7,7,8,9,8,7,0,9,5,6,3,7,2,9,8,4,5,5,4,1,5,1,6,6,5,0,6,9,5,0,6,4,7,7,4,6,6,4,5,1,2,0,8,4,9,8,8,7,6,4,0,1,6,6
+2,3,9,9,6,1,9,6,7,0,7,7,7,3,2,7,6,0,6,6,3,5,2,5,1,1,5,0,7,3,5,1,8,6,0,5,9,1,1,8,1,8,6,9,1,0,8,8,0,4,6,5,1,9,0,3,2,8,1,9,6,2,4,6,8,9,6,7,5,2,3,9,9,6,1,9,6,7,0,7,7,7,3,2,7,6,0,6,6,3,5,2,5,1,1,5,0,7,3,5,1,8,6,0,5,9,1,1,8,1,8,6,9,1,0,8,8,0,4,6,5,1,9,0,3,2,5
+1,6,6,7,7,9,9,6,9,1,2,6,6,4,7,6,9,9,4,4,0,4,7,4,3,9,8,9,2,3,7,3,1,5,3,9,4,2,7,6,4,1,2,0,7,9,7,6,0,3,1,0,7,0,6,3,9,5,1,0,3,2,9,9,4,4,1,5,7,1,6,6,7,7,9,9,6,9,1,2,6,6,4,7,6,9,9,4,4,0,4,7,4,3,9,8,9,2,3,7,3,1,5,3,9,4,2,7,6,4,1,2,0,7,9,7,6,0,3,1,0,7,0,6,3,9,4
+1,6,2,3,9,1,4,6,8,4,1,9,6,8,9,2,3,1,6,8,4,7,1,1,7,0,1,1,5,4,3,6,2,7,1,1,9,5,9,7,9,0,8,5,9,9,7,4,0,5,2,5,2,4,6,1,6,4,1,9,1,5,0,8,0,1,3,2,0,1,6,2,3,9,1,4,6,8,4,1,9,6,8,9,2,3,1,6,8,4,7,1,1,7,0,1,1,5,4,3,6,2,7,1,1,9,5,9,7,9,0,8,5,9,9,7,4,0,5,2,5,2,4,6,1,6,8
+3,6,8,1,3,9,3,2,3,3,7,6,0,1,2,9,4,8,9,1,1,3,1,2,1,8,2,9,5,9,9,8,5,7,2,8,8,5,0,1,0,9,9,1,2,3,2,8,3,1,9,6,6,2,8,7,1,4,1,4,8,9,6,5,0,8,4,5,7,3,6,8,1,3,9,3,2,3,3,7,6,0,1,2,9,4,8,9,1,1,3,1,2,1,8,2,9,5,9,9,8,5,7,2,8,8,5,0,1,0,9,9,1,2,3,2,8,3,1,9,6,6,2,8,7,1,0
+6,4,1,8,7,3,1,1,4,5,4,3,1,0,8,2,9,9,4,8,5,6,8,1,6,5,0,5,0,3,5,9,9,7,9,8,2,0,9,6,7,3,2,1,5,0,3,5,9,7,5,4,5,4,7,2,9,9,6,1,8,4,8,7,8,8,5,3,0,6,4,1,8,7,3,1,1,4,5,4,3,1,0,8,2,9,9,4,8,5,6,8,1,6,5,0,5,0,3,5,9,9,7,9,8,2,0,9,6,7,3,2,1,5,0,3,5,9,7,5,4,5,4,7,2,9,7
+2,2,8,4,5,3,4,0,8,3,7,4,9,5,0,7,7,1,6,6,5,1,0,8,6,4,2,9,0,7,1,2,1,9,7,6,5,1,6,3,7,5,9,8,2,9,7,9,3,4,7,8,5,8,7,1,4,7,2,3,4,3,4,1,2,3,4,4,2,2,2,8,4,5,3,4,0,8,3,7,4,9,5,0,7,7,1,6,6,5,1,0,8,6,4,2,9,0,7,1,2,1,9,7,6,5,1,6,3,7,5,9,8,2,9,7,9,3,4,7,8,5,8,7,1,4,9
+6,6,1,7,6,3,7,4,5,2,0,4,0,7,4,9,1,8,1,3,4,9,9,1,1,7,8,8,9,7,4,7,5,7,5,2,2,4,6,9,6,6,4,8,3,8,8,6,7,9,0,1,0,1,4,1,8,2,4,8,6,6,9,7,5,7,2,9,5,6,6,1,7,6,3,7,4,5,2,0,4,0,7,4,9,1,8,1,3,4,9,9,1,1,7,8,8,9,7,4,7,5,7,5,2,2,4,6,9,6,6,4,8,3,8,8,6,7,9,0,1,0,1,4,1,8,5
+9,8,6,5,7,1,3,5,8,2,6,8,6,6,1,2,0,0,7,2,2,2,0,1,0,7,8,2,6,8,2,7,7,8,2,6,9,8,3,9,2,9,9,8,7,1,3,9,3,0,1,5,4,3,6,4,0,2,0,2,6,9,8,5,4,0,9,0,8,9,8,6,5,7,1,3,5,8,2,6,8,6,6,1,2,0,0,7,2,2,2,0,1,0,7,8,2,6,8,2,7,7,8,2,6,9,8,3,9,2,9,9,8,7,1,3,9,3,0,1,5,4,3,6,4,0,6
+1,1,6,3,2,3,4,5,3,7,7,6,2,2,0,0,8,0,7,7,9,4,9,6,0,2,5,2,4,4,7,7,7,3,0,9,8,4,4,3,3,4,0,7,6,2,8,4,4,7,3,4,3,5,0,3,7,8,7,5,0,4,4,0,9,0,2,9,5,1,1,6,3,2,3,4,5,3,7,7,6,2,2,0,0,8,0,7,7,9,4,9,6,0,2,5,2,4,4,7,7,7,3,0,9,8,4,4,3,3,4,0,7,6,2,8,4,4,7,3,4,3,5,0,3,7,7
+9,9,8,1,6,6,3,6,3,7,5,6,3,8,3,3,3,0,0,0,3,5,4,2,6,1,3,6,7,0,2,8,9,3,9,8,9,4,6,4,1,2,3,5,2,6,0,8,7,3,8,0,8,3,4,4,4,5,1,3,2,8,0,7,9,0,5,5,4,9,9,8,1,6,6,3,6,3,7,5,6,3,8,3,3,3,0,0,0,3,5,4,2,6,1,3,6,7,0,2,8,9,3,9,8,9,4,6,4,1,2,3,5,2,6,0,8,7,3,8,0,8,3,4,4,4,9
+6,8,2,1,5,6,7,7,4,6,0,5,9,1,0,3,5,6,5,0,0,5,7,3,8,9,6,0,2,4,8,8,4,2,1,9,8,9,9,5,5,9,0,6,0,2,2,8,8,7,0,0,4,7,6,2,8,2,3,0,7,1,1,0,2,9,1,6,8,6,8,2,1,5,6,7,7,4,6,0,5,9,1,0,3,5,6,5,0,0,5,7,3,8,9,6,0,2,4,8,8,4,2,1,9,8,9,9,5,5,9,0,6,0,2,2,8,8,7,0,0,4,7,6,2,8,4
+0,9,5,2,7,7,4,9,5,2,6,7,5,2,6,1,5,4,5,9,5,5,2,8,0,8,0,5,3,4,0,3,5,7,5,4,5,9,4,2,4,0,0,1,5,6,2,0,1,9,1,8,6,3,8,7,4,2,0,8,2,1,3,4,2,4,3,3,3,0,9,5,2,7,7,4,9,5,2,6,7,5,2,6,1,5,4,5,9,5,5,2,8,0,8,0,5,3,4,0,3,5,7,5,4,5,9,4,2,4,0,0,1,5,6,2,0,1,9,1,8,6,3,8,7,4,8
+1,6,4,1,7,9,0,1,9,3,2,1,1,8,6,1,5,0,9,1,0,6,8,3,9,2,1,7,1,1,9,4,9,6,8,6,5,8,7,7,1,1,8,4,0,6,5,7,9,6,1,9,4,9,2,6,1,4,7,4,4,1,1,4,8,6,9,0,2,1,6,4,1,7,9,0,1,9,3,2,1,1,8,6,1,5,0,9,1,0,6,8,3,9,2,1,7,1,1,9,4,9,6,8,6,5,8,7,7,1,1,8,4,0,6,5,7,9,6,1,9,4,9,2,6,1,5
+3,7,6,3,1,8,2,8,7,1,5,8,0,1,7,4,7,8,9,3,2,8,8,3,7,1,9,4,9,6,8,5,3,6,8,7,6,0,7,4,3,4,4,5,6,2,9,3,2,1,8,7,9,6,0,8,9,3,2,7,5,8,8,1,6,5,6,4,4,3,7,6,3,1,8,2,8,7,1,5,8,0,1,7,4,7,8,9,3,2,8,8,3,7,1,9,4,9,6,8,5,3,6,8,7,6,0,7,4,3,4,4,5,6,2,9,3,2,1,8,7,9,6,0,8,9,1
+2,0,4,6,8,2,0,7,5,3,0,6,2,2,2,4,0,4,5,5,3,5,8,9,0,9,3,2,7,2,1,1,3,7,8,1,9,8,0,7,3,3,3,7,5,7,1,7,1,9,2,6,4,2,5,4,4,2,9,7,3,4,3,9,4,2,6,7,9,2,0,4,6,8,2,0,7,5,3,0,6,2,2,2,4,0,4,5,5,3,5,8,9,0,9,3,2,7,2,1,1,3,7,8,1,9,8,0,7,3,3,3,7,5,7,1,7,1,9,2,6,4,2,5,4,4,1
+7,9,7,0,6,2,0,0,9,1,9,4,0,3,8,5,9,2,8,7,6,2,6,3,2,7,6,4,6,1,8,5,2,5,8,9,9,8,9,0,1,8,6,1,3,5,9,2,9,7,9,7,1,7,0,4,5,6,3,3,9,5,8,9,3,1,8,3,4,7,9,7,0,6,2,0,0,9,1,9,4,0,3,8,5,9,2,8,7,6,2,6,3,2,7,6,4,6,1,8,5,2,5,8,9,9,8,9,0,1,8,6,1,3,5,9,2,9,7,9,7,1,7,0,4,5,8
+4,8,4,1,1,7,6,0,1,7,0,2,5,1,0,5,7,7,4,5,0,6,5,0,0,8,9,6,2,5,2,7,5,7,0,7,6,6,9,0,3,9,2,0,3,4,6,0,1,2,8,3,8,3,4,0,4,8,3,0,8,8,4,3,6,3,2,6,4,4,8,4,1,1,7,6,0,1,7,0,2,5,1,0,5,7,7,4,5,0,6,5,0,0,8,9,6,2,5,2,7,5,7,0,7,6,6,9,0,3,9,2,0,3,4,6,0,1,2,8,3,8,3,4,0,4,5
+6,9,4,9,9,7,3,7,9,7,9,9,0,9,5,6,2,9,1,0,7,2,1,5,8,1,2,3,8,8,7,4,7,3,5,8,2,9,6,2,6,7,3,8,7,8,5,1,9,6,1,9,8,3,4,8,6,8,8,0,1,5,6,8,5,3,6,3,2,6,9,4,9,9,7,3,7,9,7,9,9,0,9,5,6,2,9,1,0,7,2,1,5,8,1,2,3,8,8,7,4,7,3,5,8,2,9,6,2,6,7,3,8,7,8,5,1,9,6,1,9,8,3,4,8,6,8
+1,3,9,6,2,8,5,9,9,6,5,3,5,4,8,9,4,4,0,8,1,6,1,2,4,7,0,0,6,8,2,9,3,3,8,7,4,3,6,5,1,2,8,7,8,6,8,2,3,8,2,4,7,5,8,1,3,3,4,6,1,1,5,6,6,4,9,7,2,1,3,9,6,2,8,5,9,9,6,5,3,5,4,8,9,4,4,0,8,1,6,1,2,4,7,0,0,6,8,2,9,3,3,8,7,4,3,6,5,1,2,8,7,8,6,8,2,3,8,2,4,7,5,8,1,3,8
+0,7,0,0,4,8,9,5,2,4,3,5,8,2,0,8,3,5,8,6,9,7,3,4,9,4,5,0,0,3,6,2,0,8,3,7,8,4,2,1,8,7,8,8,0,0,6,3,6,4,2,7,1,5,1,2,1,1,1,8,5,3,2,0,1,9,4,6,6,0,7,0,0,4,8,9,5,2,4,3,5,8,2,0,8,3,5,8,6,9,7,3,4,9,4,5,0,0,3,6,2,0,8,3,7,8,4,2,1,8,7,8,8,0,0,6,3,6,4,2,7,1,5,1,2,1,8
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 3501f2183f04034748f9c6da83f6499952e815ba..a57e57323d7a3a5b6079a0eb061656d7d34be294 100755 (executable)
@@ -77,50 +77,39 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------------+------+
-|   Variable   |Format|
-#==============#======#
-|AlphaBetaGamma|F8.0  |
-|B             |F8.0  |
-|X             |F8.0  |
-|Yabbadabbadoo |F8.0  |
-+--------------+------+
-AlphaBetaGamma        B        X Yabbadabbadoo
--------------- -------- -------- -------------
-          2.00     3.00     4.00          5.00 
-2.1 CROSSTABS.  Summary.
-#===============#=====================================================#
-#               #                        Cases                        #
-#               #-----------------+-----------------+-----------------#
-#               #      Valid      |     Missing     |      Total      #
-#               #--------+--------+--------+--------+--------+--------#
-#               #       N| Percent|       N| Percent|       N| Percent#
-#---------------#--------+--------+--------+--------+--------+--------#
-#X *            #       1|  100.0%|       0|    0.0%|       1|  100.0%#
-#Yabbadabbadoo  #        |        |        |        |        |        #
-#===============#========#========#========#========#========#========#
-2.2 CROSSTABS.  X * Yabbadabbadoo [count].
-#===============#==============================================================#========#
-#               #                         Yabbadabbadoo                        |        #
-#               #--------+--------+--------+--------+--------+--------+--------+        #
-#              X#    1.00|    2.00|    3.00|    4.00|    5.00|    6.00|    7.00|  Total #
-#---------------#--------+--------+--------+--------+--------+--------+--------+--------#
-#           1.00#      .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|      .0|     1.0#
-#           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|      .0|     1.0#
-#===============#========#========#========#========#========#========#========#========#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+AlphaBetaGamma,F8.0
+B,F8.0
+X,F8.0
+Yabbadabbadoo,F8.0
+
+Table: Data List
+AlphaBetaGamma,B,X,Yabbadabbadoo
+2.00,3.00,4.00,5.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+X * Yabbadabbadoo,1,100.0%,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,.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,.0,1.0
+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,.0,1.0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 813777f4acea547542e62ce827faecb439877bac..c49633e61767065742f8ae89ed98527d4701d05b 100755 (executable)
@@ -131,7 +131,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e $TEMPDIR/stdout $TEMPDIR/loop.stat 
+$SUPERVISOR $PSPP -o pspp.csv -e $TEMPDIR/stdout $TEMPDIR/loop.stat 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare stdout"
@@ -141,82 +141,155 @@ EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list  - <<EOF
+diff -c $TEMPDIR/pspp.csv  - <<EOF
 Loop with index
-    1.00 
-    2.00 
+
+1.00 
+
+2.00 
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
-    3.00 
-    6.00 
-    9.00 
+
+3.00 
+
+6.00 
+
+9.00 
+
 --------
+
 --------
+
 Loop with IF condition
-    1.00 
-    2.00 
+
+1.00 
+
+2.00 
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
-    3.00 
-    6.00 
-    9.00 
+
+3.00 
+
+6.00 
+
+9.00 
+
 --------
+
 --------
+
 Loop with END IF condition
-    1.00 
-    2.00 
+
+1.00 
+
+2.00 
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
-    3.00 
-    6.00 
-    9.00 
+
+3.00 
+
+6.00 
+
+9.00 
+
 --------
-    4.00 
+
+4.00 
+
 --------
+
 Loop with index and IF condition based on index
-    1.00 
-    2.00 
+
+1.00 
+
+2.00 
+
 --------
-    2.00 
+
+2.00 
+
 --------
-    3.00 
+
+3.00 
+
 --------
+
 --------
+
 Loop with index and END IF condition based on index
-    1.00 
-    2.00 
+
+1.00 
+
+2.00 
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
-    3.00 
-    6.00 
+
+3.00 
+
+6.00 
+
 --------
+
 --------
+
 Loop with index and IF and END IF condition based on index
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
+
 --------
+
 --------
+
 Loop with no conditions
-    1.00 
+
+1.00 
+
 --------
-    2.00 
-    4.00 
+
+2.00 
+
+4.00 
+
 --------
-    3.00 
-    6.00 
+
+3.00 
+
+6.00 
+
 --------
-    4.00 
+
+4.00 
+
 --------
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
index 9726b065c7da65d9bf09a13e188da46d062d8ad8..29d566961753387677ebbfb87b2b9d166d3a8f13 100755 (executable)
@@ -85,40 +85,40 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 cat > ff.out <<EOF
-A B C D INA INB FIRST LAST
-- - - - --- --- ----- ----
-0 a A     1   0     1    1
-1 a B N   1   1     1    0
-1 a C     1   0     0    1
-2 a D     1   0     1    1
-3 a E O   1   1     1    1
-4 a F P   1   1     1    1
-5 a G     1   0     1    0
-5 a H     1   0     0    1
-6 a I Q   1   1     1    1
-7 a J R   1   1     1    0
-7 a K     1   0     0    0
-7 a L     1   0     0    1
-8 a M     1   0     1    1
-9 b   S   0   1     1    1
+Table: Data List
+A,B,C,D,INA,INB,FIRST,LAST
+0,a,A,,1,0,1,1
+1,a,B,N,1,1,1,0
+1,a,C,,1,0,0,1
+2,a,D,,1,0,1,1
+3,a,E,O,1,1,1,1
+4,a,F,P,1,1,1,1
+5,a,G,,1,0,1,0
+5,a,H,,1,0,0,1
+6,a,I,Q,1,1,1,1
+7,a,J,R,1,1,1,0
+7,a,K,,1,0,0,0
+7,a,L,,1,0,0,1
+8,a,M,,1,0,1,1
+9,b,,S,0,1,1,1
 EOF
 
 cat > ft.out <<EOF
-A B C D INA INB FIRST LAST
-- - - - --- --- ----- ----
-0 a A     1   0     1    1
-1 a B N   1   1     1    0
-1 a C N   1   1     0    1
-2 a D     1   0     1    1
-3 a E O   1   1     1    1
-4 a F P   1   1     1    1
-5 a G     1   0     1    0
-5 a H     1   0     0    1
-6 a I Q   1   1     1    1
-7 a J R   1   1     1    0
-7 a K R   1   1     0    0
-7 a L R   1   1     0    1
-8 a M     1   0     1    1
+Table: Data List
+A,B,C,D,INA,INB,FIRST,LAST
+0,a,A,,1,0,1,1
+1,a,B,N,1,1,1,0
+1,a,C,N,1,1,0,1
+2,a,D,,1,0,1,1
+3,a,E,O,1,1,1,1
+4,a,F,P,1,1,1,1
+5,a,G,,1,0,1,0
+5,a,H,,1,0,0,1
+6,a,I,Q,1,1,1,1
+7,a,J,R,1,1,1,0
+7,a,K,R,1,1,0,0
+7,a,L,R,1,1,0,1
+8,a,M,,1,0,1,1
 EOF
 
 # Test nonparallel match and table lookup.
@@ -174,13 +174,11 @@ EOF
        if [ $? -ne 0 ] ; then no_result ; fi
 
        activity="run $name.pspp"
-       $SUPERVISOR $PSPP --testing-mode -e /dev/null $name.pspp 
+       $SUPERVISOR $PSPP -o pspp.csv -e /dev/null $name.pspp 
        if [ $? -ne 0 ] ; then no_result ; fi
 
        activity="check $name output"
-       perl -pi -e 's/^\s*$//g' pspp.list
-       perl -pi -e 's/^\s*$//g' $types.out
-       diff -b -w pspp.list $types.out
+       diff -c pspp.csv $types.out
        if [ $? -ne 0 ] ; then fail ; fi
     done
 done
@@ -199,27 +197,26 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run $name.pspp"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $name.pspp 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $name.pspp 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check $name output"
-perl -pi -e 's/^\s*$//g' pspp.list
-diff -b -w - pspp.list <<EOF
-A B C D E F
-- - - - - -
-1 a B 1 b N
-8 a M 3 b O
-3 a E 4 b P
-5 a G 6 b Q
-0 a A 7 b R
-5 a H 9 b S
-6 a I
-7 a J
-2 a D
-7 a K
-1 a C
-7 a L
-4 a F
+diff -c - pspp.csv <<EOF
+Table: Data List
+A,B,C,D,E,F
+1,a,B,1,b,N
+8,a,M,3,b,O
+3,a,E,4,b,P
+5,a,G,6,b,Q
+0,a,A,7,b,R
+5,a,H,9,b,S
+6,a,I,,,
+7,a,J,,,
+2,a,D,,,
+7,a,K,,,
+1,a,C,,,
+7,a,L,,,
+4,a,F,,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -248,17 +245,16 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run $name.pspp"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $name.pspp 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $name.pspp 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check $name output"
-perl -pi -e 's/^\s*$//g' pspp.list
-diff -b -w - pspp.list <<EOF | perl -e 's/^\s*$//g'
-        x        z        y
- -------- -------- --------
-     3.00     8.00    30.00 
-     2.00      .      21.00 
-     1.00      .      22.00 
+diff -c - pspp.csv <<EOF
+Table: Data List
+x,z,y
+3.00,8.00,30.00
+2.00,.  ,21.00
+1.00,.  ,22.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index c01adf3112749194e5037eb80cfe3cf8fc01d4fa..a4cde41ba952b58680ae119f9fde138c9f65403b 100755 (executable)
@@ -119,7 +119,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode --error-file=$TEMPDIR/errs $TEMPDIR/missing-values.stat 
+$SUPERVISOR $PSPP -o pspp.csv --error-file=$TEMPDIR/errs $TEMPDIR/missing-values.stat 
 # Note   vv   --- there are errors in input.  Therefore, the  command must FAIL
 if [ $? -eq 0 ] ; then fail ; fi
 
index 547135559f13de4dc1b815d9cbcdbda13ca6eced..bb685f84ac311bb5da2918ecdfa731f4dad1934e 100755 (executable)
@@ -76,30 +76,29 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-       X
---------
-    1.00 
-    2.00 
-    3.00 
-    4.00 
-    5.00 
-    6.00 
-    7.00 
-    8.00 
-    9.00 
-   10.00 
-   11.00 
-   12.00 
-   13.00 
-   14.00 
-   15.00 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Data List
+X
+1.00
+2.00
+3.00
+4.00
+5.00
+6.00
+7.00
+8.00
+9.00
+10.00
+11.00
+12.00
+13.00
+14.00
+15.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 0c94051a1eb8e5e8098e42d5b50cee7b5938a483..9e7921225b9aaab00cac5b1f87228235272bd3d9 100755 (executable)
@@ -68,49 +68,42 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' pspp.list
-diff -b -w pspp.list - <<EOF
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|cont    |continents of the world                    |       1|
-|        |Format: A32                                |        |
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|size    |sq km                                      |       2|
-|        |Format: F8.2                               |        |
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|pop     |population                                 |       3|
-|        |Format: F8.2                               |        |
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|count   |number of countries                        |       4|
-|        |Format: F8.2                               |        |
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-                            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 
+diff -c pspp.csv - <<EOF
+Variable,Description,,Position
+cont,continents of the world,,1
+,Format: A32,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+size,sq km,,2
+,Format: F8.2,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+pop,population,,3
+,Format: F8.2,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+count,number of countries,,4
+,Format: F8.2,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 0db048dd34703054bd88b7da91a17f81ae579812..ea892b15ca6eaebab45170222048c0e570fce2a2 100755 (executable)
@@ -247,111 +247,98 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - << EOF
+diff -c $TEMPDIR/pspp.csv - << EOF
 P < 0.5; N1/N2 < 1
-1.1 NPAR TESTS.  Binomial Test
-+-+------#--------+-----+--------------+----------+---------------------+
-| |      #Category|  N  |Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+-----+--------------+----------+---------------------+
-|x|Group1#    1.00| 6.00|          .286|      .300|                 .551|
-| |Group2#    2.00|15.00|          .714|          |                     |
-| |Total #        |21.00|         1.000|          |                     |
-+-+------#--------+-----+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1.00,6.00,.286,.300,.551
+,Group2,2.00,15.00,.714,,
+,Total,,21.00,1.000,,
+
 P < 0.5; N1/N2 > 1
-2.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1| 7|          .538|      .400|                 .229|
-| |Group2#       2| 6|          .462|          |                     |
-| |Total #        |13|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1,7,.538,.400,.229
+,Group2,2,6,.462,,
+,Total,,13,1.000,,
+
 P < 0.5; N1/N2 = 1
-3.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1| 8|          .500|      .400|                 .284|
-| |Group2#       2| 8|          .500|          |                     |
-| |Total #        |16|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1,8,.500,.400,.284
+,Group2,2,8,.500,,
+,Total,,16,1.000,,
+
 P > 0.5; N1/N2 < 1
-4.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1|11|          .478|      .600|                 .164|
-| |Group2#       2|12|          .522|          |                     |
-| |Total #        |23|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1,11,.478,.600,.164
+,Group2,2,12,.522,,
+,Total,,23,1.000,,
+
 P > 0.5; N1/N2 > 1
-5.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1|11|          .550|      .600|                 .404|
-| |Group2#       2| 9|          .450|          |                     |
-| |Total #        |20|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1,11,.550,.600,.404
+,Group2,2,9,.450,,
+,Total,,20,1.000,,
+
 P > 0.5; N1/N2 == 1
-6.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (1-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1|11|          .500|      .600|                 .228|
-| |Group2#       2|11|          .500|          |                     |
-| |Total #        |22|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (1-tailed)
+x,Group1,1,11,.500,.600,.228
+,Group2,2,11,.500,,
+,Total,,22,1.000,,
+
 P == 0.5; N1/N2 < 1
-7.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (2-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1| 8|          .348|      .500|                 .210|
-| |Group2#       2|15|          .652|          |                     |
-| |Total #        |23|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
+x,Group1,1,8,.348,.500,.210
+,Group2,2,15,.652,,
+,Total,,23,1.000,,
+
 P == 0.5; N1/N2 > 1
-8.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (2-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1|12|          .667|      .500|                 .238|
-| |Group2#       2| 6|          .333|          |                     |
-| |Total #        |18|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+Table: Binomial Test
+,,Category,N,Observed Prop.,Test Prop.,Exact Sig. (2-tailed)
+x,Group1,1,12,.667,.500,.238
+,Group2,2,6,.333,,
+,Total,,18,1.000,,
+
 P == 0.5; N1/N2 == 1
-9.1 NPAR TESTS.  Binomial Test
-+-+------#--------+--+--------------+----------+---------------------+
-| |      #Category| N|Observed Prop.|Test Prop.|Exact Sig. (2-tailed)|
-+-+------#--------+--+--------------+----------+---------------------+
-|x|Group1#       1|10|          .500|      .500|                1.000|
-| |Group2#       2|10|          .500|          |                     |
-| |Total #        |20|         1.000|          |                     |
-+-+------#--------+--+--------------+----------+---------------------+
+
+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,,
+,Total,,20,1.000,,
+
 P == 0.5; N1/N2 == 1 Cutpoint
-10.1 NPAR TESTS.  Binomial Test
-+-+------#--------+------+--------------+----------+---------------------+
-| |      #Category|   N  |Observed Prop.|Test Prop.|Exact Sig. (2-tailed)|
-+-+------#--------+------+--------------+----------+---------------------+
-|x|Group1#   <= 10|10.000|          .385|      .500|                 .327|
-| |Group2#        |16.000|          .615|          |                     |
-| |Total #        |26.000|         1.000|          |                     |
-+-+------#--------+------+--------------+----------+---------------------+
+
+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,,
+,Total,,26.000,1.000,,
+
 P == 0.5; N1/N2 == 1 Named values
-11.1 NPAR TESTS.  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|          |                     |
-| |Total #        |23.000|         1.000|          |                     |
-+-+------#--------+------+--------------+----------+---------------------+
+
+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,,
+,Total,,23.000,1.000,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 33e2311bc9b49bfcd3756b5ccc91373d35db4fc1..8ee9bb8e5996421541492269246e14a0b659c807 100755 (executable)
@@ -92,79 +92,62 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - << EOF
-1.1 NPAR TESTS.  x
-+--------#----------+----------+--------+
-|        #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|
-|    3.20#      1.00|      2.33|   -1.33|
-|    4.00#      2.00|      2.33|    -.33|
-|    5.00#      1.00|      2.33|   -1.33|
-|Total   #     14.00|          |        |
-+--------#----------+----------+--------+
-1.2 NPAR TESTS.  y
-+--------#----------+----------+--------+
-|        #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|
-|    4.00#      2.00|      3.50|   -1.50|
-|Total   #     14.00|          |        |
-+--------#----------+----------+--------+
-1.3 NPAR TESTS.  Test Statistics
-+-----------#----+----+
-|           #  x |  y |
-+-----------#----+----+
-|Chi-Square #3.14|6.00|
-|df         #   5|   3|
-|Asymp. Sig.# .68| .11|
-+-----------#----+----+
-2.1 NPAR TESTS.  y
-+--------#----------+----------+--------+
-|        #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|
-|    4.00#      2.00|      3.50|   -1.50|
-|Total   #     14.00|          |        |
-+--------#----------+----------+--------+
-2.2 NPAR TESTS.  Test Statistics
-+-----------#-----+
-|           #  y  |
-+-----------#-----+
-|Chi-Square #10.61|
-|df         #    3|
-|Asymp. Sig.#  .01|
-+-----------#-----+
-3.1 NPAR TESTS.  Frequencies
-+-----#---------------------------------------#---------------------------------------+
-|     #                   x                   #                   y                   |
-|     #--------+----------+----------+--------#--------+----------+----------+--------+
-|     #Category|Observed N|Expected N|Residual#Category|Observed N|Expected N|Residual|
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-|1    #    2.00|      3.00|      3.16|    -.16#    2.00|      4.00|      2.21|    1.79|
-|2    #    3.00|      5.00|      5.26|    -.26#    3.00|      1.00|      3.68|   -2.68|
-|3    #    4.00|      2.00|      1.58|     .42#    4.00|      2.00|      1.11|     .89|
-|Total#        |     10.00|          |        #        |      7.00|          |        |
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-3.2 NPAR TESTS.  Test Statistics
-+-----------#---+----+
-|           # x |  y |
-+-----------#---+----+
-|Chi-Square #.13|4.13|
-|df         #  2|   2|
-|Asymp. Sig.#.94| .13|
-+-----------#---+----+
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: x
+,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
+3.20,1.00,2.33,-1.33
+4.00,2.00,2.33,-.33
+5.00,1.00,2.33,-1.33
+Total,14.00,,
+
+Table: y
+,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
+4.00,2.00,3.50,-1.50
+Total,14.00,,
+
+Table: Test Statistics
+,x,y
+Chi-Square,3.14,6.00
+df,5,3
+Asymp. Sig.,.68,.11
+
+Table: y
+,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
+4.00,2.00,3.50,-1.50
+Total,14.00,,
+
+Table: Test Statistics
+,y
+Chi-Square,10.61
+df,3
+Asymp. Sig.,.01
+
+Table: Frequencies
+,x,,,,y,,,
+,Category,Observed N,Expected N,Residual,Category,Observed N,Expected N,Residual
+1,2.00,3.00,3.16,-.16,2.00,4.00,2.21,1.79
+2,3.00,5.00,5.26,-.26,3.00,1.00,3.68,-2.68
+3,4.00,2.00,1.58,.42,4.00,2.00,1.11,.89
+Total,,10.00,,,,7.00,,
+
+Table: Test Statistics
+,x,y
+Chi-Square,.13,4.13
+df,2,2
+Asymp. Sig.,.94,.13
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -193,7 +176,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE  > $TEMPDIR/output
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE  > $TEMPDIR/output
 if [ $? -eq 0 ] ; then no_result ; fi
 
 activity="compare errors 2"
@@ -232,45 +215,36 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output 3"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 NPAR TESTS.  Frequencies
-+-----#---------------------------------------#---------------------------------------+
-|     #                   x                   #                   y                   |
-|     #--------+----------+----------+--------#--------+----------+----------+--------+
-|     #Category|Observed N|Expected N|Residual#Category|Observed N|Expected N|Residual|
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-|1    #   -2.00|       .00|      1.50|   -1.50#   -2.00|       .00|      1.88|   -1.88|
-|2    #   -1.00|       .00|      1.50|   -1.50#   -1.00|       .00|      1.88|   -1.88|
-|3    #     .00|       .00|      1.50|   -1.50#     .00|       .00|      1.88|   -1.88|
-|4    #    1.00|      3.00|      1.50|    1.50#    1.00|      7.00|      1.88|    5.13|
-|5    #    2.00|      3.00|      1.50|    1.50#    2.00|      4.00|      1.88|    2.13|
-|6    #    3.00|      5.00|      1.50|    3.50#    3.00|      1.00|      1.88|    -.88|
-|7    #    4.00|       .00|      1.50|   -1.50#    4.00|      2.00|      1.88|     .13|
-|8    #    5.00|      1.00|      1.50|    -.50#    5.00|      1.00|      1.88|    -.88|
-|Total#        |     12.00|          |        #        |     15.00|          |        |
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-1.2 NPAR TESTS.  Test Statistics
-+-----------#-----+-----+
-|           #  x  |  y  |
-+-----------#-----+-----+
-|Chi-Square #17.33|22.87|
-|df         #    7|    7|
-|Asymp. Sig.#  .02|  .00|
-+-----------#-----+-----+
-1.3 NPAR TESTS.  Descriptive Statistics
-+-#-----+----+----+----+----+
-| #  N  |Mean|Std.|Mini|Maxi|
-| #     |    |Devi| mum| mum|
-#=#=====#====#====#====#====#
-|x#12.00|2.47|1.19|1.00|5.00|
-|y#15.00|2.07|1.33|1.00|5.00|
-+-#-----+----+----+----+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Frequencies
+,x,,,,y,,,
+,Category,Observed N,Expected N,Residual,Category,Observed N,Expected N,Residual
+1,-2.00,.00,1.50,-1.50,-2.00,.00,1.88,-1.88
+2,-1.00,.00,1.50,-1.50,-1.00,.00,1.88,-1.88
+3,.00,.00,1.50,-1.50,.00,.00,1.88,-1.88
+4,1.00,3.00,1.50,1.50,1.00,7.00,1.88,5.13
+5,2.00,3.00,1.50,1.50,2.00,4.00,1.88,2.13
+6,3.00,5.00,1.50,3.50,3.00,1.00,1.88,-.88
+7,4.00,.00,1.50,-1.50,4.00,2.00,1.88,.13
+8,5.00,1.00,1.50,-.50,5.00,1.00,1.88,-.88
+Total,,12.00,,,,15.00,,
+
+Table: Test Statistics
+,x,y
+Chi-Square,17.33,22.87
+df,7,7
+Asymp. Sig.,.02,.00
+
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -303,45 +277,36 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 4"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output 4"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 NPAR TESTS.  Frequencies
-+-----#---------------------------------------#---------------------------------------+
-|     #                   x                   #                   y                   |
-|     #--------+----------+----------+--------#--------+----------+----------+--------+
-|     #Category|Observed N|Expected N|Residual#Category|Observed N|Expected N|Residual|
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-|1    #   -2.00|       .00|      1.75|   -1.75#   -2.00|       .00|      1.75|   -1.75|
-|2    #   -1.00|       .00|      1.75|   -1.75#   -1.00|       .00|      1.75|   -1.75|
-|3    #     .00|       .00|      1.75|   -1.75#     .00|       .00|      1.75|   -1.75|
-|4    #    1.00|      3.00|      1.75|    1.25#    1.00|      7.00|      1.75|    5.25|
-|5    #    2.00|      3.00|      1.75|    1.25#    2.00|      4.00|      1.75|    2.25|
-|6    #    3.00|      5.00|      1.75|    3.25#    3.00|      1.00|      1.75|    -.75|
-|7    #    4.00|      2.00|      1.75|     .25#    4.00|      2.00|      1.75|     .25|
-|8    #    5.00|      1.00|      1.75|    -.75#    5.00|       .00|      1.75|   -1.75|
-|Total#        |     14.00|          |        #        |     14.00|          |        |
-+-----#--------+----------+----------+--------#--------+----------+----------+--------+
-1.2 NPAR TESTS.  Test Statistics
-+-----------#-----+-----+
-|           #  x  |  y  |
-+-----------#-----+-----+
-|Chi-Square #13.43|26.00|
-|df         #    7|    7|
-|Asymp. Sig.#  .06|  .00|
-+-----------#-----+-----+
-1.3 NPAR TESTS.  Descriptive Statistics
-+-#-----+----+----+----+----+
-| #  N  |Mean|Std.|Mini|Maxi|
-| #     |    |Devi| mum| mum|
-#=#=====#====#====#====#====#
-|x#14.00|2.69|1.23|1.00|5.00|
-|y#14.00|1.86|1.10|1.00|4.00|
-+-#-----+----+----+----+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Frequencies
+,x,,,,y,,,
+,Category,Observed N,Expected N,Residual,Category,Observed N,Expected N,Residual
+1,-2.00,.00,1.75,-1.75,-2.00,.00,1.75,-1.75
+2,-1.00,.00,1.75,-1.75,-1.00,.00,1.75,-1.75
+3,.00,.00,1.75,-1.75,.00,.00,1.75,-1.75
+4,1.00,3.00,1.75,1.25,1.00,7.00,1.75,5.25
+5,2.00,3.00,1.75,1.25,2.00,4.00,1.75,2.25
+6,3.00,5.00,1.75,3.25,3.00,1.00,1.75,-.75
+7,4.00,2.00,1.75,.25,4.00,2.00,1.75,.25
+8,5.00,1.00,1.75,-.75,5.00,.00,1.75,-1.75
+Total,,14.00,,,,14.00,,
+
+Table: Test Statistics
+,x,y
+Chi-Square,13.43,26.00
+df,7,7
+Asymp. Sig.,.06,.00
+
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 17c0c239985023f41d098e3e29596bc6956c01a8..03c8117c91ce38cf55b87635c8863bce326c7220 100755 (executable)
@@ -81,35 +81,27 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 1"
-diff - $TEMPDIR/pspp.list <<EOF
-1.1 NPAR TESTS.  Frequencies
-#=================================#=#
-#                                 |N#
-#---------------------------------+-#
-#height - age Negative Differences|1#
-#             Positive Differences|3#
-#             Ties                |2#
-#             Total               |6#
-#---------------------------------+-#
-#rank - heightNegative Differences|3#
-#             Positive Differences|2#
-#             Ties                |1#
-#             Total               |6#
-#=================================#=#
-
-1.2 NPAR TESTS.  Test Statistics
-#=====================#============#=============#
-#                     |height - age|rank - height#
-#=====================#============#=============#
-#Exact Sig. (2-tailed)|        .625|        1.000#
-#Exact Sig. (1-tailed)|        .312|         .500#
-#Point Probability    |        .250|         .312#
-#=====================#============#=============#
-
+diff -c - $TEMPDIR/pspp.csv <<EOF
+Table: Frequencies
+,,N
+height - age,Negative Differences,1
+,Positive Differences,3
+,Ties,2
+,Total,6
+rank - height,Negative Differences,3
+,Positive Differences,2
+,Ties,1
+,Total,6
+
+Table: Test Statistics
+,height - age,rank - height
+Exact Sig. (2-tailed),.625,1.000
+Exact Sig. (1-tailed),.312,.500
+Point Probability,.250,.312
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 4242b55b6581dcd82e551392856857c7fc3919e0..f259ea957add9dd5b44d6bcb02da4f5bfcabd87e 100755 (executable)
@@ -91,37 +91,30 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="generate results"
-cat > $TEMPDIR/results.txt <<EOF
-1.1 NPAR TESTS.  Ranks
-#============================#==#=========#============#
-#                            # N|Mean Rank|Sum of Ranks#
-#============================#==#=========#============#
-#second - firstNegative Ranks# 5|     8.60|       43.00#
-#              Positive Ranks# 8|     6.00|       48.00#
-#              Ties          # 2|         |            #
-#              Total         #15|         |            #
-#============================#==#=========#============#
-
-1.2 NPAR TESTS.  Test Statistics
-#======================#==============#
-#                      #second - first#
-#======================#==============#
-#Z                     #          -.18#
-#Asymp. Sig. (2-tailed)#           .86#
-#Exact Sig. (2-tailed) #           .89#
-#Exact Sig. (1-tailed) #           .45#
-#======================#==============#
-
+cat > $TEMPDIR/results.csv <<EOF
+Table: Ranks
+,,N,Mean Rank,Sum of Ranks
+second - first,Negative Ranks,5,8.60,43.00
+,Positive Ranks,8,6.00,48.00
+,Ties,2,,
+,Total,15,,
+
+Table: Test Statistics
+,second - first
+Z,-.18
+Asymp. Sig. (2-tailed),.86
+Exact Sig. (2-tailed),.89
+Exact Sig. (1-tailed),.45
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output 1"
-diff pspp.list $TEMPDIR/results.txt
+diff -c pspp.csv $TEMPDIR/results.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
@@ -161,11 +154,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output 2"
-diff pspp.list $TEMPDIR/results.txt
+diff pspp.csv $TEMPDIR/results.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 2b16368b121d4c3b270055fe3b87fc381258a6bc..5fe701b0a225270dafe7c41fa83dce55c2d154fa 100755 (executable)
@@ -88,11 +88,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/pspp.list1
+cp $TEMPDIR/pspp.csv $TEMPDIR/pspp.csv1
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -126,11 +126,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare outputs"
-diff $TEMPDIR/pspp.list $TEMPDIR/pspp.list1
+diff $TEMPDIR/pspp.csv $TEMPDIR/pspp.csv1
 if [ $? -ne 0 ] ; then fail ; fi
 
 # Now try a missing dependent variable
@@ -166,11 +166,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare outputs"
-diff $TEMPDIR/pspp.list $TEMPDIR/pspp.list1
+diff $TEMPDIR/pspp.csv $TEMPDIR/pspp.csv1
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 7197a096f8ee59709e9ef7529ed7baec9c2bbf5d..35cc76de5bf55b9b9e62d759ca737bb2b70fbdd8 100755 (executable)
@@ -96,120 +96,81 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e s/^\s*\$//g $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF | perl -e 's/^\s*$//g'
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|QUALITY |F8.0  |
-|BRAND   |F8.0  |
-|S       |F8.0  |
-+--------+------+
-
-Variable Value    Label
-S            1.00
-
-2.1 ONEWAY.  Descriptives
-#===============#=======#=#====#==============#==========#=======================#=======#=======#
-#               |       # |    |              |          |    95% Confidence     |       |       #
-#               |       # |    |              |          +-----------+-----------+       |       #
-#               |       #N|Mean|Std. Deviation|Std. Error|Lower Bound|Upper Bound|Minimum|Maximum#
-#===============#=======#=#====#==============#==========#===========#===========#=======#=======#
-#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#
-#===============#=======#=#====#==============#==========#===========#===========#=======#=======#
-
-2.2 ONEWAY.  Test of Homogeneity of Variances
-#===============#================#===#===#============#
-#               #Levene Statistic|df1|df2|Significance#
-#===============#================#===#===#============#
-#Breaking Strain#           1.086|  1|  5|        .345#
-#===============#================#===#===#============#
-
-2.3 ONEWAY.  ANOVA
-#==============================#==============#==#===========#=====#============#
-#                              #Sum of Squares|df|Mean Square|  F  |Significance#
-#===============#==============#==============#==#===========#=====#============#
-#Breaking Strain|Between Groups#          2.41| 1|      2.414|1.068|        .349#
-#               |Within Groups #         11.30| 5|      2.260|     |            #
-#               |Total         #         13.71| 6|           |     |            #
-#===============#==============#==============#==#===========#=====#============#
-
-2.4 ONEWAY.  Contrast Coefficients
-#==========#==============#
-#          # Manufacturer #
-#          #-------+------#
-#          #Aspeger|Bloggs#
-#========#=#=======#======#
-#Contrast|1#     -2|     2#
-#        |2#     -1|     1#
-#========#=#=======#======#
-
-2.5 ONEWAY.  Contrast Tests
-#===============================================#=================#==========#=====#=====#===============#
-#                                       Contrast#Value of Contrast|Std. Error|  t  |  df |Sig. (2-tailed)#
-#===============#======================#========#=================#==========#=====#=====#===============#
-#Breaking Strain|Assume equal variances|    1   #             2.60|     2.516|1.034|    5|           .349#
-#               |                      |    2   #             1.30|     1.258|1.034|    5|           .349#
-#               |Does not assume equal |    1   #             2.60|     3.219| .808|1.318|           .539#
-#               |                      |    2   #             1.30|     1.609| .808|1.318|           .539#
-#===============#======================#========#=================#==========#=====#=====#===============#
-
-Variable Value    Label
-S            2.00
-
-2.6 ONEWAY.  Descriptives
-#===============#========#=#====#==============#==========#=======================#=======#=======#
-#               |        # |    |              |          |    95% Confidence     |       |       #
-#               |        # |    |              |          +-----------+-----------+       |       #
-#               |        #N|Mean|Std. Deviation|Std. Error|Lower Bound|Upper Bound|Minimum|Maximum#
-#===============#========#=#====#==============#==========#===========#===========#=======#=======#
-#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#
-#===============#========#=#====#==============#==========#===========#===========#=======#=======#
-
-2.7 ONEWAY.  Test of Homogeneity of Variances
-#===============#================#===#===#============#
-#               #Levene Statistic|df1|df2|Significance#
-#===============#================#===#===#============#
-#Breaking Strain#            .923|  1|  6|        .374#
-#===============#================#===#===#============#
-
-2.8 ONEWAY.  ANOVA
-#==============================#==============#==#===========#=====#============#
-#                              #Sum of Squares|df|Mean Square|  F  |Significance#
-#===============#==============#==============#==#===========#=====#============#
-#Breaking Strain|Between Groups#          7.50| 1|      7.500|3.750|        .101#
-#               |Within Groups #         12.00| 6|      2.000|     |            #
-#               |Total         #         19.50| 7|           |     |            #
-#===============#==============#==============#==#===========#=====#============#
-
-2.9 ONEWAY.  Contrast Coefficients
-#==========#===============#
-#          #  Manufacturer #
-#          #------+--------#
-#          #Bloggs|Charlies#
-#========#=#======#========#
-#Contrast|1#    -2|       2#
-#        |2#    -1|       1#
-#========#=#======#========#
-
-2.10 ONEWAY.  Contrast Tests
-#===============================================#=================#==========#=====#=====#===============#
-#                                       Contrast#Value of Contrast|Std. Error|  t  |  df |Sig. (2-tailed)#
-#===============#======================#========#=================#==========#=====#=====#===============#
-#Breaking Strain|Assume equal variances|    1   #             4.00|     2.066|1.936|    6|           .101#
-#               |                      |    2   #             2.00|     1.033|1.936|    6|           .101#
-#               |Does not assume equal |    1   #             4.00|     1.826|2.191|5.882|           .072#
-#               |                      |    2   #             2.00|      .913|2.191|5.882|           .072#
-#===============#======================#========#=================#==========#=====#=====#===============#
-
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+QUALITY,F8.0
+BRAND,F8.0
+S,F8.0
+
+Variable,Value,Label
+S,1.00,
+
+Table: Descriptives
+,,,,,,95% Confidence Interval for Mean,,,
+,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+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
+
+Table: Test of Homogeneity of Variances
+,Levene Statistic,df1,df2,Significance
+Breaking Strain,1.09,1,5,.35
+
+Table: ANOVA
+,,Sum of Squares,df,Mean Square,F,Significance
+Breaking Strain,Between Groups,2.41,1,2.41,1.07,.35
+,Within Groups,11.30,5,2.26,,
+,Total,13.71,6,,,
+
+Table: Contrast Coefficients
+,,Manufacturer,
+,,Aspeger,Bloggs
+Contrast,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,.35
+,,2,1.30,1.26,1.03,5,.35
+,Does not assume equal,1,2.60,3.22,.81,1.32,.54
+,,2,1.30,1.61,.81,1.32,.54
+
+Variable,Value,Label
+S,2.00,
+
+Table: Descriptives
+,,,,,,95% Confidence Interval for Mean,,,
+,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+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
+
+Table: Test of Homogeneity of Variances
+,Levene Statistic,df1,df2,Significance
+Breaking Strain,.92,1,6,.37
+
+Table: ANOVA
+,,Sum of Squares,df,Mean Square,F,Significance
+Breaking Strain,Between Groups,7.50,1,7.50,3.75,.10
+,Within Groups,12.00,6,2.00,,
+,Total,19.50,7,,,
+
+Table: Contrast Coefficients
+,,Manufacturer,
+,,Bloggs,Charlies
+Contrast,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,.10
+,,2,2.00,1.03,1.94,6,.10
+,Does not assume equal,1,4.00,1.83,2.19,5.88,.07
+,,2,2.00,.91,2.19,5.88,.07
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 339456d3d9680dd327fbeebc34344558d3504db4..cb7fb79b1447744ad09b021a13dbfb5ff7f9eff7 100755 (executable)
@@ -93,61 +93,45 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|QUALITY |F8.0  |
-|BRAND   |F8.0  |
-+--------+------+
-2.1 ONEWAY.  Descriptives
-#===============#========#==#====#==============#==========#=======================#=======#=======#
-#               |        #  |    |              |          |95% Confidence Interval|       |       #
-#               |        #  |    |              |          +-----------+-----------+       |       #
-#               |        # N|Mean|Std. Deviation|Std. Error|Lower Bound|Upper Bound|Minimum|Maximum#
-#===============#========#==#====#==============#==========#===========#===========#=======#=======#
-#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#
-#               |Total   #15|3.47|          1.77|       .46|       2.49|       4.45|   1.00|   7.00#
-#===============#========#==#====#==============#==========#===========#===========#=======#=======#
-2.2 ONEWAY.  Test of Homogeneity of Variances
-#===============#================#===#===#============#
-#               #Levene Statistic|df1|df2|Significance#
-#===============#================#===#===#============#
-#Breaking Strain#             .09|  2| 12|         .91#
-#===============#================#===#===#============#
-2.3 ONEWAY.  ANOVA
-#==============================#==============#==#===========#====#============#
-#                              #Sum of Squares|df|Mean Square|  F |Significance#
-#===============#==============#==============#==#===========#====#============#
-#Breaking Strain|Between Groups#         20.13| 2|      10.07|5.12|         .02#
-#               |Within Groups #         23.60|12|       1.97|    |            #
-#               |Total         #         43.73|14|           |    |            #
-#===============#==============#==============#==#===========#====#============#
-2.4 ONEWAY.  Contrast Coefficients
-#==========#=======================#
-#          #      Manufacturer     #
-#          #-------+------+--------#
-#          #Aspeger|Bloggs|Charlies#
-#========#=#=======#======#========#
-#Contrast|1#     -2|     1|       1#
-#        |2#      0|    -1|       1#
-#========#=#=======#======#========#
-2.5 ONEWAY.  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|            .03#
-#               |                      |    2   #             1.80|       .89|2.03|  12|            .07#
-#               |Does not assume equal |    1   #             3.80|      1.48|2.56|8.74|            .03#
-#               |                      |    2   #             1.80|       .92|1.96|7.72|            .09#
-#===============#======================#========#=================#==========#====#====#===============#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+QUALITY,F8.0
+BRAND,F8.0
+
+Table: Descriptives
+,,,,,,95% Confidence Interval for Mean,,,
+,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
+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
+,Total,15,3.47,1.77,.46,2.49,4.45,1.00,7.00
+
+Table: Test of Homogeneity of Variances
+,Levene Statistic,df1,df2,Significance
+Breaking Strain,.09,2,12,.91
+
+Table: ANOVA
+,,Sum of Squares,df,Mean Square,F,Significance
+Breaking Strain,Between Groups,20.13,2,10.07,5.12,.02
+,Within Groups,23.60,12,1.97,,
+,Total,43.73,14,,,
+
+Table: Contrast Coefficients
+,,Manufacturer,,
+,,Aspeger,Bloggs,Charlies
+Contrast,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,.03
+,,2,1.80,.89,2.03,12,.07
+,Does not assume equal,1,3.80,1.48,2.56,8.74,.03
+,,2,1.80,.92,1.96,7.72,.09
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index db54cd5ade4ae8ec0b5fd8fbccc07aee8ea8d5e1..0234187ee825d02f276c1dabe38e0d13c20d5541 100755 (executable)
@@ -70,7 +70,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/per.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/per.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="Check Permissions"
@@ -86,7 +86,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/per.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/per.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="Check Permissions"
index 5fb730063ff4721779e0075d515f78bc96944eb1..b8ac189ee5237b8b86f8ed5aae0de66c98a06021 100755 (executable)
@@ -79,7 +79,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
index 4a0527588de2cb321887549d094b5927433e6cbb..a0b806e5e0f6453f55bad717a3a644b9acf5da50 100755 (executable)
@@ -105,7 +105,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode --error-file=$TEMPDIR/errs $TEMPDIR/print.stat 
+$SUPERVISOR $PSPP -o pspp.csv --error-file=$TEMPDIR/errs $TEMPDIR/print.stat 
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare print.out"
@@ -159,32 +159,56 @@ EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output"
-diff $TEMPDIR/pspp.list - << EOF
+diff $TEMPDIR/pspp.csv - << EOF
 1 2 
 
+
+
 12
+
 1 -2 
 
+
+
 3 4 
 
+
+
 34
+
 3 -4 
 
+
+
 . 6 
 
+
+
 .6
+
 . -6 
 
+
+
 7 . 
 
+
+
 7.
+
 7 -. 
 
+
+
 9 0 
 
+
+
 90
+
 9 -0 
 
+
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index d98c8e2211c67b0316334b2973f84ed9e726f00f..67e19c9fda6bcc5828418a46fa1fe9c58284521e 100755 (executable)
@@ -82,7 +82,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 # Check that it properly handles failed transformations.
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -e $TEMPDIR/err $TESTFILE 
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv -e $TEMPDIR/err $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 activity="diff 1"
@@ -131,12 +131,12 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program (syntax errors)"
-$SUPERVISOR $PSPP --testing-mode -e $TEMPDIR/errs $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e $TEMPDIR/errs $TESTFILE 
 if [ $? -ne 1 ] ; then fail ; fi
 
 activity="compare errors"
 perl -pi -e 's/^\s*$//g' $TEMPDIR/errs
-diff  -b $TEMPDIR/errs - << EOF
+diff -b $TEMPDIR/errs - << EOF
 $TEMPDIR/rank.sh.sps:15: error: RANK: Syntax error expecting \`(' at end of command.
 $TEMPDIR/rank.sh.sps:19: error: RANK: Syntax error expecting integer at \`d'.
 $TEMPDIR/rank.sh.sps:25: error: RANK: Variable x already exists.
@@ -359,199 +359,247 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 3"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output 3"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
+diff -c $TEMPDIR/pspp.csv - <<EOF
 Simple example using defaults
+
 Variables Created By RANK
+
+
+
 x into Rx(RANK of x)
-       x        Rx
--------- ---------
-      -1     1.000 
-       0     2.000 
-       1     3.000 
-       2     4.500 
-       2     4.500 
-       4     6.000 
-       5     7.000 
+
+Table: Data List
+x,Rx
+-1,1.000
+0,2.000
+1,3.000
+2,4.500
+2,4.500
+4,6.000
+5,7.000
+
 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)
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|a       |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|b       |Format: F8.2                               |       2|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|count   |N of a                                     |       3|
-|        |Format: F6.0                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|Ra      |RANK of a                                  |       4|
-|        |Format: F9.3                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|Rb      |RANK of b                                  |       5|
-|        |Format: F9.3                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|RFR001  |RFRACTION of a                             |       6|
-|        |Format: F6.4                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|RFR002  |RFRACTION of b                             |       7|
-|        |Format: F6.4                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|Nb      |N of b                                     |       8|
-|        |Format: F6.0                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-       a        b  count        Ra        Rb RFR001 RFR002     Nb
--------- -------- ------ --------- --------- ------ ------ ------
-     .00    24.00     10    10.000     8.000 1.0000  .8889      9 
-    1.00    32.00     10     9.000     4.000  .9000  .4444      9 
-    2.00    31.00     10     8.000     5.000  .8000  .5556      9 
-    2.00    32.00     10     8.000     4.000  .8000  .4444      9 
-    4.00    30.00     10     6.000     6.000  .6000  .6667      9 
-    5.00    29.00     10     5.000     7.000  .5000  .7778      9 
-    6.00     1.00     10     4.000     9.000  .4000 1.0000      9 
-    7.00    43.00     10     3.000     2.000  .3000  .2222      9 
-    8.00      .       10     2.000      .     .2000  .          . 
-    9.00    45.00     10     1.000     1.000  .1000  .1111      9 
+
+Variable,Description,,Position
+a,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+b,Format: F8.2,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+count,N of a,,3
+,Format: F6.0,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+Ra,RANK of a,,4
+,Format: F9.3,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+Rb,RANK of b,,5
+,Format: F9.3,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+RFR001,RFRACTION of a,,6
+,Format: F6.4,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+RFR002,RFRACTION of b,,7
+,Format: F6.4,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+Nb,N of b,,8
+,Format: F6.0,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
+Table: Data List
+a,b,count,Ra,Rb,RFR001,RFR002,Nb
+.00,24.00,10,10.000,8.000,1.0000,.8889,9
+1.00,32.00,10,9.000,4.000,.9000,.4444,9
+2.00,31.00,10,8.000,5.000,.8000,.5556,9
+2.00,32.00,10,8.000,4.000,.8000,.4444,9
+4.00,30.00,10,6.000,6.000,.6000,.6667,9
+5.00,29.00,10,5.000,7.000,.5000,.7778,9
+6.00,1.00,10,4.000,9.000,.4000,1.0000,9
+7.00,43.00,10,3.000,2.000,.3000,.2222,9
+8.00,.  ,10,2.000,.   ,.2000,.    ,.
+9.00,45.00,10,1.000,1.000,.1000,.1111,9
+
 Test variable name fallback
+
 Variables Created By RANK
+
+
+
 foo into RAN001(RANK of foo)
-2.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|foo     |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|rfoo    |Format: F8.2                               |       2|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|ran003  |Format: F8.2                               |       3|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
-|RAN001  |RANK of foo                                |       4|
-|        |Format: F9.3                               |        |
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 8                           |        |
-+--------+-------------------------------------------+--------+
+
+Variable,Description,,Position
+foo,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+rfoo,Format: F8.2,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+ran003,Format: F8.2,,3
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+RAN001,RANK of foo,,4
+,Format: F9.3,,
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+
 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)
-       a        b       Sa     Pa PRO001  Na NOR001
--------- -------- -------- ------ ------ --- ------
-     .00    24.00   -.9000  10.00  .0610   1 -1.547 
-    1.00    32.00   -.7889  20.00  .1585   1 -1.000 
-    2.00    31.00   -.5925  30.00  .2561   2 -.6554 
-    2.00    32.00   -.5925  30.00  .2561   2 -.6554 
-    4.00    30.00   -.3544  40.00  .3537   2 -.3755 
-    5.00    29.00   -.1544  50.00  .4512   2 -.1226 
-    6.00     1.00    .0956  60.00  .5488   3  .1226 
-    7.00    43.00    .4290  70.00  .6463   3  .3755 
-    8.00     8.00    .9290  80.00  .7439   3  .6554 
-    9.00    45.00   1.9290  90.00  .8415   4 1.0005 
+
+Table: Data List
+a,b,Sa,Pa,PRO001,Na,NOR001
+.00,24.00,-.9000,10.00,.0610,1,-1.547
+1.00,32.00,-.7889,20.00,.1585,1,-1.000
+2.00,31.00,-.5925,30.00,.2561,2,-.6554
+2.00,32.00,-.5925,30.00,.2561,2,-.6554
+4.00,30.00,-.3544,40.00,.3537,2,-.3755
+5.00,29.00,-.1544,50.00,.4512,2,-.1226
+6.00,1.00,.0956,60.00,.5488,3,.1226
+7.00,43.00,.4290,70.00,.6463,3,.3755
+8.00,8.00,.9290,80.00,.7439,3,.6554
+9.00,45.00,1.9290,90.00,.8415,4,1.0005
+
 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)
+
 a into NOR001(NORMAL of a using RANKIT BY g2)
-       a       g1       g2        Ra     Na    RAN001 NOR001 
--------- -------- -------- --------- ------ --------- ------ 
-    2.00     1.00     2.00     8.000  .9674     4.000  .5244  
-    2.00     1.00     2.00     8.000  .9674     4.000  .5244  
-    3.00     1.00     2.00     7.000  .5895     3.000  .0000  
-    4.00     1.00     2.00     6.000  .2822     2.000 -.5244  
-    5.00     1.00     2.00     5.000  .0000     1.000 -1.282  
-    1.00      .00     2.00     8.000 1.5341     8.000 1.5341  
-    2.00      .00     2.00     7.000  .8871     7.000  .8871  
-    3.00      .00     2.00     6.000  .4888     6.000  .4888  
-    4.00      .00     2.00     5.000  .1573     5.000  .1573  
-    5.00      .00     2.00     4.000 -.1573     4.000 -.1573  
-    6.00      .00     2.00     3.000 -.4888     3.000 -.4888  
-    7.00      .00     2.00     2.000 -.8871     2.000 -.8871  
-    8.00      .00     2.00     1.000 -1.534     1.000 -1.534  
-    6.00     1.00     2.00     4.000 -.2822     4.000 1.1503  
-    7.00     1.00     2.00     2.000 -.9674     2.000 -.3186  
-    7.00     1.00     2.00     2.000 -.9674     2.000 -.3186  
-    8.00     1.00     2.00     1.000 -1.593     1.000 -1.150  
-    9.00     1.00     1.00     1.000  .0000     1.000  .0000  
+
+Table: Data List
+a,g1,g2,Ra,Na,RAN001,NOR001
+2.00,1.00,2.00,8.000,.9674,4.000,.5244
+2.00,1.00,2.00,8.000,.9674,4.000,.5244
+3.00,1.00,2.00,7.000,.5895,3.000,.0000
+4.00,1.00,2.00,6.000,.2822,2.000,-.5244
+5.00,1.00,2.00,5.000,.0000,1.000,-1.282
+1.00,.00,2.00,8.000,1.5341,8.000,1.5341
+2.00,.00,2.00,7.000,.8871,7.000,.8871
+3.00,.00,2.00,6.000,.4888,6.000,.4888
+4.00,.00,2.00,5.000,.1573,5.000,.1573
+5.00,.00,2.00,4.000,-.1573,4.000,-.1573
+6.00,.00,2.00,3.000,-.4888,3.000,-.4888
+7.00,.00,2.00,2.000,-.8871,2.000,-.8871
+8.00,.00,2.00,1.000,-1.534,1.000,-1.534
+6.00,1.00,2.00,4.000,-.2822,4.000,1.1503
+7.00,1.00,2.00,2.000,-.9674,2.000,-.3186
+7.00,1.00,2.00,2.000,-.9674,2.000,-.3186
+8.00,1.00,2.00,1.000,-1.593,1.000,-1.150
+9.00,1.00,1.00,1.000,.0000,1.000,.0000
+
 fractional ranks ( including small ones for special case of SAVAGE ranks)
+
 Variables Created By RANK
+
+
+
 a into Pa(PROPORTION of a using TUKEY)
+
 a into Sa(SAVAGE of a)
-       a        w     Pa       Sa
--------- -------- ------ --------
-    1.00     1.50  .1285   -.8016 
-    2.00      .20  .1776   -.6905 
-    3.00      .10  .1986   -.6905 
-    4.00     1.00  .3458   -.5305 
-    5.00     1.00  .4860   -.2905 
-    6.00     1.00  .6262    .0262 
-    7.00     1.00  .7664    .4929 
-    8.00     1.00  .9065   1.3929 
+
+Table: Data List
+a,w,Pa,Sa
+1.00,1.50,.1285,-.8016
+2.00,.20,.1776,-.6905
+3.00,.10,.1986,-.6905
+4.00,1.00,.3458,-.5305
+5.00,1.00,.4860,-.2905
+6.00,1.00,.6262,.0262
+7.00,1.00,.7664,.4929
+8.00,1.00,.9065,1.3929
+
 test all the ties cases with low caseweight values
+
 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
+
+
+
 x into Nx(NORMAL of x using VW)
-       x        w        xl        xh        xc     Nx
--------- -------- --------- --------- --------- ------
-    1.00      .10      .000      .100     1.000 -1.938 
-    2.00      .10      .100      .200     2.000 -1.412 
-    3.00      .10      .200      .300     3.000 -1.119 
-    4.00      .20      .300      .500     4.000 -.8046 
-    5.00      .10      .500      .600     5.000 -.5549 
-    6.00      .10      .600      .700     6.000 -.4067 
-    7.00      .10      .700      .800     7.000 -.2670 
-    8.00      .10      .800      .900     8.000 -.1323 
+
+Table: Data List
+x,w,xl,xh,xc,Nx
+1.00,.10,.000,.100,1.000,-1.938
+2.00,.10,.100,.200,2.000,-1.412
+3.00,.10,.200,.300,3.000,-1.119
+4.00,.20,.300,.500,4.000,-.8046
+5.00,.10,.500,.600,5.000,-.5549
+6.00,.10,.600,.700,6.000,-.4067
+7.00,.10,.700,.800,7.000,-.2670
+8.00,.10,.800,.900,8.000,-.1323
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -581,31 +629,41 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 4"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 
 activity="compare output 4"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - << EOF
-$TEMPDIR/rank.sh.sps:3: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:4: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:5: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:6: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:7: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:8: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
-$TEMPDIR/rank.sh.sps:9: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate.
+diff -c $TEMPDIR/pspp.csv - << EOF
+"$TEMPDIR/rank.sh.sps:3: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:4: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:5: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:6: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:7: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:8: warning: BEGIN DATA: Missing value(s) for all variables from rx onward.  These will be filled with the system-missing value or blanks, as appropriate."
+
+"$TEMPDIR/rank.sh.sps:9: warning: BEGIN DATA: 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)
-       x       rx   RNKRA01
--------- -------- ---------
-    1.00      .       1.000 
-    2.00      .       2.000 
-    3.00      .       3.000 
-    4.00      .       4.000 
-    5.00      .       5.000 
-    6.00      .       6.000 
-    7.00      .       7.000 
+
+Table: Data List
+x,rx,RNKRA01
+1.00,.  ,1.000
+2.00,.  ,2.000
+3.00,.  ,3.000
+4.00,.  ,4.000
+5.00,.  ,5.000
+6.00,.  ,6.000
+7.00,.  ,7.000
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 6f9b3490cb96cc1716935fdf46009904919b4fa4..7cbb81564742f7c3790320975c10ba61e2892b33 100755 (executable)
@@ -1566,40 +1566,30 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|v0      |F8.0  |
-|v1      |F8.0  |
-+--------+------+
-2.1 REGRESSION.  Model Summary
-#============#========#=================#==========================#
-#          R #R Square|Adjusted R Square|Std. Error of the Estimate#
-#========#===#========#=================#==========================#
-#        |.05#     .00|              .00|                      8.11#
-#========#===#========#=================#==========================#
-2.2 REGRESSION.  ANOVA
-#===================#==============#====#===========#====#============#
-#                   #Sum of Squares| df |Mean Square|  F |Significance#
-#========#==========#==============#====#===========#====#============#
-#        |Regression#        235.23|   1|     235.23|3.58|         .06#
-#        |Residual  #      98438.40|1498|      65.71|    |            #
-#        |Total     #      98673.63|1499|           |    |            #
-#========#==========#==============#====#===========#====#============#
-2.3 REGRESSION.  Coefficients
-#===================#====#==========#====#====#============#
-#                   #  B |Std. Error|Beta|  t |Significance#
-#========#==========#====#==========#====#====#============#
-#        |(Constant)#1.24|       .42| .00|2.95|         .21#
-#        |    v1    #1.37|       .72| .05|1.89|         .06#
-#        |          #    |          |    |    |            #
-#========#==========#====#==========#====#====#============#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+v0,F8.0
+v1,F8.0
+
+Table: Model Summary
+,R,R Square,Adjusted R Square,Std. Error of the Estimate
+,.05,.00,.00,8.11
+
+Table: ANOVA
+,,Sum of Squares,df,Mean Square,F,Significance
+,Regression,235.23,1,235.23,3.58,.06
+,Residual,98438.40,1498,65.71,,
+,Total,98673.63,1499,,,
+
+Table: Coefficients
+,,B,Std. Error,Beta,t,Significance
+,(Constant),1.24,.42,.00,2.95,.21
+,v1,1.37,.72,.05,1.89,.06
+,,,,,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 9f8da00249a9682aa106bf521f0bf05203d8ddc2..4ff48e51f28bf56928b00f46880910e0eabe2d5b 100755 (executable)
@@ -78,54 +78,45 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|v0      |F8.0  |
-|v1      |F8.0  |
-|v2      |F8.0  |
-+--------+------+
-2.1 REGRESSION.  Model Summary
-#============#========#=================#==========================#
-#          R #R Square|Adjusted R Square|Std. Error of the Estimate#
-#========#===#========#=================#==========================#
-#        |.97#     .94|              .93|                      1.34#
-#========#===#========#=================#==========================#
-2.2 REGRESSION.  ANOVA
-#===================#==============#==#===========#=====#============#
-#                   #Sum of Squares|df|Mean Square|  F  |Significance#
-#========#==========#==============#==#===========#=====#============#
-#        |Regression#        202.75| 2|     101.38|56.75|         .00#
-#        |Residual  #         12.50| 7|       1.79|     |            #
-#        |Total     #        215.26| 9|           |     |            #
-#========#==========#==============#==#===========#=====#============#
-2.3 REGRESSION.  Coefficients
-#===================#=====#==========#=====#======#============#
-#                   #  B  |Std. Error| Beta|   t  |Significance#
-#========#==========#=====#==========#=====#======#============#
-#        |(Constant)# 2.19|      2.36|  .00|   .93|         .52#
-#        |    v0    # 1.81|      1.05|  .17|  1.72|         .12#
-#        |    v1    #-3.43|       .33|-1.03|-10.33|         .00#
-#        |          #     |          |     |      |            #
-#========#==========#=====#==========#=====#======#============#
-      v0       v1       v2     RES1    PRED1
--------- -------- -------- -------- --------
-     .65     7.74   -23.98     -.84   -23.13 
-    -.13     6.14   -19.64     -.54   -19.10 
-     .35     7.65   -25.27    -1.87   -23.40 
-     .69     6.13   -16.57      .97   -17.54 
-    -.07     8.25   -25.80      .40   -26.20 
-    -.34     6.03   -17.57     1.53   -19.10 
-     .76     9.83   -28.36     1.77   -30.13 
-    -.47     5.34   -16.80      .18   -16.97 
-    -.06     8.84   -29.26    -1.05   -28.21 
-     .56     6.20   -18.58     -.54   -18.04 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+v0,F8.0
+v1,F8.0
+v2,F8.0
+
+Table: Model Summary
+,R,R Square,Adjusted R Square,Std. Error of the Estimate
+,.97,.94,.93,1.34
+
+Table: ANOVA
+,,Sum of Squares,df,Mean Square,F,Significance
+,Regression,202.75,2,101.38,56.75,.00
+,Residual,12.50,7,1.79,,
+,Total,215.26,9,,,
+
+Table: Coefficients
+,,B,Std. Error,Beta,t,Significance
+,(Constant),2.19,2.36,.00,.93,.52
+,v0,1.81,1.05,.17,1.72,.12
+,v1,-3.43,.33,-1.03,-10.33,.00
+,,,,,,
+
+Table: Data List
+v0,v1,v2,RES1,PRED1
+.65,7.74,-23.98,-.84,-23.13
+-.13,6.14,-19.64,-.54,-19.10
+.35,7.65,-25.27,-1.87,-23.40
+.69,6.13,-16.57,.97,-17.54
+-.07,8.25,-25.80,.40,-26.20
+-.34,6.03,-17.57,1.53,-19.10
+.76,9.83,-28.36,1.77,-30.13
+-.47,5.34,-16.80,.18,-16.97
+-.06,8.84,-29.26,-1.05,-28.21
+.56,6.20,-18.58,-.54,-18.04
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index ed4b4b854c4a67f416be869d0705b8839fda9318..df86fa82771b028654f3c28f4ea01fb0bc86d4d5 100755 (executable)
@@ -245,99 +245,72 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-diff pspp.list - << EOF
+diff -c pspp.csv - << EOF
 Scale: Everything
 
-1.1 RELIABILITY.  Case Processing Summary
-#==============#===#======#
-#              # N |   %  #
-#==============#===#======#
-#Cases Valid   #131| 92.91#
-#      Excluded# 10|  7.09#
-#      Total   #141|100.00#
-#==============#===#======#
-
-1.2 RELIABILITY.  Reliability Statistics
-#================#==========#
-#Cronbach's Alpha#N of items#
-#================#==========#
-#             .75#         4#
-#================#==========#
+Table: Case Processing Summary
+,,N,%
+Cases,Valid,131,92.91
+,Excluded,10,7.09
+,Total,141,100.00
+
+Table: Reliability Statistics
+Cronbach's Alpha,N of items
+.75,4
 
 Scale: Nothing
 
-2.1 RELIABILITY.  Case Processing Summary
-#==============#===#======#
-#              # N |   %  #
-#==============#===#======#
-#Cases Valid   #131| 92.91#
-#      Excluded# 10|  7.09#
-#      Total   #141|100.00#
-#==============#===#======#
-
-2.2 RELIABILITY.  Reliability Statistics
-#==========================================================#===#
-#Cronbach's Alpha               Part 1           Value     #.55#
-#                                                N of Items#  2#
-#                               Part 2           Value     #.63#
-#                                                N of Items#  2#
-#                               Total N of Items           #  4#
-#Correlation Between Forms                                 #.61#
-#Spearman-Brown Coefficient     Equal Length               #.75#
-#                               Unequal Length             #.75#
-#Guttman Split-Half Coefficient                            #.75#
-#==========================================================#===#
+Table: Case Processing Summary
+,,N,%
+Cases,Valid,131,92.91
+,Excluded,10,7.09
+,Total,141,100.00
+
+Table: Reliability Statistics
+Cronbach's Alpha,Part 1,Value,.55
+,,N of Items,2
+,Part 2,Value,.63
+,,N of Items,2
+,Total N of Items,,4
+Correlation Between Forms,,,.61
+Spearman-Brown Coefficient,Equal Length,,.75
+,Unequal Length,,.75
+Guttman Split-Half Coefficient,,,.75
 
 Scale: Totals
 
-3.1 RELIABILITY.  Case Processing Summary
-#==============#===#======#
-#              # N |   %  #
-#==============#===#======#
-#Cases Valid   #131| 92.91#
-#      Excluded# 10|  7.09#
-#      Total   #141|100.00#
-#==============#===#======#
-
-3.2 RELIABILITY.  Reliability Statistics
-#================#==========#
-#Cronbach's Alpha#N of items#
-#================#==========#
-#             .75#         4#
-#================#==========#
-
-3.3 RELIABILITY.  Item-Total Statistics
-#=====#==========================#==============================#================================#================================#
-#     #Scale Mean if Item Deleted|Scale Variance if Item Deleted|Corrected Item-Total Correlation|Cronbach's Alpha if Item Deleted#
-#=====#==========================#==============================#================================#================================#
-#var6 #                     15.97|                          8.43|                             .51|                             .71#
-#var8 #                     16.56|                          7.86|                             .53|                             .70#
-#var15#                     16.47|                          8.45|                             .56|                             .68#
-#var17#                     16.60|                          8.00|                             .57|                             .67#
-#=====#==========================#==============================#================================#================================#
+Table: Case Processing Summary
+,,N,%
+Cases,Valid,131,92.91
+,Excluded,10,7.09
+,Total,141,100.00
+
+Table: Reliability Statistics
+Cronbach's Alpha,N of items
+.75,4
+
+Table: Item-Total Statistics
+,Scale Mean if Item Deleted,Scale Variance if Item Deleted,Corrected Item-Total Correlation,Cronbach's Alpha if Item Deleted
+var6,15.97,8.43,.51,.71
+var8,16.56,7.86,.53,.70
+var15,16.47,8.45,.56,.68
+var17,16.60,8.00,.57,.67
 
 Scale: ANY
 
-4.1 RELIABILITY.  Case Processing Summary
-#==============#===#======#
-#              # N |   %  #
-#==============#===#======#
-#Cases Valid   #131| 92.91#
-#      Excluded# 10|  7.09#
-#      Total   #141|100.00#
-#==============#===#======#
-
-4.2 RELIABILITY.  Reliability Statistics
-#================#==========#
-#Cronbach's Alpha#N of items#
-#================#==========#
-#             .75#         4#
-#================#==========#
+Table: Case Processing Summary
+,,N,%
+Cases,Valid,131,92.91
+,Excluded,10,7.09
+,Total,141,100.00
 
+Table: Reliability Statistics
+Cronbach's Alpha,N of items
+.75,4
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index ff46486a3f0ef81ae420e90a6bf2da75539f42e0..1e08782a4af0dc434c4008ce5b855683b053dfaa 100755 (executable)
@@ -80,7 +80,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check sysfile"
@@ -88,27 +88,25 @@ grep -i Brake $TEMPDIR/rename.sav
 if [ $? -eq 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+----------+------+
-| Variable |Format|
-#==========#======#
-|brakeFluid|F8.0  |
-|y         |F8.0  |
-+----------+------+
-brakeFluid        y
----------- --------
-      1.00     3.00 
-      2.00     3.00 
-      3.00     3.00 
-      4.00     3.00 
-applecarts        y
----------- --------
-      1.00     3.00 
-      2.00     3.00 
-      3.00     3.00 
-      4.00     3.00 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+brakeFluid,F8.0
+y,F8.0
+
+Table: Data List
+brakeFluid,y
+1.00,3.00
+2.00,3.00
+3.00,3.00
+4.00,3.00
+
+Table: Data List
+applecarts,y
+1.00,3.00
+2.00,3.00
+3.00,3.00
+4.00,3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 0c24f0c585961f799c6ccd23fdddfd0ab1dd3381..c6ab046145e15863f7faece56d8537e66e66e01b 100755 (executable)
@@ -94,79 +94,59 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 ROC.  Case Summary
-#========#===================#
-#        # Valid N (listwise)#
-#        #==========#========#
-#a       #Unweighted|Weighted#
-#========#==========#========#
-#Positive#         5|  50.000#
-#Negative#         5|  50.000#
-#========#==========#========#
-1.2 ROC.  Area Under the Curve (x)
-#====#==========#===============#=======================#
-#    |          |               | Asymp. 99% Confidence #
-#    |          |               +-----------+-----------#
-#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
-#====#==========#===============#===========#===========#
-#.910|      .030|           .000|       .839|       .981#
-#====#==========#===============#===========#===========#
-1.3 ROC.  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#
-#====================================#===========#===============#
-2.1 ROC.  Case Summary
-#========#===================#
-#        # Valid N (listwise)#
-#        #==========#========#
-#a       #Unweighted|Weighted#
-#========#==========#========#
-#Positive#         5|  50.000#
-#Negative#         5|  50.000#
-#========#==========#========#
-See pspp-1.png for a chart.
-2.2 ROC.  Area Under the Curve
-#===================#====#==========#===============#=======================#
-#                   #    |          |               | Asymp. 95%            #
-#                   #    |          |               +-----------+-----------#
-#Variable under test#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
-#===================#====#==========#===============#===========#===========#
-#                  x#.910|      .030|           .000|       .860|       .960#
-#                  y#.697|      .052|           .001|       .611|       .783#
-#===================#====#==========#===============#===========#===========#
-2.3 ROC.  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#
-#-------------#------------------------------------+-----------+---------------#
-#            y#                                .000|      1.000|          1.000#
-#             #                               1.500|       .960|           .900#
-#             #                               2.500|       .680|           .340#
-#             #                               3.000|       .600|           .340#
-#             #                               3.500|       .600|           .300#
-#             #                               4.500|       .200|           .020#
-#             #                               6.000|       .000|           .000#
-#=============#====================================#===========#===============#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Case Summary
+,Valid N (listwise),
+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: Case Summary
+,Valid N (listwise),
+a,Unweighted,Weighted
+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
+x,.910,.030,.000,.860,.960
+y,.697,.052,.001,.611,.783
+
+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
+y,.000,1.000,1.000
+,1.500,.960,.900
+,2.500,.680,.340
+,3.000,.600,.340
+,3.500,.600,.300
+,4.500,.200,.020
+,6.000,.000,.000
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index a8020b0c26c6c6f901cf1ce203fb69c5a35ac859..7976a6e4ae42f88ae56843e46742c58450de02ef 100755 (executable)
@@ -101,30 +101,22 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 ROC.  Case Summary
-#========#===================#
-#        # Valid N (listwise)#
-#        #==========#========#
-#a       #Unweighted|Weighted#
-#========#==========#========#
-#Positive#        14|  14.000#
-#Negative#        14|  14.000#
-#========#==========#========#
-1.2 ROC.  Area Under the Curve (x)
-#====#==========#===============#=======================#
-#    |          |               | Asymp. 95% Confidence #
-#    |          |               +-----------+-----------#
-#Area|Std. Error|Asymptotic Sig.|Lower Bound|Upper Bound#
-#====#==========#===============#===========#===========#
-#.490|      .111|           .927|       .307|       .673#
-#====#==========#===============#===========#===========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Case Summary
+,Valid N (listwise),
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 4f4515e2be05073a21a85232970a2bdbe77b5069..c8d25e75984e21bb44f8fb06691a7660c74e2857 100755 (executable)
@@ -81,23 +81,21 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/sample.stat 
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/sample.stat 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create head"
-grep -v '^\ *$' $TEMPDIR/pspp.list | head -2 > $TEMPDIR/head
+grep -v '^\ *$' $TEMPDIR/pspp.csv | head -1 > $TEMPDIR/head
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="extract data"
-grep  '[0-9][0-9]*' $TEMPDIR/pspp.list > $TEMPDIR/data
+grep  '[0-9][0-9]*' $TEMPDIR/pspp.csv > $TEMPDIR/data
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare head"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/head
 diff -b $TEMPDIR/head - << EOF
- A
---
+Table: Data List
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index d66681be7bf9e9b588d4c7be3886f4f9936df6e2..409c11965ffadd42f8578e296d381fc0927d7a81 100755 (executable)
@@ -121,7 +121,7 @@ for count_repeat_buffers in \
   } > sort.pspp || no_result
   
   activity="run program"
-  $SUPERVISOR $PSPP --testing-mode sort.pspp
+  $SUPERVISOR $PSPP --testing-mode -o pspp.csv sort.pspp
   if [ $? -ne 0 ] ; then no_result ; fi
   
   perl -pi -e 's/^\s*$//g' sort.exp sort.out
index eb2c991c1e97d328d120c76fe9915c67fbde93d3..5bebedc75c3b5a9960e5aa2d8dfaa3ed739ba2a4 100755 (executable)
@@ -85,33 +85,37 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/split.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/split.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-Variable Value Label
-X            1
-X Y
-- -
-1 2 
-1 6 
-1 7 
-1 9 
-1 5 
-1 4 
-Variable Value Label
-X            2
-X Y
-- -
-2 7 
-2 0 
-2 6 
-2 5 
-2 8 
-2 9 
-2 4
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Title: Test SPLIT FILE utility
+
+Variable,Value,Label
+X,1,
+
+Table: Data List
+X,Y
+1,2
+1,6
+1,7
+1,9
+1,5
+1,4
+
+Variable,Value,Label
+X,2,
+
+Table: Data List
+X,Y
+2,7
+2,0
+2,6
+2,5
+2,8
+2,9
+2,4
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index d8f8ae3647ffe306e531c945184190eb9d0478a8..35a4e53f32812321dbd742df62426d55f654c3a0 100755 (executable)
@@ -74,47 +74,38 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="filter output"
-egrep -v '^(Created|Endian|Integer Format|Real Format): ' $TEMPDIR/pspp.list > $TEMPDIR/out-filtered
+egrep -v '^(Created|Endian|Integer Format|Real Format):,' $TEMPDIR/pspp.csv > $TEMPDIR/out-filtered
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/out-filtered
-diff -b -w $TEMPDIR/out-filtered - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|x       |F8.0  |
-|name    |A10   |
-+--------+------+
-2.1 SYSFILE INFO.  
-File:           pro.sav
-Label:          No label.
-Variables:      2
-Cases:          3
-Type:           System File
-Weight:         Not weighted.
-Mode:           Compression on.
-Charset:        Unknown
-+--------+-------------+---+
-|Variable|Description  |Pos|
-|        |             |iti|
-|        |             |on |
-#========#=============#===#
-|x       |Format: F8.2 |  1|
-|        |Measure:     |   |
-|        |Display      |   |
-|        |Display      |   |
-+--------+-------------+---+
-|name    |Format: A10  |  2|
-|        |Measure:     |   |
-|        |Display      |   |
-|        |Display      |   |
-+--------+-------------+---+
+diff -c $TEMPDIR/out-filtered - << EOF
+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:,System File
+Weight:,Not weighted.
+Mode:,Compression on.
+Charset:,Unknown
+
+Variable,Description,,Position
+x,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+name,Format: A10,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 10,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index df16690b01e18bba127ff1f7705e95dd528ecbf2..fefe3afccaff4c143093c6e6da9c71c05541f891 100755 (executable)
@@ -84,7 +84,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="check file exists"
@@ -97,18 +97,17 @@ grep  'X=X' $TEMPDIR/foo.sav
 if [ $? -eq 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-       x variable variab_a variab_b
--------- -------- -------- --------
-    1.00     1.00     1.00     2.00 
-    1.00     1.00     2.00    30.00 
-    1.00     2.00     1.00     8.00 
-    1.00     2.00     2.00    20.00 
-    2.00     1.00     1.00     2.00 
-    2.00     1.00     2.00    22.00 
-    2.00     2.00     1.00     1.00 
-    2.00     2.00     2.00     3.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+x,variable,variab_a,variab_b
+1.00,1.00,1.00,2.00
+1.00,1.00,2.00,30.00
+1.00,2.00,1.00,8.00
+1.00,2.00,2.00,20.00
+2.00,1.00,1.00,2.00
+2.00,1.00,2.00,22.00
+2.00,2.00,1.00,1.00
+2.00,2.00,2.00,3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index d4f59052de98b9d5e99820a2dce6beffbe221a89..08b28888e267a237465cde420b85b9b0edc465d9 100755 (executable)
@@ -83,22 +83,21 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  -w $TEMPDIR/pspp.list - << EOF
-variable001 variable002 variable003 variable004
------------ ----------- ----------- -----------
-       1.00        1.00        1.00        2.00  
-       1.00        1.00        2.00       30.00 
-       1.00        2.00        1.00       8.00 
-       1.00        2.00        2.00      20.00 
-       2.00        1.00        1.00       2.00 
-       2.00        1.00        2.00      22.00 
-       2.00        2.00        1.00       1.00 
-       2.00        2.00        2.00       3.00 
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+variable001,variable002,variable003,variable004
+1.00,1.00,1.00,2.00
+1.00,1.00,2.00,30.00
+1.00,2.00,1.00,8.00
+1.00,2.00,2.00,20.00
+2.00,1.00,1.00,2.00
+2.00,1.00,2.00,22.00
+2.00,2.00,1.00,1.00
+2.00,2.00,2.00,3.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index ba3e5c5f4e15aabccc4e8c96da676f4327e29da7..04f6b05e1a792f0848e414742e52996877e60bf7 100755 (executable)
@@ -90,38 +90,28 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|INDEP   |F8.0  |
-|DEP     |F8.0  |
-+--------+------+
-2.1 T-TEST.  Group Statistics
-#===========#==#====#==============#=========#
-#     INDEP | N|Mean|Std. Deviation|S.E. Mean#
-#===========#==#====#==============#=========#
-#DEP >=1.514|11|9.00|          3.82|     1.15#
-#    <1.514 |11|8.00|          2.86|      .86#
-#===========#==#====#==============#=========#
-2.2 T-TEST.  Independent Samples Test
-#==============================#========#============================================================================#
-#                              #Levene's|                        t-test for Equality of Means                        #
-#                              #---+----+----+-----+---------------+---------------+---------------------+-----------#
-#                              #   |    |    |     |               |               |                     |    95%    #
-#                              #   |    |    |     |               |               |                     +-----+-----#
-#                              # F |Sig.|  t |  df |Sig. (2-tailed)|Mean Difference|Std. Error Difference|Lower|Upper#
-#==============================#===#====#====#=====#===============#===============#=====================#=====#=====#
-#DEPEqual variances assumed    #.17| .68|-.69|20.00|            .50|          -1.00|                 1.44|-4.00| 2.00#
-#   Equal variances not assumed#   |    |-.69|18.54|            .50|          -1.00|                 1.44|-4.02| 2.02#
-#==============================#===#====#====#=====#===============#===============#=====================#=====#=====#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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
+DEP,>=1.514,11,9.00,3.82,1.15
+,<1.514,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
+DEP,Equal variances assumed,.17,.68,-.69,20.00,.50,-1.00,1.44,-4.00,2.00
+,Equal variances not assumed,,,-.69,18.54,.50,-1.00,1.44,-4.02,2.02
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 4cc2effa5b9c946e0425f714bf1feb1329350060..7694349142936ca42f54fc5683027e12203b6575 100755 (executable)
@@ -75,11 +75,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/ref.list
+cp $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
@@ -101,11 +101,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 07471484868d9e27af76a784d8bdca77858275bc..476f2fe0bc9ca15c929c7b74a52066343760c4b1 100755 (executable)
@@ -74,11 +74,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/ref.list
+cp $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
@@ -101,11 +101,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 843698182f461315511502fd77861d7c725237b2..b0bb6ab4781695ee8f392eb6fd49ccce79f23407 100755 (executable)
@@ -74,35 +74,25 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|ID      |F8.0  |
-|ABC     |F8.0  |
-+--------+------+
-2.1 T-TEST.  One-Sample Statistics
-#===#=#====#==============#=========#
-#   #N|Mean|Std. Deviation|S.E. Mean#
-#===#=#====#==============#=========#
-#ABC#6|3.00|           .84|      .34#
-#===#=#====#==============#=========#
-2.2 T-TEST.  One-Sample Test
-#===#===================================================#
-#   #               Test Value = 2.000000               #
-#   #----+--+---------------+---------------+-----------#
-#   #    |  |               |               |    95%    #
-#   #    |  |               |               +-----+-----#
-#   #  t |df|Sig. (2-tailed)|Mean Difference|Lower|Upper#
-#===#====#==#===============#===============#=====#=====#
-#ABC#2.93| 5|            .03|           1.00|  .12| 1.88#
-#===#====#==#===============#===============#=====#=====#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+ID,F8.0
+ABC,F8.0
+
+Table: One-Sample Statistics
+,N,Mean,Std. Deviation,S.E. Mean
+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
+ABC,2.93,5,.03,1.00,.12,1.88
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 53080bdf8b12c31c6bb4dfd35cca650886cc8a39..c149ea56fae041a2a599de1d08b5f2e7bd52f553 100755 (executable)
@@ -81,45 +81,33 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e s/^\s*\$//g $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF | perl -e 's/^\s*$//g'
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|ID      |F8.0  |
-|INDEP   |F8.0  |
-|DEP1    |F8.0  |
-|DEP2    |F8.0  |
-+--------+------+
-
-2.1 T-TEST.  Group Statistics
-#==========#=#====#==============#========#
-#     INDEP|N|Mean|Std. Deviation|SE. Mean#
-#==========#=#====#==============#========#
-#DEP1 1.1  |5|2.00|          .707|    .316#
-#     2.1  |5|4.00|          .707|    .316#
-#DEP2 1.1  |5|4.00|          .707|    .316#
-#     2.1  |5|2.00|          .707|    .316#
-#==========#=#====#==============#========#
-
-2.2 T-TEST.  Independent Samples Test
-#===============================#==========#===============================================================================#
-#                               # Levene's |                          t-test for Equality of Means                         #
-#                               #----+-----+------+-----+---------------+---------------+---------------------+------------#
-#                               #    |     |      |     |               |               |                     |    95%     #
-#                               #    |     |      |     |               |               |                     +------+-----#
-#                               # F  | Sig.|   t  |  df |Sig. (2-tailed)|Mean Difference|Std. Error Difference| Lower|Upper#
-#===============================#====#=====#======#=====#===============#===============#=====================#======#=====#
-#DEP1Equal variances assumed    #.000|1.000|-4.472|    8|           .002|         -2.000|                 .447|-3.031|-.969#
-#    Equal variances not assumed#    |     |-4.472|8.000|           .002|         -2.000|                 .447|-3.031|-.969#
-#DEP2Equal variances assumed    #.000|1.000| 4.472|    8|           .002|          2.000|                 .447|  .969|3.031#
-#    Equal variances not assumed#    |     | 4.472|8.000|           .002|          2.000|                 .447|  .969|3.031#
-#===============================#====#=====#======#=====#===============#===============#=====================#======#=====#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+ID,F8.0
+INDEP,F8.0
+DEP1,F8.0
+DEP2,F8.0
+
+Table: Group Statistics
+,INDEP,N,Mean,Std. Deviation,S.E. Mean
+DEP1,1.1,5,2.00,.71,.32
+,2.1,5,4.00,.71,.32
+DEP2,1.1,5,4.00,.71,.32
+,2.1,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
+DEP1,Equal variances assumed,.00,1.00,-4.47,8.00,.00,-2.00,.45,-3.03,-.97
+,Equal variances not assumed,,,-4.47,8.00,.00,-2.00,.45,-3.03,-.97
+DEP2,Equal variances assumed,.00,1.00,4.47,8.00,.00,2.00,.45,.97,3.03
+,Equal variances not assumed,,,4.47,8.00,.00,2.00,.45,.97,3.03
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index fd307ff339104fc3182b7feb5767ece35152f2a7..8f2e85975ec16c431eda15e80bb90ccec433ff8b 100755 (executable)
@@ -74,11 +74,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/ref.list
+cp $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -102,12 +102,12 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list 
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv 
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 2e62b4d2fb6137106cc13bcf43d8b0bef7aad2b3..b77c5dc129a35aa8e6acfde25deae4c806a74506 100755 (executable)
@@ -75,11 +75,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-cp $TEMPDIR/pspp.list $TEMPDIR/ref.list
+cp $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -100,12 +100,12 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list 
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv 
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index a747d4fddc2cd754c1df1050764960a9887943a2..5c40a65ce93c3cbae412fe38fb30743a14fe4b93 100755 (executable)
@@ -74,11 +74,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-mv $TEMPDIR/pspp.list $TEMPDIR/ref.list
+mv $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -100,12 +100,12 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 0f96be4e2b49cf0bfb6ecb4a4ed73b5594a4d230..700c1ca96f128b92af61c3d028501d282fcfbef0 100755 (executable)
@@ -74,11 +74,11 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="copy output"
-mv $TEMPDIR/pspp.list $TEMPDIR/ref.list
+mv $TEMPDIR/pspp.csv $TEMPDIR/ref.csv
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
@@ -100,12 +100,12 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program 2"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare outputs"
-diff $TEMPDIR/ref.list $TEMPDIR/pspp.list
+diff $TEMPDIR/ref.csv $TEMPDIR/pspp.csv
 if [ $? -ne 0 ] ; then fail ; fi
 
 
index 37f833049b0842adb2d2fc83216c571070809d59..4dc40cd8b7ddfcc6f9511d406eb6d1563c9141db 100755 (executable)
@@ -73,43 +73,31 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|ID      |F8.0  |
-|A       |F8.0  |
-|B       |F8.0  |
-+--------+------+
-2.1 T-TEST.  Paired Sample Statistics
-#========#====#=#==============#=========#
-#        #Mean|N|Std. Deviation|S.E. Mean#
-#========#====#=#==============#=========#
-#Pair 0 A#2.00|5|           .71|      .32#
-#       B#4.00|5|          1.54|      .69#
-#========#====#=#==============#=========#
-2.2 T-TEST.  Paired Samples Correlations
-#======#=====#=#===========#====#
-#      |     #N|Correlation|Sig.#
-#======#=====#=#===========#====#
-#Pair 0|A & B#5|        .92| .03#
-#======#=====#=#===========#====#
-2.3 T-TEST.  Paired Samples Test
-#===========#================================================#=====#==#===============#
-#           #               Paired Differences               |     |  |               #
-#           #-----+--------------+---------------+-----------+     |  |               #
-#           #     |              |               |    95%    |     |  |               #
-#           #     |              |               +-----+-----+     |  |               #
-#           # Mean|Std. Deviation|Std. Error Mean|Lower|Upper|  t  |df|Sig. (2-tailed)#
-#===========#=====#==============#===============#=====#=====#=====#==#===============#
-#Pair 0A - B#-2.00|           .94|            .42|-3.16| -.84|-4.78| 4|            .01#
-#===========#=====#==============#===============#=====#=====#=====#==#===============#
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+ID,F8.0
+A,F8.0
+B,F8.0
+
+Table: Paired Sample Statistics
+,,Mean,N,Std. Deviation,S.E. Mean
+Pair 0,A,2.00,5,.71,.32
+,B,4.00,5,1.54,.69
+
+Table: Paired Samples Correlations
+,,N,Correlation,Sig.
+Pair 0,A & B,5,.92,.03
+
+Table: Paired Samples Test
+,,Paired Differences,,,,,,,
+,,,,,95% Confidence Interval of the Difference,,,,
+,,Mean,Std. Deviation,Std. Error Mean,Lower,Upper,t,df,Sig. (2-tailed)
+Pair 0,A - B,-2.00,.94,.42,-3.16,-.84,-4.78,4,.01
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index ad530f45c83cb6cbfbb89881911e3b841ce8b8e7..0d05c5ab91cba917f2556394ceb970f850c41b8d 100755 (executable)
@@ -78,18 +78,15 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/tabs.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/tabs.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
-perl -pi -e s/^\s*\$//g $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - << EOF | perl -e 's/^\s*$//g'
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|X       |     1|  1- 80|A80   |
-+--------+------+-------+------+
+diff -c $TEMPDIR/pspp.csv - << EOF | perl -e 's/^\s*$//g'
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+X,1,1- 80,A80
+
     1   12  123 1234    12345
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
index 660752dd914eda2d4146a9aea42ebc7695597515..f410a9f55bf332b979908a4f44d11d7dc35e9d8c 100755 (executable)
@@ -81,48 +81,38 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DATA LIST.  Reading free-form data from INLINE.
-+--------+------+
-|Variable|Format|
-#========#======#
-|X       |F8.0  |
-|C       |F8.0  |
-+--------+------+
-2.1 EXAMINE.  Case Processing Summary
-#=#=======================================#
-# #                 Cases                 #
-# #-------------+-----------+-------------#
-# #    Valid    |  Missing  |    Total    #
-# #-----+-------+---+-------+-----+-------#
-# #  N  |Percent| N |Percent|  N  |Percent#
-#=#=====#=======#===#=======#=====#=======#
-#X#52.00|   100%|.00|     0%|52.00|   100%#
-#=#=====#=======#===#=======#=====#=======#
-2.2 EXAMINE.  Descriptives
-#==============================================#=========#==========#
-#                                              #Statistic|Std. Error#
-#==============================================#=========#==========#
-#X Mean                                        #   2.02  |    .03   #
-#  95% Confidence Interval for Mean Lower Bound#   1.95  |          #
-#                                   Upper Bound#   2.09  |          #
-#  5% Trimmed Mean                             #   2.00  |          #
-#  Median                                      #   2.00  |          #
-#  Variance                                    #   .06   |          #
-#  Std. Deviation                              #   .24   |          #
-#  Minimum                                     #   1.00  |          #
-#  Maximum                                     #   3.00  |          #
-#  Range                                       #   2.00  |          #
-#  Interquartile Range                         #   .00   |          #
-#  Skewness                                    #   1.19  |    .33   #
-#  Kurtosis                                    #  15.73  |    .65   #
-#==============================================#=========#==========#
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Reading free-form data from INLINE.
+Variable,Format
+X,F8.0
+C,F8.0
+
+Table: Case Processing Summary
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+X,52.00,100%,.00,0%,52.00,100%
+
+Table: Descriptives
+,,,Statistic,Std. Error
+X,Mean,,2.02,.03
+,95% Confidence Interval for Mean,Lower Bound,1.95,
+,,Upper Bound,2.09,
+,5% Trimmed Mean,,2.00,
+,Median,,2.00,
+,Variance,,.06,
+,Std. Deviation,,.24,
+,Minimum,,1.00,
+,Maximum,,3.00,
+,Range,,2.00,
+,Interquartile Range,,.00,
+,Skewness,,1.19,.33
+,Kurtosis,,15.73,.65
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 8bcb56715d5c8980d7f83bdc2a9450c4621f4f17..4d4da661d30720cc7d47a1b1ddd75817c1b65170 100755 (executable)
@@ -84,25 +84,24 @@ cat > b.data <<EOF
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
-cat > update.out <<EOF
-A B C D INA INB
-- - - - --- ---
-0 a A     1   0
-1 b B N   1   1
-1 a C     1   0
-2 a D     1   0
-3 b E O   1   1
-4 b F P   1   1
-5 a G     1   0
-5 a H     1   0
-6 b I Q   1   1
-7 b J R   1   1
-7 a K     1   0
-7 a L     1   0
-8 a M     1   0
-9 b   S   0   1
+cat > update.csv <<EOF
+Table: Data List
+A,B,C,D,INA,INB
+0,a,A,,1,0
+1,b,B,N,1,1
+1,a,C,,1,0
+2,a,D,,1,0
+3,b,E,O,1,1
+4,b,F,P,1,1
+5,a,G,,1,0
+5,a,H,,1,0
+6,b,I,Q,1,1
+7,b,J,R,1,1
+7,a,K,,1,0
+7,a,L,,1,0
+8,a,M,,1,0
+9,b,,S,0,1
 EOF
-perl -pi -e 's/^\s*$//g' update.out
 
 # Test UPDATE.
 dla="data list notable file='a.data' /A B C 1-3 (a)."
@@ -156,12 +155,12 @@ EOF
 
     activity="run $name.pspp"
     rm -f errors
-    $SUPERVISOR $PSPP --testing-mode --error-file=errors $name.pspp
+    $SUPERVISOR $PSPP -o pspp.csv --error-file=errors $name.pspp
     if [ $? -ne 0 ] ; then no_result ; fi
 
     activity="check $name output"
-    perl -pi -e 's/^\s*$//g' pspp.list
-    diff -c -b -w pspp.list update.out
+    perl -pi -e 's/^\s*$//g' pspp.csv
+    diff -c pspp.csv update.csv
     if [ $? -ne 0 ] ; then fail ; fi
     diff -c -b -w - errors <<EOF
 $name.pspp:8: warning: UPDATE: Encountered 3 sets of duplicate cases in the master file.
index 18b66f0f158054209c6b9eec653c08c2a062b663..7b26cd7bda33d9bc196cf59e0588af8d51435718 100755 (executable)
@@ -79,24 +79,23 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP -B $STAT_CONFIG_PATH --testing-mode $TEMPDIR/filter.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/filter.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="check results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - << EOF
- X
---
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
+diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+X
+1
+2
+3
+4
+5
+6
+7
+8
+9
 10
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
index d3f680245315d5eb00ed7b0e2d83c1d781e3cb51..5bf717191665bfe9fb2a4033e6ff68542bec546e 100755 (executable)
@@ -70,31 +70,24 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - << EOF
-1.1 DISPLAY.
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|x       |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 10                          |        |
-+--------+-------------------------------------------+--------+
-|y       |Format: F8.2                               |       2|
-|        |Measure: Ordinal                           |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 12                          |        |
-+--------+-------------------------------------------+--------+
-|z       |Format: F8.2                               |       3|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Center                  |        |
-|        |Display Width: 14                          |        |
-+--------+-------------------------------------------+--------+
+diff -c $TEMPDIR/pspp.csv - << EOF
+Variable,Description,,Position
+x,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Left,,
+,Display Width: 10,,
+y,Format: F8.2,,2
+,Measure: Ordinal,,
+,Display Alignment: Right,,
+,Display Width: 12,,
+z,Format: F8.2,,3
+,Measure: Nominal,,
+,Display Alignment: Center,,
+,Display Width: 14,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index e99fab4b3a3265abcda0b81b3871c8cfa53f89ed..a0da5f1270fe92fff9b84ab8313281935776c367 100755 (executable)
@@ -84,7 +84,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -e $TEMPDIR/stdout $TEMPDIR/vector.stat
+$SUPERVISOR $PSPP -o pspp.csv -e $TEMPDIR/stdout $TEMPDIR/vector.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare stdout"
@@ -94,61 +94,47 @@ EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list  - <<EOF
-+------+--------+--------+------------+
-|Vector|Position|Variable|Print Format|
-#======#========#========#============#
-|v     |       1|v1      |F8.2        |
-|      |       2|v2      |F8.2        |
-|      |       3|v3      |F8.2        |
-|      |       4|v4      |F8.2        |
-+------+--------+--------+------------+
-+------+--------+--------+------------+
-|Vector|Position|Variable|Print Format|
-#======#========#========#============#
-|#vec  |       1|#vec1   |COMMA10.2   |
-|      |       2|#vec2   |COMMA10.2   |
-|      |       3|#vec3   |COMMA10.2   |
-|      |       4|#vec4   |COMMA10.2   |
-+------+--------+--------+------------+
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|x5      |     1|  1-  1|F1.0  |
-|x2      |     1|  2-  2|F1.0  |
-|x3      |     1|  3-  3|F1.0  |
-|x1      |     1|  4-  4|F1.0  |
-|x4      |     1|  5-  5|F1.0  |
-+--------+------+-------+------+
-+------+--------+--------+------------+
-|Vector|Position|Variable|Print Format|
-#======#========#========#============#
-|x     |       1|x1      |F8.2        |
-|      |       2|x2      |F8.2        |
-|      |       3|x3      |F8.2        |
-|      |       4|x4      |F8.2        |
-|      |       5|x5      |F8.2        |
-+------+--------+--------+------------+
-+------+--------+--------+------------+
-|Vector|Position|Variable|Print Format|
-#======#========#========#============#
-|a     |       1|u       |F1.0        |
-|      |       2|w       |F1.0        |
-|      |       3|x       |F1.0        |
-|      |       4|y       |F1.0        |
-+------+--------+--------+------------+
-|b     |       1|x       |F1.0        |
-|      |       2|y       |F1.0        |
-|      |       3|z       |F1.0        |
-+------+--------+--------+------------+
-|c     |       1|u       |F1.0        |
-|      |       2|w       |F1.0        |
-|      |       3|x       |F1.0        |
-|      |       4|y       |F1.0        |
-|      |       5|z       |F1.0        |
-+------+--------+--------+------------+
+diff -c $TEMPDIR/pspp.csv  - <<EOF
+Vector,Position,Variable,Print Format
+v,1,v1,F8.2
+,2,v2,F8.2
+,3,v3,F8.2
+,4,v4,F8.2
+
+Vector,Position,Variable,Print Format
+#vec,1,#vec1,COMMA10.2
+,2,#vec2,COMMA10.2
+,3,#vec3,COMMA10.2
+,4,#vec4,COMMA10.2
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+x5,1,1-  1,F1.0
+x2,1,2-  2,F1.0
+x3,1,3-  3,F1.0
+x1,1,4-  4,F1.0
+x4,1,5-  5,F1.0
+
+Vector,Position,Variable,Print Format
+x,1,x1,F8.2
+,2,x2,F8.2
+,3,x3,F8.2
+,4,x4,F8.2
+,5,x5,F8.2
+
+Vector,Position,Variable,Print Format
+a,1,u,F1.0
+,2,w,F1.0
+,3,x,F1.0
+,4,y,F1.0
+b,1,x,F1.0
+,2,y,F1.0
+,3,z,F1.0
+c,1,u,F1.0
+,2,w,F1.0
+,3,x,F1.0
+,4,y,F1.0
+,5,z,F1.0
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 7c09d8dc533265ef1e868955b518a0031d4dec11..e7130c142d69ee1f5d7839d0d2035ce76c11b25b 100755 (executable)
@@ -73,67 +73,55 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program 0"
-$SUPERVISOR $PSPP --testing-mode -e /dev/null $TESTFILE 
+$SUPERVISOR $PSPP -o pspp.csv -e /dev/null $TESTFILE 
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare variable display 0"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|N       |Format: F8.2                               |       1|
-|        |Measure: Scale                             |        |
-|        |Display Alignment: Right                   |        |
-|        |Display Width: 10                          |        |
-+--------+-------------------------------------------+--------+
-|A255    |Format: A255                               |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
-|A258    |Format: A258                               |       3|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
-|A2000   |Format: A2000                              |       4|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
-       N                                                                                                                                                                                                                                                            A255                                                                                                                                                                                                                                                               A258                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            A2000
--------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-    1.00 a1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA b1BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB c1CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 
-    2.00 a2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX b2YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY c2ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
-2.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|vl255   |Format: A255                               |       1|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 26                          |        |
-+--------+-------------------------------------------+--------+
-|vl256   |Format: A256                               |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 26                          |        |
-+--------+-------------------------------------------+--------+
-|vl1335  |Format: A1335                              |       3|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 26                          |        |
-+--------+-------------------------------------------+--------+
-|vl2000  |Format: A2000                              |       4|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 26                          |        |
-+--------+-------------------------------------------+--------+
-                                                                                                                                                                                                                                                          vl255                                                                                                                                                                                                                                                            vl256                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  vl1335                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           vl2000
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Variable,Description,,Position
+N,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 10,,
+A255,Format: A255,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+A258,Format: A258,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+A2000,Format: A2000,,4
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+
+Table: Data List
+N,A255,A258,A2000
+1.00,a1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,b1BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,c1CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+2.00,a2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,b2YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY,c2ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
+
+Variable,Description,,Position
+vl255,Format: A255,,1
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 26,,
+vl256,Format: A256,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 26,,
+vl1335,Format: A1335,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 26,,
+vl2000,Format: A2000,,4
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 26,,
+
+Table: Data List
+vl255,vl256,vl1335,vl2000
+MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM,MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -164,7 +152,7 @@ EOF
 
 
     activity="run program 1 ($options)"
-    $SUPERVISOR $PSPP --testing-mode $TESTFILE
+    $SUPERVISOR $PSPP -o pspp.csv $TESTFILE
     if [ $? -ne 0 ] ; then no_result ; fi
 
     activity="Create file2 ($options)"
@@ -185,7 +173,7 @@ EOF
     if [ $? -ne 0 ] ; then no_result ; fi
 
     activity="run program 2 ($options)"
-    $SUPERVISOR $PSPP --testing-mode $TESTFILE
+    $SUPERVISOR $PSPP -o pspp.csv $TESTFILE
     if [ $? -ne 0 ] ; then no_result ; fi
 
 
@@ -197,32 +185,24 @@ EOF
 
 
     activity="compare variable display ($options)"
-    perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-    diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 DISPLAY.  
-+--------+-------------------------------------------+--------+
-|Variable|Description                                |Position|
-#========#===========================================#========#
-|a       |Format: A10                                |       1|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 10                          |        |
-+--------+-------------------------------------------+--------+
-|b       |Format: A256                               |       2|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
-|c       |Format: A200                               |       3|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
-|d       |Format: A32767                             |       4|
-|        |Measure: Nominal                           |        |
-|        |Display Alignment: Left                    |        |
-|        |Display Width: 32                          |        |
-+--------+-------------------------------------------+--------+
+    diff -c $TEMPDIR/pspp.csv - <<EOF
+Variable,Description,,Position
+a,Format: A10,,1
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 10,,
+b,Format: A256,,2
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+c,Format: A200,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+d,Format: A32767,,4
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
 EOF
     if [ $? -ne 0 ] ; then fail ; fi
 done
index 0d4fb3970b21fc685f0c059d72651ff177a75b46..5c6ce31b0e96d64f63ec84d30950f071a38bcf72 100755 (executable)
@@ -73,101 +73,92 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from "$top_srcdir/tests/weighting.data".
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|AVAR    |     1|  1-  5|F5.0  |
-|BVAR    |     1|  6- 10|F5.0  |
-+--------+------+-------+------+
-2.1 DESCRIPTIVES.  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.00|
-+--------#-------+---------+------+---------+-------+--------+--------+---------+--------+---------+------+-------+-------+--------+
-3.1 FREQUENCIES.  AVAR
-+--------+--------+---+---+
-|        |        |   |Cum|
-|  Value |  Freq  |Pct|Pct|
-#========#========#===#===#
-|      18|       1|.13|.13|
-|      19|       7|.95|1.0|
-|      20|      26|3.5|4.6|
-|      21|      76|10.|15.|
-|      22|      57|7.8|22.|
-|      23|      58|7.9|30.|
-|      24|      38|5.2|36.|
-|      25|      38|5.2|41.|
-|      26|      30|4.1|45.|
-|      27|      21|2.8|48.|
-|      28|      23|3.1|51.|
-|      29|      24|3.2|54.|
-|      30|      23|3.1|57.|
-|      31|      14|1.9|59.|
-|      32|      21|2.8|62.|
-|      33|      21|2.8|65.|
-|      34|      14|1.9|67.|
-|      35|      14|1.9|69.|
-|      36|      17|2.3|71.|
-|      37|      11|1.5|73.|
-|      38|      16|2.1|75.|
-|      39|      14|1.9|77.|
-|      40|      15|2.0|79.|
-|      41|      14|1.9|81.|
-|      42|      14|1.9|83.|
-|      43|       8|1.0|84.|
-|      44|      15|2.0|86.|
-|      45|      10|1.3|87.|
-|      46|      12|1.6|89.|
-|      47|      13|1.7|91.|
-|      48|      13|1.7|92.|
-|      49|       5|.68|93.|
-|      50|       5|.68|94.|
-|      51|       3|.41|94.|
-|      52|       7|.95|95.|
-|      53|       6|.82|96.|
-|      54|       2|.27|96.|
-|      55|       2|.27|96.|
-|      56|       2|.27|97.|
-|      57|       3|.41|97.|
-|      58|       1|.13|97.|
-|      59|       3|.41|98.|
-|      61|       1|.13|98.|
-|      62|       3|.41|98.|
-|      63|       1|.13|98.|
-|      64|       1|.13|99.|
-|      65|       2|.27|99.|
-|      70|       1|.13|99.|
-|      78|       1|.13|99.|
-|      79|       1|.13|99.|
-|      80|       1|.13|99.|
-|      94|       1|.13|100|
-+--------+--------+---+---+
-+-----------------------+--------+
-|N           Valid      |     730|
-|            Missing    |       0|
-|Mean                   |  31.515|
-|S.E. Mean              |    .405|
-|Mode                   |  21.000|
-|Std Dev                |  10.937|
-|Variance               | 119.608|
-|Kurtosis               |   2.411|
-|S.E. Kurt              |    .181|
-|Skewness               |   1.345|
-|S.E. Skew              |    .090|
-|Range                  |  76.000|
-|Minimum                |  18.000|
-|Maximum                |  94.000|
-|Sum                    |23006.00|
-|Percentiles 50 (Median)|      29|
-+-----------------------+--------+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+"Table: Reading 1 record from ""$top_srcdir/tests/weighting.data""."
+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.00
+
+Table: AVAR
+,,,Cum
+Value,Freq,Pct,Pct
+18,1,.137,.137
+19,7,.959,1.096
+20,26,3.562,4.658
+21,76,10.411,15.068
+22,57,7.808,22.877
+23,58,7.945,30.822
+24,38,5.205,36.027
+25,38,5.205,41.233
+26,30,4.110,45.342
+27,21,2.877,48.219
+28,23,3.151,51.370
+29,24,3.288,54.658
+30,23,3.151,57.808
+31,14,1.918,59.726
+32,21,2.877,62.603
+33,21,2.877,65.479
+34,14,1.918,67.397
+35,14,1.918,69.315
+36,17,2.329,71.644
+37,11,1.507,73.151
+38,16,2.192,75.342
+39,14,1.918,77.260
+40,15,2.055,79.315
+41,14,1.918,81.233
+42,14,1.918,83.151
+43,8,1.096,84.247
+44,15,2.055,86.301
+45,10,1.370,87.671
+46,12,1.644,89.315
+47,13,1.781,91.096
+48,13,1.781,92.877
+49,5,.685,93.562
+50,5,.685,94.247
+51,3,.411,94.658
+52,7,.959,95.616
+53,6,.822,96.438
+54,2,.274,96.712
+55,2,.274,96.986
+56,2,.274,97.260
+57,3,.411,97.671
+58,1,.137,97.808
+59,3,.411,98.219
+61,1,.137,98.356
+62,3,.411,98.767
+63,1,.137,98.904
+64,1,.137,99.041
+65,2,.274,99.315
+70,1,.137,99.452
+78,1,.137,99.589
+79,1,.137,99.726
+80,1,.137,99.863
+94,1,.137,100.000
+
+N,Valid,730
+,Missing,0
+Mean,,31.515
+S.E. Mean,,.405
+Mode,,21.000
+Std Dev,,10.937
+Variance,,119.608
+Kurtosis,,2.411
+S.E. Kurt,,.181
+Skewness,,1.345
+S.E. Skew,,.090
+Range,,76.000
+Minimum,,18.000
+Maximum,,94.000
+Sum,,23006.00
+Percentiles,50 (Median),29
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index de91adc6dcc8e7fad6e8408863dddd9869a46c6e..3a210783c2fed0b507cd50f67c12aa23119c7ee0 100755 (executable)
@@ -47,6 +47,6 @@ FREQUENCIES /COVERAGE
 
 EOF
 
-src/pspp -o html $TEMPDIR/cov.sps
+src/pspp -o pspp.html $TEMPDIR/cov.sps
 
 rm -rf $TEMPDIR
index c46c268376c77031baff7e6c06fa14a44808bd65..98be04fe44b25c73a7cb608596b02296b3b3894c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010 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
@@ -748,7 +748,7 @@ enum
     N_DATASHEET_OPTIONS
   };
 
-static struct argv_option datasheet_argv_options[N_DATASHEET_OPTIONS] =
+static const struct argv_option datasheet_argv_options[N_DATASHEET_OPTIONS] =
   {
     {"max-rows", 0, required_argument, OPT_MAX_ROWS},
     {"max-columns", 0, required_argument, OPT_MAX_COLUMNS},
index 1ceab30801673dc06137b1222f29eb19388c072b..dcbfc0ac4e0d59d650abd12a077db7ed8d562cd4 100755 (executable)
@@ -142,7 +142,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/epoch.stat > $TEMPDIR/epoch.err 2> $TEMPDIR/epoch.out
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv $TEMPDIR/epoch.stat > $TEMPDIR/epoch.err 2> $TEMPDIR/epoch.out
 
 activity="compare results"
 perl -pi -e 's/^\s*$//g' $TEMPDIR/epoch.out
index 339abed4dd90318ffb4fb8a27d5f6103f2c69f0b..49ad4f7d51e55f0fd84579b7a85a3836424ac2bc 100755 (executable)
@@ -1565,7 +1565,7 @@ sed < $TEMPDIR/expr-list >> $TEMPDIR/expr-opt.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run optimizing program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
         $TEMPDIR/expr-opt.stat >$TEMPDIR/expr-opt.err 2> $TEMPDIR/expr-opt.out
 
 activity="compare optimizing output"
@@ -1581,7 +1581,7 @@ sed < $TEMPDIR/expr-list >> $TEMPDIR/expr-noopt.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run non-optimizing program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
        $TEMPDIR/expr-noopt.stat >$TEMPDIR/expr-noopt.err 2> $TEMPDIR/expr-noopt.out
 
 activity="compare non-optimizing output"
@@ -1597,7 +1597,7 @@ sed < $TEMPDIR/expr-list >> $TEMPDIR/expr-opt-pos.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run optimizing postfix program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
         $TEMPDIR/expr-opt-pos.stat >$TEMPDIR/expr-opt-pos.err 2> $TEMPDIR/expr-opt-pos.out
 if [ $? -eq 0 ] ; then no_result ; fi
 
@@ -1609,7 +1609,7 @@ sed < $TEMPDIR/expr-list >> $TEMPDIR/expr-noopt-pos.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run non-optimizing postfix program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
        $TEMPDIR/expr-noopt-pos.stat >$TEMPDIR/expr-noopt-pos.err 2> $TEMPDIR/expr-noopt-pos.out
 if [ $? -eq 0 ] ; then no_result ; fi
 
index 58fe386d291f4738661c0385d1ee67faeaf0d180..88a57e5fcba4d643b2a6614a1ac0308886d9dee2 100755 (executable)
@@ -60,7 +60,7 @@ perl $top_srcdir/tests/expressions/randist/randist.pl \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run command file"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP -o pspp.csv \
     $TEMPDIR/randist.pspp >$TEMPDIR/randist.err 2> $TEMPDIR/randist.out
 if [ $? -ne 0 ] ; then fail ; fi
 
index cb0f5ba3a04161a27ca712c4b43df36c7e83e2a8..c751689e1accf24ce93dc0761cb10eefb5c0b189 100755 (executable)
@@ -88,22 +88,21 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/valuelabel.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/valuelabel.stat
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-n s     nlabel     slabel
-- - ---------- ----------
-.                         
-0 a Very dissa Wouldn't b 
-1 b Dissatisfi Unhappy    
-2 c Neutral    Bored      
-3 d Satisfied  Satiated   
-4 e Very satis Elated     
-5 f                       
-6 g                       
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Data List
+n,s,nlabel,slabel
+.,,,
+0,a,Very dissa,Wouldn't b
+1,b,Dissatisfi,Unhappy   
+2,c,Neutral   ,Bored     
+3,d,Satisfied ,Satiated  
+4,e,Very satis,Elated    
+5,f,,
+6,g,,
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index c4a2d5d46e5908aabd05e5fc3da29f1e61d419c6..64ea80d119c30b8b098532f62f35d44813af0226 100755 (executable)
@@ -101,26 +101,23 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/variables.stat > $TEMPDIR/variables.err 2> $TEMPDIR/variables.out
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/variables.stat > $TEMPDIR/variables.err 2> $TEMPDIR/variables.out
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|N1      |     1|  1-  1|F1.0  |
-|N2      |     1|  2-  2|F1.0  |
-|N3      |     1|  3-  3|F1.0  |
-|N4      |     1|  4-  4|F1.0  |
-|N5      |     1|  5-  5|F1.0  |
-+--------+------+-------+------+
-N1 N2 N3 N4 N5 P1 P2 P3 P4 P5 MC VC S1 S2 S3 S4 S5 M1 M2 M3 M4 M5 V1 V2 V3 V4 V5
--- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 1  2  3  4  5  .  2  .  .  .  4  1  0  0  0  0  0  1  0  1  1  1  1  2  3  4  5 
- 6  7  8  9  .  6  7  8  9  .  1  4  0  0  0  0  1  0  0  0  0  1  6  7  8  9  . 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+N1,1,1-  1,F1.0
+N2,1,2-  2,F1.0
+N3,1,3-  3,F1.0
+N4,1,4-  4,F1.0
+N5,1,5-  5,F1.0
+
+Table: Data List
+N1,N2,N3,N4,N5,P1,P2,P3,P4,P5,MC,VC,S1,S2,S3,S4,S5,M1,M2,M3,M4,M5,V1,V2,V3,V4,V5
+1,2,3,4,5,.,2,.,.,.,4,1,0,0,0,0,0,1,0,1,1,1,1,2,3,4,5
+6,7,8,9,.,6,7,8,9,.,1,4,0,0,0,0,1,0,0,0,0,1,6,7,8,9,.
 EOF
 
 if [ $? -ne 0 ] ; then no_result ; fi
index 57cef8b6607da8d3cba4f6ab98db333088d2e468..3eb4140476c509ae919252fc2a46f3d7e4e557dc 100755 (executable)
@@ -78,26 +78,23 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/vectors.stat > $TEMPDIR/vectors.err 2> $TEMPDIR/vectors.out
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/vectors.stat > $TEMPDIR/vectors.err 2> $TEMPDIR/vectors.out
 if [ $? -ne 0 ] ; then fail ; fi
 
 activity="compare results"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b  $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|N1      |     1|  1-  1|F1.0  |
-|N2      |     1|  2-  2|F1.0  |
-|N3      |     1|  3-  3|F1.0  |
-|N4      |     1|  4-  4|F1.0  |
-|N5      |     1|  5-  5|F1.0  |
-+--------+------+-------+------+
-N1 N2 N3 N4 N5 X1 X2 X3 X4 X5  I
--- -- -- -- -- -- -- -- -- -- --
- 1  2  3  4  5  .  3  .  .  .  5 
- 6  7  8  9  .  7  8  9 10  .  5 
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+N1,1,1-  1,F1.0
+N2,1,2-  2,F1.0
+N3,1,3-  3,F1.0
+N4,1,4-  4,F1.0
+N5,1,5-  5,F1.0
+
+Table: Data List
+N1,N2,N3,N4,N5,X1,X2,X3,X4,X5,I
+1,2,3,4,5,.,3,.,.,.,5
+6,7,8,9,.,7,8,9,10,.,5
 EOF
 
 if [ $? -ne 0 ] ; then no_result ; fi
index 5139dd30abcd6ba7565033593913a775119280da..57f928cf7cc11e6371bb47a89fc598873ab3954b 100755 (executable)
@@ -231,26 +231,26 @@ list.
 EOF
     if [ $? -ne 0 ] ; then no_result ; fi
 
-    # Make sure that pspp.list isn't left over from another run.
-    rm -f pspp.list
+    # Make sure that pspp.csv isn't left over from another run.
+    rm -f pspp.csv
 
     activity="run $type.pspp"
-    $SUPERVISOR $PSPP --testing-mode $type.pspp
+    $SUPERVISOR $PSPP -o pspp.csv $type.pspp
     if [ $? -ne 0 ] ; then fail ; fi
 
     activity="compare $type.pspp output"
-    perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-    diff -b  $TEMPDIR/pspp.list - << EOF
-     start        end count
----------- ---------- -----
-07/22/2007 10/06/2007   321
-07/14/1789 08/26/1789     4
-01/01/1972 12/31/1999   682
-     start        end count
----------- ---------- -----
-07/22/2007 10/06/2007   322
-07/14/1789 08/26/1789     5
-01/01/1972 12/31/1999   683
+    diff -c $TEMPDIR/pspp.csv - << EOF
+Table: Data List
+start,end,count
+07/22/2007,10/06/2007,321
+07/14/1789,08/26/1789,4
+01/01/1972,12/31/1999,682
+
+Table: Data List
+start,end,count
+07/22/2007,10/06/2007,322
+07/14/1789,08/26/1789,5
+01/01/1972,12/31/1999,683
 EOF
     if [ $? -ne 0 ] ; then fail ; fi
 done
index 934f4302c0fef129cec4fe0469b111aa36ea3836..46c972fead425f8deb770eb0498c448f9ea62db1 100755 (executable)
@@ -71,7 +71,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode bcd-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv bcd-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="gunzip expected results"
index caffb03b1a1073236a75549ef7c1e918504da8d0..6fb4a972460a761773313e2bf8adba08c8a0c9f4 100755 (executable)
@@ -154,7 +154,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode binhex-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv binhex-out.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="gunzip expected results"
index edadc3f5b8e184fa1fa28401f7b2359724bad4d2..9488fb9b5abbe168c9dcdbf66a549fb2fe5f7abf 100755 (executable)
@@ -254,7 +254,7 @@ $PERL date-in.pl
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode date-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv date-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare adate.out output"
index 6e28083cfaa2dd697561074582ea9ec9748d471b..5f360c73a6121bf0a3d31bcffdd554fb25137849 100755 (executable)
@@ -88,7 +88,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode date-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv date-out.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
@@ -510,7 +510,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode bad-date-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv bad-date-out.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
index 2a6b608740e1e248895056a043513f0bcdf3614d..dee97909567b6bfcfd424dc9c673f8fea89dff56 100755 (executable)
@@ -149,7 +149,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/float-format.pspp
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv $TEMPDIR/float-format.pspp
 if [ $? -ne 0 ] ; then fail ; fi
 
 pass
index 75885a7830c901fc4e0dcaba897cfb8caae28dde..c84860a737920eb090d4ca74f91f93b70836ec30 100755 (executable)
@@ -186,7 +186,7 @@ activity="create syntax file"
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
         $TEMPDIR/test.stat >$TEMPDIR/test.err 2> $TEMPDIR/test.out
 
 activity="compare output"
index 3a54c2f0fc8e515f15fa07158c2bfe67296032c7..50c8c93bea438fc16f18a5b628b4832dfae0e170 100755 (executable)
@@ -72,7 +72,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode ib-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv ib-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="gunzip expected results"
index 1087a06f1292a70b1889196cb8a0fc75757f33be..eaab8e143943b03a2ce8d7cd68afecd5b11e3871 100755 (executable)
@@ -71,7 +71,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode legacy-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv legacy-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="gunzip expected results"
index 2d32a594ec244bfd5afdeca080cf4ddd9c71eacc..dd5f02724cc418f6c296b5b9da4c2a77f9a086b2 100755 (executable)
@@ -105,7 +105,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode month-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv month-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
index 65d0a42ed29faa1106a81ff2762236008f4b6422..fba0ae8990dc17d18b9f9ebea1a23071a602cc1d 100755 (executable)
@@ -41,6 +41,7 @@ cd $TEMPDIR
 activity="write pspp syntax"
 cat > month-out.pspp <<EOF
 set errors=none.
+set mxerr=1000000.
 set mxwarns=10000000.
 data list /x 1-10.
 begin data.
@@ -111,7 +112,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode month-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv month-out.pspp
 if [ $? -eq 0 ] ; then no_result ; fi
 
 activity="compare output"
index b61019f370a57e782d05cfc352b2e6c0b363f139..d515546775d0fbefff5aa1dd3d1fbe70a2ffb7e1 100755 (executable)
@@ -200,7 +200,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 echo -n .
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode num-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv num-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 echo -n .
 
index cf4185aea3f453b86688908b9f1181337bb16f44..acf1846f79c291d57acf7f2299360be6040ba700 100755 (executable)
@@ -45,7 +45,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 echo -n .
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode num-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv num-out.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 echo -n .
 
index 69d7b84d7a165c7a4975b22ccb65a4ecfb95c48d..ca80f960d3a145bc40dd2481cadcb0d9eda2b5d4 100755 (executable)
@@ -170,7 +170,7 @@ $PERL time-in.pl
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode time-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv time-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare time.out output"
index c110b966a9668f64b51d69f617d6e0c2610e94f7..ed2f36dfc98806b772aeac5572627dfa44c02426 100755 (executable)
@@ -313,7 +313,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode time-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv time-out.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
index 6105ae07c45482ec6a362361e3f1f32b9aa4200d..b9b57484b725ff39d9919a5f88e01586255d2f40 100755 (executable)
@@ -69,7 +69,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode wkday-in.pspp
+$SUPERVISOR $PSPP -o pspp.csv wkday-in.pspp
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
index f4ea9ec34d0351f8f0b5bce97ccd9d59c1bb99b6..4116656e3679492619b230ce094f999a63c60ae3 100755 (executable)
@@ -72,7 +72,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode wkday-out.pspp
+$SUPERVISOR $PSPP -o pspp.csv wkday-out.pspp
 if [ $? -eq 0 ] ; then no_result ; fi
 
 activity="compare output"
index 4ca7f92fd73f48316bcc53c1f388bfab69427a11..64511b7bbf1d1c7dafb79857fc811b014d6e9af2 100644 (file)
@@ -342,6 +342,7 @@ check_hmap (struct hmap *hmap, const int data[], size_t cnt,
   size_t i, j;
   int *order;
 
+  check (hmap_is_empty (hmap) == (cnt == 0));
   check (hmap_count (hmap) == cnt);
   check (cnt <= hmap_capacity (hmap));
 
@@ -378,7 +379,6 @@ check_hmap (struct hmap *hmap, const int data[], size_t cnt,
       for (p = hmap_first (hmap), i = 0; i < cnt; p = hmap_next (hmap, p), i++)
         {
           struct element *e = hmap_node_to_element (p);
-          size_t j;
 
           check (hmap_node_hash (&e->node) == hash (e->data));
           for (j = 0; j < left; j++)
index fc08ca6161040a89d1c54574cb6f6ec2866886fb..5ad5d5723fcbc128645552ced1fb6de2a07c4dff 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009 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
@@ -262,6 +262,7 @@ check_hmapx (struct hmapx *hmapx, const int data[], size_t cnt,
   size_t i, j;
   int *order;
 
+  check (hmapx_is_empty (hmapx) == (cnt == 0));
   check (hmapx_count (hmapx) == cnt);
   check (cnt <= hmapx_capacity (hmapx));
 
index 2befd51a4451c899f18fac5a23146444ba9d35a2..f8fe9b73618578f50f8dad56f18a3c261122b3f3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010 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
@@ -865,6 +865,34 @@ test_find_equal (void)
   test_examine_equal_range (test_find_equal_helper);
 }
 
+/* Tests llx_find(). */
+static void
+test_find (void)
+{
+  const int max_elems = 8;
+
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      struct llx_list list;
+      struct element **elems;
+      struct llx **elemp;
+      int *values;
+
+      int i;
+
+      allocate_ascending (cnt, &list, &elems, &elemp, &values);
+
+      for (i = 0; i < cnt; i++)
+        check (llx_find (llx_head (&list), llx_null (&list), elems[i])
+               == elemp[i]);
+      check (llx_find (llx_head (&list), llx_null (&list), NULL) == NULL);
+
+      free_elements (cnt, &list, elems, elemp, values);
+    }
+}
+
 /* Helper function for testing llx_find_if. */
 static void
 test_find_if_helper (int r0, int r1, int eq_pat, struct llx **elemp)
@@ -2040,6 +2068,7 @@ main (void)
   run_test (test_remove_equal, "remove_equal");
   run_test (test_remove_if, "remove_if");
   run_test (test_find_equal, "find_equal");
+  run_test (test_find, "find");
   run_test (test_find_if, "find_if");
   run_test (test_find_adjacent_equal, "find_adjacent_equal");
   run_test (test_count_range, "count_range");
index e8cbffa5e6334408bbd69dc4c7c2a7e9dbb72829..8d6e68316834d707254b5888f92d1b41b1064bb6 100644 (file)
@@ -212,7 +212,7 @@ check_pattern (const struct range_set *rs, unsigned int pattern)
      caching. */
   for (start = 0; start <= 32; start++)
     {
-      struct range_set *nonconst_rs = (struct range_set *) rs;
+      struct range_set *nonconst_rs = CONST_CAST (struct range_set *, rs);
       nonconst_rs->cache_end = 0;
       s1 = range_set_scan (rs, start);
       s2 = next_1bit (pattern, start);
diff --git a/tests/libpspp/string-map-test.c b/tests/libpspp/string-map-test.c
new file mode 100644 (file)
index 0000000..e3f3b79
--- /dev/null
@@ -0,0 +1,906 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007, 2008, 2009 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/>. */
+
+/* This is a test program for the string_map_* routines defined in
+   string-map.c.  This test program aims to be as comprehensive as possible.
+   "gcov -a -b" should report almost complete coverage of lines, blocks and
+   branches in string-map.c, except that one branch caused by hash collision is
+   not exercised because our hash function has so few collisions.  "valgrind
+   --leak-check=yes --show-reachable=yes" should give a clean report. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libpspp/string-map.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+#include <libpspp/compiler.h>
+#include <libpspp/string-set.h>
+\f
+/* Currently running test. */
+static const char *test_name;
+
+/* Exit with a failure code.
+   (Place a breakpoint on this function while debugging.) */
+static void
+check_die (void)
+{
+  exit (EXIT_FAILURE);
+}
+
+/* If OK is not true, prints a message about failure on the
+   current source file and the given LINE and terminates. */
+static void
+check_func (bool ok, int line)
+{
+  if (!ok)
+    {
+      printf ("Check failed in %s test at %s, line %d\n",
+              test_name, __FILE__, line);
+      check_die ();
+    }
+}
+
+/* Verifies that EXPR evaluates to true.
+   If not, prints a message citing the calling line number and
+   terminates. */
+#define check(EXPR) check_func ((EXPR), __LINE__)
+
+/* Prints a message about memory exhaustion and exits with a
+   failure code. */
+static void
+xalloc_die (void)
+{
+  printf ("virtual memory exhausted\n");
+  exit (EXIT_FAILURE);
+}
+
+static void *xmalloc (size_t n) MALLOC_LIKE;
+static void *xnmalloc (size_t n, size_t m) MALLOC_LIKE;
+static void *xmemdup (const void *p, size_t n) MALLOC_LIKE;
+
+/* Allocates and returns N bytes of memory. */
+static void *
+xmalloc (size_t n)
+{
+  if (n != 0)
+    {
+      void *p = malloc (n);
+      if (p == NULL)
+        xalloc_die ();
+
+      return p;
+    }
+  else
+    return NULL;
+}
+
+static void *
+xmemdup (const void *p, size_t n)
+{
+  void *q = xmalloc (n);
+  memcpy (q, p, n);
+  return q;
+}
+
+/* Clone STRING.  */
+static char *
+xstrdup (const char *string)
+{
+  return xmemdup (string, strlen (string) + 1);
+}
+
+/* Allocates and returns N * M bytes of memory. */
+static void *
+xnmalloc (size_t n, size_t m)
+{
+  if ((size_t) -1 / m <= n)
+    xalloc_die ();
+  return xmalloc (n * m);
+}
+\f
+/* Support routines. */
+
+enum {
+  IDX_BITS = 10,
+  MAX_IDX = 1 << IDX_BITS,
+  KEY_MASK = (MAX_IDX - 1),
+  KEY_SHIFT = 0,
+  VALUE_MASK = (MAX_IDX - 1) << IDX_BITS,
+  VALUE_SHIFT = IDX_BITS
+};
+
+static char *string_table[MAX_IDX];
+
+static const char *
+get_string (int idx)
+{
+  char **s;
+
+  assert (idx >= 0 && idx < MAX_IDX);
+  s = &string_table[idx];
+  if (*s == NULL)
+    {
+      *s = xmalloc (16);
+      sprintf (*s, "%d", idx);
+    }
+  return *s;
+}
+
+static void
+free_strings (void)
+{
+  int i;
+
+  for (i = 0; i < MAX_IDX; i++)
+    free (string_table[i]);
+}
+
+static const char *
+make_key (int value)
+{
+  return get_string ((value & KEY_MASK) >> KEY_SHIFT);
+}
+
+static const char *
+make_value (int value)
+{
+  return get_string ((value & VALUE_MASK) >> VALUE_SHIFT);
+}
+
+static int
+random_value (unsigned int seed, int basis)
+{
+  return hash_int (seed, basis) & VALUE_MASK;
+}
+
+/* Swaps *A and *B. */
+static void
+swap (int *a, int *b)
+{
+  int t = *a;
+  *a = *b;
+  *b = t;
+}
+
+/* Reverses the order of the CNT integers starting at VALUES. */
+static void
+reverse (int *values, size_t cnt)
+{
+  size_t i = 0;
+  size_t j = cnt;
+
+  while (j > i)
+    swap (&values[i++], &values[--j]);
+}
+
+/* Arranges the CNT elements in VALUES into the lexicographically next greater
+   permutation.  Returns true if successful.  If VALUES is already the
+   lexicographically greatest permutation of its elements (i.e. ordered from
+   greatest to smallest), arranges them into the lexicographically least
+   permutation (i.e. ordered from smallest to largest) and returns false.
+
+   Comparisons among elements of VALUES consider only the bits in KEY_MASK. */
+static bool
+next_permutation (int *values, size_t cnt)
+{
+  if (cnt > 0)
+    {
+      size_t i = cnt - 1;
+      while (i != 0)
+        {
+          i--;
+          if ((values[i] & KEY_MASK) < (values[i + 1] & KEY_MASK))
+            {
+              size_t j;
+              for (j = cnt - 1;
+                   (values[i] & KEY_MASK) >= (values[j] & KEY_MASK);
+                   j--)
+                continue;
+              swap (values + i, values + j);
+              reverse (values + (i + 1), cnt - (i + 1));
+              return true;
+            }
+        }
+
+      reverse (values, cnt);
+    }
+
+  return false;
+}
+
+/* Returns N!. */
+static unsigned int
+factorial (unsigned int n)
+{
+  unsigned int value = 1;
+  while (n > 1)
+    value *= n--;
+  return value;
+}
+
+/* Randomly shuffles the CNT elements in ARRAY, each of which is
+   SIZE bytes in size. */
+static void
+random_shuffle (void *array_, size_t cnt, size_t size)
+{
+  char *array = array_;
+  char *tmp = xmalloc (size);
+  size_t i;
+
+  for (i = 0; i < cnt; i++)
+    {
+      size_t j = rand () % (cnt - i) + i;
+      if (i != j)
+        {
+          memcpy (tmp, array + j * size, size);
+          memcpy (array + j * size, array + i * size, size);
+          memcpy (array + i * size, tmp, size);
+        }
+    }
+
+  free (tmp);
+}
+
+/* Checks that MAP contains the CNT strings in DATA, that its structure is
+   correct, and that certain operations on MAP produce the expected results. */
+static void
+check_string_map (struct string_map *map, const int data[], size_t cnt)
+{
+  size_t i;
+
+  check (string_map_is_empty (map) == (cnt == 0));
+  check (string_map_count (map) == cnt);
+
+  for (i = 0; i < cnt; i++)
+    {
+      struct string_map_node *node;
+      const char *key = make_key (data[i]);
+      const char *value = make_value (data[i]);
+      const char *found_value;
+
+      check (string_map_contains (map, key));
+
+      node = string_map_find_node (map, key);
+      check (node != NULL);
+      check (!strcmp (key, string_map_node_get_key (node)));
+      check (!strcmp (value, string_map_node_get_value (node)));
+
+      check (node == string_map_insert (map, key, "abc"));
+      check (!strcmp (value, string_map_node_get_value (node)));
+
+      check (node == string_map_insert_nocopy (map, xstrdup (key),
+                                               xstrdup ("def")));
+      check (!strcmp (value, string_map_node_get_value (node)));
+
+      found_value = string_map_find (map, key);
+      check (found_value != NULL);
+      check (!strcmp (found_value, value));
+    }
+
+  check (!string_map_contains (map, "xxx"));
+  check (string_map_find (map, "z") == NULL);
+  check (string_map_find_node (map, "") == NULL);
+  check (!string_map_delete (map, "xyz"));
+
+  if (cnt == 0)
+    check (string_map_first (map) == NULL);
+  else
+    {
+      const struct string_map_node *node;
+      int *data_copy;
+      int left;
+
+      data_copy = xmemdup (data, cnt * sizeof *data);
+      left = cnt;
+      for (node = string_map_first (map), i = 0; i < cnt;
+           node = string_map_next (map, node), i++)
+        {
+          const char *key = string_map_node_get_key (node);
+          const char *value = string_map_node_get_value (node);
+          size_t j;
+
+          for (j = 0; j < left; j++)
+            if (!strcmp (key, make_key (data_copy[j]))
+                || !strcmp (value, make_value (data_copy[j])))
+              {
+                data_copy[j] = data_copy[--left];
+                goto next;
+              }
+          check_die ();
+
+        next: ;
+        }
+      check (node == NULL);
+      free (data_copy);
+    }
+}
+
+/* Inserts the CNT strings from 0 to CNT - 1 (inclusive) into a map in the
+   order specified by INSERTIONS, then deletes them in the order specified by
+   DELETIONS, checking the map's contents for correctness after each
+   operation.  */
+static void
+test_insert_delete (const int insertions[],
+                    const int deletions[],
+                    size_t cnt)
+{
+  struct string_map map;
+  size_t i;
+
+  string_map_init (&map);
+  check_string_map (&map, NULL, 0);
+  for (i = 0; i < cnt; i++)
+    {
+      check (string_map_insert (&map, make_key (insertions[i]),
+                                make_value (insertions[i])));
+      check_string_map (&map, insertions, i + 1);
+    }
+  for (i = 0; i < cnt; i++)
+    {
+      check (string_map_delete (&map, make_key (deletions[i])));
+      check_string_map (&map, deletions + i + 1, cnt - i - 1);
+    }
+  string_map_destroy (&map);
+}
+\f
+/* Inserts strings into a map in each possible order, then removes them in each
+   possible order, up to a specified maximum size. */
+static void
+test_insert_any_remove_any (void)
+{
+  const int basis = 0;
+  const int max_elems = 5;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *insertions, *deletions;
+      unsigned int ins_perm_cnt;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i | random_value (i, basis);
+
+      for (ins_perm_cnt = 0;
+           ins_perm_cnt == 0 || next_permutation (insertions, cnt);
+           ins_perm_cnt++)
+        {
+          unsigned int del_perm_cnt;
+          int i;
+
+          for (i = 0; i < cnt; i++)
+            deletions[i] = i | random_value (i, basis);
+
+          for (del_perm_cnt = 0;
+               del_perm_cnt == 0 || next_permutation (deletions, cnt);
+               del_perm_cnt++)
+            test_insert_delete (insertions, deletions, cnt);
+
+          check (del_perm_cnt == factorial (cnt));
+        }
+      check (ins_perm_cnt == factorial (cnt));
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts strings into a map in each possible order, then removes them in the
+   same order, up to a specified maximum size. */
+static void
+test_insert_any_remove_same (void)
+{
+  const int max_elems = 7;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *values;
+      unsigned int permutation_cnt;
+      int i;
+
+      values = xnmalloc (cnt, sizeof *values);
+      for (i = 0; i < cnt; i++)
+        values[i] = i | random_value (i, 1);
+
+      for (permutation_cnt = 0;
+           permutation_cnt == 0 || next_permutation (values, cnt);
+           permutation_cnt++)
+        test_insert_delete (values, values, cnt);
+      check (permutation_cnt == factorial (cnt));
+
+      free (values);
+    }
+}
+
+/* Inserts strings into a map in each possible order, then
+   removes them in reverse order, up to a specified maximum
+   size. */
+static void
+test_insert_any_remove_reverse (void)
+{
+  const int max_elems = 7;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *insertions, *deletions;
+      unsigned int permutation_cnt;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i | random_value (i, 2);
+
+      for (permutation_cnt = 0;
+           permutation_cnt == 0 || next_permutation (insertions, cnt);
+           permutation_cnt++)
+        {
+          memcpy (deletions, insertions, sizeof *insertions * cnt);
+          reverse (deletions, cnt);
+
+          test_insert_delete (insertions, deletions, cnt);
+        }
+      check (permutation_cnt == factorial (cnt));
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts and removes strings in a map, in random order. */
+static void
+test_random_sequence (void)
+{
+  const int basis = 3;
+  const int max_elems = 64;
+  const int max_trials = 8;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt += 2)
+    {
+      int *insertions, *deletions;
+      int trial;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i | random_value (i, basis);
+      for (i = 0; i < cnt; i++)
+        deletions[i] = i | random_value (i, basis);
+
+      for (trial = 0; trial < max_trials; trial++)
+        {
+          random_shuffle (insertions, cnt, sizeof *insertions);
+          random_shuffle (deletions, cnt, sizeof *deletions);
+
+          test_insert_delete (insertions, deletions, cnt);
+        }
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts strings into a map in ascending order, then delete in ascending
+   order. */
+static void
+test_insert_ordered (void)
+{
+  const int max_elems = 64;
+  int *values;
+  struct string_map map;
+  int i;
+
+  string_map_init (&map);
+  values = xnmalloc (max_elems, sizeof *values);
+  for (i = 0; i < max_elems; i++)
+    {
+      values[i] = i | random_value (i, 4);
+      string_map_insert_nocopy (&map, xstrdup (make_key (values[i])),
+                                xstrdup (make_value (values[i])));
+      check_string_map (&map, values, i + 1);
+    }
+  for (i = 0; i < max_elems; i++)
+    {
+      string_map_delete (&map, make_key (i));
+      check_string_map (&map, values + i + 1, max_elems - i - 1);
+    }
+  string_map_destroy (&map);
+  free (values);
+}
+
+/* Inserts and replaces strings in a map, in random order. */
+static void
+test_replace (void)
+{
+  const int basis = 15;
+  enum { MAX_ELEMS = 16 };
+  const int max_trials = 8;
+  int cnt;
+
+  for (cnt = 0; cnt <= MAX_ELEMS; cnt++)
+    {
+      int insertions[MAX_ELEMS];
+      int trial;
+      int i;
+
+      for (i = 0; i < cnt; i++)
+        insertions[i] = (i / 2) | random_value (i, basis);
+
+      for (trial = 0; trial < max_trials; trial++)
+        {
+          struct string_map map;
+          int data[MAX_ELEMS];
+          int n_data;
+
+          /* Insert with replacement in random order. */
+          n_data = 0;
+          string_map_init (&map);
+          random_shuffle (insertions, cnt, sizeof *insertions);
+          for (i = 0; i < cnt; i++)
+            {
+              const char *key = make_key (insertions[i]);
+              const char *value = make_value (insertions[i]);
+              int j;
+
+              for (j = 0; j < n_data; j++)
+                if ((data[j] & KEY_MASK) == (insertions[i] & KEY_MASK))
+                  {
+                    data[j] = insertions[i];
+                    goto found;
+                  }
+              data[n_data++] = insertions[i];
+            found:
+
+              if (i % 2)
+                string_map_replace (&map, key, value);
+              else
+                string_map_replace_nocopy (&map,
+                                           xstrdup (key), xstrdup (value));
+              check_string_map (&map, data, n_data);
+            }
+
+          /* Delete in original order. */
+          for (i = 0; i < cnt; i++)
+            {
+              const char *expected_value;
+              char *value;
+              int j;
+
+              expected_value = NULL;
+              for (j = 0; j < n_data; j++)
+                if ((data[j] & KEY_MASK) == (insertions[i] & KEY_MASK))
+                  {
+                    expected_value = make_value (data[j]);
+                    data[j] = data[--n_data];
+                    break;
+                  }
+
+              value = string_map_find_and_delete (&map,
+                                                  make_key (insertions[i]));
+              check ((value != NULL) == (expected_value != NULL));
+              check (value == NULL || !strcmp (value, expected_value));
+              free (value);
+            }
+          assert (string_map_is_empty (&map));
+
+          string_map_destroy (&map);
+        }
+    }
+}
+
+static void
+make_patterned_map (struct string_map *map, unsigned int pattern, int basis,
+                    int insertions[], int *np)
+{
+  int n;
+  int i;
+
+  string_map_init (map);
+
+  n = 0;
+  for (i = 0; pattern != 0; i++)
+    if (pattern & (1u << i))
+      {
+        pattern &= pattern - 1;
+        insertions[n] = i | random_value (i, basis);
+        check (string_map_insert (map, make_key (insertions[n]),
+                                  make_value (insertions[n])));
+        n++;
+      }
+  check_string_map (map, insertions, n);
+
+  *np = n;
+}
+
+static void
+for_each_map (void (*cb)(struct string_map *, int data[], int n),
+              int basis)
+{
+  enum { MAX_ELEMS = 5 };
+  unsigned int pattern;
+
+  for (pattern = 0; pattern < (1u << MAX_ELEMS); pattern++)
+    {
+      int data[MAX_ELEMS];
+      struct string_map map;
+      int n;
+
+      make_patterned_map (&map, pattern, basis, data, &n);
+      (*cb) (&map, data, n);
+      string_map_destroy (&map);
+    }
+}
+
+static void
+for_each_pair_of_maps (
+  void (*cb)(struct string_map *a, int a_data[], int n_a,
+             struct string_map *b, int b_data[], int n_b),
+  int a_basis, int b_basis)
+{
+  enum { MAX_ELEMS = 5 };
+  unsigned int a_pattern, b_pattern;
+
+  for (a_pattern = 0; a_pattern < (1u << MAX_ELEMS); a_pattern++)
+    for (b_pattern = 0; b_pattern < (1u << MAX_ELEMS); b_pattern++)
+      {
+        int a_data[MAX_ELEMS], b_data[MAX_ELEMS];
+        struct string_map a_map, b_map;
+        int n_a, n_b;
+
+        make_patterned_map (&a_map, a_pattern, a_basis, a_data, &n_a);
+        make_patterned_map (&b_map, b_pattern, b_basis, b_data, &n_b);
+        (*cb) (&a_map, a_data, n_a, &b_map, b_data, n_b);
+        string_map_destroy (&a_map);
+        string_map_destroy (&b_map);
+      }
+}
+
+static void
+clear_cb (struct string_map *map, int data[] UNUSED, int n UNUSED)
+{
+  string_map_clear (map);
+  check_string_map (map, NULL, 0);
+}
+
+static void
+test_clear (void)
+{
+  for_each_map (clear_cb, 5);
+}
+
+static void
+clone_cb (struct string_map *map, int data[], int n)
+{
+  struct string_map clone;
+
+  string_map_clone (&clone, map);
+  check_string_map (&clone, data, n);
+  string_map_destroy (&clone);
+}
+
+static void
+test_clone (void)
+{
+  for_each_map (clone_cb, 6);
+}
+
+static void
+node_swap_value_cb (struct string_map *map, int data[], int n)
+{
+  int i;
+
+  for (i = 0; i < n; i++)
+    {
+      const char *value = make_value (data[i]);
+      struct string_map_node *node;
+      char *old_value;
+
+      node = string_map_find_node (map, make_key (data[i]));
+      check (node != NULL);
+      check (!strcmp (string_map_node_get_value (node), value));
+      data[i] = (data[i] & KEY_MASK) | random_value (i, 15);
+      old_value = string_map_node_swap_value (node, make_value (data[i]));
+      check (old_value != NULL);
+      check (!strcmp (value, old_value));
+      free (old_value);
+    }
+}
+
+static void
+test_node_swap_value (void)
+{
+  for_each_map (node_swap_value_cb, 14);
+}
+
+static void
+swap_cb (struct string_map *a, int a_data[], int n_a,
+         struct string_map *b, int b_data[], int n_b)
+{
+  string_map_swap (a, b);
+  check_string_map (a, b_data, n_b);
+  check_string_map (b, a_data, n_a);
+}
+
+static void
+test_swap (void)
+{
+  for_each_pair_of_maps (swap_cb, 7, 8);
+}
+
+static void
+insert_map_cb (struct string_map *a, int a_data[], int n_a,
+               struct string_map *b, int b_data[], int n_b)
+{
+  int i, j;
+
+  string_map_insert_map (a, b);
+
+  for (i = 0; i < n_b; i++)
+    {
+      for (j = 0; j < n_a; j++)
+        if ((b_data[i] & KEY_MASK) == (a_data[j] & KEY_MASK))
+          goto found;
+      a_data[n_a++] = b_data[i];
+    found:;
+    }
+  check_string_map (a, a_data, n_a);
+  check_string_map (b, b_data, n_b);
+}
+
+static void
+test_insert_map (void)
+{
+  for_each_pair_of_maps (insert_map_cb, 91, 10);
+}
+
+static void
+replace_map_cb (struct string_map *a, int a_data[], int n_a,
+               struct string_map *b, int b_data[], int n_b)
+{
+  int i, j;
+
+  string_map_replace_map (a, b);
+
+  for (i = 0; i < n_b; i++)
+    {
+      for (j = 0; j < n_a; j++)
+        if ((b_data[i] & KEY_MASK) == (a_data[j] & KEY_MASK))
+          {
+            a_data[j] = (a_data[j] & KEY_MASK) | (b_data[i] & VALUE_MASK);
+            goto found;
+          }
+      a_data[n_a++] = b_data[i];
+    found:;
+    }
+  check_string_map (a, a_data, n_a);
+  check_string_map (b, b_data, n_b);
+}
+
+static void
+test_replace_map (void)
+{
+  for_each_pair_of_maps (replace_map_cb, 11, 12);
+}
+
+static void
+check_set (struct string_set *set, const int *data, int n_data,
+           int mask, int shift)
+{
+  int *unique;
+  int n_unique;
+  int i;
+
+  n_unique = 0;
+  unique = xmalloc (n_data * sizeof *unique);
+  for (i = 0; i < n_data; i++)
+    {
+      int idx = (data[i] & mask) >> shift;
+      int j;
+
+      for (j = 0; j < n_unique; j++)
+        if (unique[j] == idx)
+          goto found;
+      unique[n_unique++] = idx;
+    found:;
+    }
+
+  check (string_set_count (set) == n_unique);
+  for (i = 0; i < n_unique; i++)
+    check (string_set_contains (set, get_string (unique[i])));
+  string_set_destroy (set);
+  free (unique);
+}
+
+static void
+get_keys_and_values_cb (struct string_map *map, int data[], int n)
+{
+  struct string_set keys, values;
+
+  string_set_init (&keys);
+  string_set_init (&values);
+  string_map_get_keys (map, &keys);
+  string_map_get_values (map, &values);
+  check_set (&keys, data, n, KEY_MASK, KEY_SHIFT);
+  check_set (&values, data, n, VALUE_MASK, VALUE_SHIFT);
+}
+
+static void
+test_get_keys_and_values (void)
+{
+  for_each_map (get_keys_and_values_cb, 13);
+}
+
+static void
+test_destroy_null (void)
+{
+  string_map_destroy (NULL);
+}
+\f
+/* Main program. */
+
+/* Runs TEST_FUNCTION and prints a message about NAME. */
+static void
+run_test (void (*test_function) (void), const char *name)
+{
+  test_name = name;
+  putchar ('.');
+  fflush (stdout);
+  test_function ();
+}
+
+int
+main (void)
+{
+  run_test (test_insert_any_remove_any, "insert any order, delete any order");
+  run_test (test_insert_any_remove_same,
+            "insert any order, delete same order");
+  run_test (test_insert_any_remove_reverse,
+            "insert any order, delete reverse order");
+  run_test (test_random_sequence, "insert and delete in random sequence");
+  run_test (test_replace, "insert and replace in random sequence");
+  run_test (test_insert_ordered, "insert in ascending order");
+  run_test (test_clear, "clear");
+  run_test (test_clone, "clone");
+  run_test (test_swap, "swap");
+  run_test (test_node_swap_value, "node_swap_value");
+  run_test (test_insert_map, "insert_map");
+  run_test (test_replace_map, "replace_map");
+  run_test (test_get_keys_and_values, "get keys and values");
+  run_test (test_destroy_null, "destroying null table");
+
+  putchar ('\n');
+
+  free_strings ();
+
+  return 0;
+}
diff --git a/tests/libpspp/string-set-test.c b/tests/libpspp/string-set-test.c
new file mode 100644 (file)
index 0000000..6aafef4
--- /dev/null
@@ -0,0 +1,681 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007, 2008, 2009 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/>. */
+
+/* This is a test program for the string_set_* routines defined in
+   string-set.c.  This test program aims to be as comprehensive as possible.
+   "gcov -a -b" should report almost complete coverage of lines, blocks and
+   branches in string-set.c, except that one branch caused by hash collision is
+   not exercised because our hash function has so few collisions.  "valgrind
+   --leak-check=yes --show-reachable=yes" should give a clean report. */
+
+#include <config.h>
+
+#include <libpspp/string-set.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/compiler.h>
+\f
+/* Currently running test. */
+static const char *test_name;
+
+/* Exit with a failure code.
+   (Place a breakpoint on this function while debugging.) */
+static void
+check_die (void)
+{
+  exit (EXIT_FAILURE);
+}
+
+/* If OK is not true, prints a message about failure on the
+   current source file and the given LINE and terminates. */
+static void
+check_func (bool ok, int line)
+{
+  if (!ok)
+    {
+      printf ("Check failed in %s test at %s, line %d\n",
+              test_name, __FILE__, line);
+      check_die ();
+    }
+}
+
+/* Verifies that EXPR evaluates to true.
+   If not, prints a message citing the calling line number and
+   terminates. */
+#define check(EXPR) check_func ((EXPR), __LINE__)
+
+/* Prints a message about memory exhaustion and exits with a
+   failure code. */
+static void
+xalloc_die (void)
+{
+  printf ("virtual memory exhausted\n");
+  exit (EXIT_FAILURE);
+}
+
+static void *xmalloc (size_t n) MALLOC_LIKE;
+static void *xnmalloc (size_t n, size_t m) MALLOC_LIKE;
+static void *xmemdup (const void *p, size_t n) MALLOC_LIKE;
+
+/* Allocates and returns N bytes of memory. */
+static void *
+xmalloc (size_t n)
+{
+  if (n != 0)
+    {
+      void *p = malloc (n);
+      if (p == NULL)
+        xalloc_die ();
+
+      return p;
+    }
+  else
+    return NULL;
+}
+
+static void *
+xmemdup (const void *p, size_t n)
+{
+  void *q = xmalloc (n);
+  memcpy (q, p, n);
+  return q;
+}
+
+/* Clone STRING.  */
+static char *
+xstrdup (const char *string)
+{
+  return xmemdup (string, strlen (string) + 1);
+}
+
+/* Allocates and returns N * M bytes of memory. */
+static void *
+xnmalloc (size_t n, size_t m)
+{
+  if ((size_t) -1 / m <= n)
+    xalloc_die ();
+  return xmalloc (n * m);
+}
+\f
+/* Support routines. */
+
+enum { MAX_VALUE = 1024 };
+
+static char *string_table[MAX_VALUE];
+
+static const char *
+make_string (int value)
+{
+  char **s;
+
+  assert (value >= 0 && value < MAX_VALUE);
+  s = &string_table[value];
+  if (*s == NULL)
+    {
+      *s = xmalloc (16);
+      sprintf (*s, "%d", value);
+    }
+  return *s;
+}
+
+static void
+free_strings (void)
+{
+  int i;
+
+  for (i = 0; i < MAX_VALUE; i++)
+    free (string_table[i]);
+}
+
+/* Swaps *A and *B. */
+static void
+swap (int *a, int *b)
+{
+  int t = *a;
+  *a = *b;
+  *b = t;
+}
+
+/* Reverses the order of the CNT integers starting at VALUES. */
+static void
+reverse (int *values, size_t cnt)
+{
+  size_t i = 0;
+  size_t j = cnt;
+
+  while (j > i)
+    swap (&values[i++], &values[--j]);
+}
+
+/* Arranges the CNT elements in VALUES into the lexicographically
+   next greater permutation.  Returns true if successful.
+   If VALUES is already the lexicographically greatest
+   permutation of its elements (i.e. ordered from greatest to
+   smallest), arranges them into the lexicographically least
+   permutation (i.e. ordered from smallest to largest) and
+   returns false. */
+static bool
+next_permutation (int *values, size_t cnt)
+{
+  if (cnt > 0)
+    {
+      size_t i = cnt - 1;
+      while (i != 0)
+        {
+          i--;
+          if (values[i] < values[i + 1])
+            {
+              size_t j;
+              for (j = cnt - 1; values[i] >= values[j]; j--)
+                continue;
+              swap (values + i, values + j);
+              reverse (values + (i + 1), cnt - (i + 1));
+              return true;
+            }
+        }
+
+      reverse (values, cnt);
+    }
+
+  return false;
+}
+
+/* Returns N!. */
+static unsigned int
+factorial (unsigned int n)
+{
+  unsigned int value = 1;
+  while (n > 1)
+    value *= n--;
+  return value;
+}
+
+/* Randomly shuffles the CNT elements in ARRAY, each of which is
+   SIZE bytes in size. */
+static void
+random_shuffle (void *array_, size_t cnt, size_t size)
+{
+  char *array = array_;
+  char *tmp = xmalloc (size);
+  size_t i;
+
+  for (i = 0; i < cnt; i++)
+    {
+      size_t j = rand () % (cnt - i) + i;
+      if (i != j)
+        {
+          memcpy (tmp, array + j * size, size);
+          memcpy (array + j * size, array + i * size, size);
+          memcpy (array + i * size, tmp, size);
+        }
+    }
+
+  free (tmp);
+}
+
+/* Checks that SET contains the CNT strings in DATA, that its structure is
+   correct, and that certain operations on SET produce the expected results. */
+static void
+check_string_set (struct string_set *set, const int data[], size_t cnt)
+{
+  size_t i;
+
+  check (string_set_is_empty (set) == (cnt == 0));
+  check (string_set_count (set) == cnt);
+
+  for (i = 0; i < cnt; i++)
+    {
+      struct string_set_node *node;
+      const char *s = make_string (data[i]);
+
+      check (string_set_contains (set, s));
+      check (!string_set_insert (set, s));
+      check (!string_set_insert_nocopy (set, xstrdup (s)));
+
+      node = string_set_find_node (set, s);
+      check (node != NULL);
+      check (!strcmp (s, string_set_node_get_string (node)));
+    }
+
+  check (!string_set_contains (set, "xxx"));
+  check (string_set_find_node (set, "") == NULL);
+
+  if (cnt == 0)
+    check (string_set_first (set) == NULL);
+  else
+    {
+      const struct string_set_node *node;
+      int *data_copy;
+      int left;
+
+      data_copy = xmemdup (data, cnt * sizeof *data);
+      left = cnt;
+      for (node = string_set_first (set), i = 0; i < cnt;
+           node = string_set_next (set, node), i++)
+        {
+          const char *s = string_set_node_get_string (node);
+          size_t j;
+
+          for (j = 0; j < left; j++)
+            if (!strcmp (s, make_string (data_copy[j])))
+              {
+                data_copy[j] = data_copy[--left];
+                goto next;
+              }
+          check_die ();
+
+        next: ;
+        }
+      check (node == NULL);
+      free (data_copy);
+    }
+}
+
+/* Inserts the CNT strings from 0 to CNT - 1 (inclusive) into a set in the
+   order specified by INSERTIONS, then deletes them in the order specified by
+   DELETIONS, checking the set's contents for correctness after each
+   operation.  */
+static void
+test_insert_delete (const int insertions[],
+                    const int deletions[],
+                    size_t cnt)
+{
+  struct string_set set;
+  size_t i;
+
+  string_set_init (&set);
+  check_string_set (&set, NULL, 0);
+  for (i = 0; i < cnt; i++)
+    {
+      check (string_set_insert (&set, make_string (insertions[i])));
+      check_string_set (&set, insertions, i + 1);
+    }
+  for (i = 0; i < cnt; i++)
+    {
+      check (string_set_delete (&set, make_string (deletions[i])));
+      check_string_set (&set, deletions + i + 1, cnt - i - 1);
+    }
+  string_set_destroy (&set);
+}
+\f
+/* Inserts strings into a set in each possible order, then removes them in each
+   possible order, up to a specified maximum size. */
+static void
+test_insert_any_remove_any (void)
+{
+  const int max_elems = 5;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *insertions, *deletions;
+      unsigned int ins_perm_cnt;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i;
+
+      for (ins_perm_cnt = 0;
+           ins_perm_cnt == 0 || next_permutation (insertions, cnt);
+           ins_perm_cnt++)
+        {
+          unsigned int del_perm_cnt;
+          int i;
+
+          for (i = 0; i < cnt; i++)
+            deletions[i] = i;
+
+          for (del_perm_cnt = 0;
+               del_perm_cnt == 0 || next_permutation (deletions, cnt);
+               del_perm_cnt++)
+            test_insert_delete (insertions, deletions, cnt);
+
+          check (del_perm_cnt == factorial (cnt));
+        }
+      check (ins_perm_cnt == factorial (cnt));
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts strings into a set in each possible order, then removes them in the
+   same order, up to a specified maximum size. */
+static void
+test_insert_any_remove_same (void)
+{
+  const int max_elems = 7;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *values;
+      unsigned int permutation_cnt;
+      int i;
+
+      values = xnmalloc (cnt, sizeof *values);
+      for (i = 0; i < cnt; i++)
+        values[i] = i;
+
+      for (permutation_cnt = 0;
+           permutation_cnt == 0 || next_permutation (values, cnt);
+           permutation_cnt++)
+        test_insert_delete (values, values, cnt);
+      check (permutation_cnt == factorial (cnt));
+
+      free (values);
+    }
+}
+
+/* Inserts strings into a set in each possible order, then
+   removes them in reverse order, up to a specified maximum
+   size. */
+static void
+test_insert_any_remove_reverse (void)
+{
+  const int max_elems = 7;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt++)
+    {
+      int *insertions, *deletions;
+      unsigned int permutation_cnt;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i;
+
+      for (permutation_cnt = 0;
+           permutation_cnt == 0 || next_permutation (insertions, cnt);
+           permutation_cnt++)
+        {
+          memcpy (deletions, insertions, sizeof *insertions * cnt);
+          reverse (deletions, cnt);
+
+          test_insert_delete (insertions, deletions, cnt);
+        }
+      check (permutation_cnt == factorial (cnt));
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts and removes strings in a set, in random order. */
+static void
+test_random_sequence (void)
+{
+  const int max_elems = 64;
+  const int max_trials = 8;
+  int cnt;
+
+  for (cnt = 0; cnt <= max_elems; cnt += 2)
+    {
+      int *insertions, *deletions;
+      int trial;
+      int i;
+
+      insertions = xnmalloc (cnt, sizeof *insertions);
+      deletions = xnmalloc (cnt, sizeof *deletions);
+      for (i = 0; i < cnt; i++)
+        insertions[i] = i;
+      for (i = 0; i < cnt; i++)
+        deletions[i] = i;
+
+      for (trial = 0; trial < max_trials; trial++)
+        {
+          random_shuffle (insertions, cnt, sizeof *insertions);
+          random_shuffle (deletions, cnt, sizeof *deletions);
+
+          test_insert_delete (insertions, deletions, cnt);
+        }
+
+      free (insertions);
+      free (deletions);
+    }
+}
+
+/* Inserts strings into a set in ascending order, then delete in ascending
+   order. */
+static void
+test_insert_ordered (void)
+{
+  const int max_elems = 64;
+  int *values;
+  struct string_set set;
+  int i;
+
+  string_set_init (&set);
+  values = xnmalloc (max_elems, sizeof *values);
+  for (i = 0; i < max_elems; i++)
+    {
+      values[i] = i;
+      string_set_insert_nocopy (&set, xstrdup (make_string (i)));
+      check_string_set (&set, values, i + 1);
+    }
+  for (i = 0; i < max_elems; i++)
+    {
+      string_set_delete (&set, make_string (i));
+      check_string_set (&set, values + i + 1, max_elems - i - 1);
+    }
+  string_set_destroy (&set);
+  free (values);
+}
+
+static void
+test_boolean_ops (void (*function)(struct string_set *a, struct string_set *b,
+                                   unsigned int *a_pat, unsigned int *b_pat))
+{
+  enum { MAX_STRINGS = 7 };
+  unsigned int a_pat, b_pat;
+
+  for (a_pat = 0; a_pat < (1u << MAX_STRINGS); a_pat++)
+    for (b_pat = 0; b_pat < (1u << MAX_STRINGS); b_pat++)
+      {
+        unsigned int new_a_pat = a_pat;
+        unsigned int new_b_pat = b_pat;
+        struct string_set a, b;
+        int a_strings[MAX_STRINGS], b_strings[MAX_STRINGS];
+        size_t i, n_a, n_b;
+
+        string_set_init (&a);
+        string_set_init (&b);
+        for (i = 0; i < MAX_STRINGS; i++)
+          {
+            if (a_pat & (1u << i))
+              string_set_insert (&a, make_string (i));
+            if (b_pat & (1u << i))
+              string_set_insert (&b, make_string (i));
+          }
+
+        function (&a, &b, &new_a_pat, &new_b_pat);
+
+        n_a = n_b = 0;
+        for (i = 0; i < MAX_STRINGS; i++)
+          {
+            if (new_a_pat & (1u << i))
+              a_strings[n_a++] = i;
+            if (new_b_pat & (1u << i))
+              b_strings[n_b++] = i;
+          }
+        check_string_set (&a, a_strings, n_a);
+        check_string_set (&b, b_strings, n_b);
+        string_set_destroy (&a);
+        string_set_destroy (&b);
+      }
+}
+
+static void
+union_cb (struct string_set *a, struct string_set *b,
+          unsigned int *a_pat, unsigned int *b_pat)
+{
+  string_set_union (a, b);
+  *a_pat |= *b_pat;
+}
+
+static void
+test_union (void)
+{
+  test_boolean_ops (union_cb);
+}
+
+static void
+union_and_intersection_cb (struct string_set *a, struct string_set *b,
+                           unsigned int *a_pat, unsigned int *b_pat)
+{
+  unsigned int orig_a_pat = *a_pat;
+  unsigned int orig_b_pat = *b_pat;
+
+  string_set_union_and_intersection (a, b);
+  *a_pat = orig_a_pat | orig_b_pat;
+  *b_pat = orig_a_pat & orig_b_pat;
+}
+
+static void
+test_union_and_intersection (void)
+{
+  test_boolean_ops (union_and_intersection_cb);
+}
+
+static void
+intersect_cb (struct string_set *a, struct string_set *b,
+              unsigned int *a_pat, unsigned int *b_pat)
+{
+  string_set_intersect (a, b);
+  *a_pat &= *b_pat;
+}
+
+static void
+test_intersect (void)
+{
+  test_boolean_ops (intersect_cb);
+}
+
+static void
+subtract_cb (struct string_set *a, struct string_set *b,
+              unsigned int *a_pat, unsigned int *b_pat)
+{
+  string_set_subtract (a, b);
+  *a_pat &= ~*b_pat;
+}
+
+static void
+test_subtract (void)
+{
+  test_boolean_ops (subtract_cb);
+}
+
+static void
+swap_cb (struct string_set *a, struct string_set *b,
+         unsigned int *a_pat, unsigned int *b_pat)
+{
+  unsigned int tmp;
+  string_set_swap (a, b);
+  tmp = *a_pat;
+  *a_pat = *b_pat;
+  *b_pat = tmp;
+}
+
+static void
+test_swap (void)
+{
+  test_boolean_ops (swap_cb);
+}
+
+static void
+clear_cb (struct string_set *a, struct string_set *b UNUSED,
+         unsigned int *a_pat, unsigned int *b_pat UNUSED)
+{
+  string_set_clear (a);
+  *a_pat = 0;
+}
+
+static void
+test_clear (void)
+{
+  test_boolean_ops (clear_cb);
+}
+
+static void
+clone_cb (struct string_set *a, struct string_set *b,
+         unsigned int *a_pat, unsigned int *b_pat)
+{
+  string_set_destroy (a);
+  string_set_clone (a, b);
+  *a_pat = *b_pat;
+}
+
+static void
+test_clone (void)
+{
+  test_boolean_ops (clone_cb);
+}
+
+static void
+test_destroy_null (void)
+{
+  string_set_destroy (NULL);
+}
+\f
+/* Main program. */
+
+/* Runs TEST_FUNCTION and prints a message about NAME. */
+static void
+run_test (void (*test_function) (void), const char *name)
+{
+  test_name = name;
+  putchar ('.');
+  fflush (stdout);
+  test_function ();
+}
+
+int
+main (void)
+{
+  run_test (test_insert_any_remove_any, "insert any order, delete any order");
+  run_test (test_insert_any_remove_same,
+            "insert any order, delete same order");
+  run_test (test_insert_any_remove_reverse,
+            "insert any order, delete reverse order");
+  run_test (test_random_sequence, "insert and delete in random sequence");
+  run_test (test_insert_ordered, "insert in ascending order");
+  run_test (test_union, "union");
+  run_test (test_union_and_intersection, "union and intersection");
+  run_test (test_intersect, "intersect");
+  run_test (test_subtract, "subtract");
+  run_test (test_swap, "swap");
+  run_test (test_clear, "clear");
+  run_test (test_clone, "clone");
+  run_test (test_destroy_null, "destroying null table");
+
+  putchar ('\n');
+
+  free_strings ();
+
+  return 0;
+}
index dfe395b4fb0579287e3a99418d0247b0aa14b255..5ff5d4144d995c3b458c33353a0fc5e7507ae63a 100755 (executable)
@@ -68,7 +68,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="Run pspp 1"
-PAPERSIZE=letter $SUPERVISOR $PSPP --testing-mode paper-size.pspp > paper-size.out
+PAPERSIZE=letter $SUPERVISOR $PSPP --testing-mode -o pspp.csv paper-size.pspp > paper-size.out
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results"
@@ -88,7 +88,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="Run pspp 2"
-PAPERSIZE=a4 $SUPERVISOR $PSPP --testing-mode paper-size-2.pspp > paper-size-2.out
+PAPERSIZE=a4 $SUPERVISOR $PSPP --testing-mode -o pspp.csv paper-size-2.pspp > paper-size-2.out
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare results 2"
diff --git a/tests/output/render-test.c b/tests/output/render-test.c
new file mode 100644 (file)
index 0000000..729db85
--- /dev/null
@@ -0,0 +1,299 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2009, 2010 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 <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/string-map.h"
+#include "output/driver.h"
+#include "output/tab.h"
+#include "output/table-item.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
+
+/* --transpose: Transpose the table before outputting? */
+static int transpose;
+
+static const char *parse_options (int argc, char **argv);
+static void usage (void) NO_RETURN;
+static struct table *read_table (FILE *);
+
+int
+main (int argc, char **argv)
+{
+  struct table *table;
+  const char *input_file_name;
+  FILE *input;
+
+  set_program_name (argv[0]);
+  input_file_name = parse_options (argc, argv);
+
+  if (!strcmp (input_file_name, "-"))
+    input = stdin;
+  else
+    {
+      input = fopen (input_file_name, "r");
+      if (input == NULL)
+        error (1, errno, "%s: open failed", input_file_name);
+    }
+  table = read_table (input);
+  if (input != stdin)
+    fclose (input);
+
+  if (transpose)
+    table = table_transpose (table);
+
+  table_item_submit (table_item_create (table, NULL));
+  output_close ();
+
+  return 0;
+}
+
+static void
+configure_drivers (int width, int length)
+{
+  struct string_map options, tmp;
+  struct output_driver *driver;
+
+  string_map_init (&options);
+  string_map_insert (&options, "format", "txt");
+  string_map_insert (&options, "output-file", "-");
+  string_map_insert_nocopy (&options, xstrdup ("width"),
+                            xasprintf ("%d", width));
+  string_map_insert_nocopy (&options, xstrdup ("length"),
+                            xasprintf ("%d", length));
+
+  /* Render to stdout. */
+  string_map_clone (&tmp, &options);
+  driver = output_driver_create (&tmp);
+  if (driver == NULL)
+    exit (EXIT_FAILURE);
+  output_driver_register (driver);
+  string_map_destroy (&tmp);
+
+  /* Render to render.txt. */
+  string_map_replace (&options, "output-file", "render.txt");
+  driver = output_driver_create (&options);
+  if (driver == NULL)
+    exit (EXIT_FAILURE);
+  output_driver_register (driver);
+
+  /* Render to render.pdf. */
+  string_map_insert (&options, "output-file", "render.pdf");
+  string_map_insert (&options, "headers", "off");
+  string_map_insert (&options, "top-margin", "0");
+  string_map_insert (&options, "bottom-margin", "0");
+  string_map_insert (&options, "left-margin", "0");
+  string_map_insert (&options, "right-margin", "0");
+  string_map_insert_nocopy (&options, xstrdup ("paper-size"),
+                            xasprintf ("%dx%dpt", width * 5, length * 6));
+  driver = output_driver_create (&options);
+  if (driver == NULL)
+    exit (EXIT_FAILURE);
+  output_driver_register (driver);
+
+  string_map_destroy (&options);
+}
+
+static const char *
+parse_options (int argc, char **argv)
+{
+  int width = 79;
+  int length = 66;
+
+  for (;;)
+    {
+      enum {
+        OPT_WIDTH = UCHAR_MAX + 1,
+        OPT_LENGTH,
+        OPT_HELP
+      };
+      static const struct option options[] =
+        {
+          {"width", required_argument, NULL, OPT_WIDTH},
+          {"length", required_argument, NULL, OPT_LENGTH},
+          {"transpose", no_argument, &transpose, 1},
+          {"help", no_argument, NULL, OPT_HELP},
+          {NULL, 0, NULL, 0},
+        };
+
+      int c = getopt_long (argc, argv, "", options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case OPT_WIDTH:
+          width = atoi (optarg);
+          break;
+
+        case OPT_LENGTH:
+          length = atoi (optarg);
+          break;
+
+        case OPT_HELP:
+          usage ();
+
+        case 0:
+          break;
+
+        case '?':
+          exit(EXIT_FAILURE);
+          break;
+
+        default:
+          NOT_REACHED ();
+        }
+
+    }
+
+  configure_drivers (width, length);
+
+  if (optind + 1 != argc)
+    error (1, 0, "exactly one non-option argument required; "
+           "use --help for help");
+  return argv[optind];
+}
+
+static void
+usage (void)
+{
+  printf ("%s, to test rendering of PSPP tables\n"
+          "usage: %s [OPTIONS] INPUT\n"
+          "\nOptions:\n"
+          "  --driver=NAME:CLASS:DEVICE:OPTIONS  set output driver\n",
+          program_name, program_name);
+  exit (EXIT_SUCCESS);
+}
+
+static void
+replace_newlines (char *p)
+{
+  char *q;
+
+  for (q = p; *p != '\0'; )
+    if (*p == '\\' && p[1] == 'n')
+      {
+        *q++ = '\n';
+        p += 2;
+      }
+    else
+      *q++ = *p++;
+  *q = '\0';
+}
+
+static struct table *
+read_table (FILE *stream)
+{
+  struct tab_table *tab;
+  char buffer[1024];
+  int input[6];
+  int n_input = 0;
+  int nr, nc, hl, hr, ht, hb;
+  int r, c;
+
+  if (fgets (buffer, sizeof buffer, stream) == NULL
+      || (n_input = sscanf (buffer, "%d %d %d %d %d %d",
+                            &input[0], &input[1], &input[2],
+                            &input[3], &input[4], &input[5])) < 2)
+    error (1, 0, "syntax error reading row and column count");
+
+  nr = input[0];
+  nc = input[1];
+  hl = n_input >= 3 ? input[2] : 0;
+  hr = n_input >= 4 ? input[3] : 0;
+  ht = n_input >= 5 ? input[4] : 0;
+  hb = n_input >= 6 ? input[5] : 0;
+
+  tab = tab_create (nc, nr);
+  tab_headers (tab, hl, hr, ht, hb);
+  for (r = 0; r < nr; r++)
+    for (c = 0; c < nc; c++)
+      if (tab_cell_is_empty (tab, c, r))
+        {
+          char *new_line;
+          char *text;
+          int rs, cs;
+
+          if (fgets (buffer, sizeof buffer, stream) == NULL)
+            error (1, 0, "unexpected end of input reading row %d, column %d",
+                   r, c);
+          new_line = strchr (buffer, '\n');
+          if (new_line != NULL)
+            *new_line = '\0';
+
+          text = buffer;
+          if (sscanf (text, "%d*%d", &rs, &cs) == 2)
+            {
+              while (*text != ' ' && *text != '\0')
+                text++;
+              if (*text == ' ')
+                text++;
+            }
+          else
+            {
+              rs = 1;
+              cs = 1;
+            }
+
+          while (*text && strchr ("<>^,@", *text))
+            switch (*text++)
+              {
+              case '<':
+                tab_vline (tab, TAL_1, c, r, r + rs - 1);
+                break;
+
+              case '>':
+                tab_vline (tab, TAL_1, c + cs, r, r + rs - 1);
+                break;
+
+              case '^':
+                tab_hline (tab, TAL_1, c, c + cs - 1, r);
+                break;
+
+              case ',':
+                tab_hline (tab, TAL_1, c, c + cs - 1, r + rs);
+                break;
+
+              case '@':
+                tab_box (tab, TAL_1, TAL_1, -1, -1, c, r,
+                         c + cs - 1, r + rs - 1);
+                break;
+
+              default:
+                NOT_REACHED ();
+              }
+
+          replace_newlines (text);
+
+          tab_joint_text (tab, c, r, c + cs - 1, r + rs - 1, 0, text);
+        }
+
+  if (getc (stream) != EOF)
+    error (1, 0, "unread data at end of input");
+
+  return &tab->table;
+}
diff --git a/tests/output/render.at b/tests/output/render.at
new file mode 100644 (file)
index 0000000..b9f8e62
--- /dev/null
@@ -0,0 +1,1710 @@
+m4_define([RENDER_WEAVE_6X6],
+  [AT_DATA([input], [6 6 $1
+@a
+1*2 @bcd
+@e
+2*1 @f\ng\nh
+@i
+2*1 @j\nk\nl
+@m
+1*2 @nop
+2*1 @q\nr\ns
+2*1 @t\nu\nv
+@w
+1*2 @xyz
+@A
+2*1 @B\nC\nD
+@E
+1*2 @FGH
+1*2 @IJK
+2*1 @L\nM\nN
+@O
+@P
+@Q
+1*2 @RST
+@U
+@V
+])])
+
+m4_define([RENDER_8X8],
+  [AT_DATA([input], [8 8 $1
+@a
+@b
+@c
+@d
+@e
+@f
+@g
+@h
+@i
+1*2 @jkl
+@m
+1*2 @nop
+2*1 @q\nr\ns
+@t
+@u
+@v
+1*2 @wxy
+@z
+2*1 @A\nB\nC
+@D
+@E
+2*1 @F\nG\nH
+@I
+1*2 @JKL
+2*1 @M\nN\nO
+@P
+@Q
+2*1 @R\nS\nT
+1*2 @UVW
+@X
+@Y
+@Z
+2*1 @0\n1\n2
+@3
+1*2 @456
+@7
+@8
+@9
+1*2 @abc
+@d
+1*2 @efg
+@h
+@i
+@j
+@k
+@l
+@m
+@n
+@o
+@p
+])])
+
+# This input is something of a counterexample, in that it could render
+# compactly as this if the algorithm for choosing cell widths and
+# heights were smarter:
+#
+# +---+---+---+-+-+
+# |abc|jkl|mno|v|x|
+# |def+---+pqr+-+-+
+# |ghi|yzA|stu|HIJ|
+# +-+-+BCD+-+-+KLM|
+# |Q|V|EFG|W|Z|NOP|
+# |R+-+-+-+X+-+-+-+
+# |S|012|9|Y|abc|j|
+# |T|345+-+-+def|k|
+# |U|678|opq|ghi|l|
+# +-+-+-+rst+---+m|
+# |xyz|G|uvw|JKL|n|
+# |ABC|H+---+-+-+-+
+# |DEF|I|MNOPQ|123|
+# +---+-+RSTUV|456|
+# |abcde|WXYZ0|789|
+# +-----+-----+---+
+m4_define([RENDER_8X8_2],
+  [AT_DATA([input], [8 8 $1
+2*2 @abc\ndef\nghi
+1*2 @jkl
+2*2 @mno\npqr\nstu
+1*2 @vwx
+2*2 @yzA\nBCD\nEFG
+2*2 @HIJ\nKLM\nNOP
+3*1 @Q\nR\nS\nT\nU
+@V
+2*1 @W\nX\nY
+@Z
+2*2 @012\n345\n678
+@9
+2*2 @abc\ndef\nghi
+3*1 @j\nk\nl\nm\nn
+2*2 @opq\nrst\nuvw
+2*2 @xyz\nABC\nDEF
+2*1 @G\nH\nI
+1*2 @JKL
+2*3 @MNOPQ\nRSTUV\nWXYZ0
+2*2 @123\n456\n789
+1*3 @abcde
+])])
+\f
+AT_BANNER([output rendering -- no page breaking])
+
+AT_SETUP([single cell])
+AT_DATA([input], [1 1
+abc
+])
+AT_CHECK([render-test input], [0], [abc
+])
+AT_CLEANUP
+
+AT_SETUP([single cell with border])
+AT_DATA([input], [1 1
+@abc
+])
+AT_CHECK([render-test input], [0], [dnl
++---+
+|abc|
++---+
+])
+AT_CLEANUP
+
+AT_SETUP([joined columns])
+AT_DATA([input], [2 2
+1*2 @abcdefg
+@hij
+@klm
+])
+AT_CHECK([render-test input], [0], [dnl
++-------+
+|abcdefg|
++---+---+
+|hij|klm|
++---+---+
+])
+AT_CLEANUP
+
+AT_SETUP([3x3, joined rows and columns])
+AT_DATA([input], [3 3
+1*2 @abc
+2*1 @d\ne\nf
+2*1 @g\nh\ni
+@j
+1*2 @klm
+])
+AT_CHECK([render-test input], [0], [dnl
++---+-+
+|abc|d|
++-+-+e|
+|g|j|f|
+|h+-+-+
+|i|klm|
++-+---+
+])
+AT_CLEANUP
+
+AT_SETUP([6x6, joined rows and columns])
+RENDER_WEAVE_6X6
+AT_CHECK([render-test input], [0], [dnl
++-+---+-+-+-+
+|a|bcd|e|f|i|
++-+-+-+-+g+-+
+|j|m|nop|h|q|
+|k+-+-+-+-+r|
+|l|t|w|xyz|s|
++-+u+-+-+-+-+
+|A|v|B|E|FGH|
++-+-+C+-+-+-+
+|IJK|D|L|O|P|
++-+-+-+M+-+-+
+|Q|RST|N|U|V|
++-+---+-+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([3 rows with many joined cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [3 19
+m4_foreach([x], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s], [x
+])@1
+m4_for([x], [2], [19], [1], [1*2 @x
+])@20
+])
+AT_CHECK([render-test input], [0], [dnl
+ a b c d e f g h i j k l m n o p q r  s
++-+---+---+---+---+---+---+---+---+----+
+|1|  2|  3|  4|  5|  6|  7|  8|  9|  10|
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
+| 11| 12| 13| 14| 15| 16| 17| 18| 19|20|
++---+---+---+---+---+---+---+---+---+--+
+])
+AT_CLEANUP
+
+AT_SETUP([3 columns with many joined cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [3 19
+m4_foreach([x], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s], [x
+])@1
+m4_for([x], [2], [19], [1], [1*2 @x\nab\ncd
+])@20
+])
+AT_CHECK([render-test --transpose input], [0], [dnl
+ +--+--+
+a| 1|11|
+ +--+ab|
+b| 2|cd|
+ |ab+--+
+c|cd|12|
+ +--+ab|
+d| 3|cd|
+ |ab+--+
+e|cd|13|
+ +--+ab|
+f| 4|cd|
+ |ab+--+
+g|cd|14|
+ +--+ab|
+h| 5|cd|
+ |ab+--+
+i|cd|15|
+ +--+ab|
+j| 6|cd|
+ |ab+--+
+k|cd|16|
+ +--+ab|
+l| 7|cd|
+ |ab+--+
+m|cd|17|
+ +--+ab|
+n| 8|cd|
+ |ab+--+
+o|cd|18|
+ +--+ab|
+p| 9|cd|
+ |ab+--+
+q|cd|19|
+ +--+ab|
+r|10|cd|
+ |ab+--+
+s|cd|20|
+ +--+--+
+])
+AT_CLEANUP
+
+AT_SETUP([joined rows])
+AT_DATA([input], [2 2
+2*1 @ab\ncd\nef
+@hij
+@klm
+])
+AT_CHECK([render-test input], [0], [dnl
++--+---+
+|ab|hij|
+|cd+---+
+|ef|klm|
++--+---+
+])
+AT_CLEANUP
+
+AT_SETUP([5 big narrow cells])
+AT_DATA([input], [1 5
+@This cell has a lot of text but its minimum width is pretty narrow.
+@This cell also has a lot of text but its minimum width is pretty narrow.
+@A third cell with a lot of text but a pretty narrow minimum width.
+@A fourth cell with a lot of text but a pretty narrow minimum width.
+@A fifth cell with a lot of text but a pretty narrow minimum width.
+])
+AT_CHECK([render-test input], [0], [dnl
++---------------+---------------+--------------+---------------+--------------+
+|This cell has a| This cell also|  A third cell|  A fourth cell|  A fifth cell|
+|lot of text but|   has a lot of| with a lot of|  with a lot of| with a lot of|
+|    its minimum|   text but its|    text but a|     text but a|    text but a|
+|width is pretty|  minimum width| pretty narrow|  pretty narrow| pretty narrow|
+|        narrow.|      is pretty|minimum width.| minimum width.|minimum width.|
+|               |        narrow.|              |               |              |
++---------------+---------------+--------------+---------------+--------------+
+])
+AT_CLEANUP
+
+AT_SETUP([9 big narrow cells])
+AT_DATA([input], [1 9
+@This cell has a lot of text but its minimum width is pretty narrow.
+@This cell also has a lot of text but its minimum width is pretty narrow.
+@A third cell with a lot of text but a pretty narrow minimum width.
+@A fourth cell with a lot of text but a pretty narrow minimum width.
+@A fifth cell with a lot of text but a pretty narrow minimum width.
+@A sixth cell with a lot of text but a pretty narrow minimum width.
+@A seventh cell with a lot of text but a pretty narrow minimum width.
+@A eighth cell with a lot of text but a pretty narrow minimum width.
+@A ninth cell with a lot of text but a pretty narrow minimum width.
+])
+AT_CHECK([render-test input], [0], [dnl
++--------+-------+--------+--------+-------+--------+--------+-------+--------+
+|    This|   This| A third|A fourth|A fifth| A sixth|       A|      A| A ninth|
+|cell has|   cell|    cell|    cell|   cell|    cell| seventh| eighth|    cell|
+|a lot of|   also|  with a|  with a| with a|  with a|    cell|   cell|  with a|
+|text but|  has a|  lot of|  lot of| lot of|  lot of|  with a| with a|  lot of|
+|     its| lot of|text but|text but|   text|text but|  lot of| lot of|text but|
+| minimum|   text|a pretty|a pretty|  but a|a pretty|text but|   text|a pretty|
+|width is|but its|  narrow|  narrow| pretty|  narrow|a pretty|  but a|  narrow|
+|  pretty|minimum| minimum| minimum| narrow| minimum|  narrow| pretty| minimum|
+| narrow.|  width|  width.|  width.|minimum|  width.| minimum| narrow|  width.|
+|        |     is|        |        | width.|        |  width.|minimum|        |
+|        | pretty|        |        |       |        |        | width.|        |
+|        |narrow.|        |        |       |        |        |       |        |
++--------+-------+--------+--------+-------+--------+--------+-------+--------+
+])
+AT_CLEANUP
+
+AT_SETUP([2 big cells with new-lines])
+AT_DATA([input], [1 2
+@PSPP does not place many restrictions on ordering of commands. The main restriction is that variables must be defined before they are otherwise referenced.  This section describes the details of command ordering, but most users will have no need to refer to them. PSPP possesses five internal states, called initial, INPUT PROGRAM, FILE TYPE, transformation, and procedure states.
+@PSPP includes special support\nfor unknown numeric data values.\nMissing observations are assigned\na special value, called the\n``system-missing value''.  This\n``value'' actually indicates the\nabsence of a value; it\nmeans that the actual\nvalue is unknown.
+])
+AT_CHECK([render-test input], [0], [dnl
++----------------------------------------------------------+------------------+
+|      PSPP does not place many restrictions on ordering of|     PSPP includes|
+|  commands. The main restriction is that variables must be|   special support|
+|       defined before they are otherwise referenced.  This|       for unknown|
+|    section describes the details of command ordering, but|      numeric data|
+|       most users will have no need to refer to them. PSPP|           values.|
+|     possesses five internal states, called initial, INPUT|           Missing|
+| PROGRAM, FILE TYPE, transformation, and procedure states.|  observations are|
+|                                                          |          assigned|
+|                                                          |  a special value,|
+|                                                          |        called the|
+|                                                          |  ``system-missing|
+|                                                          |    value''.  This|
+|                                                          |``value'' actually|
+|                                                          |     indicates the|
+|                                                          |      absence of a|
+|                                                          |         value; it|
+|                                                          |    means that the|
+|                                                          |            actual|
+|                                                          | value is unknown.|
++----------------------------------------------------------+------------------+
+])
+AT_CLEANUP
+
+AT_SETUP([8x8 with many 2x2 joins])
+RENDER_8X8_2
+AT_CHECK([render-test input], [0],[dnl
++---+---+----+----+
+|abc|jkl| mno| vwx|
+|def|   | pqr|    |
+|ghi+---+ stu+----+
+|   |yzA|    | HIJ|
++-+-+BCD+-+--+ KLM|
+|Q|V|EFG|W| Z| NOP|
+|R| |   |X|  |    |
+|S+-+-+-+Y+--+-+--+
+|T|012|9| | abc| j|
+|U|345| | | def| k|
+| |678+-+-+ ghi| l|
+| |   |opq|    | m|
++-+-+-+rst+----+ n|
+|xyz|G|uvw| JKL|  |
+|ABC|H|   |    |  |
+|DEF|I+---+--+-+--+
+|   | | MNOPQ| 123|
++---+-+ RSTUV| 456|
+|abcde| WXYZ0| 789|
+|     |      |    |
++-----+------+----+
+])
+AT_CLEANUP
+\f
+AT_BANNER([output rendering -- horizontal page breaks])
+
+AT_SETUP([breaking row of many small cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 50
+m4_for([x], [1], [50], [1], [@x
+])])
+AT_CHECK([render-test input], [0], [dnl
++-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|
++-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking row of many small cells, with headers])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 54 2 2
+@ha
+@hb
+m4_for([x], [1], [50], [1], [@x
+])dnl
+@hc
+@hd
+])
+AT_CHECK([render-test input], [0], [dnl
++--+--+-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+|ha|hb|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|hc|hd|
++--+--+-+-+-+-+-+-+-+-+-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+|ha|hb|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|hc|hd|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
++--+--+--+--+--+--+--+
+|ha|hb|48|49|50|hc|hd|
++--+--+--+--+--+--+--+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking row of many medium-size cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 50
+m4_for([x], [1], [50], [1], [@cell x
+])])
+AT_CHECK([render-test input], [0], [dnl
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|
+|   1|   2|   3|   4|   5|   6|   7|   8|   9|  10|  11|  12|  13|  14|  15|
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|
+|  16|  17|  18|  19|  20|  21|  22|  23|  24|  25|  26|  27|  28|  29|  30|
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|
+|  31|  32|  33|  34|  35|  36|  37|  38|  39|  40|  41|  42|  43|  44|  45|
++----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
+
++----+----+----+----+----+
+|cell|cell|cell|cell|cell|
+|  46|  47|  48|  49|  50|
++----+----+----+----+----+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking row of many medium-size cells, with headers])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 52 1 1
+header1
+m4_for([x], [1], [50], [1], [@cell x
+])dnl
+header2
+])
+AT_CHECK([render-test input], [0], [dnl
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+header1|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|header2
+       |   1|   2|   3|   4|   5|   6|   7|   8|   9|  10|  11|  12|
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+header1|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|header2
+       |  13|  14|  15|  16|  17|  18|  19|  20|  21|  22|  23|  24|
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+header1|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|header2
+       |  25|  26|  27|  28|  29|  30|  31|  32|  33|  34|  35|  36|
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+header1|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|cell|header2
+       |  37|  38|  39|  40|  41|  42|  43|  44|  45|  46|  47|  48|
+       +----+----+----+----+----+----+----+----+----+----+----+----+
+
+       +----+----+
+header1|cell|cell|header2
+       |  49|  50|
+       +----+----+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking row of many big narrow cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 50
+m4_for([x], [1], [50], [1], [@This is cell x in a series of 50.
+])])
+AT_CHECK([render-test input], [0], [dnl
++------+------+------+------+------+------+------+------+------+------+------+
+|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|
+|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|
+|cell 1|cell 2|cell 3|cell 4|cell 5|cell 6|cell 7|cell 8|cell 9|  cell|  cell|
+|  in a|  in a|  in a|  in a|  in a|  in a|  in a|  in a|  in a| 10 in| 11 in|
+|series|series|series|series|series|series|series|series|series|     a|     a|
+|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|series|series|
+|      |      |      |      |      |      |      |      |      |of 50.|of 50.|
++------+------+------+------+------+------+------+------+------+------+------+
+
++------+------+------+------+------+------+------+------+------+------+------+
+|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|
+|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|
+|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|
+| 12 in| 13 in| 14 in| 15 in| 16 in| 17 in| 18 in| 19 in| 20 in| 21 in| 22 in|
+|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|
+|series|series|series|series|series|series|series|series|series|series|series|
+|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|
++------+------+------+------+------+------+------+------+------+------+------+
+
++------+------+------+------+------+------+------+------+------+------+------+
+|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|
+|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|
+|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|
+| 23 in| 24 in| 25 in| 26 in| 27 in| 28 in| 29 in| 30 in| 31 in| 32 in| 33 in|
+|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|
+|series|series|series|series|series|series|series|series|series|series|series|
+|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|
++------+------+------+------+------+------+------+------+------+------+------+
+
++------+------+------+------+------+------+------+------+------+------+------+
+|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|  This|
+|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|    is|
+|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|  cell|
+| 34 in| 35 in| 36 in| 37 in| 38 in| 39 in| 40 in| 41 in| 42 in| 43 in| 44 in|
+|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|     a|
+|series|series|series|series|series|series|series|series|series|series|series|
+|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|
++------+------+------+------+------+------+------+------+------+------+------+
+
++------+------+------+------+------+------+
+|  This|  This|  This|  This|  This|  This|
+|    is|    is|    is|    is|    is|    is|
+|  cell|  cell|  cell|  cell|  cell|  cell|
+| 45 in| 46 in| 47 in| 48 in| 49 in| 50 in|
+|     a|     a|     a|     a|     a|     a|
+|series|series|series|series|series|series|
+|of 50.|of 50.|of 50.|of 50.|of 50.|of 50.|
++------+------+------+------+------+------+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking 2 rows of many small cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [2 50
+m4_for([x], [1], [100], [1], [@x
+])])
+AT_CHECK([render-test input], [0], [dnl
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---+
+|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49| 50|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---+
+|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|
++--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+---+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking 3 rows with many joined cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [3 49
+m4_foreach([var], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,dnl
+A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W], [var
+])@1
+m4_for([x], [2], [49], [1], [1*2 @x
+])@50
+])
+AT_CHECK([render-test input], [0], [dnl
+ a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M
++-+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+|1|  2|  3|  4|  5|  6|  7|  8|  9| 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 20|
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| 26| 27| 28| 29| 30| 31| 32| 33| 34| 35| 36| 37| 38| 39| 40| 41| 42| 43| 44| 4
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+--
+
+ N O P Q R S T U V  W
++---+---+---+---+----+
+| 21| 22| 23| 24|  25|
++-+-+-+-+-+-+-+-+-+--+
+45| 46| 47| 48| 49|50|
+--+---+---+---+---+--+
+])
+AT_CLEANUP
+
+AT_SETUP([horz break 6x6, joined rows and columns])
+RENDER_WEAVE_6X6
+AT_CHECK([render-test --width=6 input], [0], [dnl
++-+--
+|a|bc
++-+-+
+|j|m|
+|k+-+
+|l|t|
++-+u|
+|A|v|
++-+-+
+|IJK|
++-+-+
+|Q|RS
++-+--
+
+--+-+
+cd|e|
++-+-+
+|nop|
++-+-+
+|w|xy
++-+-+
+|B|E|
+|C+-+
+|D|L|
++-+M|
+ST|N|
+--+-+
+
++-+-+
+|f|i|
+|g+-+
+|h|q|
++-+r|
+yz|s|
++-+-+
+|FGH|
++-+-+
+|O|P|
++-+-+
+|U|V|
++-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([horz break 6x6, joined rows and columns, left header])
+RENDER_WEAVE_6X6([1 0 0 0])
+AT_CHECK([render-test --width=10 input], [0], [dnl
++-+---+-+
+|a|bcd|e|
++-+-+-+-+
+|j|m|nop|
+|k+-+-+-+
+|l|t|w|xy
++-+u+-+-+
+|A|v|B|E|
++-+-+C+-+
+|K K|D|L|
++-+-+-+M|
+|Q|RST|N|
++-+---+-+
+
++-+-+-+
+|a|f|i|
++-+g+-+
+|j|h|q|
+|k+-+r|
+|l|z|s|
++-+-+-+
+|A|FGH|
++-+-+-+
+|K|O|P|
++-+-+-+
+|Q|U|V|
++-+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([horz break 6x6, joined rows and columns, right header])
+RENDER_WEAVE_6X6([0 1 0 0])
+AT_CHECK([render-test --width=10 input], [0], [dnl
++-+---+-+
+|a|bcd|i|
++-+-+-+-+
+|j|m|n|q|
+|k+-+-+r|
+|l|t|w|s|
++-+u+-+-+
+|A|v|B|H|
++-+-+C+-+
+|IJK|D|P|
++-+-+-+-+
+|Q|RST|V|
++-+---+-+
+
++-+-+-+
+|e|f|i|
++-+g+-+
+op|h|q|
++-+-+r|
+|xyz|s|
++-+-+-+
+|E|F H|
++-+-+-+
+|L|O|P|
+|M+-+-+
+|N|U|V|
++-+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking joined cells too wide for page])
+AT_DATA([input], [4 6
+1*6 @abc def ghi jkl
+1*3 @mno pqr
+1*3 @stu vwx
+1*2 @yzA
+1*2 @BCD
+1*2 @EFG
+@H
+@I
+@J
+@K
+@L
+@M
+])
+AT_CHECK([render-test --width=10 input], [0], [dnl
++--------
+|abc def
+|
++-----+--
+|  mno|
+|  pqr|
++---+-+-+
+|yzA|BCD|
++-+-+-+-+
+|H|I|J|K|
++-+-+-+-+
+
+----+
+ ghi|
+ jkl|
+----+
+ stu|
+ vwx|
++---+
+|EFG|
++-+-+
+|L|M|
++-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking joined cells much too wide for page])
+AT_DATA([input], [4 6
+1*6 @abc def ghi jkl
+1*3 @mno pqr
+1*3 @stu vwx
+1*2 @yzA
+1*2 @BCD
+1*2 @EFG
+@H
+@I
+@J
+@K
+@L
+@M
+])
+AT_CHECK([render-test --width=6 input], [0], [dnl
++----
+|abc
+|
++----
+|  mn
+|  pq
++---+
+|yzA|
++-+-+
+|H|I|
++-+-+
+
+-----
+ def
+
+--+--
+no|
+qr|
++-+-+
+|BCD|
++-+-+
+|J|K|
++-+-+
+
+----+
+ ghi|
+ jkl|
+----+
+ stu|
+ vwx|
++---+
+|EFG|
++-+-+
+|L|M|
++-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking cell too wide for page, no border])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 1
+abcdefghijklmnopqrstuvwxyz
+])
+AT_CHECK([render-test --width=6 input], [0], [dnl
+abcdef
+
+ghijkl
+
+mnopqr
+
+stuvwx
+
+yz
+])
+AT_CLEANUP
+
+AT_SETUP([breaking cell too wide for page, with border])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 1
+@abcdefghijklmnopqrstuvwxyz
+])
+AT_CHECK([render-test --width=6 input], [0], [dnl
++-----
+|abcde
++-----
+
+------
+defghi
+------
+
+------
+hijklm
+------
+
+------
+lmnopq
+------
+
+------
+pqrstu
+------
+
+------
+tuvwxy
+------
+
+---+
+xyz|
+---+
+])
+AT_CLEANUP
+
+AT_SETUP([horz break 8x8 with many 2x2 joins])
+RENDER_8X8_2
+AT_CHECK([render-test --width=8 input], [0],[dnl
++---+--
+|abc|jk
+|def|  
+|ghi+--
+|   |yz
++-+-+BC
+|Q|V|EF
+|R| |  
+|S+-+-+
+|T|012|
+|U|345|
+| |678|
+| |   |
++-+-+-+
+|xyz|G|
+|ABC|H|
+|DEF|I|
+|   | |
++---+-+
+|abcde|
+|     |
++-----+
+
+--+----+
+kl| mno|
+  | pqr|
+--+ stu|
+zA|    |
+CD+-+--+
+FG|W| Z|
+  |X|  |
++-+Y+--+
+|9| | ab
+| | | de
++-+-+ gh
+|opq|   
+|rst+---
+|uvw| JK
+|   |   
++---+--+
+| MNOPQ|
+| RSTUV|
+| WXYZ0|
+|      |
++------+
+
++----+
+| vwx|
+|    |
++----+
+| HIJ|
+| KLM|
+| NOP|
+|    |
++-+--+
+bc| j|
+ef| k|
+hi| l|
+  | m|
+--+ n|
+KL|  |
+  |  |
++-+--+
+| 123|
+| 456|
+
+| 456|
+| 789|
+|    |
++----+
+])
+AT_CLEANUP
+\f
+AT_BANNER([output rendering -- vertical page breaks])
+
+AT_SETUP([breaking column of many small cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [20 1
+m4_for([x], [1], [20], [1], [@x
+])])
+AT_CHECK([render-test --length=10 input], [0], [dnl
++--+
+| 1|
++--+
+| 2|
++--+
+| 3|
++--+
+| 4|
++--+
+
++--+
+| 5|
++--+
+| 6|
++--+
+| 7|
++--+
+| 8|
++--+
+
++--+
+| 9|
++--+
+|10|
++--+
+|11|
++--+
+|12|
++--+
+
++--+
+|13|
++--+
+|14|
++--+
+|15|
++--+
+|16|
++--+
+
++--+
+|17|
++--+
+|18|
++--+
+|19|
++--+
+|20|
++--+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking column of many small cells, with headers])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [17 1 0 0 1 1
+@a
+m4_for([x], [1], [15], [1], [@x
+])@b
+])
+AT_CHECK([render-test --length=13 input], [0], [dnl
++--+
+| a|
++--+
+| 1|
++--+
+| 2|
++--+
+| 3|
++--+
+| 4|
++--+
+| b|
++--+
+
++--+
+| a|
++--+
+| 5|
++--+
+| 6|
++--+
+| 7|
++--+
+| 8|
++--+
+| b|
++--+
+
++--+
+| a|
++--+
+| 9|
++--+
+|10|
++--+
+|11|
++--+
+|12|
++--+
+| b|
++--+
+
++--+
+| a|
++--+
+|13|
++--+
+|14|
++--+
+|15|
++--+
+| b|
++--+
+])
+AT_CLEANUP
+
+AT_SETUP([disabling too-big headers])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [17 1 0 0 1 1
+@a
+m4_for([x], [1], [15], [1], [@x
+])@b
+])
+AT_CHECK([render-test --length=10 input], [0], [dnl
++--+
+| a|
++--+
+| 1|
++--+
+| 2|
++--+
+| 3|
++--+
+
++--+
+| 4|
++--+
+| 5|
++--+
+| 6|
++--+
+| 7|
++--+
+
++--+
+| 8|
++--+
+| 9|
++--+
+|10|
++--+
+|11|
++--+
+
++--+
+|12|
++--+
+|13|
++--+
+|14|
++--+
+|15|
++--+
+
++--+
+| b|
++--+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking column of many medium-size cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [20 1
+m4_for([x], [1], [20], [1], [@top x\ncell x\nbottom x
+])])
+AT_CHECK([render-test --length 10 input], [0], [dnl
++---------+
+|    top 1|
+|   cell 1|
+| bottom 1|
++---------+
+|    top 2|
+|   cell 2|
+| bottom 2|
++---------+
+
++---------+
+|    top 3|
+|   cell 3|
+| bottom 3|
++---------+
+|    top 4|
+|   cell 4|
+| bottom 4|
++---------+
+
++---------+
+|    top 5|
+|   cell 5|
+| bottom 5|
++---------+
+|    top 6|
+|   cell 6|
+| bottom 6|
++---------+
+
++---------+
+|    top 7|
+|   cell 7|
+| bottom 7|
++---------+
+|    top 8|
+|   cell 8|
+| bottom 8|
++---------+
+
++---------+
+|    top 9|
+|   cell 9|
+| bottom 9|
++---------+
+|   top 10|
+|  cell 10|
+|bottom 10|
++---------+
+
++---------+
+|   top 11|
+|  cell 11|
+|bottom 11|
++---------+
+|   top 12|
+|  cell 12|
+|bottom 12|
++---------+
+
++---------+
+|   top 13|
+|  cell 13|
+|bottom 13|
++---------+
+|   top 14|
+|  cell 14|
+|bottom 14|
++---------+
+
++---------+
+|   top 15|
+|  cell 15|
+|bottom 15|
++---------+
+|   top 16|
+|  cell 16|
+|bottom 16|
++---------+
+
++---------+
+|   top 17|
+|  cell 17|
+|bottom 17|
++---------+
+|   top 18|
+|  cell 18|
+|bottom 18|
++---------+
+
++---------+
+|   top 19|
+|  cell 19|
+|bottom 19|
++---------+
+|   top 20|
+|  cell 20|
+|bottom 20|
++---------+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking 3 columns with many joined cells])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [3 19
+m4_foreach([x], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s], [x
+])@1
+m4_for([x], [2], [19], [1], [1*2 @x\nab\ncd
+])@20
+])
+AT_CHECK([render-test --length=6 --transpose input], [0], [dnl
+ +--+--+
+a| 1|11|
+ +--+ab|
+b| 2|cd|
+ |ab+--+
+
+ |ab+--+
+c|cd|12|
+ +--+ab|
+d| 3|cd|
+ |ab+--+
+
+ |ab+--+
+e|cd|13|
+ +--+ab|
+f| 4|cd|
+ |ab+--+
+
+ |ab+--+
+g|cd|14|
+ +--+ab|
+h| 5|cd|
+ |ab+--+
+
+ |ab+--+
+i|cd|15|
+ +--+ab|
+j| 6|cd|
+ |ab+--+
+
+ |ab+--+
+k|cd|16|
+ +--+ab|
+l| 7|cd|
+ |ab+--+
+
+ |ab+--+
+m|cd|17|
+ +--+ab|
+n| 8|cd|
+ |ab+--+
+
+ |ab+--+
+o|cd|18|
+ +--+ab|
+p| 9|cd|
+ |ab+--+
+
+ |ab+--+
+q|cd|19|
+ +--+ab|
+r|10|cd|
+ |ab+--+
+
+ |ab+--+
+s|cd|20|
+ +--+--+
+])
+AT_CLEANUP
+
+AT_SETUP([vert break 6x6, joined rows and columns])
+RENDER_WEAVE_6X6
+AT_CHECK([render-test --length=6 input], [0], [dnl
++-+---+-+-+-+
+|a|bcd|e|f|i|
++-+-+-+-+g+-+
+|j|m|nop|h|q|
+|k+-+---+-+r|
+
+|k+-+-+---+r|
+|l|t|w|xyz|s|
++-+u+-+-+-+-+
+|A|v|B|E|FGH|
++-+-+C+-+---+
+
++---+C+-+-+-+
+|IJK|D|L|O|P|
++-+-+-+M+-+-+
+|Q|RST|N|U|V|
++-+---+-+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking joined cells too tall for page])
+AT_DATA([input], [4 6
+1*6 @abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyzA\nBCD\nEFG
+1*3 @HIJ\nKLM\nOPQ\nRST\nUVW
+1*3 @XYZ\n012\n345\n678\n90a
+1*2 @bcd\nefg\nhij
+1*2 @klm\nnop\nqrs
+1*2 @tuv\nwxy\nzAB
+@C
+@D
+@E
+@F
+@G
+@H
+])
+AT_CHECK([render-test --transpose --length=6 input], [0], [dnl
++---+---+---+-+
+|abc|HIJ|bcd|C|
+|def|KLM|efg+-+
+|ghi|OPQ|hij|D|
+|jkl|RST+---+-+
+
+|jkl|RST+---+-+
+|mno|UVW|klm|E|
+|pqr+---+nop+-+
+|stu|XYZ|qrs|F|
+|vwx|012+---+-+
+
+|vwx|012+---+-+
+|yzA|345|tuv|G|
+|BCD|678|wxy+-+
+|EFG|90a|zAB|H|
++---+---+---+-+
+])
+AT_CLEANUP
+
+AT_SETUP([breaking cell too tall for page, no border])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 1
+abc defg hij klmn opq rstu vwx yz ABCDE FGH I JK LMNOP QR STU VWXYZ
+])
+AT_CHECK([render-test --width=6 --length=6 input], [0], [dnl
+   abc
+  defg
+   hij
+  klmn
+   opq
+  rstu
+
+vwx yz
+ ABCDE
+ FGH I
+    JK
+ LMNOP
+QR STU
+
+ VWXYZ
+])
+AT_CLEANUP
+
+AT_SETUP([breaking cell too tall for page, with border])
+AT_CAPTURE_FILE([input])
+AT_DATA([input], [1 1
+@abc defg hij klmn opq rstu vwx yz ABCDE FGH I JK LMNOP QR STU VWXYZ
+])
+AT_CHECK([render-test --width=7 --length=6 input], [0], [dnl
++-----+
+|  abc|
+| defg|
+|  hij|
+| klmn|
+|  opq|
+
+| klmn|
+|  opq|
+| rstu|
+|  vwx|
+|   yz|
+|ABCDE|
+
+|   yz|
+|ABCDE|
+|FGH I|
+|   JK|
+|LMNOP|
+|   QR|
+
+|LMNOP|
+|   QR|
+|  STU|
+|VWXYZ|
++-----+
+])
+AT_CLEANUP
+\f
+AT_BANNER([output rendering -- double page breaks])
+
+AT_SETUP([double break 6x6, joined rows and columns])
+RENDER_WEAVE_6X6
+AT_CHECK([render-test --width=6 --length=6 input], [0], [dnl
++-+--
+|a|bc
++-+-+
+|j|m|
+|k+-+
+
+|k+-+
+|l|t|
++-+u|
+|A|v|
++-+-+
+
++---+
+|IJK|
++-+-+
+|Q|RS
++-+--
+
+--+-+
+cd|e|
++-+-+
+|nop|
++---+
+
++-+--
+|w|xy
++-+-+
+|B|E|
+|C+-+
+
+|C+-+
+|D|L|
++-+M|
+ST|N|
+--+-+
+
++-+-+
+|f|i|
+|g+-+
+|h|q|
++-+r|
+
+--+r|
+yz|s|
++-+-+
+|FGH|
++---+
+
++-+-+
+|O|P|
++-+-+
+|U|V|
++-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([double break 8x8, with joins, left and right headers])
+RENDER_8X8([1 1 0 0])
+AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
++-+-+-+-+-+-+
+|a|b|c|d|e|h|
++-+-+-+-+-+-+
+|i|jkl|m|n|t|
++-+-+-+-+-+-+
+|u|v|wxy|z|D|
++-+-+-+-+-+-+
+|E|F|I|JKL|P|
++-+G+-+---+-+
+|Q|H|R|UVW|Y|
++-+-+S+-+-+-+
+|Z|0|T|3|4|8|
++-+1+-+-+-+-+
+
++-+1+---+-+-+
+|9|2|abc|d|h|
++-+-+-+-+-+-+
+|i|j|k|l|m|p|
++-+-+-+-+-+-+
+
++-+--+-+-+
+|a| f|g|h|
++-+--+-+-+
+|i|op|q|t|
++-+--+r+-+
+|u| A|s|D|
++-+ B+-+-+
+
++-+ B+-+-+
+|E| C|M|P|
++-+--+N+-+
+|Q| X|O|Y|
++-+--+-+-+
+|Z|56|7|8|
++-+--+-+-+
+|9| efg|h|
++-+--+-+-+
+|i| n|o|p|
++-+--+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([double break 8x8, with joins, top and bottom headers])
+RENDER_8X8([0 0 1 1])
+AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
++-+-+-+-+-+-+
+|a|b|c|d|e|f|
++-+-+-+-+-+-+
+|i|jkl|m|nop|
++-+-+-+-+-+-+
+|u|v|wxy|z|A|
++-+-+-+-+-+B|
+|E|F|I|JKL|C|
++-+G+-+---+-+
+|Q|H|R|UVW|X|
++-+-+-+-+-+-+
+|i|j|k|l|m|n|
++-+-+-+-+-+-+
+
++-+-+-+-+-+-+
+|a|b|c|d|e|f|
++-+-+-+-+-+-+
+|Z|0|S|3|456|
+| |1|T| |   |
++-+2+-+-+-+-+
+|9| |abc|d|ef
++-+-+-+-+-+-+
+|i|j|k|l|m|n|
++-+-+-+-+-+-+
+
++-+-+
+|g|h|
++-+-+
+|q|t|
+|r+-+
+|s|D|
++-+-+
+|M|P|
+|N+-+
+|O|Y|
++-+-+
+|o|p|
++-+-+
+
++-+-+
+|g|h|
++-+-+
+|7|8|
+| | |
++-+-+
+fg|h|
++-+-+
+|o|p|
++-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([double break 8x8, with joins, all headers])
+RENDER_8X8([1 1 1 1])
+AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
++-+-+-+-+-+-+
+|a|b|c|d|e|h|
++-+-+-+-+-+-+
+|i|jkl|m|n|t|
++-+-+-+-+-+-+
+|u|v|wxy|z|D|
++-+-+-+-+-+-+
+|E|F|I|JKL|P|
++-+G+-+---+-+
+|Q|H|R|UVW|Y|
++-+-+-+-+-+-+
+|i|j|k|l|m|p|
++-+-+-+-+-+-+
+
++-+-+-+-+-+-+
+|a|b|c|d|e|h|
++-+-+-+-+-+-+
+|Z|0|S|3|4|8|
+| |1|T| | | |
++-+2+-+-+-+-+
+|9| |abc|d|h|
++-+-+-+-+-+-+
+|i|j|k|l|m|p|
++-+-+-+-+-+-+
+
++-+--+-+-+
+|a| f|g|h|
++-+--+-+-+
+|i|op|q|t|
++-+--+r+-+
+|u| A|s|D|
++-+ B+-+-+
+|E| C|M|P|
++-+--+N+-+
+|Q| X|O|Y|
++-+--+-+-+
+|i| n|o|p|
++-+--+-+-+
+
++-+--+-+-+
+|a| f|g|h|
++-+--+-+-+
+|Z|56|7|8|
+| |  | | |
++-+--+-+-+
+|9| efg|h|
++-+--+-+-+
+|i| n|o|p|
++-+--+-+-+
+])
+AT_CLEANUP
+
+AT_SETUP([double break joined cells too big for page])
+AT_DATA([input], [7 7
+@a
+@b
+@c
+@d
+@e
+@f
+@g
+@h
+6*6 @The MISSING subcommand determines the handling of missing variables.  If INCLUDE is set, then user-missing values are included in the calculations.  If NOINCLUDE is set, which is the default, user-missing values are excluded.
+@i
+@j
+@k
+@l
+@m
+])
+AT_CHECK([render-test --width=15 --length=15 input], [0], [dnl
++-+--+--+---+
+|a| b| c|  d|
++-+--+--+---+
+|h|       The
+| |        su
+| |    determ
++-+       han
+|i|missing va
+| |     If IN
+| |         s
++-+      user
+|j|        va
+| |   include
+| | calculati
++-+ NOINCLUDE
+
++-+ NOINCLUDE
+|k|      whic
+| |
++-+      user
+|l|        va
+| |         e
+| |
++-+
+|m|
+| |
+| |
++-+----------
+
++--+--+--+
+| e| f| g|
++--+--+--+
+e MISSING|
+ubcommand|
+mines the|
+ndling of|
+ariables.|
+NCLUDE is|
+set, then|
+r-missing|
+alues are|
+ed in the|
+ions.  If|
+E is set,|
+
+E is set,|
+ch is the|
+ default,|
+r-missing|
+alues are|
+excluded.|
+         |
+         |
+         |
+         |
+         |
+---------+
+])
+AT_CLEANUP
index a1f4a64e6aaf18d52fae489164f38f56e1c250c1..3577a03b8cd9d18cf06d420ecbe23ec9ed29e35f 100755 (executable)
@@ -82,56 +82,52 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/descript.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/descript.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|V0      |     1|  1-  1|F1.0  |
-|V1      |     1|  2-  2|F1.0  |
-|V2      |     1|  3-  3|F1.0  |
-|V3      |     1|  4-  4|F1.0  |
-|V4      |     1|  5-  5|F1.0  |
-|V5      |     1|  6-  6|F1.0  |
-|V6      |     1|  7-  7|F1.0  |
-|V7      |     1|  8-  8|F1.0  |
-|V8      |     1|  9-  9|F1.0  |
-|V9      |     1| 10- 10|F1.0  |
-|V10     |     1| 11- 11|F1.0  |
-|V11     |     1| 12- 12|F1.0  |
-|V12     |     1| 13- 13|F1.0  |
-|V13     |     1| 14- 14|F1.0  |
-|V14     |     1| 15- 15|F1.0  |
-|V15     |     1| 16- 16|F1.0  |
-|V16     |     1| 17- 17|F1.0  |
-+--------+------+-------+------+
-2.1 DESCRIPTIVES.  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|
-+--------#-------+---------+----+---------+-------+--------+--------+---------+--------+---------+-----+-------+-------+-----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Title: Test DESCRIPTIVES procedure
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+V0,1,1-  1,F1.0
+V1,1,2-  2,F1.0
+V2,1,3-  3,F1.0
+V3,1,4-  4,F1.0
+V4,1,5-  5,F1.0
+V5,1,6-  6,F1.0
+V6,1,7-  7,F1.0
+V7,1,8-  8,F1.0
+V8,1,9-  9,F1.0
+V9,1,10- 10,F1.0
+V10,1,11- 11,F1.0
+V11,1,12- 12,F1.0
+V12,1,13- 13,F1.0
+V13,1,14- 14,F1.0
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index eb12331b9308ca30e67bf4deb534f0969f3c6ba2..4a8853b47e4109cccdc12531865371bf861e21a5 100755 (executable)
@@ -77,18 +77,14 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/descript.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/descript.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 DESCRIPTIVES.  Valid cases = 6; cases with missing value(s) = 0.
-+--------#-+-----+
-|Variable#N| Mean|
-#========#=#=====#
-|X       #6|2.500|
-+--------#-+-----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Valid cases = 6; cases with missing value(s) = 0.
+Variable,N,Mean
+X,6,2.500
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 9de2770e1e5ae3bf1007636d84db803278926f19..2370a1d58ab2537983d250f15a9af5f13b07d267 100755 (executable)
@@ -83,52 +83,42 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/descript.stat
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/descript.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 DATA LIST.  Reading 1 record from INLINE.
-+--------+------+-------+------+
-|Variable|Record|Columns|Format|
-#========#======#=======#======#
-|V1      |     1|  1-  1|F1.0  |
-|V2      |     1|  2-  2|F1.0  |
-|V3      |     1|  3-  3|F1.0  |
-+--------+------+-------+------+
-2.1 DESCRIPTIVES.  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|
-+--------#-------+---------+----+---------+-------+--------+--------+---------+--------+---------+-----+-------+-------+----+
-3.1 DESCRIPTIVES.  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|
-+--------#-------+---------+----+---------+-------+--------+--------+---------+--------+---------+-----+-------+-------+-----+
-4.1 DESCRIPTIVES.  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|
-+--------#-------+---------+----+---------+-------+--------+--------+---------+--------+---------+-----+-------+-------+----+
-5.1 DESCRIPTIVES.  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|
-+--------#-------+---------+----+---------+-------+--------+--------+---------+--------+---------+-----+-------+-------+-----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Title: Test DESCRIPTIVES procedure
+
+Table: Reading 1 record from INLINE.
+Variable,Record,Columns,Format
+V1,1,1-  1,F1.0
+V2,1,2-  2,F1.0
+V3,1,3-  3,F1.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
+
+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
+
+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
+
+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
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 89854285a0f0cde4fc9b7ad801a7db58e9970249..5fc7c69092abda94fc73a93caab68c57e0c97fbb 100755 (executable)
@@ -84,7 +84,7 @@ sed < $TEMPDIR/moments-list-2p >> $TEMPDIR/moments-2p.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run two-pass program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
         $TEMPDIR/moments-2p.stat >$TEMPDIR/moments-2p.err 2> $TEMPDIR/moments-2p.out
 
 activity="compare two-pass output"
@@ -98,7 +98,7 @@ sed < $TEMPDIR/moments-list-1p >> $TEMPDIR/moments-1p.stat \
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run one-pass program"
-$SUPERVISOR $PSPP --testing-mode \
+$SUPERVISOR $PSPP --testing-mode -o pspp.csv \
         $TEMPDIR/moments-1p.stat >$TEMPDIR/moments-1p.err 2> $TEMPDIR/moments-1p.out
 
 activity="compare one-pass output"
index dd00a361368128d3d02dbe834514a971b8c7a003..697cc4269f751bdd87b930bbcbf5a80ba072a02c 100755 (executable)
@@ -77,11 +77,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result; fi
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="move output"
-cp $TEMPDIR/pspp.list $TEMPDIR/list.ref
+cp $TEMPDIR/pspp.csv $TEMPDIR/list.ref
 if [ $? -ne 0 ] ; then no_result ; fi
 
 i=$[$i+1];
@@ -106,11 +106,11 @@ EOF
 if [ $? -ne 0 ] ; then no_result; fi
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output"
-diff $TEMPDIR/pspp.list $TEMPDIR/list.ref
+diff $TEMPDIR/pspp.csv $TEMPDIR/list.ref
 if [ $? -ne 0 ] ; then fail; fi
 
 
index 9b170240538561a34803fbe91e38f093356081cf..e546a45b82e4017406f15e3ac744908f7776d59c 100755 (executable)
@@ -82,37 +82,31 @@ EOF
 if [ $? -ne 0 ] ; then no_result; fi
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output $i"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+-----------------------+----+
-|N           Valid      |   5|
-|            Missing    |   0|
-|Mean                   |3.00|
-|Std Dev                |1.58|
-|Minimum                |1.00|
-|Maximum                |5.00|
-|Percentiles 0          |1.00|
-|            25         |1.50|
-|            50 (Median)|3.00|
-|            75         |4.50|
-|            100        |5.00|
-+-----------------------+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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,
+
+N,Valid,5
+,Missing,0
+Mean,,3.00
+Std Dev,,1.58
+Minimum,,1.00
+Maximum,,5.00
+Percentiles,0,1.00
+,25,1.50
+,50 (Median),3.00
+,75,4.50
+,100,5.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 9ee5a8c9b7d084a74055e099afc61a97e457db5f..03643f5b0d6f27982748d507564b8b3686b4bebf 100755 (executable)
@@ -81,37 +81,31 @@ EOF
 if [ $? -ne 0 ] ; then no_result; fi
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output $i"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+-----------------------+----+
-|N           Valid      |   5|
-|            Missing    |   0|
-|Mean                   |3.00|
-|Std Dev                |1.58|
-|Minimum                |1.00|
-|Maximum                |5.00|
-|Percentiles 0          |1.00|
-|            25         |2.00|
-|            50 (Median)|3.00|
-|            75         |4.00|
-|            100        |5.00|
-+-----------------------+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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,
+
+N,Valid,5
+,Missing,0
+Mean,,3.00
+Std Dev,,1.58
+Minimum,,1.00
+Maximum,,5.00
+Percentiles,0,1.00
+,25,2.00
+,50 (Median),3.00
+,75,4.00
+,100,5.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -143,37 +137,31 @@ if [ $? -ne 0 ] ; then no_result; fi
 
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output $i"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+-----------------------+-----+
-|N           Valid      |10.00|
-|            Missing    |  .00|
-|Mean                   | 3.00|
-|Std Dev                | 1.49|
-|Minimum                | 1.00|
-|Maximum                | 5.00|
-|Percentiles 0          | 1.00|
-|            25         | 2.00|
-|            50 (Median)| 3.00|
-|            75         | 4.00|
-|            100        | 5.00|
-+-----------------------+-----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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,
+
+N,Valid,10.00
+,Missing,.00
+Mean,,3.00
+Std Dev,,1.49
+Minimum,,1.00
+Maximum,,5.00
+Percentiles,0,1.00
+,25,2.00
+,50 (Median),3.00
+,75,4.00
+,100,5.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -203,36 +191,30 @@ if [ $? -ne 0 ] ; then no_result; fi
 
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output $i"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff  -b $TEMPDIR/pspp.list - <<EOF
-1.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+-----------------------+----+
-|N           Valid      |6.00|
-|            Missing    | .00|
-|Mean                   |3.50|
-|Std Dev                |1.52|
-|Minimum                |1.00|
-|Maximum                |5.00|
-|Percentiles 0          |1.00|
-|            25         |3.00|
-|            50 (Median)|3.50|
-|            75         |4.75|
-|            100        |5.00|
-+-----------------------+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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,
+
+N,Valid,6.00
+,Missing,.00
+Mean,,3.50
+Std Dev,,1.52
+Minimum,,1.00
+Maximum,,5.00
+Percentiles,0,1.00
+,25,3.00
+,50 (Median),3.50
+,75,4.75
+,100,5.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
@@ -262,37 +244,31 @@ if [ $? -ne 0 ] ; then no_result; fi
 
 
 activity="run program $i"
-$SUPERVISOR $PSPP --testing-mode $TEMPDIR/prog.sps
+$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="compare output $i"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -b $TEMPDIR/pspp.list - <<EOF
-1.1 FREQUENCIES.  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|           |
-+--------------------+---------+--------+-------------+-----------+
-+-----------------------+----+
-|N           Valid      |6.00|
-|            Missing    |4.00|
-|Mean                   |3.50|
-|Std Dev                |1.52|
-|Minimum                |1.00|
-|Maximum                |5.00|
-|Percentiles 0          |1.00|
-|            25         |3.00|
-|            50 (Median)|3.50|
-|            75         |4.75|
-|            100        |5.00|
-+-----------------------+----+
+diff -c $TEMPDIR/pspp.csv - <<EOF
+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,
+
+N,Valid,6.00
+,Missing,4.00
+Mean,,3.50
+Std Dev,,1.52
+Minimum,,1.00
+Maximum,,5.00
+Percentiles,0,1.00
+,25,3.00
+,50 (Median),3.50
+,75,4.75
+,100,5.00
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
index 5c996621ebd3130db798823dd2540fa9f147f6ee..41f00bce4da949340e767891badb24124092fb87 100755 (executable)
@@ -62,7 +62,7 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
diff --git a/tests/testsuite.at b/tests/testsuite.at
new file mode 100644 (file)
index 0000000..fbf821a
--- /dev/null
@@ -0,0 +1,5 @@
+AT_INIT
+
+AT_TESTED([pspp])
+
+m4_include([tests/output/render.at])
index ae29cc4d1d48cc0bf962facc9072cc2ceb93628b..a0119cb4c951846ca34f148bf2f766b5d63f5ac4 100755 (executable)
@@ -162,103 +162,108 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="run program"
-$SUPERVISOR $PSPP --testing-mode $TESTFILE
+$SUPERVISOR $PSPP -o pspp.csv $TESTFILE
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="test output"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/pspp.list
-diff -bu $TEMPDIR/pspp.list - <<EOF
-x  x0  x1  x2  x3  x4  x5  x6  x7  x8
-- --- --- --- --- --- --- --- --- ---
-0   0   0   0   0   0   1   0   3   0 
-1   9   9   8  10  10   1   1   3   1 
-2   2   2   9  10  10   1   2   3   2 
-3   3   8   9  10  10   1   3   3   3 
-4   4   4   9  10  10   1   2   3   4 
-5   5   7   9  10  10   1   2   3   5 
-6   6   6   9  10  10   6   2   3   6 
-7   7   7   7  10  10   7   2   3   7 
-8   8   8   9  10  10   8   2   3   8 
-9   9   9   1  10  11   9   2   3   9 
-.   .   .   .  11  11   .   .   .   4 
-x ix0 ix1 ix2 ix3 ix4 ix5 ix6 ix7 ix8
-- --- --- --- --- --- --- --- --- ---
-0   .   .   .   .   .   1   .   3   . 
-1   9   9   8  10  10   1   .   3   . 
-2   .   .   9  10  10   1   .   3   . 
-3   .   8   9  10  10   1   .   3   . 
-4   .   .   9  10  10   1   2   3   . 
-5   .   7   9  10  10   1   2   3   . 
-6   .   .   9  10  10   .   2   3   . 
-7   .   .   .  10  10   .   2   3   . 
-8   .   .   9  10  10   .   2   3   . 
-9   .   .   1  10  11   .   2   3   . 
-.   .   .   .  11  11   .   .   .   4 
-x cx0 cx1 cx2 cx3 cx4 cx5 cx6 cx7 cx8      cx9
-- --- --- --- --- --- --- --- --- --- --------
-0   0   0   0   0   0   1   0   3   0    22.00 
-1   9   9   8  10  10   1   1   3   1    22.00 
-2   2   2   9  10  10   1   2   3   2    22.00 
-3   3   8   9  10  10   1   3   3   3    22.00 
-4   4   4   9  10  10   1   2   3   4    22.00 
-5   5   7   9  10  10   1   2   3   5     5.00 
-6   6   6   9  10  10   6   2   3   6    22.00 
-7   7   7   7  10  10   7   2   3   7    22.00 
-8   8   8   9  10  10   8   2   3   8    22.00 
-9   9   9   1  10  11   9   2   3   9    22.00 
-.   .   .   .  11  11   .   .   .   4    22.00 
-   s          t   s0   s1   s2   s3         t0         t1         t2         t3
----- ---------- ---- ---- ---- ---- ---------- ---------- ---------- ----------
-                          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  
-   s          t  cs0  cs1  cs2        ct0        ct1        ct2        ct3
----- ---------- ---- ---- ---- ---------- ---------- ---------- ----------
-                          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  
-   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 
-x        sx0        sx1        sx2
-- ---------- ---------- ----------
-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        
+diff -c $TEMPDIR/pspp.csv - <<EOF
+Table: Data List
+x,x0,x1,x2,x3,x4,x5,x6,x7,x8
+0,0,0,0,0,0,1,0,3,0
+1,9,9,8,10,10,1,1,3,1
+2,2,2,9,10,10,1,2,3,2
+3,3,8,9,10,10,1,3,3,3
+4,4,4,9,10,10,1,2,3,4
+5,5,7,9,10,10,1,2,3,5
+6,6,6,9,10,10,6,2,3,6
+7,7,7,7,10,10,7,2,3,7
+8,8,8,9,10,10,8,2,3,8
+9,9,9,1,10,11,9,2,3,9
+.,.,.,.,11,11,.,.,.,4
+
+Table: Data List
+x,ix0,ix1,ix2,ix3,ix4,ix5,ix6,ix7,ix8
+0,.,.,.,.,.,1,.,3,.
+1,9,9,8,10,10,1,.,3,.
+2,.,.,9,10,10,1,.,3,.
+3,.,8,9,10,10,1,.,3,.
+4,.,.,9,10,10,1,2,3,.
+5,.,7,9,10,10,1,2,3,.
+6,.,.,9,10,10,.,2,3,.
+7,.,.,.,10,10,.,2,3,.
+8,.,.,9,10,10,.,2,3,.
+9,.,.,1,10,11,.,2,3,.
+.,.,.,.,11,11,.,.,.,4
+
+Table: Data List
+x,cx0,cx1,cx2,cx3,cx4,cx5,cx6,cx7,cx8,cx9
+0,0,0,0,0,0,1,0,3,0,22.00
+1,9,9,8,10,10,1,1,3,1,22.00
+2,2,2,9,10,10,1,2,3,2,22.00
+3,3,8,9,10,10,1,3,3,3,22.00
+4,4,4,9,10,10,1,2,3,4,22.00
+5,5,7,9,10,10,1,2,3,5,5.00
+6,6,6,9,10,10,6,2,3,6,22.00
+7,7,7,7,10,10,7,2,3,7,22.00
+8,8,8,9,10,10,8,2,3,8,22.00
+9,9,9,1,10,11,9,2,3,9,22.00
+.,.,.,.,11,11,.,.,.,4,22.00
+
+Table: Data List
+s,t,s0,s1,s2,s3,t0,t1,t2,t3
+,,,,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 
+
+Table: Data List
+s,t,cs0,cs1,cs2,ct0,ct1,ct2,ct3
+,,,,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 
+
+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
+
+Table: Data List
+x,sx0,sx1,sx2
+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       
 EOF
 if [ $? -ne 0 ] ; then fail ; fi