Merge remote branch 'savannah/master' into sourceview origin/sourceview
authorJohn Darrington <john@darrington.wattle.id.au>
Fri, 1 Jul 2011 12:54:36 +0000 (14:54 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Fri, 1 Jul 2011 12:54:36 +0000 (14:54 +0200)
Conflicts:
src/ui/gui/automake.mk
src/ui/gui/psppire-data-window.c
src/ui/gui/psppire-syntax-window.c
src/ui/gui/psppire-syntax-window.h

612 files changed:
AUTHORS
INSTALL
Makefile.am
NEWS
README
README.Git
Smake
configure.ac
doc/.gitignore
doc/combining.texi
doc/data-io.texi
doc/data-selection.texi
doc/dev/concepts.texi
doc/dev/data.texi
doc/dev/system-file-format.texi
doc/expressions.texi
doc/files.texi
doc/flow-control.texi
doc/invoking.texi
doc/language.texi
doc/regression.texi
doc/statistics.texi
doc/transformation.texi
doc/utilities.texi
doc/variables.texi
glade/dialog.c
lib/gtk-contrib/psppire-sheet.c
perl-module/PSPP.xs
perl-module/t/Pspp.t
po/automake.mk
po/ca.po
po/en_GB.po
po/es.po
po/lt.po [new file with mode: 0644]
po/nl.po
src/data/any-reader.c
src/data/any-writer.c
src/data/attributes.c
src/data/attributes.h
src/data/automake.mk
src/data/calendar.c
src/data/case-map.c
src/data/case-matcher.c
src/data/case-tmpfile.c
src/data/case-tmpfile.h
src/data/case.c
src/data/case.h
src/data/casegrouper.c
src/data/caseinit.c
src/data/caseinit.h
src/data/caseproto.c
src/data/caseproto.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.h
src/data/casewindow.c
src/data/casewindow.h
src/data/casewriter-provider.h
src/data/casewriter-translator.c
src/data/casewriter.c
src/data/casewriter.h
src/data/csv-file-writer.c
src/data/data-in.c
src/data/data-in.h
src/data/data-out.c
src/data/data-out.h
src/data/dataset-reader.c [new file with mode: 0644]
src/data/dataset-reader.h [new file with mode: 0644]
src/data/dataset-writer.c [new file with mode: 0644]
src/data/dataset-writer.h [new file with mode: 0644]
src/data/dataset.c [new file with mode: 0644]
src/data/dataset.h [new file with mode: 0644]
src/data/datasheet.c
src/data/datasheet.h
src/data/dict-class.c
src/data/dictionary.c
src/data/dictionary.h
src/data/file-handle-def.c
src/data/file-handle-def.h
src/data/file-name.c
src/data/format-guesser.c
src/data/format-guesser.h
src/data/format.c
src/data/format.h
src/data/gnumeric-reader.c
src/data/gnumeric-reader.h
src/data/identifier.c
src/data/identifier.h
src/data/identifier2.c [new file with mode: 0644]
src/data/lazy-casereader.c
src/data/lazy-casereader.h
src/data/missing-values.c
src/data/mrset.c
src/data/mrset.h
src/data/por-file-reader.c
src/data/por-file-writer.c
src/data/procedure.c [deleted file]
src/data/procedure.h [deleted file]
src/data/psql-reader.c
src/data/psql-reader.h
src/data/scratch-handle.c [deleted file]
src/data/scratch-handle.h [deleted file]
src/data/scratch-reader.c [deleted file]
src/data/scratch-reader.h [deleted file]
src/data/scratch-writer.c [deleted file]
src/data/scratch-writer.h [deleted file]
src/data/session.c [new file with mode: 0644]
src/data/session.h [new file with mode: 0644]
src/data/settings.c
src/data/settings.h
src/data/short-names.c
src/data/subcase.c
src/data/sys-file-encoding.c [new file with mode: 0644]
src/data/sys-file-encoding.pl [new file with mode: 0755]
src/data/sys-file-private.c
src/data/sys-file-private.h
src/data/sys-file-reader.c
src/data/sys-file-reader.h
src/data/sys-file-writer.c
src/data/transformations.c
src/data/transformations.h
src/data/val-type.h
src/data/value-labels.c
src/data/value-labels.h
src/data/value.c
src/data/variable.c
src/data/variable.h
src/data/vector.c
src/data/vector.h
src/language/automake.mk
src/language/command.c
src/language/command.def
src/language/command.h
src/language/control/automake.mk
src/language/control/control-stack.c
src/language/control/do-if.c
src/language/control/loop.c
src/language/control/repeat.c
src/language/control/repeat.h [deleted file]
src/language/control/temporary.c
src/language/data-io/automake.mk
src/language/data-io/combine-files.c
src/language/data-io/data-list.c
src/language/data-io/data-parser.c
src/language/data-io/data-parser.h
src/language/data-io/data-reader.c
src/language/data-io/data-reader.h
src/language/data-io/data-writer.c
src/language/data-io/dataset.c [new file with mode: 0644]
src/language/data-io/file-handle.h
src/language/data-io/file-handle.q
src/language/data-io/get-data.c
src/language/data-io/get.c
src/language/data-io/inpt-pgm.c
src/language/data-io/list.q
src/language/data-io/placement-parser.c
src/language/data-io/print-space.c
src/language/data-io/print.c
src/language/data-io/save-translate.c
src/language/data-io/save.c
src/language/data-io/trim.c
src/language/dictionary/apply-dictionary.c
src/language/dictionary/attributes.c
src/language/dictionary/delete-variables.c
src/language/dictionary/formats.c
src/language/dictionary/missing-values.c
src/language/dictionary/modify-variables.c
src/language/dictionary/mrsets.c
src/language/dictionary/numeric.c
src/language/dictionary/rename-variables.c
src/language/dictionary/split-file.c
src/language/dictionary/sys-file-info.c
src/language/dictionary/value-labels.c
src/language/dictionary/variable-display.c
src/language/dictionary/variable-label.c
src/language/dictionary/vector.c
src/language/dictionary/weight.c
src/language/expressions/evaluate.c
src/language/expressions/helpers.c
src/language/expressions/helpers.h
src/language/expressions/operations.def
src/language/expressions/optimize.c
src/language/expressions/parse.c
src/language/expressions/private.h
src/language/lexer/automake.mk
src/language/lexer/command-name.c [new file with mode: 0644]
src/language/lexer/command-name.h [new file with mode: 0644]
src/language/lexer/format-parser.c
src/language/lexer/include-path.c [new file with mode: 0644]
src/language/lexer/include-path.h [new file with mode: 0644]
src/language/lexer/lexer.c
src/language/lexer/lexer.h
src/language/lexer/q2c.c
src/language/lexer/scan.c [new file with mode: 0644]
src/language/lexer/scan.h [new file with mode: 0644]
src/language/lexer/segment.c [new file with mode: 0644]
src/language/lexer/segment.h [new file with mode: 0644]
src/language/lexer/token.c [new file with mode: 0644]
src/language/lexer/token.h [new file with mode: 0644]
src/language/lexer/value-parser.c
src/language/lexer/value-parser.h
src/language/lexer/variable-parser.c
src/language/lexer/variable-parser.h
src/language/prompt.c [deleted file]
src/language/prompt.h [deleted file]
src/language/stats/aggregate.c
src/language/stats/aggregate.h
src/language/stats/automake.mk
src/language/stats/autorecode.c
src/language/stats/binomial.c
src/language/stats/chisquare.c
src/language/stats/chisquare.h
src/language/stats/cochran.c [new file with mode: 0644]
src/language/stats/cochran.h [new file with mode: 0644]
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/flip.c
src/language/stats/frequencies.q
src/language/stats/friedman.c [new file with mode: 0644]
src/language/stats/friedman.h [new file with mode: 0644]
src/language/stats/glm.c
src/language/stats/kruskal-wallis.c
src/language/stats/kruskal-wallis.h
src/language/stats/mann-whitney.c [new file with mode: 0644]
src/language/stats/mann-whitney.h [new file with mode: 0644]
src/language/stats/npar-summary.c
src/language/stats/npar-summary.h
src/language/stats/npar.c
src/language/stats/npar.h
src/language/stats/oneway.c
src/language/stats/quick-cluster.c [new file with mode: 0644]
src/language/stats/rank.q
src/language/stats/regression.q
src/language/stats/reliability.c
src/language/stats/roc.c
src/language/stats/runs.c [new file with mode: 0644]
src/language/stats/runs.h [new file with mode: 0644]
src/language/stats/sign.c
src/language/stats/sign.h
src/language/stats/sort-cases.c
src/language/stats/sort-criteria.c
src/language/stats/t-test.q
src/language/stats/wilcoxon.c
src/language/stats/wilcoxon.h
src/language/syntax-file.c [deleted file]
src/language/syntax-file.h [deleted file]
src/language/syntax-string-source.c [deleted file]
src/language/syntax-string-source.h [deleted file]
src/language/tests/float-format.c
src/language/tests/format-guesser-test.c
src/language/tests/moments-test.c
src/language/tests/paper-size.c
src/language/tests/pool-test.c
src/language/utilities/automake.mk
src/language/utilities/cache.c [new file with mode: 0644]
src/language/utilities/cd.c
src/language/utilities/date.c
src/language/utilities/echo.c
src/language/utilities/host.c
src/language/utilities/include.c
src/language/utilities/permissions.c
src/language/utilities/set.q
src/language/utilities/title.c
src/language/xforms/compute.c
src/language/xforms/count.c
src/language/xforms/fail.c
src/language/xforms/recode.c
src/language/xforms/sample.c
src/language/xforms/select-if.c
src/libpspp/abt.c
src/libpspp/abt.h
src/libpspp/argv-parser.c
src/libpspp/array.c
src/libpspp/automake.mk
src/libpspp/bt.c
src/libpspp/bt.h
src/libpspp/deque.c
src/libpspp/deque.h
src/libpspp/encoding-guesser.c [new file with mode: 0644]
src/libpspp/encoding-guesser.h [new file with mode: 0644]
src/libpspp/ext-array.c
src/libpspp/float-format.c
src/libpspp/float-format.h
src/libpspp/getl.c [deleted file]
src/libpspp/getl.h [deleted file]
src/libpspp/hash-functions.c
src/libpspp/hash-functions.h
src/libpspp/hash.c
src/libpspp/hash.h
src/libpspp/heap.c
src/libpspp/heap.h
src/libpspp/hmap.c
src/libpspp/hmap.h
src/libpspp/hmapx.h
src/libpspp/i18n.c
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 [deleted file]
src/libpspp/legacy-encoding.h [deleted file]
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/model-checker.c
src/libpspp/model-checker.h
src/libpspp/msg-locator.c [deleted file]
src/libpspp/msg-locator.h [deleted file]
src/libpspp/pool.c
src/libpspp/prompt.c [new file with mode: 0644]
src/libpspp/prompt.h [new file with mode: 0644]
src/libpspp/range-map.c
src/libpspp/range-map.h
src/libpspp/range-set.c
src/libpspp/range-set.h
src/libpspp/sparse-array.c
src/libpspp/sparse-xarray.c
src/libpspp/str.c
src/libpspp/str.h
src/libpspp/string-map.c
src/libpspp/string-map.h
src/libpspp/string-set.c
src/libpspp/string-set.h
src/libpspp/stringi-map.h
src/libpspp/stringi-set.h
src/libpspp/taint.c
src/libpspp/taint.h
src/libpspp/temp-file.c
src/libpspp/tower.c
src/libpspp/tower.h
src/libpspp/u8-istream.c [new file with mode: 0644]
src/libpspp/u8-istream.h [new file with mode: 0644]
src/math/box-whisker.c
src/math/box-whisker.h
src/math/categoricals.c
src/math/categoricals.h
src/math/correlation.c
src/math/covariance.c
src/math/covariance.h
src/math/extrema.c
src/math/extrema.h
src/math/group.c
src/math/group.h
src/math/histogram.c
src/math/histogram.h
src/math/interaction.c
src/math/interaction.h
src/math/levene.c
src/math/linreg.c
src/math/linreg.h
src/math/merge.c
src/math/moments.c
src/math/moments.h
src/math/np.c
src/math/order-stats.c
src/math/order-stats.h
src/math/percentiles.c
src/math/sort.c
src/math/trimmed-mean.c
src/math/ts/innovations.c
src/math/ts/innovations.h
src/math/tukey-hinges.c
src/output/ascii.c
src/output/ascii.h [new file with mode: 0644]
src/output/automake.mk
src/output/cairo-chart.c
src/output/cairo-chart.h
src/output/cairo.c
src/output/chart-item-provider.h
src/output/chart-item.c
src/output/chart-item.h
src/output/charts/boxplot-cairo.c
src/output/charts/boxplot.c
src/output/charts/boxplot.h
src/output/charts/np-plot-cairo.c
src/output/charts/np-plot.c
src/output/charts/np-plot.h
src/output/charts/piechart-cairo.c
src/output/charts/piechart.c
src/output/charts/piechart.h
src/output/charts/plot-hist-cairo.c
src/output/charts/plot-hist.c
src/output/charts/plot-hist.h
src/output/charts/roc-chart-cairo.c
src/output/charts/roc-chart.c
src/output/charts/roc-chart.h
src/output/charts/scree-cairo.c
src/output/charts/scree.c
src/output/charts/scree.h
src/output/csv.c
src/output/driver.c
src/output/html.c
src/output/measure.c
src/output/message-item.h
src/output/mk-class-boilerplate
src/output/odt.c
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/text-item.c
src/output/text-item.h
src/ui/gui/aggregate-dialog.c
src/ui/gui/aggregate-dialog.h
src/ui/gui/aggregate.ui
src/ui/gui/automake.mk
src/ui/gui/binomial-dialog.c
src/ui/gui/binomial-dialog.h
src/ui/gui/chi-square-dialog.c
src/ui/gui/chi-square-dialog.h
src/ui/gui/comments-dialog.c
src/ui/gui/compute-dialog.c
src/ui/gui/compute-dialog.h
src/ui/gui/correlation-dialog.c
src/ui/gui/correlation-dialog.h
src/ui/gui/crosstabs-dialog.c
src/ui/gui/crosstabs-dialog.h
src/ui/gui/customentry.c
src/ui/gui/data-editor.ui
src/ui/gui/descriptives-dialog.c
src/ui/gui/descriptives-dialog.h
src/ui/gui/entry-dialog.c [new file with mode: 0644]
src/ui/gui/entry-dialog.h [new file with mode: 0644]
src/ui/gui/entry-dialog.ui [new file with mode: 0644]
src/ui/gui/examine-dialog.c
src/ui/gui/examine-dialog.h
src/ui/gui/executor.c
src/ui/gui/executor.h
src/ui/gui/factor-dialog.c
src/ui/gui/factor-dialog.h
src/ui/gui/factor.ui
src/ui/gui/find-dialog.c
src/ui/gui/find-dialog.h
src/ui/gui/frequencies-dialog.c
src/ui/gui/frequencies-dialog.h
src/ui/gui/goto-case-dialog.h
src/ui/gui/helper.c
src/ui/gui/helper.h
src/ui/gui/include/gtk/gtk.in.h [new file with mode: 0644]
src/ui/gui/k-related-dialog.c [new file with mode: 0644]
src/ui/gui/k-related-dialog.h [new file with mode: 0644]
src/ui/gui/k-related.ui [new file with mode: 0644]
src/ui/gui/main.c
src/ui/gui/missing-val-dialog.c
src/ui/gui/missing-val-dialog.h
src/ui/gui/oneway-anova-dialog.c
src/ui/gui/output-viewer.ui
src/ui/gui/pspp.desktop
src/ui/gui/psppire-acr.h
src/ui/gui/psppire-buttonbox.c
src/ui/gui/psppire-buttonbox.h
src/ui/gui/psppire-conf.h
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-editor.h
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-data-window.c
src/ui/gui/psppire-data-window.h
src/ui/gui/psppire-dialog.c
src/ui/gui/psppire-dialog.h
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dictview.c
src/ui/gui/psppire-dictview.h
src/ui/gui/psppire-encoding-selector.c [new file with mode: 0644]
src/ui/gui/psppire-encoding-selector.h [new file with mode: 0644]
src/ui/gui/psppire-hbuttonbox.c
src/ui/gui/psppire-keypad.c
src/ui/gui/psppire-keypad.h
src/ui/gui/psppire-output-window.c
src/ui/gui/psppire-output-window.h
src/ui/gui/psppire-select-dest.c
src/ui/gui/psppire-selector.c
src/ui/gui/psppire-selector.h
src/ui/gui/psppire-syntax-window.c
src/ui/gui/psppire-syntax-window.h
src/ui/gui/psppire-var-sheet.c
src/ui/gui/psppire-var-store.c
src/ui/gui/psppire-var-view.c
src/ui/gui/psppire-var-view.h
src/ui/gui/psppire-vbuttonbox.c
src/ui/gui/psppire-window.c
src/ui/gui/psppire-window.h
src/ui/gui/psppire.c
src/ui/gui/psppire.h
src/ui/gui/rank-dialog.c
src/ui/gui/recode-dialog.c
src/ui/gui/regression-dialog.c
src/ui/gui/reliability-dialog.c
src/ui/gui/roc-dialog.c
src/ui/gui/select-cases-dialog.c
src/ui/gui/sort-cases-dialog.c
src/ui/gui/split-file-dialog.c
src/ui/gui/syntax-editor-source.c [deleted file]
src/ui/gui/syntax-editor-source.h [deleted file]
src/ui/gui/syntax-editor.ui
src/ui/gui/t-test-independent-samples-dialog.c
src/ui/gui/t-test-one-sample.c
src/ui/gui/t-test-paired-samples.c
src/ui/gui/text-data-import-dialog.c
src/ui/gui/text-data-import-dialog.h
src/ui/gui/transpose-dialog.c
src/ui/gui/val-labs-dialog.c
src/ui/gui/val-labs-dialog.h
src/ui/gui/var-display.c
src/ui/gui/var-display.h
src/ui/gui/var-type-dialog.c
src/ui/gui/var-type-dialog.h
src/ui/gui/variable-info-dialog.c
src/ui/gui/weight-cases-dialog.c
src/ui/gui/widget-io.c
src/ui/source-init-opts.c
src/ui/source-init-opts.h
src/ui/syntax-gen.c
src/ui/syntax-gen.h
src/ui/terminal/automake.mk
src/ui/terminal/main.c
src/ui/terminal/msg-ui.c [deleted file]
src/ui/terminal/msg-ui.h [deleted file]
src/ui/terminal/read-line.c [deleted file]
src/ui/terminal/read-line.h [deleted file]
src/ui/terminal/terminal-opts.c
src/ui/terminal/terminal-opts.h
src/ui/terminal/terminal-reader.c [new file with mode: 0644]
src/ui/terminal/terminal-reader.h [new file with mode: 0644]
tests/atlocal.in
tests/automake.mk
tests/data/data-in.at
tests/data/data-out.at
tests/data/sack.c [new file with mode: 0644]
tests/data/sys-file-reader.at [new file with mode: 0644]
tests/data/sys-file.at
tests/dissect-sysfile.c [deleted file]
tests/language/command.at
tests/language/control/do-repeat.at
tests/language/data-io/data-list.at
tests/language/data-io/data-reader.at
tests/language/data-io/dataset.at [new file with mode: 0644]
tests/language/data-io/get-data-txt.at
tests/language/data-io/get.at
tests/language/data-io/inpt-pgm.at
tests/language/data-io/list.at
tests/language/data-io/match-files.at
tests/language/data-io/print-space.at [new file with mode: 0644]
tests/language/data-io/print.at
tests/language/dictionary/formats.at [new file with mode: 0644]
tests/language/dictionary/missing-values.at
tests/language/dictionary/mrsets.at
tests/language/dictionary/sys-file-info.at
tests/language/dictionary/value-labels.at
tests/language/dictionary/weight.at
tests/language/expressions/evaluate.at
tests/language/expressions/parse.at
tests/language/lexer/command-name-test.c [new file with mode: 0644]
tests/language/lexer/command-name.at [new file with mode: 0644]
tests/language/lexer/lexer.at
tests/language/lexer/q2c.at
tests/language/lexer/scan-test.c [new file with mode: 0644]
tests/language/lexer/scan.at [new file with mode: 0644]
tests/language/lexer/segment-test.c [new file with mode: 0644]
tests/language/lexer/segment.at [new file with mode: 0644]
tests/language/stats/aggregate.at
tests/language/stats/autorecode.at
tests/language/stats/crosstabs.at
tests/language/stats/frequencies.at
tests/language/stats/npar.at
tests/language/stats/oneway.at
tests/language/stats/quick-cluster.at [new file with mode: 0644]
tests/language/stats/rank.at
tests/language/stats/regression.at
tests/language/stats/sort-cases.at
tests/language/stats/t-test.at
tests/language/utilities/cache.at [new file with mode: 0644]
tests/language/utilities/cd.at [new file with mode: 0644]
tests/language/utilities/insert.at
tests/language/utilities/title.at
tests/libpspp/encoding-guesser-test.c [new file with mode: 0644]
tests/libpspp/encoding-guesser.at [new file with mode: 0644]
tests/libpspp/float-format.at
tests/libpspp/i18n-test.c
tests/libpspp/i18n.at
tests/libpspp/sparse-xarray-test.at
tests/libpspp/u8-istream-test.c [new file with mode: 0644]
tests/libpspp/u8-istream.at [new file with mode: 0644]
tests/output/ascii.at [new file with mode: 0644]
tests/output/render-test.c
tests/output/render.at
tests/perl-module.at
tests/stats/moments.sh [deleted file]
tests/stats/percentiles-enhanced.sh [deleted file]
tests/valgrind-wrapper.in [new file with mode: 0755]
utilities/automake.mk [new file with mode: 0644]
utilities/pspp-dump-sav.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 1003445bdb38ace03711769d8756a298a6cb3008..022a70d0085fafa737cb4d85c595082b5203a221 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,6 +14,8 @@ revisions to other modules.
 including lib/gslextras and the linear regression features. Jason 
 is also an important contributor to GSL, which is used by PSPP. 
 
+* Mehmet Hakan Satman wrote the QUICK CLUSTER command.
+
 * Translators:
 
   - Dutch: Harry Thijssen.
@@ -25,6 +27,8 @@ is also an important contributor to GSL, which is used by PSPP.
 
   - Brazilian Portuguese: Michel Almada de Castro Boaventura.
 
+  - Lithuanian: Mindaugas Baranauskas
+
 We also thank past contributors:
 
 * John Williams wrote an initial draft of the T-TEST procedure.
diff --git a/INSTALL b/INSTALL
index 23bbf8a4b1ead5afaf8aab88c36afbb68f835808..3e9456ef3507893e69018fda27b82b5851999f3d 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -89,8 +89,14 @@ The following packages are optional.
       later.  Installing Texinfo will allow you to build PSPP
       documentation in PostScript or PDF format.
 
-    * libpq, from Postgresql (http://postgresql.org). This enables PSPP 
-      to read Postgresql databases.
+    * libpq, from Postgresql (http://postgresql.org).  This enables PSPP 
+      to read Postgresql databases.  The tests for the Postgresql
+      interface, but not the Postgresql interface itself, requires the
+      Postgresql server to be installed.
+
+    * The Text::Diff module for Perl (http://cpan.org).  This enables
+      PSPP to test the Perl module more thoroughly.  It is not needed
+      to build or use the Perl module.
 
 Basic Installation
 ==================
@@ -163,6 +169,10 @@ release.
      root permissions.  If you cannot get root permissions, see
      "Installation Names", below.
 
+     Please note:  The `make install' target does NOT install the perl
+     module (see below).  To install the perl module, you must change to
+     the `perl-module' directory and manually run `make install' there.
+
   5. You can remove the program binaries and object files from the
      source code directory by typing `make clean'.  To also remove the
      files that `configure' created (so you can compile the package for
index 6cffa402776cf5f4fb5f8f5064d64edada8f74ba..bed99f40c9a44a023f0423083e2c3109f60123e2 100644 (file)
@@ -45,6 +45,7 @@ INSTALL_DATA_HOOKS =
 UNINSTALL_DATA_HOOKS =
 PHONY =
 SUFFIXES = .q
+LDADD = gl/libgl.la
 
 generate-changelog:
        if test -d $(top_srcdir)/.git; then                     \
@@ -62,6 +63,7 @@ include $(top_srcdir)/lib/automake.mk
 include $(top_srcdir)/doc/automake.mk
 include $(top_srcdir)/examples/automake.mk
 include $(top_srcdir)/src/automake.mk
+include $(top_srcdir)/utilities/automake.mk
 
 include $(top_srcdir)/tests/automake.mk
 
diff --git a/NEWS b/NEWS
index 3c09bf8bad9865d398835bc33207b1f3fb16f4b8..57d2d7b59cae7d1f01c580e8d315e49090cca9f5 100644 (file)
--- a/NEWS
+++ b/NEWS
 PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2010-10-16 13:05:30 blp>
-Copyright (C) 1996-9, 2000, 2008, 2009, 2010 Free Software Foundation, Inc.
+Copyright (C) 1996-9, 2000, 2008, 2009, 2010, 2011 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.3 to 0.7.6:
+Changes from 0.6.2 to 0.7.8:
 
- * NPAR TESTS now supports the /KRUSKAL-WALLIS subcommand.
+ * New commands:
 
- * AUTORECODE now supports the /GROUP subcommand.
+   - ADD FILES
+   - CORRELATIONS
+   - DATAFILE ATTRIBUTES
+   - DATASET ACTIVATE
+   - DATASET CLOSE
+   - DATASET COPY
+   - DATASET DECLARE
+   - DATASET DISPLAY
+   - DATASET NAME
+   - MATCH FILES
+   - MRSETS
+   - PRESERVE and RESTORE
+   - QUICK CLUSTER
+   - RELIABILITY
+   - ROC
+   - SAVE TRANSLATE to CSV and tab-delimited files
+   - UPDATE
+   - VARIABLE ATTRIBUTES
 
- * The MRSETS command is now implemented.
+ * Changes to existing commands:
 
- * SAVE TRANSLATE is now implemented, with initial support for saving
-   data in comma-separated value and tab-delimited formats.
+   - AUTORECODE has a new GROUP subcommand.
 
* The PRESERVE and RESTORE commands are now implemented.
  - CROSSTABS has been re-implemented to fix numerous bugs.
 
- * The HOST command has been updated to use more modern syntax.
+   - DO REPEAT command has been reimplemented.  Now, when DO REPEAT
+     contains an INCLUDE or INSERT command, substitutions are not
+     applied to the included file.
 
-Changes from 0.7.2 to 0.7.3:
+   - HOST has been updated to use more modern syntax.
 
- * 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.
+   - INCLUDE and INSERT have a new ENCODING subcommand.
 
- * 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.
+   - MISSING VALUES can now assign missing values to long string
+     variables.
 
-Changes from 0.7.1 to 0.7.2:
+   - NPAR TESTS has new KRUSKAL-WALLIS, SIGN, WILCOXON, and RUNS
+     subcommands.
 
- * Updated Perl module interface.
+   - SET and SHOW no longer have ENDCMD, NULLINE, PROMPT, CPROMPT, and
+     DPROMPT subcommands.  The defaults are now fixed values.
 
- * Value labels for long string variables are now supported.
+   - VALUE LABELS can now assign value labels to long string
+     variables.
 
- * Missing values for long string variables are now supported.
+ * Other language changes:
 
-Changes from 0.7.0 to 0.7.1:
+   - The new DATASET commands replace the "scratch file" PSPP
+     extension, which is no longer supported.
 
- *  Added a perl module to facilitate reading and writing of pspp system 
-    files from perl programs.
+   - Strings may now include arbitrary Unicode code points specified
+     in hexadecimal, using the syntax U'hhhh'.  For example, Unicode
+     code point U+1D11E, the musical G clef character, may be
+     expressed as U'1D11E'.
 
-Changes from 0.6.2-pre6 to 0.7.0:
+     See the "Tokens" section in the PSPP manual for more information.
 
-  * Custom variable and data file attributes are now supported.
-    Commands VARIABLE ATTRIBUTE and DATAFILE ATTRIBUTE have been added
-    for setting and clear attributes.  Support for attributes has also
-    been added to commands that read and write system files, such as
-    SAVE and GET, as well as to the DISPLAY command.
+   - In previous versions of PSPP, in a string expressed in
+     hexadecimal with X'hh' syntax, the hexadecimal digits expressed
+     bytes in the locale encoding.  In this version of PSPP, X'hh'
+     syntax always expresses bytes in UTF-8 encoding.
 
-  * Numererous improvements to the Graphical User Interface have
-    made.  Notable improvements include:
+     See the "Tokens" section in the PSPP manual for more information.
 
-    - Non-Ascii characters in strings, labels and variable names are
-      now supported.
+ * PSPPIRE graphical user interface improvements:
 
-    - A "Split Window" function is available, which makes it easier to
-      see different parts of a large data file.
+   - Added support for non-ASCII characters in strings, labels and
+     variable names.
 
-    - Data files can now be opened by specifing their name as the first
-      argument.  This means that on a properly configured desktop, double
-      clicking on an icon will open the file.
-    
+   - A "Split Window" function is available, which makes it easier to
+     see different parts of a large data file.
 
-  * New statistical procedures:
-    - CORRELATIONS
-    - ROC
-    - RELIABILITY
+   - Data files can now be opened by specifing their name as the first
+     argument.  This means that on a properly configured desktop, double
+     clicking on an icon will open the file.
 
-    NPAR TESTS now supports the WILCOXON and SIGN subcommands.
+ * Output changes:
 
-    The CROSSTABS command has been completely re-implemented to fix numerous bugs.
+   - 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.
 
-  * Three new commands to combine data files have been added: MATCH FILES,
-   UPDATE and  ADD FILES.
+   - 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.
 
-  * A tutorial chapter has been added to the user manual.
+   - The plain text output driver now properly supports multibyte UTF-8
+     characters, including double-width characters and combining
+     accents.
 
-Changes from 0.6.1 to 0.6.2
+ * The "pspp" program has a new option --batch (or -b) that selects
+   "batch" syntax mode.  In previous versions of PSPP this syntax mode
+   was the default.  Now a new "auto" syntax mode is the default.  In
+   "auto" mode, PSPP interprets most syntax files correctly regardless
+   of their intended syntax mode.
+
+   See the "Syntax Variants" section in the PSPP manual for more
+   information.
+
+ * The "pspp" program has a new option --syntax-encoding that
+   specifies the encoding for syntax files listed on the command line,
+   as well as the default encoding for syntax files included with
+   INCLUDE or INSERT.  The default is to accept the system locale
+   encoding, UTF-8, UTF-16, or UTF-32, automatically detecting which
+   one the system file uses.
+
+   See the documentation for the INSERT command in the PSPP manual for
+   more information.
+
+ * A new Perl module allows Perl programs to read and write PSPP
+   system files.
+
+ * A tutorial chapter has been added to the user manual.
+\f
+Changes from 0.6.1 to 0.6.2:
 
   * New translations:
 
diff --git a/README b/README
index d1c78db2c20bca092cbde646171aec4fc78068b6..35e44ae7421f006b5b64c91f49c537f04bf46e77 100644 (file)
--- a/README
+++ b/README
@@ -88,3 +88,6 @@ following:
           statistical procedures is evolving quickly enough that a
           plug-in model does not make sense.  Over the long term, it
           may make sense to introduce plug-ins.
+
+For any copyright year range specified as YYYY-ZZZZ in this package note
+that the range specifies every single year in that closed interval.
index 70a29ecd525fcd3a9a9e28d11ea9ed55985b6341..b8cc4207cec19dc69f177fb44b197207d2c2ec2e 100644 (file)
@@ -34,15 +34,14 @@ This version of PSPP should work with the Gnulib commit shown below.
 Gnulib does not maintain a stable API or ABI, so it is possible that
 PSPP will not work with older or newer versions of Gnulib.
 
-
-  commit 52a32bbd66601d12627e104cd82d9b9094d942c3
+  commit a38e4bbf37c4a77ea65f548dfcf590cf23e73d7e
   Author: Bruno Haible <bruno@clisp.org>
-  Date:   Fri Sep 24 14:36:26 2010 +0200
+  Date:   Sun Feb 13 18:04:55 2011 +0100
 
-      unistr/u8-strchr: Fix a test failure on i586 glibc systems.
-    
-      * tests/unistr/test-strchr.h (test_strchr): Disable an invalid check.
+      mbsinit: Don't crash for a NULL argument.
 
+      * lib/mbsinit.c (mbsinit): When the argument is NULL, return 1.
+      * tests/test-mbsinit.c (mbsinit): Check this behaviour.
 
 To clone Gnulib into a directory named "gnulib" using Git, and then
 check out this particular commit, run these commands:
diff --git a/Smake b/Smake
index 3ca1187520fc4baebe45af5b51a37d1141a32618..4cbe44ece9a3060f9549b2fe7e345591b5f48623 100644 (file)
--- a/Smake
+++ b/Smake
@@ -7,6 +7,8 @@ GNULIB_TOOL = $(GNULIB)/gnulib-tool
 GNULIB_MODULES = \
        assert \
        byteswap \
+       c-strcase \
+       c-strcasestr \
        c-ctype \
        c-strtod \
        clean-temp \
@@ -15,7 +17,9 @@ GNULIB_MODULES = \
        count-one-bits \
        crc \
        crypto/md4 \
+       crypto/md5 \
        dirname \
+       dtoastr \
        environ \
        fatal-signal \
        fcntl \
@@ -27,10 +31,11 @@ GNULIB_MODULES = \
         ftello \
        fwriteerror \
        getline \
-       gettext-h \
+       gettext \
        gettimeofday \
         getopt-gnu \
        gitlog-to-changelog \
+       include_next \
        isfinite \
        isinf \
        isnan \
@@ -41,12 +46,15 @@ GNULIB_MODULES = \
        memcasecmp \
        memchr \
        mempcpy \
+       memrchr \
        minmax \
        mkdtemp \
        mkstemp \
        printf-posix \
        printf-safe \
        progname \
+       rawmemchr \
+       read-file \
        regex \
        relocatable-prog \
        rename \
@@ -68,11 +76,23 @@ GNULIB_MODULES = \
        sys_stat \
        tempname \
        trunc \
-       unilbrk/ulc-width-linebreaks \
+       unictype/ctype-print \
+       unictype/property-id-continue \
+       unictype/property-id-start \
+       unigbrk/uc-is-grapheme-break \
+       unilbrk/u8-possible-linebreaks \
        unistd \
+       unistr/u8-check \
        unistr/u8-cpy \
+       unistr/u8-mblen \
+       unistr/u8-mbtouc \
+       unistr/u8-mbtoucr \
        unistr/u8-strlen \
+       unistr/u8-strmbtouc \
        unistr/u8-strncat \
+       unistr/u8-uctomb \
+       uniwidth/u8-strwidth \
+       unitypes \
        unlocked-io \
        vasprintf-posix \
        version-etc \
@@ -94,16 +114,20 @@ all:
        test -e ChangeLog || touch ChangeLog
        test -d m4 || mkdir m4
        touch m4/Makefile.am
-       $(GNULIB_TOOL) --import --no-changelog --m4-base=gl/m4 \
-               --source-base=gl --lib=libgl --tests-base=tests \
-               --doc-base=gl/doc --aux-dir=build-aux --import \
-               --libtool $(GNULIB_MODULES)
+       $(MAKE) -f Smake gnulib
        libtoolize --force --automake
        aclocal -I m4 -I gl/m4
        autoconf
        autoheader
        automake --add-missing --copy --no-force
 
+gnulib:
+       $(GNULIB_TOOL) --add-import --no-changelog --m4-base=gl/m4 \
+               --source-base=gl --lib=libgl --tests-base=tests \
+               --doc-base=gl/doc --aux-dir=build-aux --import \
+               --libtool $(GNULIB_MODULES)
+
+
 gettextize:
        test -d m4 || mkdir m4
        touch m4/Makefile.am
index abf7afadedb7f247295e88545270abbaad9dec53..766d5a43859d43a26aa9c7771dcf959379861a98 100644 (file)
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
 
 dnl Initialize.
 AC_PREREQ(2.63)
-AC_INIT([GNU PSPP], [0.7.6], [bug-gnu-pspp@gnu.org], [pspp])
+AC_INIT([GNU PSPP], [0.7.8], [bug-gnu-pspp@gnu.org], [pspp])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_TESTDIR([tests])
@@ -32,15 +32,14 @@ AM_CONDITIONAL(cc_is_gcc, test x"$GCC" = x"yes" )
 PSPP_CC_FOR_BUILD
 PSPP_PERL
 
-dnl Internationalization macros.
-AC_PROVIDE([AM_PO_SUBDIRS])    # PSPP provides its own po/ support.
+dnl Disable automatic po/ support, because PSPP provides its own po/ support.
+AC_PROVIDE([AM_PO_SUBDIRS])
 AM_GNU_GETTEXT([external], [need-ngettext])
-AM_GNU_GETTEXT_VERSION([0.17])
+LIBS="$LIBINTL $LIBS"
 
 dnl Checks for libraries.
 AC_SYS_LARGEFILE
 AC_SEARCH_LIBS([sin], [m])
-AC_SEARCH_LIBS([dcgettext], [intl])
 PSPP_LC_PAPER
 
 
@@ -84,6 +83,8 @@ if test "$with_cairo" != no && test "$with_gui" != "no"; then
   if test "x$GLIB_GENMARSHAL" = x; then
     PSPP_REQUIRED_PREREQ([glib-genmarshal (or use --without-gui)])
   fi
+
+  gl_NEXT_HEADERS([gtk/gtk.h])
 fi
 
 dnl Checks needed for psql reader
@@ -291,12 +292,24 @@ PSPP_READLINE
 dnl Checks for header files.
 AC_CHECK_HEADERS([sys/wait.h fpu_control.h ieeefp.h fenv.h pwd.h])
 
+dnl Some systems dont have SIGWINCH
+AC_CHECK_DECLS([SIGWINCH], [], [],
+          [#include <signal.h>
+          /* NetBSD declares sys_siglist in unistd.h.  */
+          #ifdef HAVE_UNISTD_H
+          # include <unistd.h>
+          #endif
+          ])
+
+
 # For gnulib.
 gl_INIT
 
 AC_C_INLINE
 
-AC_CHECK_SIZEOF(double)
+AC_CHECK_SIZEOF([size_t])
+SIZEOF_SIZE_T=$ac_cv_sizeof_size_t
+AC_SUBST([SIZEOF_SIZE_T])
 
 AC_C_BIGENDIAN
 
@@ -313,9 +326,11 @@ if test x"$enable_debug" = x"yes"  ; then
 fi
 
 # iconv is required
+AM_ICONV
 if test "$am_cv_func_iconv" != "yes"; then
    PSPP_REQUIRED_PREREQ([iconv (see http://www.gnu.org/software/libiconv/)])
 fi
+LIBS="$LIBICONV $LIBS"
 
 dnl Required by the gnulib 'relocatable-prog' module.
 dnl See doc/relocatable-maint.texi in the gnulib tree for details.
index c375556614708dbe4d085e3066efc56809a0007e..841188dcb114a7de81bdfa4749b8656397825b60 100644 (file)
@@ -6,5 +6,6 @@ pspp.info*
 pspp.xml
 stamp-1
 stamp-vti
+tut.texi
 version-dev.texi
 version.texi
index a77c3b07b72c794e689a1c8de1adc097c1400efe..a4f683d56910601605a7c30d9ac173e3738582ba 100644 (file)
@@ -2,8 +2,8 @@
 @chapter Combining Data Files
 
 This chapter describes commands that allow data from system files,
-portable file, scratch files, and the active file to be combined to
-form a new active file.  These commands can combine data files in the
+portable files, and open datasets to be combined to
+form a new active dataset.  These commands can combine data files in the
 following ways:
 
 @itemize
@@ -59,17 +59,17 @@ This section describes the syntactical features in common among the
 following sections describe details specific to each command.
 
 Each of these commands reads two or more input files and combines
-them.  The command's output becomes the new active file.  The input
+them.  The command's output becomes the new active dataset.  The input
 files are not changed on disk.
 
 The syntax of each command begins with a specification of the files to
-be read as input.  For each input file, specify FILE with a system,
-portable, or scratch file's name as a string or a file handle
-(@pxref{File Handles}), or specify an asterisk (@samp{*}) to use the
-active file as input.  Use of portable or scratch files on FILE is a
+be read as input.  For each input file, specify FILE with a system
+file or portable file's name as a string, a dataset (@pxref{Datasets})
+or file handle name, (@pxref{File Handles}), or an asterisk (@samp{*})
+to use the active dataset as input.  Use of portable files on FILE is a
 PSPP extension.
 
-At least two FILE subcommands must be specified.  If the active file
+At least two FILE subcommands must be specified.  If the active dataset
 is used as an input source, then @cmd{TEMPORARY} must not be in
 effect.
 
@@ -95,12 +95,12 @@ When SORT is specified, PSPP sorts the input file's data on the BY
 variables before it applies it to the command.  When SORT is used, BY
 is required.  SORT is a PSPP extension.
 
-PSPP merges the dictionaries of all of the input files to form the new
-active file dictionary, like so:
+PSPP merges the dictionaries of all of the input files to form the
+dictionary of the new active dataset, like so:
 
 @itemize @bullet
 @item
-The new active file's variables are the union of all the input files'
+The variables in the new active dataset are the union of all the input files'
 variables, matched based on their name.  When a single input file
 contains a variable with a given name, the output file will contain
 exactly that variable.  When more than one input file contains a
@@ -115,18 +115,18 @@ specified input file that has a variable label for that variable, and
 similarly for value labels and missing values.
 
 @item
-The new active file's file label (@pxref{FILE LABEL}) is that of the
+The file label of the new active dataset (@pxref{FILE LABEL}) is that of the
 first specified FILE that has a file label.
 
 @item
-The new active file's documents (@pxref{DOCUMENT}) are the
+The documents in the new active dataset (@pxref{DOCUMENT}) are the
 concatenation of all the input files' documents, in the order in which
 the FILE subcommands are specified.
 
 @item
 If all of the input files are weighted on the same variable, then the
-new active file is weighted on that variable.  Otherwise, the new
-active file is not weighted.
+new active dataset is weighted on that variable.  Otherwise, the new
+active dataset is not weighted.
 @end itemize
 
 The remaining subcommands apply to the output file as a whole, rather
@@ -150,13 +150,13 @@ to specify variables to include in the output; all variables not
 listed are dropped.  DROP and KEEP are executed in left-to-right order
 and may be repeated any number of times.  DROP and KEEP do not affect
 variables created by the IN, FIRST, and LAST subcommands, which are
-always included in the new active file, but they can be used to drop
+always included in the new active dataset, but they can be used to drop
 BY variables.
 
 The FIRST and LAST subcommands are optional.  They may only be
 specified on @cmd{MATCH FILES} and @cmd{ADD FILES}, and only when BY
 is used.  FIRST and LIST each adds a numeric variable to the new
-active file, with the name given as the subcommand's argument and F1.0
+active dataset, with the name given as the subcommand's argument and F1.0
 print and write formats.  The value of the FIRST variable is 1 in the
 first output case with a given set of values for the BY variables, and
 0 in other cases.  Similarly, the LAST variable is 1 in the last case
@@ -190,7 +190,7 @@ Once per command:
 @end display
 
 @cmd{ADD FILES} adds cases from multiple input files.  The output,
-which replaces the active file, consists all of the cases in all of
+which replaces the active dataset, consists all of the cases in all of
 the input files.
 
 ADD FILES shares the bulk of its syntax with other PSPP commands for
index fc521caee6beb8411803b4196fc850ec90fc04db..cfb99eb7927d8b2f7a7940e32c81d9f2a4ef4e4b 100644 (file)
@@ -26,13 +26,14 @@ actually be read until a procedure is executed.
 * BEGIN DATA::                  Embed data within a syntax file.
 * CLOSE FILE HANDLE::           Close a file handle.
 * DATAFILE ATTRIBUTE::          Set custom attributes on data files.
+* DATASET::                     Manage multiple datasets.
 * DATA LIST::                   Fundamental data reading command.
 * END CASE::                    Output the current case.
 * END FILE::                    Terminate the current input program.
 * FILE HANDLE::                 Support for special file formats.
 * INPUT PROGRAM::               Support for complex input programs.
-* LIST::                        List cases in the active file.
-* NEW FILE::                    Clear the active file and dictionary.
+* LIST::                        List cases in the active dataset.
+* NEW FILE::                    Clear the active dataset.
 * PRINT::                       Display values in print formats.
 * PRINT EJECT::                 Eject the current page then print.
 * PRINT SPACE::                 Print blank lines.
@@ -78,12 +79,6 @@ given file.  The only specification is the name of the handle to close.
 Afterward
 @cmd{FILE HANDLE}.
 
-If the file handle name refers to a scratch file, then the storage
-associated with the scratch file in memory or on disk will be freed.
-If the scratch file is in use, e.g.@: it has been specified on a
-@cmd{GET} command whose execution has not completed, then freeing is
-delayed until it is no longer in use.
-
 The file named INLINE, which represents data entered between @cmd{BEGIN
 DATA} and @cmd{END DATA}, cannot be closed.  Attempts to close it with
 @cmd{CLOSE FILE HANDLE} have no effect.
@@ -103,7 +98,7 @@ DATAFILE ATTRIBUTE
 @end display
 
 @cmd{DATAFILE ATTRIBUTE} adds, modifies, or removes user-defined
-attributes associated with the active file.  Custom data file
+attributes associated with the active dataset.  Custom data file
 attributes are not interpreted by PSPP, but they are saved as part of
 system files and may be used by other software that reads them.
 
@@ -130,12 +125,91 @@ elements numbered higher than the deleted element are shifted down,
 filling the vacated position.
 
 To associate custom attributes with particular variables, instead of
-with the entire active file, use @cmd{VARIABLE ATTRIBUTE} (@pxref{VARIABLE ATTRIBUTE}) instead.
+with the entire active dataset, use @cmd{VARIABLE ATTRIBUTE}
+(@pxref{VARIABLE ATTRIBUTE}) instead.
 
 @cmd{DATAFILE ATTRIBUTE} takes effect immediately.  It is not affected
 by conditional and looping structures such as @cmd{DO IF} or
 @cmd{LOOP}.
 
+@node DATASET
+@section DATASET commands
+@vindex DATASET
+
+@display
+DATASET NAME name [WINDOW=@{ASIS,FRONT@}].
+DATASET ACTIVATE name [WINDOW=@{ASIS,FRONT@}].
+DATASET COPY name [WINDOW=@{MINIMIZED,HIDDEN,FRONT@}].
+DATASET DECLARE name [WINDOW=@{MINIMIZED,HIDDEN,FRONT@}].
+DATASET CLOSE @{name,*,ALL@}.
+DATASET DISPLAY.
+@end display
+
+The @cmd{DATASET} commands simplify use of multiple datasets within a
+PSPP session.  They allow datasets to be created and destroyed.  At
+any given time, most PSPP commands work with a single dataset, called
+the active dataset.
+
+@vindex DATASET NAME
+The DATASET NAME command gives the active dataset the specified name, or
+if it already had a name, it renames it.  If another dataset already
+had the given name, that dataset is deleted.
+
+@vindex DATASET ACTIVATE
+The DATASET ACTIVATE command selects the named dataset, which must
+already exist, as the active dataset.  Before switching the active
+dataset, any pending transformations are executed, as if @cmd{EXECUTE}
+had been specified.  If the active dataset is unnamed before
+switching, then it is deleted and becomes unavailable after switching.
+
+@vindex DATASET COPY
+The DATASET COPY command creates a new dataset with the specified
+name, whose contents are a copy of the active dataset.  Any pending
+transformations are executed, as if @cmd{EXECUTE} had been specified,
+before making the copy.  If a dataset with the given name already
+exists, it is replaced.  If the name is the name of the active
+dataset, then the active dataset becomes unnamed.
+
+@vindex DATASET DECLARE
+The DATASET DECLARE command creates a new dataset that is initially
+``empty,'' that is, it has no dictionary or data.  If a dataset with
+the given name already exists, this has no effect.  The new dataset
+can be used with commands that support output to a dataset,
+e.g. AGGREGATE (@pxref{AGGREGATE}).
+
+@vindex DATASET CLOSE
+The DATASET CLOSE command deletes a dataset.  If the active dataset is
+specified by name, or if @samp{*} is specified, then the active
+dataset becomes unnamed.  If a different dataset is specified by name,
+then it is deleted and becomes unavailable.  Specifying ALL deletes
+all datasets except for the active dataset, which becomes unnamed.
+
+@vindex DATASET DISPLAY
+The DATASET DISPLAY command lists all the currently defined datasets.
+
+Many DATASET commands accept an optional WINDOW subcommand.  In the
+PSPPIRE GUI, the value given for this subcommand influences how the
+dataset's window is displayed.  Outside the GUI, the WINDOW subcommand
+has no effect.  The valid values are:
+
+@table @asis
+@item ASIS
+Do not change how the window is displayed.  This is the default for
+DATASET NAME and DATASET ACTIVATE.
+
+@item FRONT
+Raise the dataset's window to the top.  Make it the default dataset
+for running syntax.
+
+@item MINIMIZED
+Display the window ``minimized'' to an icon.  Prefer other datasets
+for running syntax.  This is the default for DATASET COPY and DATASET
+DECLARE.
+
+@item HIDDEN
+Hide the dataset's window.  Prefer other datasets for running syntax.
+@end table
+
 @node DATA LIST
 @section DATA LIST
 @vindex DATA LIST
@@ -511,10 +585,6 @@ For binary files encoded in EBCDIC:
                 /MODE=360
                 /RECFORM=@{FIXED,VARIABLE,SPANNED@}
                 [/LRECL=rec_len]
-
-To explicitly declare a scratch handle:
-        FILE HANDLE handle_name
-                /MODE=SCRATCH
 @end display
 
 Use @cmd{FILE HANDLE} to associate a file handle name with a file and
@@ -644,13 +714,6 @@ set, which are then translated from EBCDIC to the native character
 set.  Thus, when the host's native character set is based on ASCII,
 these fields are effectively padded with character @code{X'80'}.  This
 wart is implemented for compatibility.
-
-@item
-SCRATCH mode is a PSPP extension that designates the file handle as a
-scratch file handle.
-Its use is usually unnecessary because file handle names that begin with
-@samp{#} are assumed to refer to scratch files.  @pxref{File Handles},
-for more information.
 @end itemize
 
 The NAME subcommand specifies the name of the file associated with the
@@ -771,7 +834,7 @@ LIST.
 @end example
 
 The above example reads data from file @file{a.data}, then from
-@file{b.data}, and concatenates them into a single active file.
+@file{b.data}, and concatenates them into a single active dataset.
 
 @c If you change this example, change the regression test4 in
 @c tests/command/input-program.sh to match.
@@ -815,7 +878,7 @@ END INPUT PROGRAM.
 LIST/FORMAT=NUMBERED.
 @end example
 
-The above example causes an active file to be created consisting of 50
+The above example causes an active dataset to be created consisting of 50
 random variates between 0 and 10.
 
 @node LIST
@@ -834,7 +897,7 @@ listing file.
 
 The VARIABLES subcommand specifies the variables whose values are to be
 printed.  Keyword VARIABLES is optional.  If VARIABLES subcommand is not
-specified then all variables in the active file are printed.
+specified then all variables in the active dataset are printed.
 
 The CASES subcommand can be used to specify a subset of cases to be
 printed.  Specify FROM and the case number of the first case to print,
@@ -864,7 +927,8 @@ cannot fit on a single line, then a multi-line format will be used.
 NEW FILE.
 @end display
 
-@cmd{NEW FILE} command clears the current active file.
+@cmd{NEW FILE} command clears the dictionary and data from the current
+active dataset.
 
 @node PRINT
 @section PRINT
index 04269f32413733af6d626c3320b3142755264912..d46dd310aa1654efdfa8486926afb9241fa2e60e 100644 (file)
@@ -2,11 +2,11 @@
 @chapter Selecting data for analysis
 
 This chapter documents PSPP commands that temporarily or permanently
-select data records from the active file for analysis.
+select data records from the active dataset for analysis.
 
 @menu
 * FILTER::                      Exclude cases based on a variable.
-* N OF CASES::                  Limit the size of the active file.
+* N OF CASES::                  Limit the size of the active dataset.
 * SAMPLE::                      Select a specified proportion of cases.
 * SELECT IF::                   Permanently delete selected cases.
 * SPLIT FILE::                  Do multiple analyses with one command.
@@ -61,14 +61,14 @@ only the next procedure (@pxref{TEMPORARY}).  Otherwise, cases beyond
 the limit specified are not processed by any later procedure.
 
 If the limit specified on @cmd{N OF CASES} is greater than the number
-of cases in the active file, it has no effect.
+of cases in the active dataset, it has no effect.
 
 When @cmd{N OF CASES} is used along with @cmd{SAMPLE} or @cmd{SELECT
 IF}, the case limit is applied to the cases obtained after sampling or
 case selection, regardless of how @cmd{N OF CASES} is placed relative
 to @cmd{SAMPLE} or @cmd{SELECT IF} in the command file.  Thus, the
 commands @code{N OF CASES 100} and @code{SAMPLE .5} will both randomly
-sample approximately half of the active file's cases, then select the
+sample approximately half of the active dataset's cases, then select the
 first 100 of those sampled, regardless of their order in the command
 file.
 
@@ -87,11 +87,11 @@ SAMPLE num1 [FROM num2].
 
 @cmd{SAMPLE} randomly samples a proportion of the cases in the active
 file.  Unless it follows @cmd{TEMPORARY}, it operates as a
-transformation, permanently removing cases from the active file.
+transformation, permanently removing cases from the active dataset.
 
 The proportion to sample can be expressed as a single number between 0
 and 1.  If @code{k} is the number specified, and @code{N} is the number
-of currently-selected cases in the active file, then after
+of currently-selected cases in the active dataset, then after
 @code{SAMPLE @var{k}.}, approximately @code{k*N} cases will be
 selected.
 
@@ -101,16 +101,16 @@ The proportion to sample can also be specified in the style @code{SAMPLE
 @enumerate
 @item
 If @var{N} is equal to the number of currently-selected cases in the
-active file, exactly @var{m} cases will be selected.
+active dataset, exactly @var{m} cases will be selected.
 
 @item
 If @var{N} is greater than the number of currently-selected cases in the
-active file, an equivalent proportion of cases will be selected.
+active dataset, an equivalent proportion of cases will be selected.
 
 @item
 If @var{N} is less than the number of currently-selected cases in the
 active, exactly @var{m} cases will be selected @emph{from the first
-@var{N} cases in the active file.}
+@var{N} cases in the active dataset.}
 @end enumerate
 
 @cmd{SAMPLE} and @cmd{SELECT IF} are performed in
@@ -136,7 +136,7 @@ SELECT IF expression.
 
 @cmd{SELECT IF} selects cases for analysis based on the value of a
 boolean expression.  Cases not selected are permanently eliminated
-from the active file, unless @cmd{TEMPORARY} is in effect
+from the active dataset, unless @cmd{TEMPORARY} is in effect
 (@pxref{TEMPORARY}).
 
 Specify a boolean expression (@pxref{Expressions}).  If the value of the
@@ -180,7 +180,7 @@ using a variable where like values are not adjacent in the working file,
 you should first sort the data by that variable (@pxref{SORT CASES}).
 
 Specify OFF to disable @cmd{SPLIT FILE} and resume analysis of the
-entire active file as a single group of data.
+entire active dataset as a single group of data.
 
 When @cmd{SPLIT FILE} is specified after @cmd{TEMPORARY}, it affects only
 the next procedure (@pxref{TEMPORARY}).
@@ -196,7 +196,7 @@ TEMPORARY.
 @cmd{TEMPORARY} is used to make the effects of transformations
 following its execution temporary.  These transformations will
 affect only the execution of the next procedure or procedure-like
-command.  Their effects will not be saved to the active file.
+command.  Their effects will not be saved to the active dataset.
 
 The only specification on @cmd{TEMPORARY} is the command name.
 
@@ -239,7 +239,7 @@ WEIGHT OFF.
 @end display
 
 @cmd{WEIGHT} assigns cases varying weights,
-changing the frequency distribution of the active file.  Execution of
+changing the frequency distribution of the active dataset.  Execution of
 @cmd{WEIGHT} is delayed until data have been read.
 
 If a variable name is specified, @cmd{WEIGHT} causes the values of that
@@ -262,5 +262,5 @@ values are not treated specially.
 When @cmd{WEIGHT} is specified after @cmd{TEMPORARY}, it affects only
 the next procedure (@pxref{TEMPORARY}).
 
-@cmd{WEIGHT} does not cause cases in the active file to be replicated in
-memory.
+@cmd{WEIGHT} does not cause cases in the active dataset to be
+replicated in memory.
index f1347379347af558112140837de5cfe0b06e859c..8d1e8ac0663604ba526332fa7c9bcf8653955f8e 100644 (file)
@@ -637,11 +637,6 @@ work with these global styles:
 Returns the numeric style for the given format @var{type}.
 @end deftypefun
 
-@deftypefun void fmt_check_style (const struct fmt_number_style *@var{style})
-Asserts that style is self consistent.
-@end deftypefun
-
-
 @deftypefun {const char *} fmt_name (enum fmt_type @var{type})
 Returns the name of the given format @var{type}.
 @end deftypefun
@@ -1225,12 +1220,12 @@ The following sections describe variable-related functions and macros.
 @node Variable Name
 @subsection Variable Name
 
-A variable name is a string between 1 and @code{VAR_NAME_LEN} bytes
+A variable name is a string between 1 and @code{ID_MAX_LEN} bytes
 long that satisfies the rules for PSPP identifiers
 (@pxref{Tokens,,,pspp, PSPP Users Guide}).  Variable names are
 mixed-case and treated case-insensitively.
 
-@deftypefn Macro int VAR_NAME_LEN
+@deftypefn Macro int ID_MAX_LEN
 Maximum length of a variable name, in bytes, currently 64.
 @end deftypefn
 
@@ -1253,23 +1248,6 @@ dictionary.  Use @func{dict_rename_var} instead (@pxref{Dictionary
 Renaming Variables}).
 @end deftypefun
 
-@anchor{var_is_plausible_name}
-@deftypefun {bool} var_is_valid_name (const char *@var{name}, bool @var{issue_error})
-@deftypefunx {bool} var_is_plausible_name (const char *@var{name}, bool @var{issue_error})
-Tests @var{name} for validity or ``plausibility.''  Returns true if
-the name is acceptable, false otherwise.  If the name is not
-acceptable and @var{issue_error} is true, also issues an error message
-explaining the violation.
-
-A valid name is one that fully satisfies all of the requirements for
-variable names (@pxref{Tokens,,,pspp, PSPP Users Guide}).  A
-``plausible'' name is simply a string whose length is in the valid
-range and that is not a reserved word.  PSPP accepts plausible but
-invalid names as variable names in some contexts where the character
-encoding scheme is ambiguous, as when reading variable names from
-system files.
-@end deftypefun
-
 @deftypefun {enum dict_class} var_get_dict_class (const struct variable *@var{var})
 Returns the dictionary class of @var{var}'s name (@pxref{Dictionary
 Class}).
@@ -1769,7 +1747,7 @@ To delete a variable from a dictionary and destroy it, use
 @node Variable Short Names
 @subsection Variable Short Names
 
-PSPP variable names may be up to 64 (@code{VAR_NAME_LEN}) bytes long.
+PSPP variable names may be up to 64 (@code{ID_MAX_LEN}) bytes long.
 The system and portable file formats, however, were designed when
 variable names were limited to 8 bytes in length.  Since then, the
 system file format has been augmented with an extension record that
@@ -1834,7 +1812,7 @@ been assigned a short name.
 Sets @var{var}'s short name to @var{short_name}, or removes
 @var{var}'s short name if @var{short_name} is a null pointer.  If it
 is non-null, then @var{short_name} must be a plausible name for a
-variable (@pxref{var_is_plausible_name}).  The name will be truncated
+variable.  The name will be truncated
 to 8 bytes in length and converted to all-uppercase.
 @end deftypefun
 
@@ -1888,16 +1866,16 @@ associate data with a variable.
 
 To prevent multiple clients from attempting to use a variable's single
 auxiliary data field at the same time, we adopt the convention that
-use of auxiliary data in the active file dictionary is restricted to
+use of auxiliary data in the active dataset dictionary is restricted to
 the currently executing command.  In particular, transformations must
-not attach auxiliary data to a variable in the active file in the
-expectation that it can be used later when the active file is read and
+not attach auxiliary data to a variable in the active dataset in the
+expectation that it can be used later when the active dataset is read and
 the transformation is executed.  To help enforce this restriction,
-auxiliary data is deleted from all variables in the active file
+auxiliary data is deleted from all variables in the active dataset
 dictionary after the execution of each PSPP command.
 
 This convention for safe use of auxiliary data applies only to the
-active file dictionary.  Rules for other dictionaries may be
+active dataset dictionary.  Rules for other dictionaries may be
 established separately.
 
 Auxiliary data should be replaced by a more flexible mechanism at some
@@ -2131,10 +2109,10 @@ variables.  They also destroy the removed variables and free their
 associated storage.
 
 Deleting a variable to which there might be external pointers is a bad
-idea.  In particular, deleting variables from the active file
+idea.  In particular, deleting variables from the active dataset
 dictionary is a risky proposition, because transformations can retain
 references to arbitrary variables.  Therefore, no variable should be
-deleted from the active file dictionary when any transformations are
+deleted from the active dataset dictionary when any transformations are
 active, because those transformations might reference the variable to
 be deleted.  The safest time to delete a variable is just after a
 procedure has been executed, as done by @cmd{DELETE VARIABLES}.
@@ -2266,7 +2244,7 @@ is null, then @var{dict}'s weighting variable, if any, is cleared.
 @node Dictionary Filter Variable
 @subsection Filter Variable
 
-When the active file is read by a procedure, cases can be excluded
+When the active dataset is read by a procedure, cases can be excluded
 from analysis based on the values of a @dfn{filter variable}.
 @xref{FILTER,,,pspp, PSPP Users Guide}, for a user view of filtering.
 
@@ -2312,7 +2290,7 @@ Sets @var{dict}'s case limit to @var{limit}.
 
 The user may use the @cmd{SPLIT FILE} command (@pxref{SPLIT
 FILE,,,pspp, PSPP Users Guide}) to select a set of variables on which
-to split the active file into groups of cases to be analyzed
+to split the active dataset into groups of cases to be analyzed
 independently in each statistical procedure.  The set of split
 variables is stored as part of the dictionary, although the effect on
 data analysis is implemented by each individual statistical procedure.
index 356b5e03aaebddd34a6154f15cc147e69a6ad7ec..309e9562d62a3f072f6872978fb2258834b268fe 100644 (file)
@@ -18,13 +18,13 @@ Proposed outline:
 ** Reading data
 *** Casereaders generalities
 *** Casereaders from data files
-*** Casereaders from the active file
+*** Casereaders from the active dataset
 *** Other casereaders
 ** Writing data
 *** Casewriters generally
 *** Casewriters to data files
-*** Modifying the active file
-**** Modifying cases obtained from active file casereaders has no real effect
+*** Modifying the active dataset
+**** Modifying cases obtained from active dataset casereaders has no real effect
 **** Transformations; procedures that transform
 ** Transforming data
 *** Sorting and merging
index 972b1331b4fb0f0be54ff7b2118f8bb204a71293..7b0eff9f79823f0bb623e10d2f1da8c22922eff7 100644 (file)
@@ -60,7 +60,8 @@ if present.
 Document record, if present.
 
 @item
-Any records not explicitly included in this list, in any order.
+Extension (type 7) records, in ascending numerical order of their
+subtypes.
 
 @item
 Dictionary termination record.
@@ -390,6 +391,11 @@ Format types are defined as follows:
 @end multitable
 @end quotation
 
+A few system files have been observed in the wild with invalid
+@code{write} fields, in particular with value 0.  Readers should
+probably treat invalid @code{print} or @code{write} fields as some
+default format.
+
 @node Value Labels Records
 @section Value Labels Records
 
@@ -549,14 +555,45 @@ Compression code.  Always set to 1.
 Machine endianness.  1 indicates big-endian, 2 indicates little-endian.
 
 @item int32 character_code;
-@anchor{character-code}
-Character code.  1 indicates EBCDIC, 2 indicates 7-bit ASCII, 3
-indicates 8-bit ASCII, 4 indicates DEC Kanji.
-Windows code page numbers are also valid.
-
-Experience has shown that in many files, this field is ignored or incorrect.
-For a more reliable indication of the file's character encoding
-see @ref{Character Encoding Record}.
+@anchor{character-code} Character code.  The following values have
+been actually observed in system files:
+
+@table @asis
+@item 2
+7-bit ASCII.
+
+@item 1250
+The @code{windows-1250} code page for Central European and Eastern
+European languages.
+
+@item 1252
+The @code{windows-1252} code page for Western European languages.
+
+@item 28591
+ISO 8859-1.
+
+@item 65001
+UTF-8.
+@end table
+
+The following additional values are known to be defined:
+
+@table @asis
+@item 1
+EBCDIC.
+
+@item 3
+8-bit ``ASCII''.
+
+@item 4
+DEC Kanji.
+@end table
+
+Other Windows code page numbers are known to be generally valid.
+
+Old versions of SPSS always wrote value 2 in this field, regardless of
+the encoding in use.  Newer versions also write the character encoding
+as a string (see @ref{Character Encoding Record}).
 @end table
 
 @node Machine Floating-Point Info Record
@@ -644,7 +681,8 @@ following:
 
 @itemize @bullet
 @item
-The set's name (an identifier that begins with @samp{$}).
+The set's name (an identifier that begins with @samp{$}), in mixed
+upper and lower case.
 
 @item
 An equals sign (@samp{=}).
@@ -685,8 +723,8 @@ written if LABELSOURCE=VARLABEL was specified.
 A space.
 
 @item
-The names of the variables in the set, each separated from the
-previous by a single space.
+The short names of the variables in the set, converted to lowercase,
+each separated from the previous by a single space.
 
 @item
 A line feed (byte 0x0a).
@@ -774,8 +812,8 @@ Ordinal Scale
 Continuous Scale
 @end table
 
-SPSS 14 sometimes writes a @code{measure} of 0.  PSPP interprets this
-as nominal scale.
+SPSS 14 sometimes writes a @code{measure} of 0 for string variables.
+PSPP interprets this as nominal scale.
 
 @item int32 width;
 The width of the display column for the variable in characters.
@@ -955,12 +993,29 @@ The size of each element in the @code{encoding} member. Always set to 1.
 The total number of bytes in @code{encoding}.
 
 @item char encoding[];
-The name of the character encoding.  Normally this will be an official IANA characterset name or alias.
+The name of the character encoding.  Normally this will be an official
+IANA character set name or alias.
 See @url{http://www.iana.org/assignments/character-sets}.
+Character set names are not case-sensitive, but SPSS appears to write
+them in all-uppercase.
 @end table
 
-This record is not present in files generated by older software.
-See also @ref{character-code}.
+This record is not present in files generated by older software.  See
+also the @code{character_code} field in the machine integer info
+record (@pxref{character-code}).
+
+When the character encoding record and the machine integer info record
+are both present, all system files observed in practice indicate the
+same character encoding, e.g.@: 1252 as @code{character_code} and
+@code{windows-1252} as @code{encoding}, 65001 and @code{UTF-8}, etc.
+
+If, for testing purposes, a file is crafted with different
+@code{character_code} and @code{encoding}, it seems that
+@code{character_code} controls the encoding for all strings in the
+system file before the dictionary termination record, including
+strings in data (e.g.@: string missing values), and @code{encoding}
+controls the encoding for strings following the dictionary termination
+record.
 
 @node Long String Value Labels Record
 @section Long String Value Labels Record
@@ -1087,8 +1142,8 @@ element.
 In record type 18, this field contains a sequence of one or more
 variable attribute sets.  If more than one variable attribute set is
 present, each one after the first is delimited from the previous by
-@code{/}.  Each variable attribute set consists of a (potentially
-long) variable name,
+@code{/}.  Each variable attribute set consists of a long
+variable name,
 followed by @code{:}, followed by an attribute set with the same
 syntax as on record type 17.
 
index 345e59669d36ad6f0cc08a8f95251e3b0760fdbc..c77ddcae844687c189ff276ce322f0c338c3b574 100644 (file)
@@ -1077,7 +1077,8 @@ yields the value of that variable for the case @var{n} before the
 current one.  Results in system-missing (for numeric variables) or
 blanks (for string variables) for the first @var{n} cases.
 
-@code{LAG} obtains values from the cases that become the new active file
+@code{LAG} obtains values from the cases that become the new active
+dataset
 after a procedure executes.  Thus, @code{LAG} will not return values
 from cases dropped by transformations such as @cmd{SELECT IF}, and
 transformations like @cmd{COMPUTE} that modify data will change the
index 5f0c527c4738c90ffaeab349c357dba46c73e4ca..89d043f8769f67c6c898dcf9a7729d0fbcd3356d 100644 (file)
@@ -5,7 +5,7 @@ The commands in this chapter read, write, and examine system files and
 portable files.
 
 @menu
-* APPLY DICTIONARY::            Apply system file dictionary to active file.
+* APPLY DICTIONARY::            Apply system file dictionary to active dataset.
 * EXPORT::                      Write to a portable file.
 * GET::                         Read from a system file.
 * GET DATA::                    Read from foreign files.
@@ -27,39 +27,39 @@ APPLY DICTIONARY FROM=@{'file-name',file_handle@}.
 
 @cmd{APPLY DICTIONARY} applies the variable labels, value labels,
 and missing values taken from a file to corresponding
-variables in the active file.  In some cases it also updates the
+variables in the active dataset.  In some cases it also updates the
 weighting variable.
 
-Specify a system file, portable file, or scratch file with a file name
-string or as a file handle (@pxref{File Handles}).  The dictionary in the
-file will be read, but it will not replace the active file dictionary.
-The file's data will not be read.
+Specify a system file or portable file's name, a data set name
+(@pxref{Datasets}), or a file handle name (@pxref{File Handles}).  The
+dictionary in the file will be read, but it will not replace the
+active dataset's dictionary.  The file's data will not be read.
 
-Only variables with names that exist in both the active file and the
+Only variables with names that exist in both the active dataset and the
 system file are considered.  Variables with the same name but different
 types (numeric, string) will cause an error message.  Otherwise, the
 system file variables' attributes will replace those in their matching
-active file variables:
+active dataset variables:
 
 @itemize @bullet
 @item
-If a system file variable has a variable label, then it will replace the
-active file variable's variable label.  If the system file variable does
-not have a variable label, then the active file variable's variable
-label, if any, will be retained.  
+If a system file variable has a variable label, then it will replace
+the variable label of the active dataset variable.  If the system
+file variable does not have a variable label, then the active dataset
+variable's variable label, if any, will be retained.
 
 @item
 If the system file variable has custom attributes (@pxref{VARIABLE
-ATTRIBUTE}), then those attributes replace the active file variable's
+ATTRIBUTE}), then those attributes replace the active dataset variable's
 custom attributes.  If the system file variable does not have custom
-attributes, then the active file variable's custom attributes, if any,
+attributes, then the active dataset variable's custom attributes, if any,
 will be retained.
 
 @item
-If the active file variable is numeric or short string, then value
-labels and missing values, if any, will be copied to the active file
+If the active dataset variable is numeric or short string, then value
+labels and missing values, if any, will be copied to the active dataset
 variable.  If the system file variable does not have value labels or
-missing values, then those in the active file variable, if any, will not
+missing values, then those in the active dataset variable, if any, will not
 be disturbed.
 @end itemize
 
@@ -69,20 +69,19 @@ file dictionary as a whole are updated:
 @itemize @bullet
 @item
 If the system file has custom attributes (@pxref{DATAFILE ATTRIBUTE}),
-then those attributes replace the active file variable's custom
+then those attributes replace the active dataset variable's custom
 attributes.
 
 @item
-If the active file has a weighting variable (@pxref{WEIGHT}), and the
+If the active dataset has a weighting variable (@pxref{WEIGHT}), and the
 system file does not, or if the weighting variable in the system file
-does not exist in the active file, then the active file weighting
+does not exist in the active dataset, then the active dataset weighting
 variable, if any, is retained.  Otherwise, the weighting variable in
-the system file becomes the active file weighting variable.
+the system file becomes the active dataset weighting variable.
 @end itemize
 
 @cmd{APPLY DICTIONARY} takes effect immediately.  It does not read the
-active
-file.  The system file is not modified.
+active dataset.  The system file is not modified.
 
 @node EXPORT
 @section EXPORT
@@ -100,8 +99,8 @@ EXPORT
         /MAP
 @end display
 
-The @cmd{EXPORT} procedure writes the active file dictionary and data to a
-specified portable file or scratch file.
+The @cmd{EXPORT} procedure writes the active dataset's dictionary and
+data to a specified portable file.
 
 By default, cases excluded with FILTER are written to the
 file.  These can be excluded by specifying DELETE on the UNSELECTED
@@ -117,7 +116,7 @@ subcommand may be used to specify the number of decimal digits of
 precision to write.  DIGITS applies only to non-integers.
 
 The OUTFILE subcommand, which is the only required subcommand, specifies
-the portable file or scratch file to be written as a file name string or
+the portable file to be written as a file name string or
 a file handle (@pxref{File Handles}).
 
 DROP, KEEP, and RENAME follow the same format as the SAVE procedure
@@ -128,7 +127,7 @@ portable file.  Its value is currently not used.
 
 The MAP subcommand is currently ignored.
 
-@cmd{EXPORT} is a procedure.  It causes the active file to be read.
+@cmd{EXPORT} is a procedure.  It causes the active dataset to be read.
 
 @node GET
 @section GET
@@ -142,11 +141,11 @@ GET
         /RENAME=(src_names=target_names)@dots{}
 @end display
 
-@cmd{GET} clears the current dictionary and active file and
+@cmd{GET} clears the current dictionary and active dataset and
 replaces them with the dictionary and data from a specified file.
 
 The FILE subcommand is the only required subcommand.  Specify the system
-file, portable file, or scratch file to be read as a string file name or
+file or portable file to be read as a string file name or
 a file handle (@pxref{File Handles}).
 
 By default, all the variables in a file are read.  The DROP
@@ -169,14 +168,13 @@ deprecated.
 
 DROP, KEEP, and RENAME are executed in left-to-right order.  
 Each may be present any number of times.  @cmd{GET} never modifies a
-file on disk.  Only the active file read from the file
+file on disk.  Only the active dataset read from the file
 is affected by these subcommands.
 
 @cmd{GET} does not cause the data to be read, only the dictionary.  The data
 is read later, when a procedure is executed.
 
-Use of @cmd{GET} to read a portable file or scratch file is a PSPP
-extension.
+Use of @cmd{GET} to read a portable file is a PSPP extension.
 
 @node GET DATA
 @section GET DATA
@@ -188,10 +186,10 @@ GET DATA
         @dots{}additional subcommands depending on TYPE@dots{}
 @end display
 
-The @cmd{GET DATA} command is used to read files and other data sources 
-created by other applications. 
-When this command is executed, the current dictionary and active file are
-replaced  with variables and data read from the specified source.
+The @cmd{GET DATA} command is used to read files and other data
+sources created by other applications.  When this command is executed,
+the current dictionary and active dataset are replaced with variables
+and data read from the specified source.
 
 The TYPE subcommand is mandatory and must be the first subcommand
 specified.  It determines the type of the file or source to read.
@@ -585,8 +583,9 @@ value is 1.
 The VARIABLES subcommand, which is required, specifies the positions
 at which each variable can be found.  For each variable, specify its
 name, followed by its start and end column separated by @samp{-}
-(e.g.@: @samp{0-9}), followed by the input format type (e.g.@:
-@samp{F}).  For this command, columns are numbered starting from 0 at
+(e.g.@: @samp{0-9}), followed by an input format type (e.g.@:
+@samp{F}) or a full format specification (e.g.@: @samp{DOLLAR12.2}).
+For this command, columns are numbered starting from 0 at
 the left column.  Introduce the variables in the second and later
 lines of a case by a slash followed by the number of the line within
 the case, e.g.@: @samp{/2} for the second line.
@@ -632,10 +631,10 @@ IMPORT
         /RENAME=(src_names=target_names)@dots{}
 @end display
 
-The @cmd{IMPORT} transformation clears the active file dictionary and
+The @cmd{IMPORT} transformation clears the active dataset dictionary and
 data and
-replaces them with a dictionary and data from a system, portable file,
-or scratch file.
+replaces them with a dictionary and data from a system file or
+portable file.
 
 The FILE subcommand, which is the only required subcommand, specifies
 the portable file to be read as a file name string or a file handle
@@ -648,8 +647,7 @@ DROP, KEEP, and RENAME follow the syntax used by @cmd{GET} (@pxref{GET}).
 @cmd{IMPORT} does not cause the data to be read, only the dictionary.  The
 data is read later, when a procedure is executed.
 
-Use of @cmd{IMPORT} to read a system file or scratch file is a PSPP
-extension.
+Use of @cmd{IMPORT} to read a system file is a PSPP extension.
 
 @node SAVE
 @section SAVE
@@ -670,11 +668,11 @@ SAVE
 @end display
 
 The @cmd{SAVE} procedure causes the dictionary and data in the active
-file to
-be written to a system file or scratch file.
+dataset to
+be written to a system file.
 
-OUTFILE is the only required subcommand.  Specify the system file or
-scratch file to be written as a string file name or a file handle
+OUTFILE is the only required subcommand.  Specify the system file
+to be written as a string file name or a file handle
 (@pxref{File Handles}).
 
 By default, cases excluded with FILTER are written to the system file.
@@ -689,13 +687,13 @@ The PERMISSIONS subcommand specifies permissions for the new system
 file.  WRITEABLE, the default, creates the file with read and write
 permission.  READONLY creates the file for read-only access.
 
-By default, all the variables in the active file dictionary are written
+By default, all the variables in the active dataset dictionary are written
 to the system file.  The DROP subcommand can be used to specify a list
 of variables not to be written.  In contrast, KEEP specifies variables
 to be written, with all variables not specified not written.
 
 Normally variables are saved to a system file under the same names they
-have in the active file.  Use the RENAME subcommand to change these names.
+have in the active dataset.  Use the RENAME subcommand to change these names.
 Specify, within parentheses, a list of variable names followed by an
 equals sign (@samp{=}) and the names that they should be renamed to.
 Multiple parenthesized groups of variable names can be included on a
@@ -709,7 +707,7 @@ deprecated.
 
 DROP, KEEP, and RENAME are performed in left-to-right order.  They
 each may be present any number of times.  @cmd{SAVE} never modifies
-the active file.  DROP, KEEP, and RENAME only affect the system file
+the active dataset.  DROP, KEEP, and RENAME only affect the system file
 written to disk.
 
 The VERSION subcommand specifies the version of the file format. Valid
@@ -765,7 +763,7 @@ values as if they were not missing.  Specify MISSING=RECODE to output
 numeric user-missing values like system-missing values and string
 user-missing values as all spaces.
 
-By default, all the variables in the active file dictionary are saved
+By default, all the variables in the active dataset dictionary are saved
 to the system file, but DROP or KEEP can select a subset of variable
 to save.  The RENAME subcommand can also be used to change the names
 under which variables are saved.  UNSELECTED determines whether cases
@@ -869,7 +867,7 @@ displays the information in its dictionary.
 Specify a file name or file handle.  @cmd{SYSFILE INFO} reads that file as
 a system file and displays information on its dictionary.
 
-@cmd{SYSFILE INFO} does not affect the current active file.
+@cmd{SYSFILE INFO} does not affect the current active dataset.
 
 @node XEXPORT
 @section XEXPORT
@@ -886,7 +884,7 @@ XEXPORT
         /MAP
 @end display
 
-The @cmd{EXPORT} transformation writes the active file dictionary and
+The @cmd{EXPORT} transformation writes the active dataset dictionary and
 data to a specified portable file.
 
 This transformation is a PSPP extension.
@@ -921,8 +919,8 @@ XSAVE
         /MAP
 @end display
 
-The @cmd{XSAVE} transformation writes the active file dictionary and
-data to a system file or scratch file.  It is similar to the @cmd{SAVE}
+The @cmd{XSAVE} transformation writes the active dataset's dictionary and
+data to a system file.  It is similar to the @cmd{SAVE}
 procedure, with two differences:
 
 @itemize
index 868143b35a5a0ba8b73c5f628834f9b7a39cc87a..892887e211f9cb5b9f68f4f79a562b7796b33d55 100644 (file)
@@ -72,6 +72,7 @@ expansion takes one of the following forms:
         var_list
         num_or_range@dots{}
         'string'@dots{}
+        ALL
 
 num_or_range takes one of the following forms:
         number
@@ -82,13 +83,11 @@ num_or_range takes one of the following forms:
 different variables, numbers, or strings into the block with each
 repetition.
 
-Specify a dummy variable name followed by an equals sign (@samp{=}) and
-the list of replacements.  Replacements can be a list of variables
-(which may be existing variables or new variables or some combination),
-numbers, or strings.  When new variable names are
-specified, @cmd{DO REPEAT} creates them as numeric variables.  When numbers
-are specified, runs of increasing integers may be indicated as
-@code{@var{num1} TO @var{num2}}, so that
+Specify a dummy variable name followed by an equals sign (@samp{=})
+and the list of replacements.  Replacements can be a list of existing
+or new variables, numbers, strings, or @code{ALL} to specify all
+existing variables.  When numbers are specified, runs of increasing
+integers may be indicated as @code{@var{num1} TO @var{num2}}, so that
 @samp{1 TO 5} is short for @samp{1 2 3 4 5}.
 
 Multiple dummy variables can be specified.  Each
@@ -100,10 +99,22 @@ each dummy variable is substituted; the second time, the second value
 for each dummy variable is substituted; and so on.
 
 Dummy variable substitutions work like macros.  They take place
-anywhere in a line that the dummy variable name occurs as a token,
-including command and subcommand names.  For this reason,
-words commonly used in command and subcommand names should not be used
-as dummy variable identifiers.
+anywhere in a line that the dummy variable name occurs.  This includes
+command and subcommand names, so command and subcommand names that
+appear in the code block should not be used as dummy variable
+identifiers.  Dummy variable substitutions do not occur inside quoted
+strings, comments, unquoted strings (such as the text on the
+@cmd{TITLE} or @cmd{DOCUMENT} command), or inside @cmd{BEGIN
+DATA}@dots{}@cmd{END DATA}.
+
+New variable names used as replacements are not automatically created
+as variables, but only if used in the code block in a context that
+would create them, e.g.@: on a @cmd{NUMERIC} or @cmd{STRING} command
+or on the left side of a @cmd{COMPUTE} assignment.
+
+Any command may appear within DO REPEAT, including nested DO REPEAT
+commands.  If @cmd{INCLUDE} or @cmd{INSERT} appears within DO REPEAT,
+the substitutions do not apply to the included file.
 
 If PRINT is specified on @cmd{END REPEAT}, the commands after substitutions
 are made are printed to the listing file, prefixed by a plus sign
index 2080a3e2259b3202e54280c05537f3b848db57eb..b37d59564b642e542dd4c86c071feef80a448fe5 100644 (file)
@@ -49,10 +49,12 @@ corresponding short options.
 @example
 -I, --include=@var{dir}
 -I-, --no-include
+-b, --batch
 -i, --interactive
 -r, --no-statrc
 -a, --algorithm=@{compatible|enhanced@}
 -x, --syntax=@{compatible|enhanced@}
+--syntax-encoding=@var{encoding}
 @end example
 
 @item Informational options
@@ -135,11 +137,13 @@ inserted in the include path by default.  The default include path is
 user's home directory, followed by PSPP's system configuration
 directory (usually @file{/etc/pspp} or @file{/usr/local/etc/pspp}).
 
+@item -b
+@item --batch
 @item -i
 @itemx --interactive
-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.
+These options forces syntax files to be interpreted in batch mode or
+interactive mode, respectively, rather than the default ``auto'' mode.
+@xref{Syntax Variants}, for a description of the differences.
 
 @item -r
 @itemx --no-statrc
@@ -161,8 +165,14 @@ 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
+@item --syntax-encoding=@var{encoding}
+Specifies @var{encoding} as the encoding for syntax files named on the
+command line.  The @var{encoding} also becomes the default encoding
+for other syntax files read during the PSPP session by the
+@cmd{INCLUDE} and @cmd{INSERT} commands.  @xref{INSERT}, for the
+accepted forms of @var{encoding}.
+
+@item --help
 Prints a message describing PSPP command-line syntax and the available
 device formats, then exits.
 
@@ -263,6 +273,8 @@ specify @option{-o @var{file}} on the PSPP command line, optionally
 followed by options from the table below to customize the output
 format.
 
+Plain text output is encoded in UTF-8.
+
 @table @code
 @item -O format=txt
 Specify the output format.  This is only necessary if the file name
@@ -309,26 +321,11 @@ the page length.  Default: @code{0}.
 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 box=@{ascii|unicode@}
+Sets the characters used for lines in tables.  The default,
+@code{ascii}, uses @samp{-}, @samp{|}, and @samp{+} for single-width
+lines and @samp{=} and @samp{#} for double-width lines.  Specify
+@code{unicode} to use Unicode box drawing characters.
 
 @item -O emphasis=@{none|bold|underline@}
 How to emphasize text.  Bold and underline emphasis are achieved with
@@ -379,8 +376,19 @@ Specify the output format.  This is only necessary if the file name
 given on @option{-o} does not end in @file{.csv}.
 
 @item -O separator=@var{field-separator}
-Sets the character used to separate fields.  The default is a comma
+Sets the character used to separate fields.  Default: a comma
 (@samp{,}).
+
+@item -O quote=@var{qualifier}
+Sets @var{qualifier} as the character used to quote fields that
+contain white space, the separator (or any of the characters in the
+separator, if it contains more than one character), or the quote
+character itself.  If @var{qualifier} is longer than one character,
+only the first character is used; if @var{qualifier} is the empty
+string, then fields are never quoted.
+
+@item -O captions=@var{boolean}
+Whether table captions should be printed.  Default: @code{on}.
 @end table
 
 The CSV format used is an extension to that specified in RFC 4180:
@@ -390,8 +398,9 @@ The CSV format used is an extension to that specified in RFC 4180:
 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:}.
+output as empty fields.  When a table has a caption and captions are
+enabled, the caption 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
index d117a0eeb0e2cd75d7aa5ec03b6c495ee5a6d384..a5ef4b69d6e338084847b97278a1357d8478ebaa 100644 (file)
@@ -13,7 +13,7 @@ Later chapters will describe individual commands in detail.
 * Types of Commands::           Commands come in several flavors.
 * Order of Commands::           Commands combine to form syntax files.
 * Missing Observations::        Handling missing observations.
-* Variables::                   The unit of data storage.
+* Datasets::                    Data organization.
 * Files::                       Files used by PSPP.
 * File Handles::                How files are named.
 * BNF::                         How command syntax is described.
@@ -111,26 +111,29 @@ character used for quoting in the string, double it, e.g.@:
 significant inside strings.
 
 Strings can be concatenated using @samp{+}, so that @samp{"a" + 'b' +
-'c'} is equivalent to @samp{'abc'}.  Concatenation is useful for
-splitting a single string across multiple source lines.
-
-Strings may also be expressed as hexadecimal, octal, or binary
-character values by prefixing the initial quote character by @samp{X},
-@samp{O}, or @samp{B} or their lowercase equivalents.  Each pair,
-triplet, or octet of characters, according to the radix, is
-transformed into a single character with the given value.  If there is
-an incomplete group of characters, the missing final digits are
-assumed to be @samp{0}.  These forms of strings are nonportable
-because numeric values are associated with different characters by
-different operating systems.  Therefore, their use should be confined
-to syntax files that will not be widely distributed.
-
-@cindex characters, reserved
-@cindex 0
-@cindex white space
-The character with value 00 is reserved for
-internal use by PSPP.  Its use in strings causes an error and
-replacement by a space character.
+'c'} is equivalent to @samp{'abc'}.  So that a long string may be
+broken across lines, a line break may precede or follow, or both
+precede and follow, the @samp{+}.  (However, an entirely blank line
+preceding or following the @samp{+} is interpreted as ending the
+current command.)
+
+Strings may also be expressed as hexadecimal character values by
+prefixing the initial quote character by @samp{x} or @samp{X}.
+Regardless of the syntax file or active dataset's encoding, the
+hexadecimal digits in the string are interpreted as Unicode characters
+in UTF-8 encoding.
+
+Individual Unicode code points may also be expressed by specifying the
+hexadecimal code point number in single or double quotes preceded by
+@samp{u} or @samp{U}.  For example, Unicode code point U+1D11E, the
+musical G clef character, could be expressed as @code{U'1D11E'}.
+Invalid Unicode code points (above U+10FFFF or in between U+D800 and
+U+DFFF) are not allowed.
+
+When strings are concatenated with @samp{+}, each segment's prefix is
+considered individually.  For example, @code{'The G clef symbol is:' +
+u"1d11e" + "."} inserts a G clef symbol in the middle of an otherwise
+plain text string.
 
 @item Punctuators and Operators
 @cindex punctuators
@@ -147,11 +150,6 @@ punctuator only as the last character on a line (except white space).
 When it is the last non-space character on a line, a period is not
 treated as part of another token, even if it would otherwise be part
 of, e.g.@:, an identifier or a floating-point number.
-
-Actually, the character that ends a command can be changed with
-@cmd{SET}'s ENDCMD subcommand (@pxref{SET}), but we do not recommend
-doing so.  Throughout the remainder of this manual we will assume that
-the default setting is in effect.
 @end table
 
 @node Commands
@@ -179,38 +177,43 @@ by a forward slash (@samp{/}).
 There are multiple ways to mark the end of a command.  The most common
 way is to end the last line of the command with a period (@samp{.}) as
 described in the previous section (@pxref{Tokens}).  A blank line, or
-one that consists only of white space or comments, also ends a command
-by default, although you can use the NULLINE subcommand of @cmd{SET}
-to disable this feature (@pxref{SET}).
+one that consists only of white space or comments, also ends a command.
 
 @node Syntax Variants
-@section Variants of syntax.
+@section Syntax Variants
 
 @cindex Batch syntax
 @cindex Interactive syntax
 
-There are two variants of command syntax, @i{viz}: @dfn{batch} mode and
-@dfn{interactive} mode.
-Batch mode is the default when reading commands from a file.
-Interactive mode is the default when commands are typed at a prompt
-by a user.
-Certain commands, such as @cmd{INSERT} (@pxref{INSERT}), may explicitly
-change the syntax mode. 
-
-In batch mode, any line that contains a non-space character
-in the leftmost column begins a new command. 
-Thus, each command consists of a flush-left line followed by any
-number of lines indented from the left margin. 
-In this mode, a plus or minus sign (@samp{+}, @samp{@minus{}}) as the
-first character in a line is ignored and causes that line to begin a
-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 be terminated with a period
-or by a blank line.
-The use of @samp{+} and @samp{@minus{}} as continuation characters is not
-permitted.
+There are three variants of command syntax, which vary only in how
+they detect the end of one command and the start of the next.
+
+In @dfn{interactive mode}, which is the default for syntax typed at a
+command prompt, a period as the last non-blank character on a line
+ends a command.  A blank line also ends a command.
+
+In @dfn{batch mode}, an end-of-line period or a blank line also ends a
+command.  Additionally, it treats any line that has a non-blank
+character in the leftmost column as beginning a new command.  Thus, in
+batch mode the second and subsequent lines in a command must be
+indented.
+
+Regardless of the syntax mode, a plus sign, minus sign, or period in
+the leftmost column of a line is ignored and causes that line to begin
+a new command.  This is most useful in batch mode, in which the first
+line of a new command could not otherwise be indented, but it is
+accepted regardless of syntax mode.
+
+The default mode for reading commands from a file is @dfn{auto mode}.
+It is the same as batch mode, except that a line with a non-blank in
+the leftmost column only starts a new command if that line begins with
+the name of a PSPP command.  This correctly interprets most valid PSPP
+syntax files regardless of the syntax mode for which they are
+intended.
+
+The @option{--interactive} (or @option{-i}) or @option{--batch} (or
+@option{-b}) options set the syntax mode for files listed on the PSPP
+command line.  @xref{Main Options}, for more details.
 
 @node Types of Commands
 @section Types of Commands
@@ -252,7 +255,7 @@ of Commands}, for details.
 Analyze data, writing results of analyses to the listing file.  Cause
 transformations specified earlier in the file to be performed.  In a
 more general sense, a @dfn{procedure} is any command that causes the
-active file (the data) to be read.
+active dataset (the data) to be read.
 @end table
 
 @node Order of Commands
@@ -293,7 +296,7 @@ Valid in any state.
 When executed in the initial or procedure state, causes a transition to
 the transformation state.  
 @item
-Clears the active file if executed in the procedure or transformation
+Clears the active dataset if executed in the procedure or transformation
 state.
 @end itemize
 
@@ -304,7 +307,7 @@ Invalid in INPUT PROGRAM and FILE TYPE states.
 @item
 Causes a transition to the INPUT PROGRAM state.  
 @item
-Clears the active file.
+Clears the active dataset.
 @end itemize
 
 @item @cmd{FILE TYPE}
@@ -314,7 +317,7 @@ Invalid in INPUT PROGRAM and FILE TYPE states.
 @item
 Causes a transition to the FILE TYPE state.
 @item
-Clears the active file.
+Clears the active dataset.
 @end itemize
 
 @item Other file definition commands
@@ -324,7 +327,7 @@ Invalid in INPUT PROGRAM and FILE TYPE states.
 @item
 Cause a transition to the transformation state.
 @item
-Clear the active file, except for @cmd{ADD FILES}, @cmd{MATCH FILES},
+Clear the active dataset, except for @cmd{ADD FILES}, @cmd{MATCH FILES},
 and @cmd{UPDATE}.
 @end itemize
 
@@ -377,19 +380,29 @@ for that variable.  However, most of the time user-missing values are
 treated in the same way as the system-missing value.
 
 For more information on missing values, see the following sections:
-@ref{Variables}, @ref{MISSING VALUES}, @ref{Expressions}.  See also the
+@ref{Datasets}, @ref{MISSING VALUES}, @ref{Expressions}.  See also the
 documentation on individual procedures for information on how they
 handle missing values.
 
-@node Variables
-@section Variables
-@cindex variables
+@node Datasets
+@section Datasets
+@cindex dataset
+@cindex variable
 @cindex dictionary
 
-Variables are the basic unit of data storage in PSPP.  All the
-variables in a file taken together, apart from any associated data, are
-said to form a @dfn{dictionary}.  
-Some details of variables are described in the sections below.
+PSPP works with data organized into @dfn{datasets}.  A dataset
+consists of a set of @dfn{variables}, which taken together are said to
+form a @dfn{dictionary}, and one or more @dfn{cases}, each of which
+has one value for each variable.
+
+At any given time PSPP has exactly one distinguished dataset, called
+the @dfn{active dataset}.  Most PSPP commands work only with the
+active dataset.  In addition to the active dataset, PSPP also supports
+any number of additional open datasets.  The @cmd{DATASET} commands
+can choose a new active dataset from among those that are open, as
+well as create and destroy datasets (@pxref{DATASET}).
+
+The sections below describe variables in more detail.
 
 @menu
 * Attributes::                  Attributes of variables.
@@ -527,7 +540,7 @@ System missing value, in format F1.
 
 @cindex @code{$TIME}
 @item $TIME
-Number of seconds between midnight 14 Oct 1582 and the time the active file
+Number of seconds between midnight 14 Oct 1582 and the time the active dataset
 was read, in format F20.
 
 @cindex @code{$WIDTH}
@@ -573,7 +586,7 @@ input field as a number or a string.  It might specify that the field
 contains an ordinary decimal number, a time or date, a number in binary
 or hexadecimal notation, or one of several other notations.  Input
 formats are used by commands such as @cmd{DATA LIST} that read data or
-syntax files into the PSPP active file.
+syntax files into the PSPP active dataset.
 
 Every input format corresponds to a default @dfn{output format} that
 specifies the formatting used when the value is output later.  It is
@@ -1251,7 +1264,7 @@ format is A format with half the input width.
 
 @cindex scratch variables
 Most of the time, variables don't retain their values between cases.
-Instead, either they're being read from a data file or the active file,
+Instead, either they're being read from a data file or the active dataset,
 in which case they assume the value read, or, if created with
 @cmd{COMPUTE} or
 another transformation, they're initialized to the system-missing value
@@ -1304,14 +1317,6 @@ run.  The output files receive the tables and charts produced by
 statistical procedures.  The output files may be in any number of formats,
 depending on how PSPP is configured.
 
-@cindex active file
-@cindex file, active
-@item active file
-The active file is the ``file'' on which all PSPP procedures are
-performed.  The active file consists of a dictionary and a set of cases.
-The active file is not necessarily a disk file: it is stored in memory
-if there is room.
-
 @cindex system file
 @cindex file, system
 @item system file
@@ -1324,24 +1329,14 @@ cases.  @cmd{GET} and @cmd{SAVE} read and write system files.
 Portable files are files in a text-based format that store a dictionary
 and a set of cases.  @cmd{IMPORT} and @cmd{EXPORT} read and write
 portable files.
-
-@cindex scratch file
-@cindex file, scratch
-@item scratch file
-Scratch files consist of a dictionary and cases and may be stored in
-memory or on disk.  Most procedures that act on a system file or
-portable file can use a scratch file instead.  The contents of scratch
-files persist within a single PSPP session only.  @cmd{GET} and
-@cmd{SAVE} can be used to read and write scratch files.  Scratch files
-are a PSPP extension.
 @end table
 
 @node File Handles
 @section File Handles
 @cindex file handles
 
-A @dfn{file handle} is a reference to a data file, system file, portable
-file, or scratch file.  Most often, a file handle is specified as the
+A @dfn{file handle} is a reference to a data file, system file, or 
+portable file.  Most often, a file handle is specified as the
 name of a file as a string, that is, enclosed within @samp{'} or
 @samp{"}.
 
@@ -1362,15 +1357,6 @@ the syntax later to use a different file.  Use of @cmd{FILE HANDLE} is
 also required to read data files in binary formats.  @xref{FILE HANDLE},
 for more information.
 
-PSPP assumes that a file handle name that begins with @samp{#} refers to
-a scratch file, unless the name has already been declared on @cmd{FILE
-HANDLE} to refer to another kind of file.  A scratch file is similar to
-a system file, except that it persists only for the duration of a given
-PSPP session.  Most commands that read or write a system or portable
-file, such as @cmd{GET} and @cmd{SAVE}, also accept scratch file
-handles.  Scratch file handles may also be declared explicitly with
-@cmd{FILE HANDLE}.  Scratch files are a PSPP extension.
-
 In some circumstances, PSPP must distinguish whether a file handle
 refers to a system file or a portable file.  When this is necessary to
 read a file, e.g.@: as an input file for @cmd{GET} or @cmd{MATCH FILES},
@@ -1386,8 +1372,7 @@ file'' embedded into the syntax file between @cmd{BEGIN DATA} and
 
 The file to which a file handle refers may be reassigned on a later
 @cmd{FILE HANDLE} command if it is first closed using @cmd{CLOSE FILE
-HANDLE}.  The @cmd{CLOSE FILE HANDLE} command is also useful to free the
-storage associated with a scratch file.  @xref{CLOSE FILE HANDLE}, for
+HANDLE}.  @xref{CLOSE FILE HANDLE}, for
 more information.
 
 @node BNF
index b47416b70191c1a1af0129ca073a36fa7a390056..9885d8444a8335468c64c5f6079a5945919a5d29 100644 (file)
@@ -50,7 +50,7 @@ REGRESSION
         /SAVE=@{PRED, RESID@}
 @end display
 
-The @cmd{REGRESSION} procedure reads the active file and outputs
+The @cmd{REGRESSION} procedure reads the active dataset and outputs
 statistics relevant to the linear model specified by the user.
 
 The VARIABLES subcommand, which is required, specifies the list of
@@ -80,7 +80,7 @@ The covariance matrix for the estimated model coefficients.
 
 The SAVE subcommand causes PSPP to save the residuals or predicted
 values from the fitted
-model to the active file. PSPP will store the residuals in a variable
+model to the active dataset. PSPP will store the residuals in a variable
 called RES1 if no such variable exists, RES2 if RES1 already exists,
 RES3 if RES1 and RES2 already exist, etc. It will choose the name of
 the variable for the predicted values similarly, but with PRED as a
@@ -89,7 +89,7 @@ prefix.
 @node Examples
 @subsection Examples
 The following PSPP syntax will generate the default output and save the
-predicted values and residuals to the active file.
+predicted values and residuals to the active dataset.
 
 @example
 title 'Demonstrate REGRESSION procedure'.
index be696009e4249ddc1f80eded72921e08e4b51502..e5e299a47f8a66ae63688581de53a4b57e18d35b 100644 (file)
@@ -38,7 +38,7 @@ DESCRIPTIVES
               @{A,D@}
 @end display
 
-The @cmd{DESCRIPTIVES} procedure reads the active file and outputs
+The @cmd{DESCRIPTIVES} procedure reads the active dataset and outputs
 descriptive
 statistics requested by the user.  In addition, it can optionally
 compute Z-scores.
@@ -681,9 +681,14 @@ is used.
 @menu
 * BINOMIAL::                Binomial Test
 * CHISQUARE::               Chisquare Test
+* COCHRAN::                 Cochran Q Test
+* FRIEDMAN::                Friedman Test
+* KENDALL::                 Kendall's W Test
 * KRUSKAL-WALLIS::          Kruskal-Wallis Test
-* WILCOXON::                Wilcoxon Signed Ranks Test
+* MANN-WHITNEY::            Mann Whitney U Test
+* RUNS::                    Runs Test
 * SIGN::                    The Sign Test
+* WILCOXON::                Wilcoxon Signed Ranks Test
 @end menu
 
 
@@ -764,9 +769,53 @@ If no /EXPECTED subcommand is given, then then equal frequencies
 are expected.
 
 
+@node COCHRAN
+@subsection Cochran Q Test
+@vindex Cochran
+@cindex Cochran Q test
+@cindex Q, Cochran Q
+
+@display
+     [ /COCHRAN = varlist ]
+@end display
+
+The Cochran Q test is used to test for differences between three or more groups.
+The data for @var{varlist} in all cases must assume exactly two distinct values (other than missing values). 
+
+The value of Q will be displayed and its Asymptotic significance based on a chi-square distribution.
+
+@node FRIEDMAN
+@subsection Friedman Test
+@vindex FRIEDMAN
+@cindex Friedman test
+
+@display
+     [ /FRIEDMAN = varlist ]
+@end display
+
+The Friedman test is used to test for differences between repeated measures when there is no indication that the distributions are normally distributed.
+
+A list of variables which contain the measured data must be given.  The procedure prints the sum of ranks for each variable, the test statistic and its significance.
+
+@node KENDALL
+@subsection Kendall's W Test
+@vindex KENDALL
+@cindex Kendall's W test
+@cindex coefficient of concordance
+
+@display
+     [ /KENDALL = varlist ]
+@end display
+
+The Kendall test investigates whether an arbitrary number of related samples come from the 
+same population.
+It is identical to the Friedman test except that the additional statistic W, Kendall's Coefficient of Concordance is printed.
+It has the range [0,1] --- a value of zero indicates no agreement between the samples whereas a value of
+unity indicates complete agreement.
+
+
 @node KRUSKAL-WALLIS
 @subsection Kruskal-Wallis Test
-@comment  node-name,  next,  previous,  up
 @vindex KRUSKAL-WALLIS
 @vindex K-W
 @cindex Kruskal-Wallis test
@@ -789,20 +838,61 @@ of the test will be printed.
 The abbreviated subcommand  K-W may be used in place of KRUSKAL-WALLIS.
 
 
-@node WILCOXON
-@subsection Wilcoxon Matched Pairs Signed Ranks Test
-@comment  node-name,  next,  previous,  up
-@vindex WILCOXON
-@cindex wilcoxon matched pairs signed ranks test
+@node MANN-WHITNEY
+@subsection Mann-Whitney U Test
+@vindex MANN-WHITNEY
+@vindex M-W
+@cindex Mann-Whitney U test
+@cindex U, Mann-Whitney U
 
 @display
-     [ /WILCOXON varlist [ WITH varlist [ (PAIRED) ]]]
+     [ /MANN-WHITNEY = varlist BY var (group1, group2) ]
 @end display
 
-The /WILCOXON subcommand tests for differences between medians of the 
+The Mann-Whitney subcommand is used to test whether two groups of data come from different populations.
+The variables to be tested should be specified in @var{varlist} and the grouping variable, that determines to which group the test variables belong, in @var{var}.
+@var{Var} may be either a string or an alpha variable.
+@var{Group1} and @var{group2} specify the
+two values of @var{var} which determine the groups of the test data.
+Cases for which the @var{var} value is neither @var{group1} or @var{group2} will be ignored.
+
+The value of the Mann-Whitney U statistic, the Wilcoxon W, and the significance will be printed.
+The abbreviated subcommand  M-W may be used in place of MANN-WHITNEY.
+
+
+@node RUNS
+@subsection Runs Test
+@vindex RUNS
+@cindex runs test
+
+@display 
+     [ /RUNS (@{MEAN, MEDIAN, MODE, value@}) varlist ]
+@end display
+
+The /RUNS subcommand tests whether a data sequence is randomly ordered.
+
+It works by examining the number of times a variable's value crosses a given threshold. 
+The desired threshold must be specified within parentheses.
+It may either be specified as a number or as one of MEAN, MEDIAN or MODE.
+Following the threshold specification comes the list of variables whose values are to be
+tested.
+
+The subcommand shows the number of runs, the asymptotic significance based on the
+length of the data.
+
+@node SIGN
+@subsection Sign Test
+@vindex SIGN
+@cindex sign test
+
+@display
+     [ /SIGN varlist [ WITH varlist [ (PAIRED) ]]]
+@end display
+
+The /SIGN subcommand tests for differences between medians of the 
 variables listed.
-The test does not make any assumptions about the variances of the samples.
-It does however assume that the distribution is symetrical.
+The test does not make any assumptions about the
+distribution of the data.
 
 If the @code{WITH} keyword is omitted, then tests for all
 combinations of the listed variables are performed.
@@ -816,20 +906,20 @@ If the @code{WITH} keyword is given, but the
 of variable preceding @code{WITH} against variable following
 @code{WITH} are performed.
 
-
-@node SIGN
-@subsection Sign Test
-@vindex SIGN
-@cindex sign test
+@node WILCOXON
+@subsection Wilcoxon Matched Pairs Signed Ranks Test
+@comment  node-name,  next,  previous,  up
+@vindex WILCOXON
+@cindex wilcoxon matched pairs signed ranks test
 
 @display
-     [ /SIGN varlist [ WITH varlist [ (PAIRED) ]]]
+     [ /WILCOXON varlist [ WITH varlist [ (PAIRED) ]]]
 @end display
 
-The /SIGN subcommand tests for differences between medians of the 
+The /WILCOXON subcommand tests for differences between medians of the 
 variables listed.
-The test does not make any assumptions about the
-distribution of the data.
+The test does not make any assumptions about the variances of the samples.
+It does however assume that the distribution is symetrical.
 
 If the @code{WITH} keyword is omitted, then tests for all
 combinations of the listed variables are performed.
index 6964facd31c9695adcb93c7959e9f5439b9cc516..f1d1cbf2617b649c5393b10428325329c696447d 100644 (file)
@@ -3,7 +3,7 @@
 @cindex transformations
 
 The PSPP procedures examined in this chapter manipulate data and
-prepare the active file for later analyses.  They do not produce output,
+prepare the active dataset for later analyses.  They do not produce output,
 as a rule.
 
 @menu
@@ -14,7 +14,7 @@ as a rule.
 * FLIP::                        Exchange variables with cases.
 * IF::                          Conditionally assigning a calculated value.
 * RECODE::                      Mapping values from one set to another.
-* SORT CASES::                  Sort the active file.
+* SORT CASES::                  Sort the active dataset.
 @end menu
 
 @node AGGREGATE
@@ -37,37 +37,38 @@ variables called @dfn{break variables}.  Several functions are available
 for summarizing case contents.
 
 The OUTFILE subcommand is required and must appear first.  Specify a
-system file, portable file, or scratch file by file name or file
-handle (@pxref{File Handles}).
+system file or portable file by file name or file
+handle (@pxref{File Handles}), or a dataset by its name
+(@pxref{Datasets}).
 The aggregated cases are written to this file.  If @samp{*} is
-specified, then the aggregated cases replace the active file.
-Use of OUTFILE to write a portable file or scratch file is a PSPP extension.
+specified, then the aggregated cases replace the active dataset's data.
+Use of OUTFILE to write a portable file is a PSPP extension.
 
 If OUTFILE=@samp{*} is given, then the subcommand MODE may also be
 specified.
 The mode subcommand has two possible values: ADDVARIABLES or REPLACE.
-In REPLACE mode, the entire active file is replaced by a new file
+In REPLACE mode, the entire active dataset is replaced by a new dataset
 which contains just the break variables and the destination varibles.
 In this mode, the new file will contain as many cases as there are
 unique combinations of the break variables.
 In ADDVARIABLES mode, the destination variables will be appended to 
-the existing active file.
+the existing active dataset.
 Cases which have identical combinations of values in their break
 variables, will receive identical values for the destination variables.
-The number of cases in the active file will remain unchanged.
+The number of cases in the active dataset will remain unchanged.
 Note that if ADDVARIABLES is specified, then the data @emph{must} be
 sorted on the break variables.
 
-By default, the active file will be sorted based on the break variables
-before aggregation takes place.  If the active file is already sorted
+By default, the active dataset will be sorted based on the break variables
+before aggregation takes place.  If the active dataset is already sorted
 or otherwise grouped in terms of the break variables, specify
 PRESORTED to save time.
 PRESORTED is assumed if MODE=ADDVARIABLES is used.
 
-Specify DOCUMENT to copy the documents from the active file into the
+Specify DOCUMENT to copy the documents from the active dataset into the
 aggregate file (@pxref{DOCUMENT}).  Otherwise, the aggregate file will
 not contain any documents, even if the aggregate file replaces the
-active file.
+active dataset.
 
 Normally, only a single case (for SD and SD., two cases) need be
 non-missing in each group for the aggregate variable to be
@@ -80,7 +81,7 @@ between OUTFILE and BREAK.
 
 At least one break variable must be specified on BREAK, a
 required subcommand.  The values of these variables are used to divide
-the active file into groups to be summarized.  In addition, at least
+the active dataset into groups to be summarized.  In addition, at least
 one @var{dest_var} must be specified.
 
 One or more sets of aggregation variables must be specified.  Each set
@@ -281,7 +282,7 @@ Using @cmd{COMPUTE} to assign to a variable specified on @cmd{LEAVE}
 (@pxref{LEAVE}) resets the variable's left state.  Therefore,
 @code{LEAVE} should be specified following @cmd{COMPUTE}, not before.
 
-@cmd{COMPUTE} is a transformation.  It does not cause the active file to be
+@cmd{COMPUTE} is a transformation.  It does not cause the active dataset to be
 read.
 
 When @cmd{COMPUTE} is specified following @cmd{TEMPORARY}
@@ -400,10 +401,10 @@ DESCRIPTIVES QVALID /STATISTICS=MEAN.
 FLIP /VARIABLES=var_list /NEWNAMES=var_name.
 @end display
 
-@cmd{FLIP} transposes rows and columns in the active file.  It
+@cmd{FLIP} transposes rows and columns in the active dataset.  It
 causes cases to be swapped with variables, and vice versa.
 
-All variables in the transposed active file are numeric.  String
+All variables in the transposed active dataset are numeric.  String
 variables take on the system-missing value in the transposed file.
 
 No subcommands are required.  If specified, the VARIABLES subcommand
@@ -430,7 +431,7 @@ FLIP operation aborts.
 The resultant dictionary contains a CASE_LBL variable, a string
 variable of width 8, which stores the names of the variables in the
 dictionary before the transposition.  Variables names longer than 8
-characters are truncated.  If the active file is subsequently
+characters are truncated.  If the active dataset is subsequently
 transposed using @cmd{FLIP}, this variable can be used to recreate the
 original variable names.
 
@@ -552,7 +553,7 @@ separate them from the previous recodings.
 SORT CASES BY var_list[(@{D|A@}] [ var_list[(@{D|A@}] ] ...
 @end display
 
-@cmd{SORT CASES} sorts the active file by the values of one or more
+@cmd{SORT CASES} sorts the active dataset by the values of one or more
 variables.
 
 Specify BY and a list of variables to sort by.  By default, variables
@@ -569,7 +570,7 @@ cases.
 
 @cmd{SORT CASES} is a procedure.  It causes the data to be read.
 
-@cmd{SORT CASES} attempts to sort the entire active file in main memory.
+@cmd{SORT CASES} attempts to sort the entire active dataset in main memory.
 If workspace is exhausted, it falls back to a merge sort algorithm that
 involves creates numerous temporary files.
 
index 9f57a76739b43c0a7921b96df18bf66c32905e26..fdad9a59ac7d74990f8ba6a1323d15ea17da1311 100644 (file)
@@ -9,17 +9,18 @@ they take effect only once, unconditionally, at the time that they are
 encountered in the input.
 
 @menu
-* ADD DOCUMENT::                Add documentary text to the active file.
+* ADD DOCUMENT::                Add documentary text to the active dataset.
+* CACHE::                       Ignored for compatibility.
 * CD::                          Change the current directory.
 * COMMENT::                     Document your syntax file.
-* DOCUMENT::                    Document the active file.
-* DISPLAY DOCUMENTS::           Display active file documents.
-* DISPLAY FILE LABEL::          Display the active file label.
-* DROP DOCUMENTS::              Remove documents from the active file.
+* DOCUMENT::                    Document the active dataset.
+* DISPLAY DOCUMENTS::           Display active dataset documents.
+* DISPLAY FILE LABEL::          Display the active dataset label.
+* DROP DOCUMENTS::              Remove documents from the active dataset.
 * ECHO::                        Write a string to the output stream.
 * ERASE::                       Erase a file.
 * EXECUTE::                     Execute pending transformations.
-* FILE LABEL::                  Set the active file's label.
+* FILE LABEL::                  Set the active dataset's label.
 * FINISH::                      Terminate the PSPP session.
 * HOST::                        Temporarily return to the operating system.
 * INCLUDE::                     Include a file within the current one.
@@ -44,14 +45,24 @@ ADD DOCUMENT
 
 
 @cmd{ADD DOCUMENT} adds one or more lines of descriptive commentary to 
-the active file.  Documents added in this way are saved to system files.
+the active dataset.  Documents added in this way are saved to system files.
 They can be viewed using @cmd{SYSFILE INFO} or @cmd{DISPLAY
-DOCUMENTS}.  They can be removed from the active file with @cmd{DROP
+DOCUMENTS}.  They can be removed from the active dataset with @cmd{DROP
 DOCUMENTS}.
 
 Each line of documentary text must be enclosed in quotation marks, and 
 may not be more than 80 bytes long. @xref{DOCUMENT}.
 
+@node CACHE
+@section CACHE
+@vindex CACHE
+
+@display
+CACHE.
+@end display
+
+This command is accepted, for compatibility, but it has no effect.
+
 @node CD
 @section CD
 @vindex CD
@@ -92,9 +103,9 @@ DOCUMENT @var{documentary_text}.
 @end display
 
 @cmd{DOCUMENT} adds one or more lines of descriptive commentary to the
-active file.  Documents added in this way are saved to system files.
+active dataset.  Documents added in this way are saved to system files.
 They can be viewed using @cmd{SYSFILE INFO} or @cmd{DISPLAY
-DOCUMENTS}.  They can be removed from the active file with @cmd{DROP
+DOCUMENTS}.  They can be removed from the active dataset with @cmd{DROP
 DOCUMENTS}.
 
 Specify the @var{documentary text} following the DOCUMENT keyword.  
@@ -112,7 +123,7 @@ the command with a dot or a blank line. @xref{ADD DOCUMENT}.
 DISPLAY DOCUMENTS.
 @end display
 
-@cmd{DISPLAY DOCUMENTS} displays the documents in the active file.  Each
+@cmd{DISPLAY DOCUMENTS} displays the documents in the active dataset.  Each
 document is preceded by a line giving the time and date that it was
 added.  @xref{DOCUMENT}.
 
@@ -125,7 +136,7 @@ DISPLAY FILE LABEL.
 @end display
 
 @cmd{DISPLAY FILE LABEL} displays the file label contained in the
-active file,
+active dataset,
 if any.  @xref{FILE LABEL}.
 
 This command is a PSPP extension.
@@ -138,10 +149,10 @@ This command is a PSPP extension.
 DROP DOCUMENTS.
 @end display
 
-@cmd{DROP DOCUMENTS} removes all documents from the active file.
+@cmd{DROP DOCUMENTS} removes all documents from the active dataset.
 New documents can be added with @cmd{DOCUMENT} (@pxref{DOCUMENT}).
 
-@cmd{DROP DOCUMENTS} changes only the active file.  It does not modify any
+@cmd{DROP DOCUMENTS} changes only the active dataset.  It does not modify any
 system files stored on disk.
 
 @node ECHO
@@ -176,7 +187,7 @@ This command cannot be used if the SAFER setting is active.
 EXECUTE.
 @end display
 
-@cmd{EXECUTE} causes the active file to be read and all pending
+@cmd{EXECUTE} causes the active dataset to be read and all pending
 transformations to be executed.
 
 @node FILE LABEL
@@ -187,7 +198,7 @@ transformations to be executed.
 FILE LABEL file_label.
 @end display
 
-@cmd{FILE LABEL} provides a title for the active file.  This
+@cmd{FILE LABEL} provides a title for the active dataset.  This
 title will be saved into system files and portable files that are
 created during this PSPP run.
 
@@ -231,7 +242,7 @@ subshell.
 @vindex INCLUDE
 
 @display
-        INCLUDE [FILE=]'file-name'.
+        INCLUDE [FILE=]'file-name' [ENCODING='encoding'].
 @end display
 
 @cmd{INCLUDE} causes the PSPP command processor to read an
@@ -242,19 +253,11 @@ stop and no more commands will be processed.
 Include files may be nested to any depth, up to the limit of available
 memory.
 
+The @cmd{INSERT} command (@pxref{INSERT}) is a more flexible
+alternative to @cmd{INCLUDE}.  An INCLUDE command acts the same as
+INSERT with ERROR=STOP CD=NO SYNTAX=BATCH specified.
 
-The @cmd{INSERT} command (@pxref{INSERT}) may be used instead of
-@cmd{INCLUDE} if you require more flexible options.
-The syntax 
-@example
-INCLUDE FILE=@var{file-name}.
-@end example
-@noindent 
-functions identically to 
-@example
-INSERT FILE=@var{file-name} ERROR=STOP CD=NO SYNTAX=BATCH.
-@end example
-
+The optional ENCODING subcommand has the same meaning as on INSERT.
 
 @node INSERT
 @section INSERT
@@ -264,7 +267,8 @@ INSERT FILE=@var{file-name} ERROR=STOP CD=NO SYNTAX=BATCH.
      INSERT [FILE=]'file-name'
         [CD=@{NO,YES@}]
         [ERROR=@{CONTINUE,STOP@}]
-        [SYNTAX=@{BATCH,INTERACTIVE@}].
+        [SYNTAX=@{BATCH,INTERACTIVE@}]
+        [ENCODING='encoding'].
 @end display
 
 @cmd{INSERT} is similar to @cmd{INCLUDE} (@pxref{INCLUDE}) 
@@ -292,6 +296,37 @@ the included file must conform to interactive syntax
 conventions. @xref{Syntax Variants}.
 The default setting is @samp{SYNTAX=BATCH}.
 
+ENCODING optionally specifies the character set used by the included
+file.  Its argument, which is not case-sensitive, must be in one of
+the following forms:
+
+@table @asis
+@item @code{Locale}
+The encoding used by the system locale, or as overridden by the SET
+LOCALE command (@pxref{SET}).  On Unix systems, environment variables,
+e.g.@: @env{LANG} or @env{LC_ALL}, determine the system locale.
+
+@item IANA character set name
+One of the character set names listed by IANA at
+@uref{http://www.iana.org/assignments/character-sets}.  Some examples
+are @code{ASCII} (United States), @code{ISO-8859-1} (western Europe),
+@code{EUC-JP} (Japan), and @code{windows-1252} (Windows).  Not all
+systems support all character sets.
+
+@item @code{Auto}
+@item @code{Auto,@var{encoding}}
+Automatically detects whether a syntax file is encoded in
+@var{encoding} or in a Unicode encoding such as UTF-8, UTF-16, or
+UTF-32.  The @var{encoding} may be an IANA character set name or
+@code{Locale} (the default).  Only ASCII compatible encodings can
+automatically be distinguished from UTF-8 (the most common locale
+encodings are all ASCII-compatible).
+@end table
+
+When ENCODING is not specified, the default is taken from the
+@option{--syntax-encoding} command option, if it was specified, and
+otherwise it is @code{Auto}.
+
 @node PERMISSIONS
 @section PERMISSIONS
 @vindex PERMISSIONS
@@ -347,19 +382,13 @@ SET
         /RIB=@{NATIVE,MSBFIRST,LSBFIRST,VAX@}
         /RRB=@{NATIVE,ISL,ISB,IDL,IDB,VF,VD,VG,ZS,ZL@}
 
-(program input)
-        /ENDCMD='.'
-        /NULLINE=@{ON,OFF@}
-
 (interaction)
-        /CPROMPT='cprompt_string'
-        /DPROMPT='dprompt_string'
         /MXERRS=max_errs
         /MXWARNS=max_warnings
-        /PROMPT='prompt'
         /WORKSPACE=workspace_size
 
-(program execution)
+(syntax execution)
+        /LOCALE='locale'
         /MEXPAND=@{ON,OFF@}
         /MITERATE=max_iterations
         /MNEST=max_nest
@@ -519,30 +548,10 @@ formats are only for use with very old input files.
 The default is NATIVE.
 @end table
 
-Program input subcommands affect the way that programs are parsed when
-they are typed interactively or run from a command file.  They are
-
-@table @asis
-@item ENDCMD
-This is a single character indicating the end of a command.  The default
-is @samp{.}.  Don't change this.
-
-@item NULLINE
-Whether a blank line is interpreted as ending the current command.  The
-default is ON.
-@end table
-
 Interaction subcommands affect the way that PSPP interacts with an
 online user.  The interaction subcommands are
 
 @table @asis
-@item CPROMPT
-The command continuation prompt.  The default is @samp{    > }.
-
-@item DPROMPT
-Prompt used when expecting data input within @cmd{BEGIN DATA} (@pxref{BEGIN
-DATA}).  The default is @samp{data> }.
-
 @item MXERRS
 The maximum number of errors before PSPP halts processing of the current
 command file.  The default is 50.
@@ -554,15 +563,22 @@ The special value of zero means that all warning situations should be ignored.
 No warnings will be issued, except a single initial warning advising the user
 that warnings will not be given.
 The default value is 100.
-
-@item PROMPT
-The command prompt.  The default is @samp{PSPP> }.
 @end table
 
-Program execution subcommands control the way that PSPP commands
-execute.  The program execution subcommands are
+Syntax execution subcommands control the way that PSPP commands
+execute.  The syntax execution subcommands are
 
 @table @asis
+@item LOCALE
+Overrides the system locale for the purpose of reading and writing
+syntax and data files.  The argument should be a locale name in the
+general form @code{language_country.encoding}, where @code{language}
+and @code{country} are 2-character language and country abbreviations,
+respectively, and @code{encoding} is an IANA character set name.
+Example locales are @code{en_US.UTF-8} (UTF-8 encoded English as
+spoken in the United States) and @code{ja_JP.EUC-JP} (EUC-JP encoded
+Japanese as spoken in Japan).
+
 @item MEXPAND
 @itemx MITERATE
 @itemx MNEST
@@ -796,7 +812,6 @@ SHOW
         [CCE]
         [COPYING]
         [DECIMALS]
-        [ENDCMD]
         [FORMAT]
         [LENGTH]
         [MXERRS]
index 6b4e574e724903a2dc9a42a5deecbfe00f2e4523..650c7d2c6143d05acb34af577a1458d82b4c227d 100644 (file)
@@ -1,13 +1,13 @@
 @node Variable Attributes
 @chapter Manipulating variables
 
-The variables in the active file dictionary are important.  There are
+The variables in the active dataset dictionary are important.  There are
 several utility functions for examining and adjusting them.
 
 @menu
 * ADD VALUE LABELS::            Add value labels to variables.
 * DELETE VARIABLES::            Delete variables.
-* DISPLAY::                     Display information about the active file.
+* DISPLAY::                     Display information about the active dataset.
 * FORMATS::                     Set print and write formats.
 * LEAVE::                       Don't clear variables between cases.
 * MISSING VALUES::              Set missing values for variables.
@@ -73,13 +73,13 @@ DISPLAY [SORTED] @@ATTRIBUTES [[/VARIABLES=]var_list].
 DISPLAY [SORTED] VECTORS.
 @end display
 
-@cmd{DISPLAY} displays information about the active file.  A variety
+@cmd{DISPLAY} displays information about the active dataset.  A variety
 of different forms of information can be requested.
 
 The following keywords primarily cause information about variables to
 be displayed.  With these keywords, by default information is
-displayed about all variable in the active file, in the order that
-variables occur in the active file dictionary.  The SORTED keyword
+displayed about all variable in the active dataset, in the order that
+variables occur in the active dataset dictionary.  The SORTED keyword
 causes output to be sorted alphabetically by variable name.  The
 VARIABLES subcommand limits output to the specified variables.
 
@@ -89,7 +89,7 @@ The variables' names are displayed.
 
 @item INDEX
 The variables' names are displayed along with a value describing their
-position within the active file dictionary.
+position within the active dataset dictionary.
 
 @item LABELS
 Variable names, positions, and variable labels are displayed.
@@ -127,19 +127,20 @@ FILE LABEL}.
 @vindex FORMATS
 
 @display
-FORMATS var_list (fmt_spec).
+FORMATS var_list (fmt_spec) [var_list (fmt_spec)]@dots{}.
 @end display
 
 @cmd{FORMATS} set both print and write formats for the specified
-numeric variables to the specified format specification.
+variables to the specified format specification.
 @xref{Input and Output Formats}.
 
 Specify a list of variables followed by a format specification in
 parentheses.  The print and write formats of the specified variables
-will be changed.
+will be changed.  All of the variables listed together must have
+the same type and, for string variables, the same width.
 
-Additional lists of variables and formats may be included if they are
-delimited by a slash (@samp{/}).
+Additional lists of variables and formats may be included following
+the first one.
 
 @cmd{FORMATS} takes effect immediately.  It is not affected by
 conditional and looping structures such as @cmd{DO IF} or @cmd{LOOP}.
@@ -156,7 +157,7 @@ LEAVE var_list.
 reinitialized whenever a new case is processed.
 
 Normally, when a data file is processed, every variable in the active
-file is initialized to the system-missing value or spaces at the
+dataset is initialized to the system-missing value or spaces at the
 beginning of processing for each case.  When a variable has been
 specified on @cmd{LEAVE}, this is not the case.  Instead, that variable is
 initialized to 0 (not system-missing) or spaces for the first case.
@@ -241,20 +242,20 @@ MODIFY VARS
 @end display
 
 @cmd{MODIFY VARS} reorders, renames, and deletes variables in the
-active file.
+active dataset.
 
 At least one subcommand must be specified, and no subcommand may be
 specified more than once.  DROP and KEEP may not both be specified.
 
 The REORDER subcommand changes the order of variables in the active
-file.  Specify one or more lists of variable names in parentheses.  By
+dataset.  Specify one or more lists of variable names in parentheses.  By
 default, each list of variables is rearranged into the specified order.
 To put the variables into the reverse of the specified order, put
 keyword BACKWARD before the parentheses.  To put them into alphabetical
 order in the dictionary, specify keyword ALPHA before the parentheses.
 BACKWARD and ALPHA may also be combined.
 
-To rename variables in the active file, specify RENAME, an equals sign
+To rename variables in the active dataset, specify RENAME, an equals sign
 (@samp{=}), and lists of the old variable names and new variable names
 separated by another equals sign within parentheses.  There must be the
 same number of old and new variable names.  Each old variable is renamed to
@@ -262,10 +263,10 @@ the corresponding new variable name.  Multiple parenthesized groups of
 variables may be specified.
 
 The DROP subcommand deletes a specified list of variables from the
-active file.
+active dataset.
 
 The KEEP subcommand keeps the specified list of variables in the active
-file.  Any unlisted variables are deleted from the active file.
+dataset.  Any unlisted variables are deleted from the active dataset.
 
 MAP is currently ignored.
 
@@ -406,11 +407,11 @@ response sets are currently used only by third party software.
 @vindex PRINT FORMATS
 
 @display
-PRINT FORMATS var_list (fmt_spec).
+PRINT FORMATS var_list (fmt_spec) [var_list (fmt_spec)]@dots{}.
 @end display
 
 @cmd{PRINT FORMATS} sets the print formats for the specified
-numeric variables to the specified format specification.
+variables to the specified format specification.
 
 Its syntax is identical to that of @cmd{FORMATS} (@pxref{FORMATS}),
 but @cmd{PRINT FORMATS} sets only print formats, not write formats.
@@ -424,7 +425,7 @@ RENAME VARIABLES (old_names=new_names)@dots{} .
 @end display
 
 @cmd{RENAME VARIABLES} changes the names of variables in the active
-file.  Specify lists of the old variable names and new
+dataset.  Specify lists of the old variable names and new
 variable names, separated by an equals sign (@samp{=}), within
 parentheses.  There must be the same number of old and new variable
 names.  Each old variable is renamed to the corresponding new variable
@@ -453,6 +454,10 @@ To set up value labels for a set of variables, specify the
 variable names after a slash (@samp{/}), followed by a list of values
 and their associated labels, separated by spaces.
 
+Value labels in output are normally broken into lines automatically.
+Put @samp{\n} in a label string to force a line break at that point.
+The label may still be broken into lines at additional points.
+
 Before @cmd{VALUE LABELS} is executed, any existing value labels
 are cleared from the variables specified.  Use @cmd{ADD VALUE LABELS}
 (@pxref{ADD VALUE LABELS}) to add value labels without clearing those
@@ -491,7 +496,7 @@ VARIABLE ATTRIBUTE
 @end display
 
 @cmd{VARIABLE ATTRIBUTE} adds, modifies, or removes user-defined
-attributes associated with variables in the active file.  Custom
+attributes associated with variables in the active dataset.  Custom
 variable attributes are not interpreted by PSPP, but they are saved as
 part of system files and may be used by other software that reads
 them.
@@ -524,7 +529,7 @@ square brackets to delete a single element of an attribute array.  In
 the latter case, all the array elements numbered higher than the
 deleted element are shifted down, filling the vacated position.
 
-To associate custom attributes with the entire active file, instead of
+To associate custom attributes with the entire active dataset, instead of
 with particular variables, use @cmd{DATAFILE ATTRIBUTE} (@pxref{DATAFILE ATTRIBUTE}) instead.
 
 @cmd{VARIABLE ATTRIBUTE} takes effect immediately.  It is not affected
@@ -655,11 +660,10 @@ Variables within a vector may be referenced in expressions using
 @vindex WRITE FORMATS
 
 @display
-WRITE FORMATS var_list (fmt_spec).
+WRITE FORMATS var_list (fmt_spec) [var_list (fmt_spec)]@dots{}.
 @end display
 
-@cmd{WRITE FORMATS} sets the write formats for the specified numeric
-variables
+@cmd{WRITE FORMATS} sets the write formats for the specified variables
 to the specified format specification.  Its syntax is identical to
 that of FORMATS (@pxref{FORMATS}), but @cmd{WRITE FORMATS} sets only
 write formats, not print formats.
index 3596e3485f00bc411ae2418fdbc5aa5dec503a9f..09330bd787955de63a4c5ccff9bce47321e716e7 100644 (file)
@@ -4,7 +4,6 @@
 #include "psppire-dialog.h"
 #include <string.h>
 #include <assert.h>
-#include <string.h>
 #include <gladeui/glade.h>
 
 
index 760b0fd12ad487fca4a1c957e3d395ab741a00e3..ecadf742cbb9e0b874bf207ecaeae832072e17b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2006, 2008, 2009 Free Software Foundation
+  Copyright (C) 2006, 2008, 2009, 2011 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
@@ -2721,13 +2721,17 @@ psppire_sheet_select_range (PsppireSheet *sheet, const PsppireSheetRange *range)
 void
 psppire_sheet_unselect_range (PsppireSheet *sheet)
 {
-  GdkRectangle area;
   sheet->select_status = PSPPIRE_SHEET_NORMAL;
 
-  rectangle_from_range (sheet, &sheet->range, &area);
-  area.x++;
-  area.y++;
-  gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);      
+  if (sheet->sheet_window != NULL)
+    {
+      GdkRectangle area;
+
+      rectangle_from_range (sheet, &sheet->range, &area);
+      area.x++;
+      area.y++;
+      gdk_window_invalidate_rect (sheet->sheet_window, &area, FALSE);
+    }
 
   g_signal_emit (sheet, sheet_signals [SELECT_COLUMN], 0, -1);
   g_signal_emit (sheet, sheet_signals [SELECT_ROW], 0, -1);  
index 400aeda7b12ce45ada26c7dc138d8b5bf0224f4a..143eb549e1a784c4df7b4c7b89fa644118f1056e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - computes sample statistics.
-   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010, 2011 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
@@ -34,6 +34,7 @@
 #include "minmax.h"
 #include <libpspp/message.h>
 #include <libpspp/version.h>
+#include <libpspp/i18n.h>
 #include <gl/xalloc.h>
 #include <data/dictionary.h>
 #include <data/case.h>
@@ -87,7 +88,7 @@ struct sysreader_info
 
 /*  A message handler which writes messages to PSPP::errstr */
 static void
-message_handler (const struct msg *m)
+message_handler (const struct msg *m, void *aux)
 {
  SV *errstr = get_sv("PSPP::errstr", TRUE);
  sv_setpv (errstr, m->text);
@@ -178,7 +179,7 @@ CODE:
  assert (0 == strncmp (ver, bare_version, strlen (ver)));
 
  i18n_init ();
- msg_init (NULL, message_handler);
+ msg_set_handler (message_handler, NULL);
  settings_init (0, 0);
  fh_init ();
 
@@ -222,7 +223,7 @@ MODULE = PSPP               PACKAGE = PSPP::Dict
 struct dictionary *
 pxs_dict_new()
 CODE:
- RETVAL = dict_create ();
+ RETVAL = dict_create ("UTF-8");
 OUTPUT:
  RETVAL
 
@@ -254,7 +255,7 @@ set_documents (dict, docs)
  struct dictionary *dict
  char *docs
 CODE:
- dict_set_documents (dict, docs);
+ dict_set_documents_string (dict, docs);
 
 
 void
@@ -262,7 +263,7 @@ add_document (dict, doc)
  struct dictionary *dict
  char *doc
 CODE:
- dict_add_document_line (dict, doc);
+ dict_add_document_line (dict, doc, false);
 
 
 void
@@ -325,7 +326,7 @@ pxs_dict_create_var (dict, name, ip_fmt)
 INIT:
  SV *errstr = get_sv("PSPP::errstr", TRUE);
  sv_setpv (errstr, "");
- if ( ! var_is_plausible_name (name, false))
+ if ( ! id_is_plausible (name, false))
   {
     sv_setpv (errstr, "The variable name is not valid.");
     XSRETURN_UNDEF;
@@ -375,7 +376,7 @@ set_label (var, label)
  struct variable *var;
  char *label
 CODE:
-  var_set_label (var, label);
+  var_set_label (var, label, false);
 
 
 void
@@ -591,7 +592,6 @@ CODE:
  struct file_handle *fh =
   fh_create_file (NULL, name, fh_default_properties () );
  struct sysfile_info *sfi = xmalloc (sizeof (*sfi));
- dict_set_encoding (dict, "UTF-8");
  sfi->writer = sfm_open_writer (fh, dict, opts);
  sfi->dict = dict;
  sfi->opened = true;
@@ -659,7 +659,7 @@ CODE:
        char *error;
        bool ok;
 
-       error = data_in (ss, LEGACY_NATIVE, ifmt->type,
+       error = data_in (ss, SvUTF8(sv) ? UTF8: "iso-8859-1", ifmt->type,
                         case_data_rw (c, v), var_get_width (v),
                         dict_get_encoding (sfi->dict));
         ok = error == NULL;
@@ -684,7 +684,8 @@ CODE:
    union value *val = case_data_rw (c, v);
    value_set_missing (val, var_get_width (v));
  }
- RETVAL = casewriter_write (sfi->writer, c);
+ casewriter_write (sfi->writer, c);
+ RETVAL = 1;
  finish:
  free (vv);
 OUTPUT:
index fce5b74dd2eede1a4d472563cbb4413b359772fa..6e267f6fb8f535c5bfff0aedd0629f555161639e 100644 (file)
@@ -72,7 +72,7 @@ sub run_pspp_syntax_cmp
   ok ($d->get_var_cnt () == 0);
 
   $d->set_label ("My Dictionary");
-  $d->set_documents ("These Documents");
+  $d->add_document ("These Documents");
 
   # Tests for variable creation
 
@@ -130,7 +130,7 @@ sub run_pspp_syntax_cmp
                          )
                         );
 
-  $d->set_documents ("This should not appear");
+  $d->add_document ("This should not appear");
   $d->clear_documents ();
   $d->add_document ("This is a document line");
 
@@ -185,11 +185,9 @@ name,Format: A20,,2
 ,Display Alignment: Left,,
 ,Display Width: 20,,
 
-File label:
+File label: This is the file label
 
-This is the file label
-
-Documents in the active file:
+Documents in the active dataset:
 
 This is a document line
 
index 945e2557bf4ae2234ac23dcee431c0b3cb11aa0b..92015ef95cd8b579d7d543a8d69c70c8e2e4e890 100644 (file)
@@ -4,7 +4,7 @@ XGETTEXT=xgettext
 MSGMERGE=msgmerge
 MSGFMT=msgfmt
 
-POFILES=po/ca.po po/en_GB.po po/es.po po/nl.po po/pt_BR.po
+POFILES=po/ca.po po/en_GB.po po/es.po po/lt.po po/nl.po po/pt_BR.po
 
 POTFILE=po/$(DOMAIN).pot
 
index 464b68b9a768ea0f681bd0d56c29121d881ae102..3058e37e53de883c2c56ff65fddaf23876d0db3b 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,24 +1,30 @@
-# Catalan messages for PSPS
+# Catalan messages for PSPP
 # Copyright (C) 2009 Free Software Foundation, Inc.
 # This file is distributed under the same licence as the pspp package.
+#
 # Francisco J. Miguel Quesada <Miguel.Quesada@uab.cat>, 2009.
 # Palmira Payá Sanchez, 2009.
 # Javier Gómez Serrano, 2009.
-# F. J. Miguel Quesada <miguel.quesada@uab.cat>, 2010.
-#
+# Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>, 2010.
+# Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>, 2011.
 msgid ""
 msgstr ""
-"Project-Id-Version: pspp-0.7.5\n"
+"Project-Id-Version: pspp-0.7.7\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2010-05-21 16:40-0700\n"
-"PO-Revision-Date: 2010-10-11 13:23+0200\n"
+"POT-Creation-Date: 2011-03-24 20:36-0700\n"
+"PO-Revision-Date: 2011-05-02 21:52+0200\n"
 "Last-Translator: Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>\n"
 "Language-Team: Catalan <ca@dodds.net>\n"
+"Language: ca\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
+#: src/ui/gui/helper.c:194
+msgid "Sorry. The help system hasn't yet been implemented."
+msgstr "Disculpeu. El sistema d'ajuda encara no ha estat implementat."
+
 #: src/ui/gui/psppire-buttonbox.c:275 src/ui/gui/psppire-buttonbox.c:437
 msgid "Continue"
 msgstr "Continuar"
@@ -48,12 +54,12 @@ msgid "Paste"
 msgstr "Enganxa"
 
 #: src/ui/gui/psppire-dictview.c:466 src/language/dictionary/split-file.c:82
-#: src/language/dictionary/sys-file-info.c:150
-#: src/language/dictionary/sys-file-info.c:340
-#: src/language/dictionary/sys-file-info.c:664
-#: src/language/stats/descriptives.c:881
-#: src/language/data-io/data-parser.c:649
-#: src/language/data-io/data-parser.c:688 src/language/data-io/print.c:403
+#: src/language/dictionary/sys-file-info.c:149
+#: src/language/dictionary/sys-file-info.c:334
+#: src/language/dictionary/sys-file-info.c:658
+#: src/language/stats/descriptives.c:895
+#: src/language/data-io/data-parser.c:683
+#: src/language/data-io/data-parser.c:722 src/language/data-io/print.c:403
 msgid "Variable"
 msgstr "Variable"
 
@@ -66,31 +72,31 @@ msgstr "Prefereixo les etiquetes de variable"
 msgid "Var%d"
 msgstr "Var%d"
 
-#: src/data/any-reader.c:56
+#: src/data/any-reader.c:60
 #, c-format
-msgid "An error occurred while opening \"%s\": %s."
-msgstr "S'ha produït un error en obrir \"%s\": %s."
+msgid "An error occurred while opening `%s': %s."
+msgstr "S'ha produït un error en obrir `%s': %s."
 
-#: src/data/any-reader.c:101
+#: src/data/any-reader.c:105
 #, c-format
-msgid "\"%s\" is not a system or portable file."
-msgstr "\"%s\" no és un arxiu del sistema o portàtil."
+msgid "`%s' is not a system or portable file."
+msgstr "`%s' no és un arxiu del sistema o portàtil."
 
-#: src/data/any-reader.c:107 src/data/any-writer.c:63
+#: src/data/any-reader.c:111 src/data/any-writer.c:67
 msgid "The inline file is not allowed here."
 msgstr "L'arxiu en línia no està permès aquí."
 
-#: src/data/calendar.c:81
+#: src/data/calendar.c:100
 #, c-format
 msgid "Month %d is not in acceptable range of 0 to 13."
 msgstr "El mes %d no està a l'interval acceptable de 0 a 13."
 
-#: src/data/calendar.c:89
+#: src/data/calendar.c:110
 #, c-format
 msgid "Day %d is not in acceptable range of 0 to 31."
 msgstr "El dia %d no hi és a l'interval acceptable de 0 a 31."
 
-#: src/data/calendar.c:96
+#: src/data/calendar.c:119
 #, c-format
 msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
 msgstr "La data %04d-%d-%d és anterior de la data acceptada més antiga, 1582-10-15."
@@ -99,127 +105,141 @@ msgstr "La data %04d-%d-%d és anterior de la data acceptada més antiga, 1582-1
 msgid "At least one case in the data read had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
 msgstr "Almenys un cas a la lectura de dades tenia un valor de ponderació que és perdut d'usuari, de sistema, zero o negatiu. Aquest(s) cas(os) van ser ignorat(s)."
 
-#: src/data/data-in.c:274 src/data/data-in.c:464
+#. TRANSLATORS: this fragment will be interpolated into messages in fh_lock()
+#. that identify types of files.
+#: src/data/csv-file-writer.c:154
+msgid "CSV file"
+msgstr "arxiu CSV"
+
+#: src/data/csv-file-writer.c:163 src/data/sys-file-writer.c:219
+#, c-format
+msgid "Error opening `%s' for writing as a system file: %s."
+msgstr "Error en obrir `%s' per gravar com arxiu de sistema: %s."
+
+#: src/data/csv-file-writer.c:464
+#, c-format
+msgid "An I/O error occurred writing CSV file `%s'."
+msgstr "S'ha produït un error de E/S al desar l'arxiu de sistema `%s'."
+
+#: src/data/data-in.c:171
+#, c-format
+msgid "Data is not valid as format %s: %s"
+msgstr "Dades no vàlides com a format %s: %s."
+
+#: src/data/data-in.c:376 src/data/data-in.c:552
 msgid "Field contents are not numeric."
 msgstr "El contingut del camp no és numèric."
 
-#: src/data/data-in.c:276 src/data/data-in.c:466
+#: src/data/data-in.c:378 src/data/data-in.c:554
 msgid "Number followed by garbage."
 msgstr "Nombre seguit per escombraria."
 
-#: src/data/data-in.c:287
+#: src/data/data-in.c:391
 msgid "Invalid numeric syntax."
 msgstr "Sintaxi numèrica no vàlida."
 
-#: src/data/data-in.c:296 src/data/data-in.c:479
+#: src/data/data-in.c:399 src/data/data-in.c:570
 msgid "Too-large number set to system-missing."
 msgstr "Nombre massa gran definit com a perdut del sistema."
 
-#: src/data/data-in.c:301 src/data/data-in.c:484
+#: src/data/data-in.c:405 src/data/data-in.c:576
 msgid "Too-small number set to zero."
 msgstr "Nombre massa petit definit com a zero. "
 
-#: src/data/data-in.c:327
+#: src/data/data-in.c:425
 msgid "All characters in field must be digits."
 msgstr "Tots els caràcters del camp han de ser dígits."
 
-#: src/data/data-in.c:350
+#: src/data/data-in.c:444
 msgid "Unrecognized character in field."
 msgstr "Caràcter no reconegut en el camp."
 
-#: src/data/data-in.c:374 src/data/data-in.c:650
+#: src/data/data-in.c:465 src/data/data-in.c:728
 msgid "Field must have even length."
 msgstr "Camp ha de tenir l'amplada divisible per 2 (parell)."
 
-#: src/data/data-in.c:379 src/data/data-in.c:661
+#: src/data/data-in.c:467 src/data/data-in.c:731
 msgid "Field must contain only hex digits."
 msgstr "Camp ha de contenir només dígits hexadecimals."
 
-#: src/data/data-in.c:700 src/data/data-in.c:747
+#: src/data/data-in.c:543
+msgid "Invalid zoned decimal syntax."
+msgstr "Sintaxi decimal no vàlida."
+
+#: src/data/data-in.c:643 src/data/data-in.c:649
+msgid "Invalid syntax for P field."
+msgstr "Sintaxi no vàlida per un camp P."
+
+#: src/data/data-in.c:767 src/data/data-in.c:813
 msgid "Syntax error in date field."
 msgstr "Error sintàctic en el camp de dades."
 
-#: src/data/data-in.c:716
+#: src/data/data-in.c:782
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr "Dia (%ld) ha de ser entre 1 i 31."
 
-#: src/data/data-in.c:763
+#: src/data/data-in.c:827
 msgid "Delimiter expected between fields in date."
 msgstr "A la data s'espera un delimitador entre els camps."
 
-#: src/data/data-in.c:837
+#: src/data/data-in.c:901
 msgid "Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names."
 msgstr "Format de mes no reconegut. Els mesos poden ser especificats com a números Aràbics o Romans, o com a mínim 3 lletres dels seus noms en Anglès."
 
-#: src/data/data-in.c:864
+#: src/data/data-in.c:928
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr "Any (%ld) ha de ser entre 1582 i 19999."
 
-#: src/data/data-in.c:876
+#: src/data/data-in.c:939
 #, c-format
-msgid "Trailing garbage \"%.*s\" following date."
-msgstr "Escombraria  \"%.*s\" darrera de la data."
+msgid "Trailing garbage `%.*s' following date."
+msgstr "Escombraria  `%.*s' darrera de la data."
 
-#: src/data/data-in.c:892
+#: src/data/data-in.c:953
 msgid "Julian day must have exactly three digits."
 msgstr "Dia Julià ha de tenir exactament tres dígits."
 
-#: src/data/data-in.c:897
+#: src/data/data-in.c:955
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr "Dia Julià (%ld) ha de ser entre 1 i 366."
 
-#: src/data/data-in.c:921
+#: src/data/data-in.c:979
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr "Trimestre (%ld) ha de ser entre 1 i 4."
 
-#: src/data/data-in.c:941
+#: src/data/data-in.c:1000
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr "Setmana (%ld) ha de ser entre 1 i 53."
 
-#: src/data/data-in.c:954
+#: src/data/data-in.c:1012
 msgid "Delimiter expected between fields in time."
 msgstr "Delimitador esperat entre camps de temps."
 
-#: src/data/data-in.c:974
+#: src/data/data-in.c:1032
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr "Minut (%ld) ha de ser entre 0 i 59."
 
-#: src/data/data-in.c:1014
+#: src/data/data-in.c:1070
 msgid "Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified."
 msgstr "Dia de la setmana no reconegut. Al menys s'han d'especificar les dues primeres lletres del nom en anglès."
 
-#: src/data/data-in.c:1152
+#: src/data/data-in.c:1196
 #, c-format
 msgid "`%c' expected in date field."
 msgstr "S'espera `%c' en un camp de dades."
 
-#: src/data/data-in.c:1193
-#, c-format
-msgid "column %d"
-msgstr "columna %d"
-
-#: src/data/data-in.c:1195
-#, c-format
-msgid "columns %d-%d"
-msgstr "columnes %d-%d"
-
-#: src/data/data-in.c:1199
-#, c-format
-msgid "%s field) "
-msgstr "%s camp)"
-
-#: src/data/data-out.c:481
+#: src/data/data-out.c:546
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr "Nombre de dia de la setmana%f no està entre 1 i 7."
 
-#: src/data/data-out.c:502
+#: src/data/data-out.c:571
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr "Nombre de mes %f no està entre 1 i 12."
@@ -236,26 +256,26 @@ msgstr "sistema"
 msgid "scratch"
 msgstr "zero"
 
-#: src/data/dictionary.c:980
+#: src/data/dictionary.c:1007
 msgid "At least one case in the data file had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
 msgstr "Almenys un cas a l'arxiu de dades tenia un valor de ponderació que és perdut d'usuari, de sistema, zero o negatiu. Aquest(s) cas(os) van ser ignorat(s)."
 
-#: src/data/dictionary.c:1283
+#: src/data/dictionary.c:1333
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr "Línia de document tallada a  %d bytes."
 
-#: src/data/file-handle-def.c:462
+#: src/data/file-handle-def.c:469
 #, c-format
 msgid "Can't read from %s as a %s because it is already being read as a %s."
 msgstr "No es pot llegir de %s com una %s perquè ja està sent llegit com una %s."
 
-#: src/data/file-handle-def.c:466
+#: src/data/file-handle-def.c:473
 #, c-format
 msgid "Can't write to %s as a %s because it is already being written as a %s."
 msgstr "No es pot escriure en %s com un %s perquè ja està escrit com un %s."
 
-#: src/data/file-handle-def.c:473
+#: src/data/file-handle-def.c:480
 #, c-format
 msgid "Can't re-open %s as a %s."
 msgstr "No es pot tornar a obrir %s com a %s."
@@ -265,86 +285,86 @@ msgstr "No es pot tornar a obrir %s com a %s."
 msgid "Not opening pipe file `%s' because SAFER option set."
 msgstr "No obrir l'arxiu de transferència '%s' perquè l'opció SAFER està activada."
 
-#: src/data/format.c:235
+#: src/data/format.c:320
 msgid "Input format"
 msgstr "Format d'entrada"
 
-#: src/data/format.c:235
+#: src/data/format.c:320
 msgid "Output format"
 msgstr "Format de sortida"
 
-#: src/data/format.c:244
+#: src/data/format.c:329
 #, c-format
 msgid "Format %s may not be used for input."
 msgstr "Format %s no pot ser utilitzat com entrada."
 
-#: src/data/format.c:251
+#: src/data/format.c:336
 #, c-format
 msgid "%s specifies width %d, but %s requires an even width."
 msgstr "%s especifica amplada %d, però %s requereix una amplada parell."
 
-#: src/data/format.c:260
+#: src/data/format.c:345
 #, c-format
 msgid "%s %s specifies width %d, but %s requires a width between %d and %d."
 msgstr "%s %s especifica amplada %d, però %s requereix una amplada entre %d i %d."
 
-#: src/data/format.c:269
+#: src/data/format.c:354
 #, c-format
 msgid "%s %s specifies %d decimal place, but %s does not allow any decimals."
 msgid_plural "%s %s specifies %d decimal places, but %s does not allow any decimals."
 msgstr[0] "%s %s especifica %d lloc decimal, però %s no en permet cap."
 msgstr[1] "%s %s especifica %d llocs decimals, però %s no en permet cap."
 
-#: src/data/format.c:280
+#: src/data/format.c:365
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width allows at most %d decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width allows at most %d decimals."
 msgstr[0] "%s %s especifica %d lloc decimal, però l'amplada donada permet com a molt %d decimals."
 msgstr[1] "%s %s especifica %d llocs decimals, però l'amplada donada permet com a molt %d decimals."
 
-#: src/data/format.c:287
+#: src/data/format.c:372
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width does not allow for any decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width does not allow for any decimals."
 msgstr[0] "%s %s especifica %d lloc decimal, però l'amplada donada no en permet cap."
 msgstr[1] "%s %s especifica %d llocs decimals, però l'amplada donada no en permet cap."
 
-#: src/data/format.c:326
+#: src/data/format.c:411
 #, c-format
 msgid "%s variables are not compatible with %s format %s."
 msgstr "Les variables %s no són compatibles amb %s format %s."
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:752
-#: src/ui/gui/psppire-var-store.c:628 src/ui/gui/psppire.ui:1960
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:629 src/ui/gui/compute.ui:503
 #: src/ui/gui/var-sheet-dialogs.ui:139
 msgid "String"
 msgstr "Cadena"
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:752
-#: src/ui/gui/psppire-var-store.c:621 src/ui/gui/psppire.ui:2040
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/compute.ui:584
 #: src/ui/gui/var-sheet-dialogs.ui:27
 msgid "Numeric"
 msgstr "Numèric"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:493
-#: src/language/xforms/recode.c:494 src/language/xforms/recode.c:506
-#: src/language/xforms/recode.c:507
+#: src/data/format.c:413 src/data/sys-file-reader.c:1663
+#: src/data/sys-file-reader.c:1665 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
-#: src/language/dictionary/apply-dictionary.c:79
 msgid "numeric"
 msgstr "numèric"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:493
-#: src/language/xforms/recode.c:494 src/language/xforms/recode.c:506
-#: src/language/xforms/recode.c:507
+#: src/data/format.c:413 src/data/sys-file-reader.c:1663
+#: src/data/sys-file-reader.c:1665 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
-#: src/language/dictionary/apply-dictionary.c:79
 msgid "string"
 msgstr "cadena"
 
-#: src/data/format.c:346
+#: src/data/format.c:431
 #, c-format
 msgid "String variable with width %d is not compatible with format %s."
 msgstr "Variable de cadena amb amplada %d no és compatible amb el format %s."
@@ -353,259 +373,273 @@ msgstr "Variable de cadena amb amplada %d no és compatible amb el format %s."
 msgid "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr "Suport per a arxius Gnumeric no va ser compilat en aquesta instal·lació de PSPP"
 
-#: src/data/gnumeric-reader.c:364
+#: src/data/gnumeric-reader.c:363
 #, c-format
-msgid "Error opening \"%s\" for reading as a Gnumeric file: %s."
-msgstr "Error en obrir \"%s\" per a la lectura com un arxiu Gnumeric: %s."
+msgid "Error opening `%s' for reading as a Gnumeric file: %s."
+msgstr "Error en obrir `%s' per a la lectura com a arxiu Gnumeric: %s."
 
-#: src/data/gnumeric-reader.c:384
+#: src/data/gnumeric-reader.c:383
 #, c-format
-msgid "Invalid cell range \"%s\""
-msgstr "Interval de cel·la \"%s\" invàlid"
+msgid "Invalid cell range `%s'"
+msgstr "Interval de cel·la `%s' invàlid"
 
-#: src/data/gnumeric-reader.c:516 src/data/psql-reader.c:187
+#: src/data/gnumeric-reader.c:522
 #, c-format
-msgid "Cannot create variable name from %s"
-msgstr "No es pot crear el nom de la variable des de %s"
+msgid "Selected sheet or range of spreadsheet `%s' is empty."
+msgstr "El full o fulls de càlcul seleccionats `%s' és buit."
 
-#: src/data/gnumeric-reader.c:528
+#: src/data/identifier2.c:60
 #, c-format
-msgid "Selected sheet or range of spreadsheet \"%s\" is empty."
-msgstr "El full o l'interval de fulls de càlcul seleccionats \"%s\" és buit."
+msgid "Identifier `%s' exceeds %d-byte limit."
+msgstr "L'identificador `%s' supera el límit de %d caràcters."
 
-#: src/data/make-file.c:68
+#: src/data/identifier2.c:84
+msgid "Identifier cannot be empty string."
+msgstr "L'identificador no pot ser una cadena buida. "
+
+#: src/data/identifier2.c:92
+#, c-format
+msgid "`%s' may not be used as an identifier because it is a reserved word."
+msgstr "'%s' no pot ser utilitzat com a identificador perquè es una paraula reservada."
+
+#: src/data/identifier2.c:103
+#, c-format
+msgid "`%s' may not be used as an identifier because it contains ill-formed UTF-8 at byte offset %tu."
+msgstr "'%s' no pot ser utilitzat com a identificador perquè conté malformació UTF-8 al byte en posició %tu."
+
+#: src/data/identifier2.c:114
 #, c-format
-msgid "%s: Creating temporary file: %s."
-msgstr "%s: Creant arxiu temporal: %s"
+msgid "Character %s (in `%s') may not appear as the first character in a identifier."
+msgstr "El caracter %s (a `%s') no pot aparèixer com a primer caracter a un identificador."
 
-#: src/data/make-file.c:110
+#: src/data/identifier2.c:126
 #, c-format
-msgid "%s: Creating file: %s."
-msgstr "%s: Creant arxiu: %s"
+msgid "Character %s (in `%s') may not appear in an identifier."
+msgstr "El caracter %s (a `%s') no pot aparèixer a un identificador."
 
-#: src/data/make-file.c:148
+#: src/data/make-file.c:71
 #, c-format
 msgid "Opening %s for writing: %s."
 msgstr "Obrint %s per a escriure: %s."
 
-#: src/data/make-file.c:157
+#: src/data/make-file.c:80
 #, c-format
 msgid "Opening stream for %s: %s."
 msgstr "Obrint flux per a %s: %s."
 
-#: src/data/make-file.c:186
+#: src/data/make-file.c:109
 #, c-format
 msgid "Creating temporary file to replace %s: %s."
 msgstr "Creant arxiu temporal per a substituir %s: %s."
 
-#: src/data/make-file.c:197
+#: src/data/make-file.c:120
 #, c-format
 msgid "Creating temporary file %s: %s."
 msgstr "Creant arxiu temporal %s: %s."
 
-#: src/data/make-file.c:209
+#: src/data/make-file.c:132
 #, c-format
 msgid "Opening stream for temporary file %s: %s."
 msgstr "Obrint flux per a l'arxiu temporal %s: %s."
 
-#: src/data/make-file.c:250
+#: src/data/make-file.c:173
 #, c-format
 msgid "Replacing %s by %s: %s."
 msgstr "Substituint %s per %s: %s."
 
-#: src/data/make-file.c:278
+#: src/data/make-file.c:201
 #, c-format
 msgid "Removing %s: %s."
 msgstr "Eliminant %s: %s."
 
-#: src/data/por-file-reader.c:99
+#: src/data/mrset.c:83
+#, c-format
+msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
+msgstr "%s no és un nom vàlid de variable per a un conjunt de resposta múltiple. Els conjunts de resposta múltiple han de començar amb `$'."
+
+#: src/data/por-file-reader.c:100
 #, c-format
 msgid "portable file %s corrupt at offset 0x%llx: "
 msgstr "l'arxiu portàtil %s és trencat a la posició 0x%llx: "
 
-#: src/data/por-file-reader.c:128
+#: src/data/por-file-reader.c:132
 #, c-format
 msgid "reading portable file %s at offset 0x%llx: "
 msgstr "Llegint l'arxiu portàtil %s en la posició 0x%llx: "
 
-#: src/data/por-file-reader.c:156
+#: src/data/por-file-reader.c:163
 #, c-format
-msgid "Error closing portable file \"%s\": %s."
-msgstr "Error en tancar l'arxiu portàtil \"%s\": %s."
+msgid "Error closing portable file `%s': %s."
+msgstr "Error en tancar l'arxiu portàtil `%s': %s."
 
-#: src/data/por-file-reader.c:208
+#: src/data/por-file-reader.c:215
 msgid "unexpected end of file"
 msgstr "fi d'arxiu inesperat"
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:149
+#: src/data/por-file-reader.c:274 src/data/por-file-writer.c:148
 msgid "portable file"
 msgstr "arxiu portàtil"
 
-#: src/data/por-file-reader.c:275
+#: src/data/por-file-reader.c:282
 #, c-format
-msgid "An error occurred while opening \"%s\" for reading as a portable file: %s."
-msgstr "Error en obrir \"%s\" per a la lectura com a arxiu portàtil: %s."
+msgid "An error occurred while opening `%s' for reading as a portable file: %s."
+msgstr "Error en obrir `%s' per a la lectura com a arxiu portàtil: %s."
 
-#: src/data/por-file-reader.c:296
+#: src/data/por-file-reader.c:303
 msgid "Data record expected."
 msgstr "Registre de dades esperat."
 
-#: src/data/por-file-reader.c:378
+#: src/data/por-file-reader.c:385
 msgid "Number expected."
 msgstr "Nombre esperat."
 
-#: src/data/por-file-reader.c:406
+#: src/data/por-file-reader.c:413
 msgid "Missing numeric terminator."
 msgstr "Manca de terminació numèrica."
 
-#: src/data/por-file-reader.c:429
+#: src/data/por-file-reader.c:436
 msgid "Invalid integer."
 msgstr "Nombre enter invàlid."
 
-#: src/data/por-file-reader.c:440 src/data/por-file-reader.c:460
+#: src/data/por-file-reader.c:447 src/data/por-file-reader.c:467
 #, c-format
 msgid "Bad string length %d."
 msgstr "Longitud de cadena %d invàlida."
 
-#: src/data/por-file-reader.c:523
+#: src/data/por-file-reader.c:530
 #, c-format
 msgid "%s: Not a portable file."
 msgstr "%s: No és un arxiu portàtil."
 
-#: src/data/por-file-reader.c:540
+#: src/data/por-file-reader.c:547
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr "Codi de versió `%c' no reconegut."
 
-#: src/data/por-file-reader.c:549
+#: src/data/por-file-reader.c:556
 #, c-format
 msgid "Bad date string length %zu."
 msgstr "Longitud de cadena de dades %zu invàlida."
 
-#: src/data/por-file-reader.c:551
+#: src/data/por-file-reader.c:558
 #, c-format
 msgid "Bad time string length %zu."
 msgstr "Longitud de cadena de temps %zu invàlida."
 
-#: src/data/por-file-reader.c:593
+#: src/data/por-file-reader.c:600
 #, c-format
 msgid "%s: Bad format specifier byte (%d).  Variable will be assigned a default format."
 msgstr "%s: Byte especificador de format invàlid (%d). S'assignarà el format predeterminat a la variable."
 
-#: src/data/por-file-reader.c:614
+#: src/data/por-file-reader.c:621
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr "La variable numèrica %s té una especificació de format invàlida %s."
 
-#: src/data/por-file-reader.c:618
+#: src/data/por-file-reader.c:625
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr "La variable en cadena %s amb longitud %d té una especificació de format invàlida %s."
 
-#: src/data/por-file-reader.c:642
+#: src/data/por-file-reader.c:649
 msgid "Expected variable count record."
 msgstr "Registre de recompte de variables esperat."
 
-#: src/data/por-file-reader.c:646
+#: src/data/por-file-reader.c:653
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr "Número invàlid de variables: %d."
 
-#: src/data/por-file-reader.c:655
+#: src/data/por-file-reader.c:662
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr "Nom de la variable ponderada (%s) truncat."
 
-#: src/data/por-file-reader.c:670
+#: src/data/por-file-reader.c:677
 msgid "Expected variable record."
 msgstr "Registre de variable esperat."
 
-#: src/data/por-file-reader.c:674
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Invalid variable width %d."
 msgstr "Amplada de la variable invàlida %d."
 
-#: src/data/por-file-reader.c:681
+#: src/data/por-file-reader.c:689
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr "Nom de la variable invàlid `%s' en la posició %d."
 
-#: src/data/por-file-reader.c:685 src/data/sys-file-reader.c:606
+#: src/data/por-file-reader.c:693 src/data/sys-file-reader.c:963
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr "Amplada %d incorrecte per a la variable %s."
 
-#: src/data/por-file-reader.c:700
-#, c-format
-msgid "Duplicate variable name %s in position %d."
-msgstr "Nom de la variable %s duplicat en la posició %d."
-
-#: src/data/por-file-reader.c:701
+#: src/data/por-file-reader.c:707
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr "Nom de la variable %s duplicat en la posició %d s'ha reanomenat a %s."
 
-#: src/data/por-file-reader.c:750
+#: src/data/por-file-reader.c:756
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr "La variable de ponderació %s no està al diccionari."
 
-#: src/data/por-file-reader.c:794
+#: src/data/por-file-reader.c:800
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr "Variable %s desconeguda mentre s'analitzaven les etiquetes de valor."
 
-#: src/data/por-file-reader.c:797
+#: src/data/por-file-reader.c:803
 #, c-format
 msgid "Cannot assign value labels to %s and %s, which have different variable types."
 msgstr "No es pot assignar etiquetes de valor a %s i %s, que tenen diferent tipus de variables."
 
-#: src/data/por-file-writer.c:141
+#: src/data/por-file-writer.c:140
 #, c-format
 msgid "Invalid decimal digits count %d.  Treating as %d."
 msgstr "Recompte de dígits decimals %d invàlid. Es tractarà com a %d."
 
-#: src/data/por-file-writer.c:161
+#: src/data/por-file-writer.c:160
 #, c-format
-msgid "Error opening \"%s\" for writing as a portable file: %s."
-msgstr "Error al obrir \"%s\" per a escriure com a arxiu  portàtil: %s."
+msgid "Error opening `%s' for writing as a portable file: %s."
+msgstr "Error al obrir `%s' per a escriure com a arxiu  portàtil: %s."
 
-#: src/data/por-file-writer.c:506
+#: src/data/por-file-writer.c:502
 #, c-format
-msgid "An I/O error occurred writing portable file \"%s\"."
-msgstr "Error I/O en escriure l'arxiu portàtil \"%s\"."
+msgid "An I/O error occurred writing portable file `%s'."
+msgstr "Error E/S en escriure l'arxiu portàtil `%s'."
 
 #: src/data/psql-reader.c:46
 msgid "Support for reading postgres databases was not compiled into this installation of PSPP"
 msgstr "El suport per a la lectura de les bases de dades postgres no va ser compilat en aquesta instal·lació de PSPP"
 
-#: src/data/psql-reader.c:242
+#: src/data/psql-reader.c:239
 msgid "Memory error whilst opening psql source"
 msgstr "Error de memòria al obrir la font psql"
 
-#: src/data/psql-reader.c:248
+#: src/data/psql-reader.c:245
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr "Error obrint la font psql: %s."
 
-#: src/data/psql-reader.c:263
+#: src/data/psql-reader.c:260
 #, c-format
 msgid "Postgres server is version %s. Reading from versions earlier than 8.0 is not supported."
 msgstr "La versió del servidor Postgres és la %s. No es possible la lectura des de versions anteriors a la 8.0."
 
-#: src/data/psql-reader.c:283
+#: src/data/psql-reader.c:280
 msgid "Connection is unencrypted, but unencrypted connections have not been permitted."
 msgstr "La connexió no està xifrada, però les connexions sense xifrar no estan permeses."
 
-#: src/data/psql-reader.c:322 src/data/psql-reader.c:347
-#: src/data/psql-reader.c:357
+#: src/data/psql-reader.c:318 src/data/psql-reader.c:343
+#: src/data/psql-reader.c:353
 #, c-format
 msgid "Error from psql source: %s."
 msgstr "Error des de la font psql: %s."
 
-#: src/data/psql-reader.c:452
+#: src/data/psql-reader.c:448
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr "OID %d no admès. Valors SYSMIS seran inserits."
@@ -617,11 +651,20 @@ msgstr "El manipulador de l'arxius de treball %s encara no s'ha escrit, utilitza
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:181
+#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:186
 msgid "scratch file"
 msgstr "arxiu de treball"
 
-#: src/data/settings.c:608
+#: src/data/settings.c:384
+msgid "MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."
+msgstr "S'assigna zero a MXWARNS.  No es proporcionaran més avisos tot, i que podrien trobar-se situacions problemàtiques posteriors."
+
+#: src/data/settings.c:391
+#, c-format
+msgid "Warnings re-enabled. %d warnings will be issued before aborting syntax processing."
+msgstr "Avisos activats de nou.  Es tindran en compte %d avisos abans d'abortar el procés."
+
+#: src/data/settings.c:599
 #, c-format
 msgid "%s: Custom currency string `%s' does not contain exactly three periods or commas (or it contains both)."
 msgstr "%s: Cadena de moneda personalitzada '%s' no conté exactament tres punts o comes (o els conté ambdós)."
@@ -630,373 +673,366 @@ msgstr "%s: Cadena de moneda personalitzada '%s' no conté exactament tres punts
 msgid "Variable suffix too large."
 msgstr "Sufix de la variable massa gran."
 
-#: src/data/sys-file-reader.c:226
-#, c-format
-msgid "Recoded variable name duplicates an existing `%s' within system file."
-msgstr "El nom de la variable recodificada duplica `%s' existent dins de l'arxiu de sistema."
-
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:290 src/data/sys-file-writer.c:207
+#: src/data/sys-file-reader.c:323 src/data/sys-file-writer.c:207
 msgid "system file"
 msgstr "arxiu de sistema"
 
-#: src/data/sys-file-reader.c:297
+#: src/data/sys-file-reader.c:330
 #, c-format
-msgid "Error opening \"%s\" for reading as a system file: %s."
-msgstr "Error al obrir \"%s\" per a la lectura com arxiu de sistema: %s."
+msgid "Error opening `%s' for reading as a system file: %s."
+msgstr "Error en obrir `%s' per a la lectura com arxiu de sistema: %s."
 
-#: src/data/sys-file-reader.c:336 tests/dissect-sysfile.c:154
+#: src/data/sys-file-reader.c:387 tests/dissect-sysfile.c:155
 msgid "Misplaced type 4 record."
 msgstr "Registre de tipus 4 fora de lloc."
 
-#: src/data/sys-file-reader.c:347 tests/dissect-sysfile.c:165
+#: src/data/sys-file-reader.c:391
+msgid "Duplicate type 6 (document) record."
+msgstr "Registre de tipus 6 (document) duplicat."
+
+#: src/data/sys-file-reader.c:400 src/data/sys-file-reader.c:900
+#, c-format
+msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Registre de tipus 7, subtipus %d no reconegut. Si us plau envieu una còpia d'aquest arxiu, així com de la sintaxi que el va crear a %s."
+
+#: src/data/sys-file-reader.c:409
+#, c-format
+msgid "Record type 7, subtype %d found here has the same type as the record found near offset 0x%llx.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Registre de tipus 7, subtipus %d que te el mateix tipus que el registre trobat prop de la posició 0x%llx. Si us plau envieu una còpia d'aquest arxiu, així com de la sintaxi que el va crear a %s."
+
+#: src/data/sys-file-reader.c:422 tests/dissect-sysfile.c:166
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr "Tipus de registre %d no reconegut."
 
-#: src/data/sys-file-reader.c:388
+#: src/data/sys-file-reader.c:467
+#, c-format
+msgid "Weighting variable must be numeric (not string variable `%s')."
+msgstr "Variable de ponderació ha de ser numèrica (no la variable de text `%s')."
+
+#: src/data/sys-file-reader.c:502
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr "Capçalera de l'arxiu requereix %d posicions de variable, però s'han llegit %d des de l'arxiu."
 
-#: src/data/sys-file-reader.c:428
+#: src/data/sys-file-reader.c:542
 #, c-format
-msgid "Error closing system file \"%s\": %s."
-msgstr "Error al tancar l'arxiu de sistema \"%s\": %s."
+msgid "Error closing system file `%s': %s."
+msgstr "Error en tancar l'arxiu de sistema `%s': %s."
 
-#: src/data/sys-file-reader.c:493 src/data/sys-file-reader.c:503
-#: tests/dissect-sysfile.c:202 tests/dissect-sysfile.c:212
+#: src/data/sys-file-reader.c:604 src/data/sys-file-reader.c:614
+#: tests/dissect-sysfile.c:203 tests/dissect-sysfile.c:213
 msgid "This is not an SPSS system file."
 msgstr "Això no és un arxiu de sistema de SPSS."
 
-#: src/data/sys-file-reader.c:525 tests/dissect-sysfile.c:227
+#: src/data/sys-file-reader.c:636 tests/dissect-sysfile.c:228
 msgid "Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format."
 msgstr "El biaix de compressió no és el valor habitual de 100, o l'arxiu de sistema utilitza un format de punt flotant no reconegut."
 
-#: src/data/sys-file-reader.c:602
-#, c-format
-msgid "Invalid variable name `%s'."
-msgstr "Nom de variable '%s' no vàlid."
-
-#: src/data/sys-file-reader.c:610
-#, c-format
-msgid "Duplicate variable name `%s' within system file."
-msgstr "Nom de variable '%s' duplicat dins de l'arxiu de sistema."
-
-#: src/data/sys-file-reader.c:618 tests/dissect-sysfile.c:356
+#: src/data/sys-file-reader.c:712 tests/dissect-sysfile.c:357
 msgid "Variable label indicator field is not 0 or 1."
 msgstr "Camp indicador d'etiqueta de variable no és 0 o 1."
 
-#: src/data/sys-file-reader.c:649 tests/dissect-sysfile.c:387
+#: src/data/sys-file-reader.c:722 tests/dissect-sysfile.c:388
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr "Camp d'indicador de valors perduts numèrics  no és -3, -2, 0, 1, 2 o 3."
 
-#: src/data/sys-file-reader.c:667 tests/dissect-sysfile.c:402
+#: src/data/sys-file-reader.c:729 tests/dissect-sysfile.c:403
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr "Camp d'indicador de valors perduts de cadena no és 0, 1, 2 o 3."
 
-#: src/data/sys-file-reader.c:699
+#: src/data/sys-file-reader.c:749
+#, c-format
+msgid "Invalid number of labels %zu."
+msgstr "Nombre invàlid d'etiquetes %zu."
+
+#: src/data/sys-file-reader.c:774 tests/dissect-sysfile.c:469
+msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
+msgstr "Registre d'índex de variable (tipus 4) no és seguit immediatament pel registre d'etiquetes de valors (tipus 3) com hauria."
+
+#: src/data/sys-file-reader.c:782
+#, c-format
+msgid "Number of variables associated with a value label (%d) is not between 1 and the number of variables (%zu)."
+msgstr "Nombre de variables associades amb una etiqueta de valors (%d) no està entre 1 i el nombre de variables (%zu)."
+
+#: src/data/sys-file-reader.c:803
+#, c-format
+msgid "Number of document lines (%d) must be greater than 0 and less than %d."
+msgstr "Nombre de línies de document (%d) ha de ser més gran que 0 i més petit que %d."
+
+#: src/data/sys-file-reader.c:876
+#, c-format
+msgid "Record type 7, subtype %d has bad size %zu (expected %d)."
+msgstr "Registre de tipus 7, subtipus %d te mida incorrecta %zu (s'espera %d)."
+
+#: src/data/sys-file-reader.c:880
+#, c-format
+msgid "Record type 7, subtype %d has bad count %zu (expected %d)."
+msgstr "Registre de tipus 7, subtipus %d te recompte incorrecte %zu (s'espera %d)."
+
+#: src/data/sys-file-reader.c:959
+#, c-format
+msgid "Invalid variable name `%s'."
+msgstr "Nom de variable '%s' no vàlid."
+
+#: src/data/sys-file-reader.c:967
+#, c-format
+msgid "Duplicate variable name `%s'."
+msgstr "Nom de la variable `%s' duplicat."
+
+#: src/data/sys-file-reader.c:1038
 msgid "Missing string continuation record."
 msgstr "Manca de registre de continuació de cadena."
 
-#: src/data/sys-file-reader.c:733
+#: src/data/sys-file-reader.c:1059
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr "Format de variable %<PRIu8> desconegut."
 
-#: src/data/sys-file-reader.c:751
+#: src/data/sys-file-reader.c:1077
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr "%s variable %s amb un format %s no vàlid %s."
 
-#: src/data/sys-file-reader.c:754
+#: src/data/sys-file-reader.c:1080
 msgid "print"
 msgstr "imprimir"
 
-#: src/data/sys-file-reader.c:754
+#: src/data/sys-file-reader.c:1080
 msgid "write"
 msgstr "escriure"
 
-#: src/data/sys-file-reader.c:758
+#: src/data/sys-file-reader.c:1084
 msgid "Suppressing further invalid format warnings."
 msgstr "Es desactiven les alertes posteriors de format no vàlid."
 
-#: src/data/sys-file-reader.c:776
-msgid "Weighting variable must be numeric."
-msgstr "Variable de ponderació ha de ser numèrica."
-
-#: src/data/sys-file-reader.c:790
-msgid "Multiple type 6 (document) records."
-msgstr "Múltiples registres de tipus 6 (document)."
-
-#: src/data/sys-file-reader.c:794
-#, c-format
-msgid "Number of document lines (%d) must be greater than 0."
-msgstr "Nombre de línies de document (%d) ha de ser major que 0."
-
-#: src/data/sys-file-reader.c:802
-msgid "Document line contains null byte."
-msgstr "Una línia del document conté un byte nul."
-
-#: src/data/sys-file-reader.c:893
-#, c-format
-msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s"
-msgstr "Registre de tipus 7, subtipus %d , no reconegut. Si us plau envieu una còpia d'aquest arxiu, així com de la sintaxi que el va crear a %s"
-
-#: src/data/sys-file-reader.c:920 tests/dissect-sysfile.c:594
-#, c-format
-msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
-msgstr "Camp de longitud (%zu) o quantitat (%zu) invàlids en el registre tipus 7, subtipus 3."
-
-#: src/data/sys-file-reader.c:940
+#: src/data/sys-file-reader.c:1136
 #, c-format
 msgid "Floating-point representation indicated by system file (%d) differs from expected (%d)."
 msgstr "Representació del punt flotant indicat per l'arxiu de sistema (%d) difereix de l'esperat (%d)."
 
-#: src/data/sys-file-reader.c:953 src/language/dictionary/sys-file-info.c:110
-msgid "Little Endian"
-msgstr "Tipus Little-Endian."
-
-#: src/data/sys-file-reader.c:953 src/language/dictionary/sys-file-info.c:109
-msgid "Big Endian"
-msgstr "Tipus Big-Endian."
-
-#: src/data/sys-file-reader.c:954
-#, c-format
-msgid "Integer format indicated by system file (%s) differs from expected (%s)."
-msgstr "Format enter indicat per l'arxiu de sistema  (%s) difereix de l'esperat (%s)."
-
-#: src/data/sys-file-reader.c:1011 tests/dissect-sysfile.c:625
+#: src/data/sys-file-reader.c:1150
 #, c-format
-msgid "Bad size (%zu) or count (%zu) on extension 4."
-msgstr "Longitud (%zu) o quantitat (%zu) de l'extensió 4 no vàlid."
+msgid "Integer format indicated by system file (%d) differs from expected (%d)."
+msgstr "Format enter indicat per l'arxiu de sistema  (%d) difereix de l'esperat (%d)."
 
-#: src/data/sys-file-reader.c:1015 src/data/sys-file-reader.c:1019
-#: src/data/sys-file-reader.c:1023 tests/dissect-sysfile.c:630
-#: tests/dissect-sysfile.c:635 tests/dissect-sysfile.c:640
+#: src/data/sys-file-reader.c:1211 src/data/sys-file-reader.c:1215
+#: src/data/sys-file-reader.c:1219 tests/dissect-sysfile.c:631
+#: tests/dissect-sysfile.c:636 tests/dissect-sysfile.c:641
 #, c-format
 msgid "File specifies unexpected value %g as %s."
 msgstr "L'arxiu especifica un valor inesperat %g com a %s."
 
-#: src/data/sys-file-reader.c:1056
+#: src/data/sys-file-reader.c:1252
 #, c-format
-msgid "Missing space following 'C' at offset %zu in MRSETS record"
-msgstr "Espai perdut darrera 'C' en la possició %zu a registre MRSETS"
+msgid "`%s' does not begin with `$' at UTF-8 offset %zu in MRSETS record."
+msgstr "`%s' not comença amb `$' a la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1074 tests/dissect-sysfile.c:691
+#: src/data/sys-file-reader.c:1263 src/data/sys-file-reader.c:1282
 #, c-format
-msgid "Missing space following 'E' at offset %zu in MRSETS record"
-msgstr "Espai perdut darrera 'E' en la possició %zu a registre MRSETS"
+msgid "Missing space following `%c' at UTF-8 offset %zu in MRSETS record."
+msgstr "Espai perdut darrera `%c' a la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1083 tests/dissect-sysfile.c:700
+#: src/data/sys-file-reader.c:1292
 #, c-format
-msgid "Unexpected label source value \"%s\" following 'E' at offset %zu in MRSETS record"
-msgstr "Valor d'etiqueta no esperat \"%s\" darrera 'E' en la possició %zu a registre MRSETS"
+msgid "Unexpected label source value `%s' following `E' at UTF-8 offset %zu in MRSETS record."
+msgstr "Valor d'etiqueta no esperat `%s' darrera `E' a la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1089
+#: src/data/sys-file-reader.c:1299
 #, c-format
-msgid "Missing 'C', 'D', or 'E' at offset %zu in MRSETS record."
-msgstr "Manca 'C', 'D' o 'E' en la possició %zu a registre MRSETS"
+msgid "Missing `C', `D', or `E' at UTF-8 offset %zu in MRSETS record."
+msgstr "Manca `C', `D' o `E' a la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1118
+#: src/data/sys-file-reader.c:1329
 #, c-format
-msgid "Missing new-line parsing variable names at offset %zu in MRSETS record."
-msgstr "Manca nom de variables de nova línia en la possició %zu a registre MRSETS"
+msgid "Missing new-line parsing variable names at UTF-8 offset %zu in MRSETS record."
+msgstr "Manca nom de variables de nova línia en la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1129
+#: src/data/sys-file-reader.c:1341
 #, c-format
-msgid "Duplicate variable name %s at offset %zu in MRSETS record."
-msgstr "Nom de la variable %s duplicat en la posició %zu a registre MRSET."
+msgid "Duplicate variable name %s at UTF-8 offset %zu in MRSETS record."
+msgstr "Nom de la variable %s duplicat a la posició UTF-8 %zu d'un registre MRSETS."
 
-#: src/data/sys-file-reader.c:1142
+#: src/data/sys-file-reader.c:1355
 #, c-format
 msgid "MRSET %s contains both string and numeric variables."
 msgstr "MRSET %s contè variables textuals i numeriques."
 
-#: src/data/sys-file-reader.c:1157
+#: src/data/sys-file-reader.c:1371
 #, c-format
 msgid "MRSET %s has only %zu variables."
 msgstr "MRSET %s nomès te %zu variables."
 
-#: src/data/sys-file-reader.c:1194 tests/dissect-sysfile.c:758
-#, c-format
-msgid "Bad size %zu on extension 11."
-msgstr "Amplada no vàlida %zu en l'extensió 11."
-
-#: src/data/sys-file-reader.c:1206 tests/dissect-sysfile.c:770
+#: src/data/sys-file-reader.c:1417 tests/dissect-sysfile.c:771
 #, c-format
 msgid "Extension 11 has bad count %zu (for %zu variables)."
 msgstr "Extensió 11 té un recompte invàlid %zu (per a %zu variables)."
 
-#: src/data/sys-file-reader.c:1227
+#: src/data/sys-file-reader.c:1451
 #, c-format
 msgid "Invalid variable display parameters for variable %zu (%s).  Default parameters substituted."
 msgstr "Paràmetres de visualització de variable no vàlids per a la variable %zu (%s). Substitució pels paràmetres per defecte."
 
-#: src/data/sys-file-reader.c:1271
+#: src/data/sys-file-reader.c:1548
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr "Identificació de variable llarga des de %s cap a un nom de variable invàlid  '%s'."
 
-#: src/data/sys-file-reader.c:1281
+#: src/data/sys-file-reader.c:1559
 #, c-format
-msgid "Duplicate long variable name `%s' within system file."
-msgstr "Nom de la variable llarga '%s' duplicat dins de l'arxiu de sistema."
+msgid "Duplicate long variable name `%s'."
+msgstr "Nom de la variable llarga `%s' duplicat."
 
-#: src/data/sys-file-reader.c:1334
+#: src/data/sys-file-reader.c:1592
 #, c-format
-msgid "%s listed as string of invalid length %s in very length string record."
-msgstr "%s figura com a cadena de longitud no vàlida %s en un registre de cadena molt llarg."
+msgid "%s listed as string of invalid length %s in very long string record."
+msgstr "%s figura com a cadena de longitud no vàlida %s a un registre de cadena molt llarg."
 
-#: src/data/sys-file-reader.c:1344
+#: src/data/sys-file-reader.c:1603
 #, c-format
 msgid "%s listed in very long string record with width %s, which requires only one segment."
 msgstr "%s figura en el registre de cadena molt llarga amb longitud %s, que requereix només un segment."
 
-#: src/data/sys-file-reader.c:1350
+#: src/data/sys-file-reader.c:1610
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr "Cadena molt llarga %s desborda el diccionari."
 
-#: src/data/sys-file-reader.c:1364
-#, c-format
-msgid "Very long string with width %ld has segment %d of width %d (expected %d)"
-msgstr "Cadena molt llarga amb una longitud de %ld té un segment %d de longitud %d (s'espera %d)"
-
-#: src/data/sys-file-reader.c:1410
+#: src/data/sys-file-reader.c:1625
 #, c-format
-msgid "Invalid number of labels: %d.  Ignoring labels."
-msgstr "Nombre d'etiquetes invàlid: %d. Ignorant etiquetes."
-
-#: src/data/sys-file-reader.c:1441 tests/dissect-sysfile.c:468
-msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
-msgstr "Registre d'índex de variable (tipus 4) no és seguit immediatament pel registre d'etiquetes de valors (tipus 3) com hauria."
+msgid "Very long string with width %ld has segment %d of width %d (expected %d)."
+msgstr "Cadena molt llarga amb una mida de %ld conté segment %d de longitud %d (s'espera %d)."
 
-#: src/data/sys-file-reader.c:1448
+#: src/data/sys-file-reader.c:1659
 #, c-format
-msgid "Number of variables associated with a value label (%d) is not between 1 and the number of variables (%zu)."
-msgstr "Nombre de variables associades amb una etiqueta de valors (%d) no està entre 1 i el nombre de variables (%zu)."
+msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
+msgstr "Les variables associades amb etiqueta de valors no són totes del mateix tipus.  La variable %s és %s, però la variable %s és %s."
 
-#: src/data/sys-file-reader.c:1459
+#: src/data/sys-file-reader.c:1676
 #, c-format
 msgid "Value labels may not be added to long string variables (e.g. %s) using records types 3 and 4."
 msgstr "No es pot afegir etiquetes dels valors a les variables de cadena llarga (e.g. %s) utilitzant els tipus de registres 3 i 4."
 
-#: src/data/sys-file-reader.c:1468
-#, c-format
-msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
-msgstr "Les variables associades amb etiqueta de valors no són totes del mateix tipus.  La variable %s és %s, però la variable %s és %s."
-
-#: src/data/sys-file-reader.c:1502
+#: src/data/sys-file-reader.c:1695
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr "Etiqueta de valors duplicats per %g en %s."
 
-#: src/data/sys-file-reader.c:1505 src/data/sys-file-reader.c:1686
+#: src/data/sys-file-reader.c:1699 src/data/sys-file-reader.c:1941
 #, c-format
-msgid "Duplicate value label for \"%.*s\" on %s."
-msgstr "Etiqueta de valor duplicat per a \"%.*s\" a %s."
+msgid "Duplicate value label for `%.*s' on %s."
+msgstr "Etiqueta de valor duplicat per a `%.*s' a %s."
 
-#: src/data/sys-file-reader.c:1543
+#: src/data/sys-file-reader.c:1724
 #, c-format
-msgid "Error parsing attribute value %s[%d]"
-msgstr "Error en analitzar el valor de l'atribut %s[%d]"
+msgid "Variable index %d not in valid range 1...%d."
+msgstr "Índex de la variable %d no en l'interval vàlid de 1...%d."
 
-#: src/data/sys-file-reader.c:1557
+#: src/data/sys-file-reader.c:1733
 #, c-format
-msgid "Attribute value %s[%d] is not quoted: %s"
-msgstr "El valor de l'atribut %s[%d] no esta entre cometes: %s"
+msgid "Variable index %d refers to long string continuation."
+msgstr "Índex de la variable %d es refereix a una continuació de cadena llarga."
 
-#: src/data/sys-file-reader.c:1620 tests/dissect-sysfile.c:936
+#: src/data/sys-file-reader.c:1769
 #, c-format
-msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
-msgstr "La longitud del nom de la variable al registre de l'etiqueta del valor de cadena llarga (%d) supera el límit %d-byte."
+msgid "Error parsing attribute value %s[%d]."
+msgstr "Error en analitzar el valor de l'atribut %s[%d]."
 
-#: src/data/sys-file-reader.c:1630
+#: src/data/sys-file-reader.c:1783
+#, c-format
+msgid "Attribute value %s[%d] is not quoted: %s."
+msgstr "El valor de l'atribut %s[%d] no esta entre cometes: %s."
+
+#: src/data/sys-file-reader.c:1836
+msgid "Long string value label record ends unexpectedly."
+msgstr "Etiqueta de valor d'un registre de text molt llarg finalitza inesperadament."
+
+#: src/data/sys-file-reader.c:1875
 #, c-format
 msgid "Ignoring long string value record for unknown variable %s."
 msgstr "Ignorant el registre del valor de cadena llarga per a la variable desconeguda %s."
 
-#: src/data/sys-file-reader.c:1637
+#: src/data/sys-file-reader.c:1880
 #, c-format
 msgid "Ignoring long string value record for numeric variable %s."
 msgstr "Ignorant el registre del valor de cadena llarga per a la variable numèrica %s."
 
-#: src/data/sys-file-reader.c:1644
+#: src/data/sys-file-reader.c:1887
 #, c-format
-msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)"
-msgstr "Ignorant el registre del valor de cadena llarga %s ja que l'amplada del registre (%d) no coincideix amb l'amplada de la variable (%d)"
+msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)."
+msgstr "Ignorant el registre del valor de cadena llarga %s ja que la mida del registre (%d) no coincideix amb la mida de la variable (%d)."
 
-#: src/data/sys-file-reader.c:1666
+#: src/data/sys-file-reader.c:1916
 #, c-format
 msgid "Ignoring long string value %zu for variable %s, with width %d, that has bad value width %zu."
 msgstr "Ignorant el valor de cadena llarga %zu per a la variable %s, d'amplada %d, que té una amplada de valor incorrecta %zu."
 
-#: src/data/sys-file-reader.c:1781
+#: src/data/sys-file-reader.c:2020
 msgid "File ends in partial case."
 msgstr "L'arxiu acaba en un cas parcial."
 
-#: src/data/sys-file-reader.c:1789
+#: src/data/sys-file-reader.c:2028
 #, c-format
 msgid "Error reading case from file %s."
 msgstr "Error llegint un cas de l'arxiu %s."
 
-#: src/data/sys-file-reader.c:1890
+#: src/data/sys-file-reader.c:2130
 msgid "Possible compressed data corruption: compressed spaces appear in numeric field."
 msgstr "Possible corrupció de dades comprimides: apareixen espais comprimits a un camp numeric."
 
-#: src/data/sys-file-reader.c:1943
+#: src/data/sys-file-reader.c:2184
 #, c-format
-msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)"
+msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)."
 msgstr "Possible corrupció de dades comprimides: una cadena textual contè un enter comprimit (opcode %d)."
 
-#: src/data/sys-file-reader.c:2035
-#, c-format
-msgid "Variable index %d not in valid range 1...%d."
-msgstr "Índex de la variable %d no en l'interval vàlid de 1...%d."
-
-#: src/data/sys-file-reader.c:2040
-#, c-format
-msgid "Variable index %d refers to long string continuation."
-msgstr "Índex de la variable %d es refereix a una continuació de cadena llarga."
-
-#: src/data/sys-file-reader.c:2108
+#: src/data/sys-file-reader.c:2273
 #, c-format
 msgid "Suppressed %d additional related warnings."
 msgstr "Suprimides %d advertències addicionals."
 
-#: src/data/sys-file-reader.c:2153 src/data/sys-file-reader.c:2170
+#: src/data/sys-file-reader.c:2318 src/data/sys-file-reader.c:2335
 #, c-format
 msgid "Dictionary record refers to unknown variable %s."
 msgstr "El registre diccionari es refereix a la variable desconeguda %s."
 
-#: src/data/sys-file-reader.c:2231
+#: src/data/sys-file-reader.c:2397
+#, c-format
+msgid "Expecting digit at UTF-8 offset %zu in MRSETS record."
+msgstr "S'espera un dígit a la posició UTF-8 %zu d'un registre MRSETS."
+
+#: src/data/sys-file-reader.c:2405
+#, c-format
+msgid "Expecting space at UTF-8 offset %zu in MRSETS record."
+msgstr "S'espera un espai a la posició UTF-8 %zu d'un registre MRSETS."
+
+#: src/data/sys-file-reader.c:2413
 #, c-format
-msgid "Expecting digit at offset %zu in MRSETS record."
-msgstr "S'espera un dígit en la posició %zu a registre MRSETS."
+msgid "%zu-byte string starting at UTF-8 offset %zu exceeds record length %zu."
+msgstr "El text de %zu-bytes que comença en la posició UTF-8 %zu excedeix la mida del registre %zu."
 
-#: src/data/sys-file-reader.c:2238
+#: src/data/sys-file-reader.c:2423
 #, c-format
-msgid "Expecting space at offset %zu in MRSETS record."
-msgstr "S'espera un espai en la posició %zu a registre MRSETS."
+msgid "Expecting space at UTF-8 offset %zu following %zu-byte string."
+msgstr "S'espera un espai en la posició UTF-8 %zu darrera d'un text de %zu-bytes."
 
-#: src/data/sys-file-reader.c:2245
+#: src/data/sys-file-reader.c:2465
 #, c-format
-msgid "%zu-byte string starting at offset %zu exceeds record length %zu."
-msgstr "El text de %zu-byte que comença en la posició %zu excedeix la llargada del registre %zu. "
+msgid "`%s' near offset 0x%llx: "
+msgstr "`%s' prop de la posició 0x%llx: "
 
-#: src/data/sys-file-reader.c:2255
+#: src/data/sys-file-reader.c:2468
 #, c-format
-msgid "Expecting space at offset %zu following %zu-byte string."
-msgstr "S'espera un espai en la posició %zu darrera dun text %zu-byte."
+msgid "`%s': "
+msgstr "`%s': "
 
-#: src/data/sys-file-reader.c:2347 tests/dissect-sysfile.c:1341
+#: src/data/sys-file-reader.c:2525 tests/dissect-sysfile.c:1356
 #, c-format
 msgid "System error: %s."
 msgstr "Error de sistema: %s."
 
-#: src/data/sys-file-reader.c:2349 tests/dissect-sysfile.c:1343
+#: src/data/sys-file-reader.c:2527 tests/dissect-sysfile.c:1358
 msgid "Unexpected end of file."
 msgstr "Final d'arxiu inesperat."
 
@@ -1005,386 +1041,343 @@ msgstr "Final d'arxiu inesperat."
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr "Versió d'arxiu de sistema %d desconeguda. Es tractarà com a versió %d."
 
-#: src/data/sys-file-writer.c:219
-#, c-format
-msgid "Error opening \"%s\" for writing as a system file: %s."
-msgstr "Error en obrir \"%s\" per gravar com arxiu de sistema: %s."
-
-#: src/data/sys-file-writer.c:989
-#, c-format
-msgid "An I/O error occurred writing system file \"%s\"."
-msgstr "S'ha produït un error de E/S al desar l'arxiu de sistema \"%s\"."
-
-#: src/data/variable.c:206
-#, c-format
-msgid "Character `%c' (in %s) may not appear as the first character in a variable name."
-msgstr "Caràcter '%c' (em %s) no pot aparèixer com el primer caràcter en un nom de variable."
-
-#: src/data/variable.c:218
-#, c-format
-msgid "Character `%c' (in %s) may not appear in a variable name."
-msgstr "Caràcter '%c' (em %s) no pot aparèixer en un nom de variable."
-
-#: src/data/variable.c:244
-msgid "Variable name cannot be empty string."
-msgstr "El nom de la variable no pot ser una cadena buida. "
-
-#: src/data/variable.c:250
+#: src/data/sys-file-writer.c:997
 #, c-format
-msgid "Variable name %s exceeds %d-character limit."
-msgstr "El nom de la variable %s supera el límit de %d caràcters."
+msgid "An I/O error occurred writing system file `%s'."
+msgstr "S'ha produït un error de E/S en desar l'arxiu de sistema `%s'."
 
-#: src/data/variable.c:258
+#: src/data/variable.c:599
 #, c-format
-msgid "`%s' may not be used as a variable name because it is a reserved word."
-msgstr "'%s' no pot ser utilitzat com a nom de variable perquè es una paraula reservada."
+msgid "Truncating variable label for variable `%s' to %d bytes."
+msgstr "Truncant la etiqueta de variable `%s' a %d caràcters."
 
-#: src/language/syntax-file.c:95
-#, c-format
-msgid "Opening `%s': %s."
-msgstr "Obrint `%s': %s."
-
-#: src/language/syntax-file.c:109
-#, c-format
-msgid "Reading `%s': %s."
-msgstr "Llegint `%s': %s."
-
-#: src/language/syntax-file.c:126
-#, c-format
-msgid "Closing `%s': %s."
-msgstr "Tancant `%s': %s."
-
-#: src/language/command.c:205 src/language/expressions/parse.c:1267
-#: src/language/utilities/set.q:213
+#: src/language/command.c:193 src/language/expressions/parse.c:1294
+#: src/language/utilities/set.q:196
 #, c-format
 msgid "%s is not yet implemented."
 msgstr "%s encara no està implementat."
 
-#: src/language/command.c:210
+#: src/language/command.c:198
 #, c-format
 msgid "%s may be used only in testing mode."
 msgstr "%s només pot ser utilitzat en el mode de prova."
 
-#: src/language/command.c:215
+#: src/language/command.c:203
 #, c-format
 msgid "%s may be used only in enhanced syntax mode."
 msgstr "%s només pot ser utilitzat en el mode de sintaxi ampliat."
 
-#: src/language/command.c:239
-msgid "Error encountered while ERROR=STOP is effective."
-msgstr "Detectat un error mentre està actiu ERROR=STOP."
-
-#: src/language/command.c:484
+#: src/language/command.c:331
 msgid "expecting command name"
 msgstr "esperant nom de comando"
 
-#: src/language/command.c:498
+#: src/language/command.c:333
 #, c-format
-msgid "Unknown command %s."
-msgstr "Comando %s desconegut."
+msgid "Unknown command `%s'."
+msgstr "Comando `%s' desconegut."
 
-#: src/language/command.c:623
+#: src/language/command.c:366
 #, c-format
-msgid "%s is allowed only before the active file has been defined."
-msgstr "%s només es permet abans que l'arxiu actiu s'ha definit."
+msgid "%s is allowed only before the active dataset has been defined."
+msgstr "%s només es permet abans que l'arxiu de dades actiu s'ha definit."
 
-#: src/language/command.c:627
+#: src/language/command.c:370
 #, c-format
-msgid "%s is allowed only after the active file has been defined."
-msgstr "%s només es permet després que l'arxiu actiu s'ha definit."
+msgid "%s is allowed only after the active dataset has been defined."
+msgstr "%s només es permet després que l'arxiu de dades actiu s'ha definit."
 
-#: src/language/command.c:631
+#: src/language/command.c:374
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM."
 msgstr "%s només es permet dins de INPUT PROGRAM."
 
-#: src/language/command.c:635
+#: src/language/command.c:378
 #, c-format
 msgid "%s is allowed only inside FILE TYPE."
 msgstr "%s només es permet dins de FILE TYPE."
 
-#: src/language/command.c:642
+#: src/language/command.c:385
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s només es permet abans que l'arxiu actiu s'ha definit o dins de INPUT PROGRAM."
+msgid "%s is allowed only before the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s només es permet abans que l'arxiu de dades actiu s'ha definit o dins de INPUT PROGRAM."
 
-#: src/language/command.c:646
+#: src/language/command.c:389
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside FILE TYPE."
-msgstr "%s només es permet abans que l'arxiu actiu s'ha definit o dins de FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined or inside FILE TYPE."
+msgstr "%s només es permet abans que l'arxiu de dades actiu s'ha definit o dins de FILE TYPE."
 
-#: src/language/command.c:650
+#: src/language/command.c:393
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s només es permet després que l'arxiu actiu s'ha definit, o dins de INPUT PROGRAM."
+msgid "%s is allowed only after the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s només es permet després que l'arxiu de dades actiu s'ha definit, o dins de INPUT PROGRAM."
 
-#: src/language/command.c:654
+#: src/language/command.c:397
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside FILE TYPE."
-msgstr "%s només es permet després que l'arxiu actiu s'ha definit, o dins de FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined or inside FILE TYPE."
+msgstr "%s només es permet després que l'arxiu de dades actiu s'ha definit, o dins de FILE TYPE."
 
-#: src/language/command.c:658
+#: src/language/command.c:401
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM or inside FILE TYPE."
 msgstr "%s només es permet dins de INPUT PROGRAM o FILE TYPE."
 
-#: src/language/command.c:664
+#: src/language/command.c:407
 #, c-format
-msgid "%s is allowed only after the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s només es permet després que l'arxiu actiu s'ha definit, dins de INPUT PROGRAM, o FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s només es permet després que l'arxiu de dades actiu s'ha definit, dins de INPUT PROGRAM, o FILE TYPE."
 
-#: src/language/command.c:669
+#: src/language/command.c:412
 #, c-format
-msgid "%s is allowed only before the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s només es permet abans que l'arxiu actiu s'ha definit, dins de INPUT PROGRAM, o FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s només es permet abans que l'arxiu de dades actiu s'ha definit, dins de INPUT PROGRAM, o FILE TYPE."
 
-#: src/language/command.c:687 src/language/command.c:689
+#: src/language/command.c:430 src/language/command.c:433
 #, c-format
 msgid "%s is not allowed inside %s."
 msgstr "%s no és permes dins de %s."
 
-#: src/language/command.c:768 src/language/command.c:876
-#: src/language/utilities/permissions.c:98
+#: src/language/command.c:515 src/language/utilities/host.c:130
+#: src/language/utilities/permissions.c:104
 msgid "This command not allowed when the SAFER option is set."
 msgstr "Aquesta ordre no està permesa quan l'opció SAFER està activa."
 
-#: src/language/command.c:780
+#: src/language/command.c:531
 #, c-format
 msgid "Error removing `%s': %s."
 msgstr "Error d'eliminació de '%s' : %s."
 
-#: src/language/command.c:830
-#, c-format
-msgid "Couldn't fork: %s."
-msgstr "Impossible crear forquilla: %s."
-
-#: src/language/command.c:845
-msgid "Interactive shell not supported on this platform."
-msgstr "Interpret d'ordres interactiu no disponible per a aquesta plataforma."
-
-#: src/language/command.c:857
-msgid "Command shell not supported on this platform."
-msgstr "Intèrpret d'ordres no disponible per aquesta plataforma."
-
-#: src/language/command.c:863
-#, c-format
-msgid "Error executing command: %s."
-msgstr "Error d'execució del comandament: %s."
-
-#: src/language/lexer/lexer.c:284
-#, c-format
-msgid "%s does not form a valid number."
-msgstr "%s no constitueix un número vàlid."
-
-#: src/language/lexer/lexer.c:390
-#, c-format
-msgid "Bad character in input: `%s'."
-msgstr "Caràcter erroni a l'entrada: `%s'."
-
-#: src/language/lexer/lexer.c:427
+#: src/language/lexer/lexer.c:276
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr "Subcomando %s només es pot especificar un cop."
 
-#: src/language/lexer/lexer.c:435
+#: src/language/lexer/lexer.c:284
 #, c-format
 msgid "missing required subcommand %s"
 msgstr "subordre requerida %s absent"
 
-#: src/language/lexer/lexer.c:464
-#, c-format
-msgid "Syntax error %s at %s."
-msgstr "Error de sintaxi %s a %s."
-
-#: src/language/lexer/lexer.c:467
-#, c-format
-msgid "Syntax error at %s."
-msgstr "Error de sintaxi a %s."
+#: src/language/lexer/lexer.c:302
+msgid "Syntax error at end of input"
+msgstr "Error de sintaxi al final de l'entrada"
 
-#: src/language/lexer/lexer.c:479 src/language/xforms/select-if.c:60
-#: src/language/stats/autorecode.c:144 src/language/data-io/print-space.c:73
+#: src/language/lexer/lexer.c:323 src/language/xforms/select-if.c:60
+#: src/language/stats/autorecode.c:162 src/language/stats/npar.c:414
+#: src/language/data-io/print-space.c:72
 msgid "expecting end of command"
 msgstr "s'espera el final de l'ordre"
 
-#: src/language/lexer/lexer.c:601 src/language/lexer/lexer.c:618
+#: src/language/lexer/lexer.c:494 src/language/lexer/lexer.c:511
 #, c-format
 msgid "expecting `%s'"
 msgstr "esperant '%s'"
 
-#: src/language/lexer/lexer.c:632
+#: src/language/lexer/lexer.c:525
 msgid "expecting string"
 msgstr "esperant cadena"
 
-#: src/language/lexer/lexer.c:646
+#: src/language/lexer/lexer.c:539
 msgid "expecting integer"
 msgstr "esperant sencer"
 
-#: src/language/lexer/lexer.c:659
+#: src/language/lexer/lexer.c:552
 msgid "expecting number"
 msgstr "esperant número"
 
-#: src/language/lexer/lexer.c:671
+#: src/language/lexer/lexer.c:564
 msgid "expecting identifier"
 msgstr "esperant identificador"
 
-#: src/language/lexer/lexer.c:1065
-msgid "binary"
-msgstr "binari"
+#: src/language/lexer/lexer.c:1187
+msgid "Syntax error at end of command"
+msgstr "Error de sintaxi al final del comando"
+
+#: src/language/lexer/lexer.c:1196
+#, c-format
+msgid "Syntax error at `%s'"
+msgstr "Error de sintaxi a `%s'"
+
+#: src/language/lexer/lexer.c:1199
+msgid "Syntax error"
+msgstr "Error de sintaxi"
+
+#: src/language/lexer/lexer.c:1358
+#, c-format
+msgid "String of hex digits has %d characters, which is not a multiple of 2"
+msgstr "La cadena de dígits hexadecimals té %d caràcters, que no és un múltiple de 2."
 
-#: src/language/lexer/lexer.c:1070
-msgid "octal"
-msgstr "octal"
+#: src/language/lexer/lexer.c:1365
+#, c-format
+msgid "`%c' is not a valid hex digit"
+msgstr "'%c' no és un dígit hexadecimal vàlid."
 
-#: src/language/lexer/lexer.c:1075
-msgid "hex"
-msgstr "hexadecimal"
+#: src/language/lexer/lexer.c:1370
+#, c-format
+msgid "Unicode string contains %d bytes, which is not in the valid range of 1 to 8 bytes"
+msgstr "Cadena Unicode conté %d bytes, que está fora del rang vàlid entre 1 y 8 bytes"
 
-#: src/language/lexer/lexer.c:1085
+#: src/language/lexer/lexer.c:1376
 #, c-format
-msgid "String of %s digits has %zu characters, which is not a multiple of %d."
-msgstr "La cadena de %s dígits té %zu caràcters, que no és un múltiple de %d."
+msgid "U+%04X is not a valid Unicode code point"
+msgstr "U+%04X no és un punt de codi Unicode vàlid"
+
+#: src/language/lexer/lexer.c:1381
+msgid "Unterminated string constant"
+msgstr "Constante de cadena inacabada"
 
-#: src/language/lexer/lexer.c:1114
+#: src/language/lexer/lexer.c:1385
 #, c-format
-msgid "`%c' is not a valid %s digit."
-msgstr "'%c' no és un dígit %s vàlid."
+msgid "Missing exponent following `%s'"
+msgstr "Manca l'exponent a continuació de `%s'"
 
-#: src/language/lexer/lexer.c:1148
-msgid "Unterminated string constant."
-msgstr "Constant de cadena inacabada."
+#: src/language/lexer/lexer.c:1390
+msgid "Unexpected `.' in middle of command"
+msgstr "`.' inesperat al mig d'un comand"
+
+#: src/language/lexer/lexer.c:1396
+#, c-format
+msgid "Bad character %s in input"
+msgstr "Caràcter erroni `%s' a l'entrada"
 
-#: src/language/lexer/lexer.c:1202
-msgid "Unexpected end of file in string concatenation."
-msgstr "Final d'arxiu inesperat a la concatenació de cadenes."
+#: src/language/lexer/lexer.c:1490
+#, c-format
+msgid "Opening `%s': %s."
+msgstr "Obrint `%s': %s."
 
-#: src/language/lexer/lexer.c:1210
-msgid "String expected following `+'."
-msgstr "S'espera una cadena seguida de `+'."
+#: src/language/lexer/lexer.c:1520
+#, c-format
+msgid "Error reading `%s': %s."
+msgstr "Error leyendo `%s': %s."
 
-#: src/language/lexer/lexer.c:1223
+#: src/language/lexer/lexer.c:1534
 #, c-format
-msgid "String exceeds 255 characters in length (%zu characters)."
-msgstr "La cadena supera els 255 caràcters de longitud (%zu caràcters)."
+msgid "Error closing `%s': %s."
+msgstr "Error tancant '%s' : %s."
 
-#: src/language/lexer/format-parser.c:88
+#: src/language/lexer/format-parser.c:79
 msgid "expecting valid format specifier"
 msgstr "esperant especificador de format vàlid"
 
-#: src/language/lexer/format-parser.c:107
-#: src/language/lexer/format-parser.c:126
-#: src/language/data-io/placement-parser.c:226
+#: src/language/lexer/format-parser.c:118
+#: src/language/lexer/format-parser.c:138
+#: src/language/data-io/placement-parser.c:225
 #, c-format
-msgid "Unknown format type \"%s\"."
-msgstr "Tipus de format \"%s\" desconegut."
+msgid "Unknown format type `%s'."
+msgstr "Tipus de format `%s' desconegut."
 
-#: src/language/lexer/format-parser.c:121
+#: src/language/lexer/format-parser.c:133
 msgid "expecting format type"
 msgstr "esperant el tipus de format"
 
-#: src/language/lexer/value-parser.c:60
+#: src/language/lexer/value-parser.c:65
 #, c-format
 msgid "Low end of range (%g) is below high end (%g).  The range will be treated as reversed."
 msgstr "El límit inferior de l'interval (%g) està per sota del límit superior (%g).  L' interval serà invertit."
 
-#: src/language/lexer/value-parser.c:68
+#: src/language/lexer/value-parser.c:73
 #, c-format
 msgid "Ends of range are equal (%g)."
 msgstr "Els límits de l'interval són iguals (%g)."
 
-#: src/language/lexer/value-parser.c:76
+#: src/language/lexer/value-parser.c:81
 msgid "LO or LOWEST must be part of a range."
 msgstr "LO o LOWEST han de ser part de l'interval."
 
-#: src/language/lexer/value-parser.c:109
+#: src/language/lexer/value-parser.c:117
 msgid "System-missing value is not valid here."
 msgstr "Valor perdut del sistema no és vàlid aquí."
 
-#: src/language/lexer/value-parser.c:117
+#: src/language/lexer/value-parser.c:125
 msgid "expecting number or data string"
 msgstr "esperant nombre o cadena de dades"
 
-#: src/language/lexer/variable-parser.c:65
+#: src/language/lexer/variable-parser.c:67
 msgid "expecting variable name"
 msgstr "esperant nom de la variable"
 
-#: src/language/lexer/variable-parser.c:75
+#: src/language/lexer/variable-parser.c:77
 #, c-format
 msgid "%s is not a variable name."
 msgstr "%s no és un nom de variable."
 
-#: src/language/lexer/variable-parser.c:178
+#: src/language/lexer/variable-parser.c:180
 #, c-format
 msgid "%s is not a numeric variable.  It will not be included in the variable list."
 msgstr "%s no és una variable numèrica. No serà inclosa a la llista de variables."
 
-#: src/language/lexer/variable-parser.c:181
+#: src/language/lexer/variable-parser.c:183
 #, c-format
 msgid "%s is not a string variable.  It will not be included in the variable list."
 msgstr "%s no és una variable de cadena. No serà inclosa a la llista de variables."
 
-#: src/language/lexer/variable-parser.c:185
+#: src/language/lexer/variable-parser.c:187
 #, c-format
 msgid "Scratch variables (such as %s) are not allowed here."
 msgstr "Les variables de treball  (com ara %s) no estan permeses aquí."
 
-#: src/language/lexer/variable-parser.c:189
+#: src/language/lexer/variable-parser.c:191
 #, c-format
 msgid "%s and %s are not the same type.  All variables in this variable list must be of the same type.  %s will be omitted from the list."
 msgstr "%s i %s no són del mateix tipus. Totes les variables d'aquesta llista han de ser del mateix tipus. %s serà omesa de la llista."
 
-#: src/language/lexer/variable-parser.c:195
+#: src/language/lexer/variable-parser.c:197
 #, c-format
 msgid "%s and %s are string variables with different widths.  All variables in this variable list must have the same width.  %s will be omitted from the list."
 msgstr "%s i %s són variables de cadena amb tamanys diferents. Totes les variables d'aquesta llista han de tenir la mateixa amplada. %s serà omesa de la llista."
 
-#: src/language/lexer/variable-parser.c:200
-#: src/language/lexer/variable-parser.c:496
+#: src/language/lexer/variable-parser.c:202
+#: src/language/lexer/variable-parser.c:404
 #, c-format
 msgid "Variable %s appears twice in variable list."
 msgstr "La variable %s apareix dues vegades en la llista de variables."
 
-#: src/language/lexer/variable-parser.c:313
+#: src/language/lexer/variable-parser.c:315
 #, c-format
 msgid "%s TO %s is not valid syntax since %s precedes %s in the dictionary."
 msgstr "%s TO %s no és una sintaxi vàlida atès que %s precedeix %s en el diccionari."
 
-#: src/language/lexer/variable-parser.c:321
+#: src/language/lexer/variable-parser.c:323
 #, c-format
 msgid "When using the TO keyword to specify several variables, both variables must be from the same variable dictionaries, of either ordinary, scratch, or system variables.  %s is a %s variable, whereas %s is %s."
 msgstr "Quan s'utilitza la paraula clau TO per especificar diverses variables, ambdues han de ser del mateix diccionari de variables, ja siguin ordinals, scratch, o variables de sistema. %s és una variable %s, atès que %s és %s."
 
-#: src/language/lexer/variable-parser.c:395
-msgid "incorrect use of TO convention"
-msgstr "ús incorrecte de la convenció TO"
+#: src/language/lexer/variable-parser.c:381
+#, c-format
+msgid "`%s' cannot be used with TO because it does not end in a digit."
+msgstr "`%s' no pot ser utilitzat amb TO perquè no acaba amb un dígit."
+
+#: src/language/lexer/variable-parser.c:389
+#, c-format
+msgid "Numeric suffix on `%s' is larger than supported with TO."
+msgstr "Sufix numèric a `%s' és més llarg del que és suportat amb TO."
 
-#: src/language/lexer/variable-parser.c:450
+#: src/language/lexer/variable-parser.c:465
 msgid "Scratch variables not allowed here."
 msgstr "Les variables de treball no estan permès aquí."
 
-#: src/language/lexer/variable-parser.c:472
+#: src/language/lexer/variable-parser.c:497
 msgid "Prefixes don't match in use of TO convention."
 msgstr "Els prefixos no coincideixen en l'ús de la convenció TO."
 
-#: src/language/lexer/variable-parser.c:477
+#: src/language/lexer/variable-parser.c:502
 msgid "Bad bounds in use of TO convention."
 msgstr "Límits incorrectes en l'ús de la convenció TO."
 
-#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:203
+#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:204
 #, c-format
 msgid "When executing COMPUTE: SYSMIS is not a valid value as an index into vector %s."
 msgstr "Quan s'executa COMPUTE: SYSMIS no és un valor vàlid com a índex en el vector %s."
 
-#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:210
+#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:211
 #, c-format
 msgid "When executing COMPUTE: %g is not a valid value as an index into vector %s."
 msgstr "Quan s'executa COMPUTE: %g no és un valor vàlid com a índex en el vector %s."
 
-#: src/language/xforms/compute.c:353
+#: src/language/xforms/compute.c:355
 #, c-format
 msgid "There is no vector named %s."
 msgstr "No hi ha cap vector anomenat %s."
 
-#: src/language/xforms/count.c:123
+#: src/language/xforms/count.c:125
 msgid "Destination cannot be a string variable."
 msgstr "El destí no pot ser una variable de cadena."
 
@@ -1397,38 +1390,38 @@ msgstr "El factor de mostratge ha d'estar exclusivament entre 0 i 1."
 msgid "Cannot sample %d observations from a population of %d."
 msgstr "No es pot fer una mostra de %d observacions d'una població de %d."
 
-#: src/language/xforms/recode.c:248
+#: src/language/xforms/recode.c:255
 msgid "Inconsistent target variable types.  Target variables must be all numeric or all string."
 msgstr "Tipus inconsistent de variables objectiu.  Les variables objectiu han de ser totes, o bé de cadena o bé numèriques."
 
-#: src/language/xforms/recode.c:269
+#: src/language/xforms/recode.c:276
 msgid "CONVERT requires string input values and numeric output values."
 msgstr "CONVERT requereix valors d'entrada de cadena i valors de sortida numèrics. "
 
-#: src/language/xforms/recode.c:324
+#: src/language/xforms/recode.c:333
 msgid "THRU is not allowed with string variables."
 msgstr "THRU no es permet amb variables de cadena."
 
-#: src/language/xforms/recode.c:403
+#: src/language/xforms/recode.c:416
 msgid "expecting output value"
 msgstr "esperant el valor de sortida"
 
-#: src/language/xforms/recode.c:460
+#: src/language/xforms/recode.c:473
 #, c-format
 msgid "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same number of variables as source and target variables."
 msgstr "%zu variable(s) no poden ser recodificades a %zu variable(s).  Especifiqueu el mateix nombre de variables com a origen i destinació."
 
-#: src/language/xforms/recode.c:475
+#: src/language/xforms/recode.c:488
 #, c-format
 msgid "There is no variable named %s.  (All string variables specified on INTO must already exist.  Use the STRING command to create a string variable.)"
 msgstr "No existeix cap variable anomenada %s. (Totes les variables de cadena especificades a INTO ja han d'existir.  Utilitzeu el comandament STRING per crear una variable de cadena.)"
 
-#: src/language/xforms/recode.c:491
+#: src/language/xforms/recode.c:504
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr "INTO és necessari amb %s valors d'entrada i %s valors de sortida."
 
-#: src/language/xforms/recode.c:504
+#: src/language/xforms/recode.c:517
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr "Desajust de tipus.  No es pot emmagatzemar %s dades a %s variable %s."
@@ -1445,17 +1438,17 @@ msgstr "La variable de filtre ha de ser numèrica."
 msgid "The filter variable may not be scratch."
 msgstr "La variable de filtre no pot ser zero."
 
-#: src/language/control/control-stack.c:27
+#: src/language/control/control-stack.c:31
 #, c-format
 msgid "%s without %s."
 msgstr "%s sense %s."
 
-#: src/language/control/control-stack.c:55
+#: src/language/control/control-stack.c:59
 #, c-format
 msgid "This command must appear inside %s...%s, without intermediate %s...%s."
 msgstr "Aquesta ordre ha d'aparèixer dins de %s...%s, sense intermediaris %s...%s."
 
-#: src/language/control/control-stack.c:72
+#: src/language/control/control-stack.c:76
 #, c-format
 msgid "This command cannot appear outside %s...%s."
 msgstr "Aquest comandament no pot aparèixer fora de %s...%s."
@@ -1468,60 +1461,65 @@ msgstr "Aquest comandament no pot seguir ELSE en DO IF...END IF."
 msgid "Only one index clause may be specified."
 msgstr "Només pot ser especificada una clàusula d'índex."
 
-#: src/language/control/temporary.c:46
-msgid "This command may only appear once between procedures and procedure-like commands."
-msgstr "Aquesta ordre només pot aparèixer una vegada entre les ordres de procediments i quasi-procediments."
-
-#: src/language/control/repeat.c:172
+#: src/language/control/repeat.c:115
 #, c-format
-msgid "Dummy variable name \"%s\" hides dictionary variable \"%s\"."
-msgstr "El nom de la variable fictícia \"%s\" oculta la variable de diccionari \"%s\"."
+msgid "Dummy variable name `%s' hides dictionary variable `%s'."
+msgstr "El nom de la variable fictícia `%s' oculta la variable de diccionari `%s'."
 
-#: src/language/control/repeat.c:177
+#: src/language/control/repeat.c:119
 #, c-format
-msgid "Dummy variable name \"%s\" is given twice."
-msgstr "El nom de la variable fictícia \"%s\" es dóna dues vegades."
+msgid "Dummy variable name `%s' is given twice."
+msgstr "El nom de la variable fictícia `%s' es dóna dues vegades."
 
-#: src/language/control/repeat.c:223
+#: src/language/control/repeat.c:162
 #, c-format
-msgid "Dummy variable \"%.*s\" had %d substitutions, so \"%.*s\" must also, but %d were specified."
-msgstr "Una variable fictícia \"%.*s\" en te %d substitucions, de manera que \"%.*s\" també n'hauria de tenir-les, però es van especificar %d."
+msgid "Dummy variable `%s' had %d substitutions, so `%s' must also, but %d were specified."
+msgstr "La variable fictícia `%.s' té %d substitucions, així que `%.s' també n'hauria de tenir-les, però es van especificar %d."
 
-#: src/language/control/repeat.c:335
-msgid "DO REPEAT may not nest in compatibility mode."
-msgstr "DO REPEAT no pot usar-se recursivament en mode de comptabilitat."
-
-#: src/language/control/repeat.c:437
-msgid "Ranges may only have integer bounds"
+#: src/language/control/repeat.c:366
+msgid "Ranges may only have integer bounds."
 msgstr "Els intervals només poden tenir límits sencers."
 
-#: src/language/control/repeat.c:446
+#: src/language/control/repeat.c:380
 #, c-format
-msgid "%g TO %g is an invalid range."
-msgstr "%g TO %g és un interval invalid."
+msgid "%ld TO %ld is an invalid range."
+msgstr "%ld TO %ld és un interval invalid."
 
-#: src/language/control/repeat.c:481
+#: src/language/control/repeat.c:414
 msgid "String expected."
 msgstr "Cadena esperada."
 
-#: src/language/control/repeat.c:500
+#: src/language/control/repeat.c:431
 msgid "No matching DO REPEAT."
 msgstr "DO REPEAT no coincideix."
 
-#: src/language/dictionary/attributes.c:108
+#: src/language/control/temporary.c:45
+msgid "This command may only appear once between procedures and procedure-like commands."
+msgstr "Aquesta ordre només pot aparèixer una vegada entre les ordres de procediments i quasi-procediments."
+
+#: src/language/dictionary/attributes.c:104
 msgid "Attribute array index must be between 1 and 65535."
 msgstr "L'índex de la taula d'atributs ha d'estar entre 1 i 65535."
 
-#: src/language/dictionary/attributes.c:189
-msgid "expecting ATTRIBUTE= or DELETE="
-msgstr "esperant ATTRIBUTE= o DELETE="
+#: src/language/dictionary/attributes.c:200
+#: src/language/data-io/get-data.c:324 src/language/data-io/get-data.c:362
+#: src/language/data-io/get.c:99 src/language/data-io/save-translate.c:118
+#: src/language/data-io/save-translate.c:135
+#: src/language/data-io/save-translate.c:148
+#: src/language/data-io/save-translate.c:196
+#: src/language/data-io/save-translate.c:210
+#: src/language/data-io/save-translate.c:228 src/language/data-io/save.c:216
+#: src/language/data-io/save.c:231 src/language/data-io/save.c:259
+#, c-format
+msgid "expecting %s or %s"
+msgstr "esperant %s o %s"
 
-#: src/language/dictionary/apply-dictionary.c:75
+#: src/language/dictionary/apply-dictionary.c:74
 #, c-format
 msgid "Variable %s is %s in target file, but %s in source file."
 msgstr "La variable %s és %s en l'arxiu de destinació, però %s en l'arxiu d'origen."
 
-#: src/language/dictionary/apply-dictionary.c:115
+#: src/language/dictionary/apply-dictionary.c:111
 msgid "No matching variables found between the source and target files."
 msgstr "No s'han trobat coincidències de variables entre els arxius d'origen i de destinació."
 
@@ -1529,59 +1527,55 @@ msgstr "No s'han trobat coincidències de variables entre els arxius d'origen i
 msgid "DELETE VARIABLES may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "DELETE VARIABLES no pot ser utilitzat després de TEMPORARY. Les transformacions temporals seran permanents."
 
-#: src/language/dictionary/delete-variables.c:48
-msgid "DELETE VARIABLES may not be used to delete all variables from the active file dictionary.  Use NEW FILE instead."
-msgstr "DELETE VARIABLES no pot ser utilitzar per esborrar totes les variables de l'arxiu de diccionari actiu. Utilitzar NEW FILE en el seu lloc."
+#: src/language/dictionary/delete-variables.c:47
+msgid "DELETE VARIABLES may not be used to delete all variables from the active dataset dictionary.  Use NEW FILE instead."
+msgstr "DELETE VARIABLES no pot ser utilitzar per esborrar totes les variables de l'arxiu de dades de diccionari actiu. Utilitzeu NEW FILE en el seu lloc."
 
 #: src/language/dictionary/formats.c:90
 msgid "`(' expected after variable list."
 msgstr "`(' esperat després de la llista de variables."
 
-#: src/language/dictionary/formats.c:100 src/language/dictionary/numeric.c:74
+#: src/language/dictionary/formats.c:100 src/language/dictionary/numeric.c:75
 msgid "`)' expected after output format."
 msgstr "`)' esperat després del format de resultats."
 
-#: src/language/dictionary/missing-values.c:56
-#: src/language/stats/aggregate.c:459
-msgid "expecting `('"
-msgstr "esperant `('"
-
-#: src/language/dictionary/missing-values.c:72
+#: src/language/dictionary/missing-values.c:70
 #, c-format
 msgid "Cannot mix numeric variables (e.g. %s) and string variables (e.g. %s) within a single list."
 msgstr "No es poden barrejar les variables numèriques (e.g. %s) i les variables de cadena (e.g. %s) dins d'una llista única."
 
-#: src/language/dictionary/missing-values.c:116
+#: src/language/dictionary/missing-values.c:119
 #, c-format
 msgid "Truncating missing value to maximum acceptable length (%d bytes)."
 msgstr "Truncant el valor perdut a la longitud màxima acceptable (%d bytes)."
 
-#: src/language/dictionary/missing-values.c:138
+#: src/language/dictionary/missing-values.c:142
 #, c-format
 msgid "Missing values provided are too long to assign to variable of width %d."
 msgstr "Els valors perduts donats són massa llargs per assignar a la variable d'amplada %d."
 
-#: src/language/dictionary/modify-variables.c:92
+#: src/language/dictionary/modify-variables.c:91
 msgid "MODIFY VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "MODIFY VARS no pot ser utilitzar després de TEMPORARY. Les transformacions temporals seran permanents."
 
-#: src/language/dictionary/modify-variables.c:114
+#: src/language/dictionary/modify-variables.c:113
 #: src/language/dictionary/modify-variables.c:177
+#: src/language/data-io/inpt-pgm.c:280
 #, c-format
 msgid "%s subcommand may be given at most once."
 msgstr "El subcomando %s pot ser utilitzat només una vegada."
 
-#: src/language/dictionary/modify-variables.c:137
+#: src/language/dictionary/modify-variables.c:136
 msgid "Cannot specify ALL after specifying a set of variables."
 msgstr "No es pot especificar ALL després de l'especificació d'un conjunt de variables."
 
-#: src/language/dictionary/modify-variables.c:147
+#: src/language/dictionary/modify-variables.c:146
 #: src/language/dictionary/modify-variables.c:190
 #, c-format
 msgid "`(' expected on %s subcommand."
 msgstr "S'espera `(' al subcomando %s."
 
-#: src/language/dictionary/modify-variables.c:159
+#: src/language/dictionary/modify-variables.c:158
 msgid "`)' expected following variable names on REORDER subcommand."
 msgstr "`)' s'esperava seguit dels noms de la variable en el subcomando REORDER."
 
@@ -1599,182 +1593,177 @@ msgstr "Diferent nombre de variables en la llista de noms antiga (%zu) i en la l
 msgid "`)' expected after variable lists on RENAME subcommand."
 msgstr "`)' esperat després de les llistes de variables en el subcomando RENAME."
 
-#: src/language/dictionary/modify-variables.c:233
+#: src/language/dictionary/modify-variables.c:234
 msgid "KEEP subcommand may be given at most once.  It may not be given in conjunction with the DROP subcommand."
 msgstr "El subcomando KEEP pot ser emès més d'una vegada. Pot ser que no sigui facilitada en relació amb el subcomando DROP."
 
-#: src/language/dictionary/modify-variables.c:276
+#: src/language/dictionary/modify-variables.c:277
 msgid "DROP subcommand may be given at most once.  It may not be given in conjunction with the KEEP subcommand."
 msgstr "El subcomando DROP pot ser utilitzat només una vegada. No pot ser utilitzat conjuntament amb el subcomando KEEP."
 
-#: src/language/dictionary/modify-variables.c:302
+#: src/language/dictionary/modify-variables.c:303
 #, c-format
 msgid "Unrecognized subcommand name `%s'."
 msgstr "Nom del subcomando no reconegut '%s'."
 
-#: src/language/dictionary/modify-variables.c:304
+#: src/language/dictionary/modify-variables.c:305
 msgid "Subcommand name expected."
 msgstr "Nom del subcomando esperat."
 
-#: src/language/dictionary/modify-variables.c:312
+#: src/language/dictionary/modify-variables.c:313
 msgid "`/' or `.' expected."
 msgstr "'/' o '.' esperat."
 
-#: src/language/dictionary/mrsets.c:98
-#, c-format
-msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
-msgstr "%s no és un nom vàlid de variable per a un conjunt de resposta múltiple. Els conjunts de resposta múltiple han de començar amb `$'."
-
-#: src/language/dictionary/mrsets.c:120
+#: src/language/dictionary/mrsets.c:116
 #, c-format
 msgid "VARIABLES specified only variable %s on %s, but at least two variables are required."
 msgstr "VARIABLES especifica només la variable %s a %s, però es requereixen al menys dues variables."
 
-#: src/language/dictionary/mrsets.c:153
+#: src/language/dictionary/mrsets.c:149
 msgid "Numeric VALUE must be an integer."
 msgstr "VALUE numèric ha de ser un enter."
 
-#: src/language/dictionary/mrsets.c:207 src/language/dictionary/mrsets.c:213
-#: src/language/dictionary/mrsets.c:223
+#: src/language/dictionary/mrsets.c:208 src/language/dictionary/mrsets.c:214
+#: src/language/dictionary/mrsets.c:224
 #, c-format
 msgid "Required %s specification missing from %s subcommand."
 msgstr "Manca la especificació %s requerida pel subcomando %s."
 
-#: src/language/dictionary/mrsets.c:231 src/language/dictionary/mrsets.c:269
+#: src/language/dictionary/mrsets.c:232 src/language/dictionary/mrsets.c:270
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies a string VALUE, but the variables specified for this group are numeric."
 msgstr "El subcomando MDGROUPS pel grup %s especifica un VALUE textual, però les variables especificades per aquest grup son numèriques."
 
-#: src/language/dictionary/mrsets.c:255
+#: src/language/dictionary/mrsets.c:256
 #, c-format
 msgid "VALUE string on MDGROUP subcommand for group %s is %d bytes long, but it must be no longer than the narrowest variable in the group, which is %s with a width of %d bytes."
 msgstr "El VALUE textual al subcomando MDGROUP pel grup %s té %d bytes, però no pot ser més llarg que la variable més curta al grup, que és %s amb llargada %d bytes."
 
-#: src/language/dictionary/mrsets.c:281
+#: src/language/dictionary/mrsets.c:282
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies LABELSOURCE=VARLABEL but not CATEGORYLABELS=COUNTEDVALUES.  Ignoring LABELSOURCE."
 msgstr "El subcomando MDGROUP pel grup %s espeficifica LABELSOURCE=VARLABEL però no CATEGORYLABELS=COUNTEDVALUES. S'ignorarà LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:287
+#: src/language/dictionary/mrsets.c:288
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies both LABEL and LABELSOURCE, but only one of these subcommands may be used at a time.  Ignoring LABELSOURCE."
 msgstr "El subcomando MDGROUP pel grup %s espeficifica LABEL i LABELSOURCE, però només un d'aquests subcomandos pot ser utilitzat alhora. S'ignorarà LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:327
+#: src/language/dictionary/mrsets.c:328
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s have the same variable label.  Categories represented by these variables will not be distinguishable in output."
 msgstr "Les variables %s i %s especificades com a part del grup dicotòmic múltiple %s tenen la mateixa etiqueta de variable. Les categories representades per aquestes variables no seran distingibles als resultats."
 
-#: src/language/dictionary/mrsets.c:357
+#: src/language/dictionary/mrsets.c:358
 #, c-format
 msgid "Variable %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) has no value label for its counted value.  This category will not be distinguishable in output."
 msgstr "La variable %s especificada com a part del grup dicotòmic múltiple %s (que té CATEGORYLABELS=COUNTEDVALUES) no en té etiqueta de valor pel seu valor de recompte. Aquesta categoria no serà distingible als resultats."
 
-#: src/language/dictionary/mrsets.c:370
+#: src/language/dictionary/mrsets.c:371
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) have the same value label for the the group's counted value.  These categories will not be distinguishable in output."
 msgstr "Les variables %s i %s  especificades com a part del grup dicotòmic múltiple %s (que té CATEGORYLABELS=COUNTEDVALUES) té la mateixa etiqueta de valor pel valor de recompte del grup. Aquestes categories no seran distingible als resultats."
 
-#: src/language/dictionary/mrsets.c:427
+#: src/language/dictionary/mrsets.c:428
 #, c-format
 msgid "Variables specified on MCGROUP should have the same categories, but %s and %s (and possibly others) in multiple category group %s have different value labels for value %s."
 msgstr "Variables especificades a MDGROUP han de tenir les mateixes categories, però %s i %s (i posiblement d'altres) al grup de caterories múltiple %s té diferents etiquetes de valors pel valor %s."
 
-#: src/language/dictionary/mrsets.c:484
+#: src/language/dictionary/mrsets.c:486
 #, c-format
 msgid "No multiple response set named %s."
 msgstr "Cap conjunt multiresposta anomenat %s."
 
-#: src/language/dictionary/mrsets.c:538
-msgid "The active file dictionary does not contain any multiple response sets."
-msgstr "El diccionari de l'arxiu actiu no conté cap conjunt de multi-resposta. "
+#: src/language/dictionary/mrsets.c:540
+msgid "The active dataset dictionary does not contain any multiple response sets."
+msgstr "El diccionari de l'arxiu de dades actiu no conté cap conjunt de multi-resposta. "
 
-#: src/language/dictionary/mrsets.c:548
+#: src/language/dictionary/mrsets.c:550
 msgid "Multiple Response Sets"
 msgstr "Conjunts Multi-Resposta"
 
-#: src/language/dictionary/mrsets.c:549 src/ui/gui/psppire-var-sheet.c:534
-#: src/ui/gui/psppire-var-store.c:832
+#: src/language/dictionary/mrsets.c:551 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:833
 msgid "Name"
 msgstr "Nom"
 
-#: src/language/dictionary/mrsets.c:550 src/ui/gui/variable-info.ui:8
+#: src/language/dictionary/mrsets.c:552 src/ui/gui/variable-info.ui:8
 msgid "Variables"
 msgstr "Variables:"
 
-#: src/language/dictionary/mrsets.c:551
+#: src/language/dictionary/mrsets.c:553
 msgid "Details"
 msgstr "Detalls"
 
-#: src/language/dictionary/mrsets.c:565
+#: src/language/dictionary/mrsets.c:567
 msgid "Multiple dichotomy set"
 msgstr "Conjunt de Dicotomies Múltiples"
 
-#: src/language/dictionary/mrsets.c:566
+#: src/language/dictionary/mrsets.c:568
 msgid "Multiple category set"
 msgstr "Conjunt de Categories Múltiples"
 
-#: src/language/dictionary/mrsets.c:568
+#: src/language/dictionary/mrsets.c:570
 #: src/language/dictionary/split-file.c:84
-#: src/language/dictionary/sys-file-info.c:344
-#: src/language/dictionary/sys-file-info.c:583
-#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:836
-#: src/ui/gui/crosstabs.ui:292 src/ui/gui/psppire.ui:1924
+#: src/language/dictionary/sys-file-info.c:338
+#: src/language/dictionary/sys-file-info.c:577
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/compute.ui:467 src/ui/gui/crosstabs.ui:292
 msgid "Label"
 msgstr "Etiqueta"
 
-#: src/language/dictionary/mrsets.c:572
+#: src/language/dictionary/mrsets.c:574
 msgid "Label source"
 msgstr "Font d'etiqueta"
 
-#: src/language/dictionary/mrsets.c:574
+#: src/language/dictionary/mrsets.c:576
 msgid "First variable label among variables"
 msgstr "Primera etiqueta de variable entre les variables"
 
-#: src/language/dictionary/mrsets.c:575
+#: src/language/dictionary/mrsets.c:577
 msgid "Provided by user"
 msgstr "Proporcionat per l'usuari"
 
-#: src/language/dictionary/mrsets.c:576
+#: src/language/dictionary/mrsets.c:578
 msgid "Counted value"
 msgstr "Valor de recompte"
 
-#: src/language/dictionary/mrsets.c:582
+#: src/language/dictionary/mrsets.c:584
 msgid "Category label source"
 msgstr "Font d'etiquetes de categoria"
 
-#: src/language/dictionary/mrsets.c:584
+#: src/language/dictionary/mrsets.c:586
 msgid "Variable labels"
 msgstr "Etiquetes de variable"
 
-#: src/language/dictionary/mrsets.c:585
+#: src/language/dictionary/mrsets.c:587
 msgid "Value labels of counted value"
 msgstr "Etiquetes de valor del valor de recompte"
 
-#: src/language/dictionary/numeric.c:67
+#: src/language/dictionary/numeric.c:68
 #, c-format
 msgid "Format type %s may not be used with a numeric variable."
 msgstr "Tipus de format %s no pot ser utilitzat amb una variable numèrica."
 
-#: src/language/dictionary/numeric.c:86 src/language/dictionary/numeric.c:155
+#: src/language/dictionary/numeric.c:87 src/language/dictionary/numeric.c:157
 #, c-format
 msgid "There is already a variable named %s."
 msgstr "Ja existeix una variable amb el nom %s."
 
-#: src/language/dictionary/numeric.c:140
+#: src/language/dictionary/numeric.c:142
 #, c-format
 msgid "Format type %s may not be used with a string variable."
 msgstr "Tipus de format %s no pot ser utilitzat amb una variable de cadena. "
 
-#: src/language/dictionary/rename-variables.c:49
+#: src/language/dictionary/rename-variables.c:48
 msgid "RENAME VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "RENAME VARS no pot ser utilitzat després de TEMPORARY.  Les transformacions temporals seran permanents."
 
-#: src/language/dictionary/rename-variables.c:59
+#: src/language/dictionary/rename-variables.c:58
 msgid "`(' expected."
 msgstr "'(' esperat."
 
-#: src/language/dictionary/rename-variables.c:67
+#: src/language/dictionary/rename-variables.c:66
 msgid "`=' expected between lists of new and old variable names."
 msgstr "`=' esperat entre llistes de nous i antics noms de la variable."
 
@@ -1788,268 +1777,265 @@ msgid "Renaming would duplicate variable name %s."
 msgstr "Canviar el nom duplicaria el nom de la variable %s."
 
 #: src/language/dictionary/split-file.c:83
-#: src/language/dictionary/sys-file-info.c:429
-#: src/language/dictionary/sys-file-info.c:582
-#: src/language/stats/crosstabs.q:1214 src/language/stats/crosstabs.q:1241
-#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1289
-#: src/language/stats/examine.q:1841 src/language/stats/frequencies.q:813
-#: src/language/stats/reliability.q:568 src/language/stats/reliability.q:579
+#: src/language/dictionary/sys-file-info.c:423
+#: src/language/dictionary/sys-file-info.c:576
+#: src/language/stats/cochran.c:170 src/language/stats/reliability.c:753
+#: src/language/stats/reliability.c:764 src/language/stats/crosstabs.q:1234
+#: src/language/stats/crosstabs.q:1261 src/language/stats/crosstabs.q:1284
+#: src/language/stats/crosstabs.q:1309 src/language/stats/examine.q:1840
+#: src/language/stats/frequencies.q:823
 msgid "Value"
 msgstr "Valor"
 
-#: src/language/dictionary/sys-file-info.c:95
+#: src/language/dictionary/sys-file-info.c:94
 msgid "File:"
 msgstr "Arxiu:"
 
-#: src/language/dictionary/sys-file-info.c:97 src/ui/gui/psppire.ui:1862
+#: src/language/dictionary/sys-file-info.c:96 src/ui/gui/compute.ui:405
 #: src/ui/gui/recode.ui:859
 msgid "Label:"
 msgstr "Etiqueta:"
 
-#: src/language/dictionary/sys-file-info.c:101
+#: src/language/dictionary/sys-file-info.c:100
 msgid "No label."
 msgstr "Sense etiqueta."
 
-#: src/language/dictionary/sys-file-info.c:104
+#: src/language/dictionary/sys-file-info.c:103
 msgid "Created:"
 msgstr "Creat:"
 
-#: src/language/dictionary/sys-file-info.c:107
+#: src/language/dictionary/sys-file-info.c:106
 msgid "Integer Format:"
 msgstr "Format Sencer:"
 
-#: src/language/dictionary/sys-file-info.c:111
-#: src/language/dictionary/sys-file-info.c:119
-#: src/language/dictionary/sys-file-info.c:124
-#: src/language/dictionary/sys-file-info.c:143
+#: src/language/dictionary/sys-file-info.c:108
+msgid "Big Endian"
+msgstr "Tipus Big-Endian."
+
+#: src/language/dictionary/sys-file-info.c:109
+msgid "Little Endian"
+msgstr "Tipus Little-Endian."
+
+#: src/language/dictionary/sys-file-info.c:110
+#: src/language/dictionary/sys-file-info.c:118
+#: src/language/dictionary/sys-file-info.c:123
+#: src/language/dictionary/sys-file-info.c:142
 msgid "Unknown"
 msgstr "Desconegut"
 
-#: src/language/dictionary/sys-file-info.c:112
+#: src/language/dictionary/sys-file-info.c:111
 msgid "Real Format:"
 msgstr "Format Real:"
 
-#: src/language/dictionary/sys-file-info.c:114
+#: src/language/dictionary/sys-file-info.c:113
 msgid "IEEE 754 LE."
 msgstr "IEEE 754 LE."
 
-#: src/language/dictionary/sys-file-info.c:115
+#: src/language/dictionary/sys-file-info.c:114
 msgid "IEEE 754 BE."
 msgstr "IEE 754 BE."
 
-#: src/language/dictionary/sys-file-info.c:116
+#: src/language/dictionary/sys-file-info.c:115
 msgid "VAX D."
 msgstr "VAX D."
 
-#: src/language/dictionary/sys-file-info.c:117
+#: src/language/dictionary/sys-file-info.c:116
 msgid "VAX G."
 msgstr "VAX G."
 
-#: src/language/dictionary/sys-file-info.c:118
+#: src/language/dictionary/sys-file-info.c:117
 msgid "IBM 390 Hex Long."
 msgstr "IBM 390 Hex Long."
 
-#: src/language/dictionary/sys-file-info.c:120 src/ui/gui/descriptives.ui:85
-#: src/ui/gui/factor.ui:173 src/ui/gui/recode.ui:960
+#: src/language/dictionary/sys-file-info.c:119 src/ui/gui/descriptives.ui:85
+#: src/ui/gui/factor.ui:181 src/ui/gui/recode.ui:960
 msgid "Variables:"
 msgstr "Variables:"
 
-#: src/language/dictionary/sys-file-info.c:122
+#: src/language/dictionary/sys-file-info.c:121
 msgid "Cases:"
 msgstr "Casos:"
 
-#: src/language/dictionary/sys-file-info.c:127
+#: src/language/dictionary/sys-file-info.c:126
 msgid "Type:"
 msgstr "Tipus:"
 
-#: src/language/dictionary/sys-file-info.c:128
-#: src/ui/gui/psppire-data-window.c:634
+#: src/language/dictionary/sys-file-info.c:127
+#: src/ui/gui/psppire-data-window.c:621
 msgid "System File"
 msgstr "Arxiu de Sistema"
 
-#: src/language/dictionary/sys-file-info.c:129
+#: src/language/dictionary/sys-file-info.c:128
 msgid "Weight:"
 msgstr "Pes:"
 
-#: src/language/dictionary/sys-file-info.c:134
+#: src/language/dictionary/sys-file-info.c:133
 msgid "Not weighted."
 msgstr "No ponderat."
 
-#: src/language/dictionary/sys-file-info.c:136
+#: src/language/dictionary/sys-file-info.c:135
 msgid "Mode:"
 msgstr "Mode:"
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 #, c-format
 msgid "Compression %s."
 msgstr "Compressió %s."
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 msgid "on"
 msgstr "activat"
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 msgid "off"
 msgstr "desactivat"
 
-#: src/language/dictionary/sys-file-info.c:141
+#: src/language/dictionary/sys-file-info.c:140
 msgid "Charset:"
 msgstr "Conjunt de caràcters:"
 
-#: src/language/dictionary/sys-file-info.c:151
-#: src/language/dictionary/sys-file-info.c:344
+#: src/language/dictionary/sys-file-info.c:150
+#: src/language/dictionary/sys-file-info.c:338
 msgid "Description"
 msgstr "Descripció"
 
-#: src/language/dictionary/sys-file-info.c:152
-#: src/language/dictionary/sys-file-info.c:346
-#: src/language/dictionary/sys-file-info.c:663
+#: src/language/dictionary/sys-file-info.c:151
+#: src/language/dictionary/sys-file-info.c:340
+#: src/language/dictionary/sys-file-info.c:657
 msgid "Position"
 msgstr "Posició"
 
-#: src/language/dictionary/sys-file-info.c:199
-msgid "The active file does not have a file label."
-msgstr "L'arxiu actiu no té etiqueta d'arxiu."
+#: src/language/dictionary/sys-file-info.c:198
+msgid "The active dataset does not have a file label."
+msgstr "L'arxiu de dades actiu no té etiqueta d'arxiu."
 
-#: src/language/dictionary/sys-file-info.c:202
+#: src/language/dictionary/sys-file-info.c:201
 msgid "File label:"
 msgstr "Etiqueta d'arxiu:"
 
-#: src/language/dictionary/sys-file-info.c:277
+#: src/language/dictionary/sys-file-info.c:276
 msgid "No variables to display."
 msgstr "Cap variable per mostrar."
 
-#: src/language/dictionary/sys-file-info.c:291
+#: src/language/dictionary/sys-file-info.c:290
 msgid "Macros not supported."
 msgstr "Macros no disponibles."
 
-#: src/language/dictionary/sys-file-info.c:300
-msgid "The active file dictionary does not contain any documents."
-msgstr "El diccionari de l'arxiu actiu no conté cap document. "
+#: src/language/dictionary/sys-file-info.c:299
+msgid "The active dataset dictionary does not contain any documents."
+msgstr "El diccionari de l'arxiu de dades actiu no conté cap document. "
 
-#: src/language/dictionary/sys-file-info.c:308
-msgid "Documents in the active file:"
-msgstr "Documents a l'arxiu actiu:"
+#: src/language/dictionary/sys-file-info.c:306
+msgid "Documents in the active dataset:"
+msgstr "Documents a l'arxiu de dades actiu:"
 
-#: src/language/dictionary/sys-file-info.c:428
+#: src/language/dictionary/sys-file-info.c:422
 msgid "Attribute"
 msgstr "Atribut"
 
-#: src/language/dictionary/sys-file-info.c:484
+#: src/language/dictionary/sys-file-info.c:478
 #, c-format
 msgid "Format: %s"
 msgstr "Format: %s"
 
-#: src/language/dictionary/sys-file-info.c:491
+#: src/language/dictionary/sys-file-info.c:485
 #, c-format
 msgid "Print Format: %s"
 msgstr "Format d'Impressió: %s"
 
-#: src/language/dictionary/sys-file-info.c:495
+#: src/language/dictionary/sys-file-info.c:489
 #, c-format
 msgid "Write Format: %s"
 msgstr "Format d'Escriptura: %s"
 
-#: src/language/dictionary/sys-file-info.c:508
+#: src/language/dictionary/sys-file-info.c:502
 #, c-format
 msgid "Measure: %s"
 msgstr "Mesura: %s"
 
-#: src/language/dictionary/sys-file-info.c:509
+#: src/language/dictionary/sys-file-info.c:503
 #: src/ui/gui/psppire-var-sheet.c:111
 msgid "Nominal"
 msgstr "Nominal"
 
-#: src/language/dictionary/sys-file-info.c:510
+#: src/language/dictionary/sys-file-info.c:504
 #: src/ui/gui/psppire-var-sheet.c:112
 msgid "Ordinal"
 msgstr "Ordinal"
 
-#: src/language/dictionary/sys-file-info.c:511
+#: src/language/dictionary/sys-file-info.c:505
 #: src/ui/gui/psppire-var-sheet.c:113
 msgid "Scale"
 msgstr "Escala"
 
-#: src/language/dictionary/sys-file-info.c:514
+#: src/language/dictionary/sys-file-info.c:508
 #, c-format
 msgid "Display Alignment: %s"
 msgstr "Alineació de la mostra: %s"
 
-#: src/language/dictionary/sys-file-info.c:515
+#: src/language/dictionary/sys-file-info.c:509
 #: src/ui/gui/psppire-var-sheet.c:104
 msgid "Left"
 msgstr "Esquerra"
 
-#: src/language/dictionary/sys-file-info.c:516
+#: src/language/dictionary/sys-file-info.c:510
 #: src/ui/gui/psppire-var-sheet.c:106
 msgid "Center"
 msgstr "Centre"
 
-#: src/language/dictionary/sys-file-info.c:517
+#: src/language/dictionary/sys-file-info.c:511
 #: src/ui/gui/psppire-var-sheet.c:105
 msgid "Right"
 msgstr "Dreta"
 
-#: src/language/dictionary/sys-file-info.c:520
+#: src/language/dictionary/sys-file-info.c:514
 #, c-format
 msgid "Display Width: %d"
 msgstr "Amplada de la mostra: %d"
 
-#: src/language/dictionary/sys-file-info.c:534
+#: src/language/dictionary/sys-file-info.c:528
 msgid "Missing Values: "
 msgstr "Valors perduts:"
 
-#: src/language/dictionary/sys-file-info.c:643
+#: src/language/dictionary/sys-file-info.c:637
 msgid "No vectors defined."
 msgstr "Vectors no definits."
 
-#: src/language/dictionary/sys-file-info.c:662
+#: src/language/dictionary/sys-file-info.c:656
 msgid "Vector"
 msgstr "Vector"
 
-#: src/language/dictionary/sys-file-info.c:665
+#: src/language/dictionary/sys-file-info.c:659
 msgid "Print Format"
 msgstr "Format d'Impressió"
 
-#: src/language/dictionary/value-labels.c:150
-msgid "Truncating value label to 60 characters."
-msgstr "Truncant etiqueta de valor a 60 caràcters."
-
-#: src/language/dictionary/variable-label.c:51
-msgid "String expected for variable label."
-msgstr "S'espera una cadena com a etiqueta de variable."
-
-#: src/language/dictionary/variable-label.c:59
-msgid "Truncating variable label to 255 characters."
-msgstr "Truncant la etiqueta de variable a 255 caràcters."
+#: src/language/dictionary/value-labels.c:154
+#, c-format
+msgid "Truncating value label to %d bytes."
+msgstr "Truncant etiqueta de valor a %d caràcters."
 
-#: src/language/dictionary/vector.c:64
+#: src/language/dictionary/vector.c:65
 #, c-format
 msgid "A vector named %s already exists."
 msgstr "Un vector anomenat %s ja existeix."
 
-#: src/language/dictionary/vector.c:72
+#: src/language/dictionary/vector.c:73
 #, c-format
 msgid "Vector name %s is given twice."
 msgstr "El nom del vector %s es dóna dues vegades."
 
-#: src/language/dictionary/vector.c:96
+#: src/language/dictionary/vector.c:97
 msgid "A slash must separate each vector specification in VECTOR's long form."
 msgstr "Una barra ha de separar cada especificació de vector en la forma llarga de VECTOR."
 
-#: src/language/dictionary/vector.c:129
+#: src/language/dictionary/vector.c:130
 msgid "Vectors must have at least one element."
 msgstr "Els vectors han de tenir almenys un element."
 
-#: src/language/dictionary/vector.c:150
+#: src/language/dictionary/vector.c:151
 msgid "expecting vector length"
 msgstr "esperant longitud del vector"
 
-#: src/language/dictionary/vector.c:166
-#, c-format
-msgid "%s is too long for a variable name."
-msgstr "%s és massa llarg per un nom de variable."
-
 #: src/language/dictionary/vector.c:171
 #, c-format
 msgid "%s is an existing variable name."
@@ -2067,201 +2053,268 @@ msgstr "La variable de ponderació ha de ser numèrica."
 msgid "The weighting variable may not be scratch."
 msgstr "La variable de ponderació no pot ser zero."
 
-#: src/language/tests/float-format.c:124
-#, c-format
-msgid "%zu-byte string needed but %zu-byte string supplied."
-msgstr "Es necessita cadena de %zu-byte però s'han subministrat de %zu-byte."
-
-#: src/language/tests/float-format.c:136
-msgid "Hexadecimal floating constant too long."
-msgstr "Constant hexadecimal flotant massa llarga."
-
-#: src/language/tests/float-format.c:201
-#, c-format
-msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
-msgstr "conversió %s de %s desde %s a %s s'hauria d'haver produït %s però actualment ha produït %s."
-
-#: src/language/tests/float-format.c:247
-msgid "Too many values in single command."
-msgstr "Massa valors en el comandament únic."
-
-#: src/language/tests/moments-test.c:47
+#: src/language/tests/moments-test.c:50
 msgid "expecting weight value"
 msgstr "esperant el valor de ponderació"
 
-#: src/language/utilities/cd.c:41
+#: src/language/utilities/cd.c:45
 #, c-format
 msgid "Cannot change directory to %s:  %s "
 msgstr "No es pot canviar el directori per %s: %s"
 
-#: src/language/utilities/date.c:32
+#: src/language/utilities/date.c:33
 msgid "Only USE ALL is currently implemented."
 msgstr "Només USE ALL s'està aplicant actualment."
 
-#: src/language/utilities/title.c:103
+#: src/language/utilities/host.c:87
 #, c-format
-msgid "   (Entered %s)"
-msgstr "   (Introduït %s)"
+msgid "Couldn't fork: %s."
+msgstr "Impossible crear forquilla: %s."
 
-#: src/language/utilities/include.c:95
-msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
-msgstr "Esperant BATCH o INTERACTIVE després de SYNTAX."
+#: src/language/utilities/host.c:102
+msgid "Interactive shell not supported on this platform."
+msgstr "Interpret d'ordres interactiu no disponible per a aquesta plataforma."
 
-#: src/language/utilities/include.c:112
-msgid "Expecting YES or NO after CD."
-msgstr "Esperant YES o NO després del CD."
+#: src/language/utilities/host.c:114
+msgid "Command shell not supported on this platform."
+msgstr "Intèrpret d'ordres no disponible per aquesta plataforma."
 
-#: src/language/utilities/include.c:129
-msgid "Expecting CONTINUE or STOP after ERROR."
-msgstr "Esperant CONTINUE o bé STOP després de l'ERROR."
+#: src/language/utilities/host.c:120
+#, c-format
+msgid "Error executing command: %s."
+msgstr "Error d'execució del comandament: %s."
 
-#: src/language/utilities/include.c:136
+#: src/language/utilities/title.c:97
 #, c-format
-msgid "Unexpected token: `%s'."
-msgstr "Testimoni inesperat: `%s'."
+msgid "   (Entered %s)"
+msgstr "   (Introduït %s)"
 
-#: src/language/utilities/include.c:181
+#: src/language/utilities/include.c:64
 msgid "expecting file name"
 msgstr "esperant nom d'arxiu"
 
-#: src/language/utilities/include.c:193
+#: src/language/utilities/include.c:74
 #, c-format
 msgid "Can't find `%s' in include file search path."
 msgstr "No es pot trobar `%s' en la ruta de cerca de l'arxiu d'inclusió."
 
-#: src/language/utilities/include.c:201
+#: src/language/utilities/include.c:107
+#, c-format
+msgid "expecting %s, %s, or %s after %s"
+msgstr "s'espera %s, %s o %s darrera %s"
+
+#: src/language/utilities/include.c:125 src/language/utilities/include.c:143
 #, c-format
-msgid "Unable to open `%s': %s."
-msgstr "No es pot obrir `%s': %s."
+msgid "expecting %s or %s after %s"
+msgstr "s'espera %s o %s darrera %s"
 
-#: src/language/utilities/permissions.c:73
+#: src/language/utilities/permissions.c:78
 #, c-format
 msgid "Expecting %s or %s."
 msgstr "Esperant %s o bé %s."
 
-#: src/language/utilities/permissions.c:106
+#: src/language/utilities/permissions.c:113
 #, c-format
 msgid "Cannot stat %s: %s"
 msgstr "No es pot dir que %s: %s"
 
-#: src/language/utilities/permissions.c:119
+#: src/language/utilities/permissions.c:127
 #, c-format
 msgid "Cannot change mode of %s: %s"
 msgstr "No es pot canviar el mode ed %s: %s"
 
-#: src/language/stats/aggregate.c:220
-msgid "while expecting COLUMNWISE"
-msgstr "mentrestant esperant COLUMNWISE"
+#: src/language/stats/aggregate.c:95
+msgid "Sum of values"
+msgstr "Suma de valors"
+
+#: src/language/stats/aggregate.c:96
+msgid "Mean average"
+msgstr "Mitjana promig"
+
+#: src/language/stats/aggregate.c:97
+msgid "Median average"
+msgstr "Mediana promig"
+
+#: src/language/stats/aggregate.c:98 src/ui/gui/descriptives-dialog.c:40
+#: src/ui/gui/frequencies-dialog.c:41
+msgid "Standard deviation"
+msgstr "Desviació Estàndard"
+
+#: src/language/stats/aggregate.c:99
+msgid "Maximum value"
+msgstr "Valor màxim"
+
+#: src/language/stats/aggregate.c:100
+msgid "Minimum value"
+msgstr "Valor mínim"
+
+#: src/language/stats/aggregate.c:101
+msgid "Percentage greater than"
+msgstr "Percentatge mes gran que"
+
+#: src/language/stats/aggregate.c:102
+msgid "Percentage less than"
+msgstr "Percentatge mes petit que"
+
+#: src/language/stats/aggregate.c:103
+msgid "Percentage included in range"
+msgstr "Percentatge inclos a l'interval"
+
+#: src/language/stats/aggregate.c:104
+msgid "Percentage excluded from range"
+msgstr "Percentatge exclos de l'interval"
+
+#: src/language/stats/aggregate.c:105
+msgid "Fraction greater than"
+msgstr "Fracció més gran que"
+
+#: src/language/stats/aggregate.c:106
+msgid "Fraction less than"
+msgstr "Fracció més petit que"
+
+#: src/language/stats/aggregate.c:107
+msgid "Fraction included in range"
+msgstr "Fracció inclosa a l'interval"
+
+#: src/language/stats/aggregate.c:108
+msgid "Fraction excluded from range"
+msgstr "Fracció exclosa de l'nterval"
+
+#: src/language/stats/aggregate.c:109
+msgid "Number of cases"
+msgstr "Nombre de casos"
 
-#: src/language/stats/aggregate.c:247
-msgid "expecting BREAK"
-msgstr "esperant BREAK"
+#: src/language/stats/aggregate.c:110
+msgid "Number of cases (unweighted)"
+msgstr "Nombre de casos (sense ponderar)"
 
-#: src/language/stats/aggregate.c:252
+#: src/language/stats/aggregate.c:111
+msgid "Number of missing values"
+msgstr "Nombre de valors perduts"
+
+#: src/language/stats/aggregate.c:112
+msgid "Number of missing values (unweighted)"
+msgstr "Nombre de valors perduts (sense ponderar)"
+
+#: src/language/stats/aggregate.c:113
+msgid "First non-missing value"
+msgstr "Primer valor no-perdut"
+
+#: src/language/stats/aggregate.c:114
+msgid "Last non-missing value"
+msgstr "Darrer valor no-perdut"
+
+#: src/language/stats/aggregate.c:226 src/language/data-io/get-data.c:473
+#, c-format
+msgid "expecting %s"
+msgstr "s'espera %s"
+
+#: src/language/stats/aggregate.c:257
 msgid "When PRESORTED is specified, specifying sorting directions with (A) or (D) has no effect.  Output data will be sorted the same way as the input data."
 msgstr "Quan s'especifica PRESORTED, donar directives d'ordenació amb  (A) o (D) no té efecte. Les dades de sortida seran ordenades de la mateixa manera que les d'entrada."
 
-#: src/language/stats/aggregate.c:424
+#: src/language/stats/aggregate.c:447
 msgid "expecting aggregation function"
 msgstr "esperant un funció agregadora"
 
-#: src/language/stats/aggregate.c:442
+#: src/language/stats/aggregate.c:459
 #, c-format
 msgid "Unknown aggregation function %s."
 msgstr "Funció desconeguda %s."
 
-#: src/language/stats/aggregate.c:498
+#: src/language/stats/aggregate.c:513
 #, c-format
 msgid "Missing argument %zu to %s."
 msgstr "Argument perdut %zu per a %s."
 
-#: src/language/stats/aggregate.c:507
+#: src/language/stats/aggregate.c:522
 #, c-format
 msgid "Arguments to %s must be of same type as source variables."
 msgstr "Els arguments per a %s han de ser del mateix tipus que les variables d'origen."
 
-#: src/language/stats/aggregate.c:517 src/language/expressions/parse.c:885
-msgid "expecting `)'"
-msgstr "esperant `)'"
-
-#: src/language/stats/aggregate.c:529
+#: src/language/stats/aggregate.c:541
 #, c-format
 msgid "Number of source variables (%zu) does not match number of target variables (%zu)."
 msgstr "Nombre de variables d'origen (%zu) no coincideix amb el nombre de variables de destinació (%zu)."
 
-#: src/language/stats/aggregate.c:545
+#: src/language/stats/aggregate.c:557
 #, c-format
 msgid "The value arguments passed to the %s function are out-of-order.  They will be treated as if they had been specified in the correct order."
 msgstr "El valor dels arguments passats a la funció %s estan fora d'ordre. Seran tractats com si haguessin estat especificats en l'ordre correcte."
 
-#: src/language/stats/aggregate.c:615
+#: src/language/stats/aggregate.c:631
 #, c-format
 msgid "Variable name %s is not unique within the aggregate file dictionary, which contains the aggregate variables and the break variables."
 msgstr "El nom de variable %s no és únic dins l'arxiu de diccionari agregat, que conté les variables agregades i les variables de tall."
 
-#: src/language/stats/autorecode.c:116
+#: src/language/stats/autorecode.c:128
 #, c-format
 msgid "Source variable count (%zu) does not match target variable count (%zu)."
 msgstr "El recompte de la variable d'origen (%zu) no coincideix amb el recompte de la variable de destí (%zu)."
 
-#: src/language/stats/autorecode.c:128
+#: src/language/stats/autorecode.c:140
 #, c-format
 msgid "Target variable %s duplicates existing variable %s."
 msgstr "Variable de destí %s duplica una variable existent %s."
 
-#: src/language/stats/binomial.c:141
+#: src/language/stats/binomial.c:136
 #, c-format
 msgid "Variable %s is not dichotomous"
 msgstr "La variable %s no és dicotòmica"
 
-#: src/language/stats/binomial.c:192 src/ui/gui/binomial.ui:13
+#: src/language/stats/binomial.c:187 src/ui/gui/binomial.ui:13
 msgid "Binomial Test"
 msgstr "Prova Binomial"
 
-#: src/language/stats/binomial.c:222
+#: src/language/stats/binomial.c:217
 msgid "Group1"
 msgstr "Grup 1"
 
-#: src/language/stats/binomial.c:223
+#: src/language/stats/binomial.c:218
 msgid "Group2"
 msgstr "Grup 2"
 
-#: src/language/stats/binomial.c:224 src/language/stats/chisquare.c:177
-#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1462
-#: src/language/stats/sign.c:92 src/language/stats/wilcoxon.c:260
-#: src/ui/gui/crosstabs-dialog.c:60 src/language/stats/crosstabs.q:823
-#: src/language/stats/crosstabs.q:1151 src/language/stats/crosstabs.q:1528
-#: src/language/stats/examine.q:1105 src/language/stats/frequencies.q:871
-#: src/language/stats/oneway.q:302 src/language/stats/oneway.q:472
-#: src/language/stats/regression.q:291 src/language/stats/reliability.q:702
+#: src/language/stats/binomial.c:219 src/language/stats/chisquare.c:177
+#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1460
+#: src/language/stats/kruskal-wallis.c:292
+#: src/language/stats/mann-whitney.c:188 src/language/stats/oneway.c:616
+#: src/language/stats/oneway.c:786 src/language/stats/reliability.c:533
+#: src/language/stats/sign.c:95 src/language/stats/wilcoxon.c:255
+#: src/ui/gui/crosstabs-dialog.c:59 src/language/stats/crosstabs.q:832
+#: src/language/stats/crosstabs.q:1176 src/language/stats/crosstabs.q:1560
+#: src/language/stats/examine.q:1104 src/language/stats/frequencies.q:881
+#: src/language/stats/regression.q:293
 msgid "Total"
 msgstr "Total"
 
-#: src/language/stats/binomial.c:257 src/language/stats/chisquare.c:199
-#: src/language/stats/crosstabs.q:1239 src/language/stats/crosstabs.q:1286
+#: src/language/stats/binomial.c:252 src/language/stats/chisquare.c:199
+#: src/language/stats/crosstabs.q:1259 src/language/stats/crosstabs.q:1306
 msgid "Category"
 msgstr "Categoria"
 
-#: src/language/stats/binomial.c:258 src/language/stats/correlations.c:119
-#: src/language/stats/correlations.c:227 src/language/stats/npar-summary.c:122
-#: src/language/stats/sign.c:72 src/language/stats/wilcoxon.c:243
-#: src/language/stats/crosstabs.q:830 src/language/stats/examine.q:1176
-#: src/language/stats/frequencies.q:1034 src/language/stats/oneway.q:385
-#: src/language/stats/reliability.q:705 src/language/stats/t-test.q:505
-#: src/language/stats/t-test.q:525 src/language/stats/t-test.q:625
-#: src/language/stats/t-test.q:1101
+#: src/language/stats/binomial.c:253 src/language/stats/cochran.c:211
+#: src/language/stats/correlations.c:120 src/language/stats/correlations.c:228
+#: src/language/stats/friedman.c:275 src/language/stats/kruskal-wallis.c:257
+#: src/language/stats/mann-whitney.c:190 src/language/stats/npar-summary.c:123
+#: src/language/stats/oneway.c:686 src/language/stats/reliability.c:536
+#: src/language/stats/sign.c:74 src/language/stats/wilcoxon.c:238
+#: src/language/stats/crosstabs.q:839 src/language/stats/examine.q:1175
+#: src/language/stats/frequencies.q:1043 src/language/stats/t-test.q:509
+#: src/language/stats/t-test.q:529 src/language/stats/t-test.q:629
+#: src/language/stats/t-test.q:1105
 msgid "N"
 msgstr "N"
 
-#: src/language/stats/binomial.c:259
+#: src/language/stats/binomial.c:254
 msgid "Observed Prop."
 msgstr "Prop. Observat"
 
-#: src/language/stats/binomial.c:260
+#: src/language/stats/binomial.c:255
 msgid "Test Prop."
 msgstr "Test Prop."
 
-#: src/language/stats/binomial.c:263
+#: src/language/stats/binomial.c:258 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1241
 #, c-format
 msgid "Exact Sig. (%d-tailed)"
 msgstr "Sig. Exact.(%d-tailed)"
@@ -2280,598 +2333,891 @@ msgid "Expected N"
 msgstr "N esperat"
 
 #: src/language/stats/chisquare.c:163 src/language/stats/chisquare.c:202
-#: src/ui/gui/crosstabs-dialog.c:62 src/language/stats/regression.q:290
+#: src/ui/gui/crosstabs-dialog.c:61 src/language/stats/regression.q:292
 msgid "Residual"
 msgstr "Residual"
 
-#: src/language/stats/chisquare.c:195 src/language/stats/sign.c:60
-#: src/ui/gui/frequencies.ui:9 src/ui/gui/frequencies.ui:669
+#: src/language/stats/chisquare.c:195 src/language/stats/cochran.c:159
+#: src/language/stats/sign.c:62 src/ui/gui/frequencies.ui:9
+#: src/ui/gui/frequencies.ui:669
 msgid "Frequencies"
 msgstr "Freqüències"
 
-#: src/language/stats/chisquare.c:249 src/language/stats/sign.c:111
-#: src/language/stats/wilcoxon.c:309
+#: src/language/stats/chisquare.c:249 src/language/stats/cochran.c:208
+#: src/language/stats/friedman.c:272 src/language/stats/kruskal-wallis.c:310
+#: src/language/stats/mann-whitney.c:251 src/language/stats/sign.c:114
+#: src/language/stats/wilcoxon.c:304
 msgid "Test Statistics"
 msgstr "Proves Estad."
 
-#: src/language/stats/chisquare.c:263
+#: src/language/stats/chisquare.c:263 src/language/stats/friedman.c:282
+#: src/language/stats/kruskal-wallis.c:313
 msgid "Chi-Square"
 msgstr "Chi-quadrat"
 
-#: src/language/stats/chisquare.c:264 src/language/stats/crosstabs.q:1215
-#: src/language/stats/oneway.q:275 src/language/stats/oneway.q:685
-#: src/language/stats/regression.q:284 src/language/stats/t-test.q:752
-#: src/language/stats/t-test.q:923 src/language/stats/t-test.q:1010
+#: src/language/stats/chisquare.c:264 src/language/stats/cochran.c:217
+#: src/language/stats/friedman.c:285 src/language/stats/kruskal-wallis.c:316
+#: src/language/stats/oneway.c:593 src/language/stats/oneway.c:1002
+#: src/language/stats/crosstabs.q:1235 src/language/stats/regression.q:286
+#: src/language/stats/t-test.q:756 src/language/stats/t-test.q:927
+#: src/language/stats/t-test.q:1014
 msgid "df"
 msgstr "df"
 
-#: src/language/stats/chisquare.c:265
+#: src/language/stats/chisquare.c:265 src/language/stats/cochran.c:220
+#: src/language/stats/friedman.c:288 src/language/stats/kruskal-wallis.c:319
 msgid "Asymp. Sig."
 msgstr "Sig. Asimpt."
 
-#: src/language/stats/correlations.c:96 src/language/stats/factor.c:1720
-#: src/language/stats/npar-summary.c:108
+#: src/language/stats/cochran.c:109
+msgid "More than two values encountered.  Cochran Q test will not be run."
+msgstr "S'han trobat més de dos valors.  El Test Q de Cochran no es pot executar."
+
+#: src/language/stats/cochran.c:172
+#, c-format
+msgid "Success (%g)"
+msgstr "Èxit (%g)"
+
+#: src/language/stats/cochran.c:173
+#, c-format
+msgid "Failure (%g)"
+msgstr "Fracàs (%g)"
+
+#: src/language/stats/cochran.c:214
+msgid "Cochran's Q"
+msgstr "Q de Cochran"
+
+#: src/language/stats/correlations.c:97 src/language/stats/factor.c:1724
+#: src/language/stats/npar-summary.c:109
 msgid "Descriptive Statistics"
 msgstr "Estadístiques Descriptives"
 
-#: src/language/stats/correlations.c:117 src/language/stats/descriptives.c:101
-#: src/language/stats/factor.c:1741 src/language/stats/npar-summary.c:125
-#: src/ui/gui/descriptives-dialog.c:40 src/ui/gui/frequencies-dialog.c:41
-#: src/language/stats/examine.q:1444 src/language/stats/frequencies.q:105
-#: src/language/stats/oneway.q:386 src/language/stats/t-test.q:506
-#: src/language/stats/t-test.q:526 src/language/stats/t-test.q:624
-#: src/language/stats/t-test.q:917
+#: src/language/stats/correlations.c:118 src/language/stats/descriptives.c:102
+#: src/language/stats/factor.c:1745 src/language/stats/npar-summary.c:126
+#: src/language/stats/oneway.c:687 src/ui/gui/descriptives-dialog.c:39
+#: src/ui/gui/frequencies-dialog.c:40 src/language/stats/examine.q:1443
+#: src/language/stats/frequencies.q:105 src/language/stats/t-test.q:510
+#: src/language/stats/t-test.q:530 src/language/stats/t-test.q:628
+#: src/language/stats/t-test.q:921
 msgid "Mean"
 msgstr "Mitjana"
 
-#: src/language/stats/correlations.c:118 src/language/stats/factor.c:1742
-#: src/language/stats/npar-summary.c:128 src/language/stats/examine.q:1479
-#: src/language/stats/oneway.q:387 src/language/stats/t-test.q:507
-#: src/language/stats/t-test.q:527 src/language/stats/t-test.q:626
-#: src/language/stats/t-test.q:918
+#: src/language/stats/correlations.c:119 src/language/stats/factor.c:1746
+#: src/language/stats/npar-summary.c:129 src/language/stats/oneway.c:688
+#: src/language/stats/examine.q:1478 src/language/stats/t-test.q:511
+#: src/language/stats/t-test.q:531 src/language/stats/t-test.q:630
+#: src/language/stats/t-test.q:922
 msgid "Std. Deviation"
 msgstr "Desviació Est."
 
-#: src/language/stats/correlations.c:190 src/language/stats/factor.c:1620
+#: src/language/stats/correlations.c:191 src/language/stats/factor.c:1618
 msgid "Correlations"
 msgstr "Correlacions"
 
-#: src/language/stats/correlations.c:216
+#: src/language/stats/correlations.c:217
 msgid "Pearson Correlation"
 msgstr "Correlació de Pearson"
 
-#: src/language/stats/correlations.c:218 src/language/stats/oneway.q:686
-#: src/language/stats/t-test.q:753 src/language/stats/t-test.q:924
-#: src/language/stats/t-test.q:1011
+#: src/language/stats/correlations.c:219 src/language/stats/oneway.c:1003
+#: src/language/stats/t-test.q:757 src/language/stats/t-test.q:928
+#: src/language/stats/t-test.q:1015
 msgid "Sig. (2-tailed)"
 msgstr "Sig. (2-cues)"
 
-#: src/language/stats/correlations.c:218
+#: src/language/stats/correlations.c:219 src/language/stats/factor.c:1630
 msgid "Sig. (1-tailed)"
 msgstr "Sig. (1-cua)"
 
-#: src/language/stats/correlations.c:222
+#: src/language/stats/correlations.c:223
 msgid "Cross-products"
 msgstr "Productes-creuats"
 
-#: src/language/stats/correlations.c:223
+#: src/language/stats/correlations.c:224
 msgid "Covariance"
 msgstr "Covariància"
 
-#: src/language/stats/correlations.c:454 src/language/stats/descriptives.c:361
-#: src/language/data-io/list.q:91
+#: src/language/stats/correlations.c:456 src/language/stats/descriptives.c:363
+#: src/language/data-io/list.q:90
 msgid "No variables specified."
 msgstr "Variables no especificades."
 
-#: src/language/stats/descriptives.c:102 src/language/stats/frequencies.q:106
-#: src/language/stats/t-test.q:508 src/language/stats/t-test.q:528
-#: src/language/stats/t-test.q:627
+#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:106
+#: src/language/stats/t-test.q:512 src/language/stats/t-test.q:532
+#: src/language/stats/t-test.q:631
 msgid "S.E. Mean"
 msgstr "E.E. Mitj."
 
-#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:109
+#: src/language/stats/descriptives.c:104 src/language/stats/frequencies.q:109
 msgid "Std Dev"
 msgstr "Desv.Std."
 
-#: src/language/stats/descriptives.c:104 src/ui/gui/descriptives-dialog.c:47
-#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1474
+#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/frequencies-dialog.c:45 src/language/stats/examine.q:1473
 #: src/language/stats/frequencies.q:110
 msgid "Variance"
 msgstr "Variància"
 
-#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:48
-#: src/ui/gui/frequencies-dialog.c:51 src/language/stats/examine.q:1510
+#: src/language/stats/descriptives.c:106 src/ui/gui/descriptives-dialog.c:47
+#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/examine.q:1509
 #: src/language/stats/frequencies.q:111
 msgid "Kurtosis"
 msgstr "Curtosi"
 
-#: src/language/stats/descriptives.c:106 src/language/stats/frequencies.q:112
+#: src/language/stats/descriptives.c:107 src/language/stats/frequencies.q:112
 msgid "S.E. Kurt"
 msgstr "E.E. Curt."
 
-#: src/language/stats/descriptives.c:107 src/ui/gui/descriptives-dialog.c:49
-#: src/ui/gui/frequencies-dialog.c:47 src/language/stats/examine.q:1505
+#: src/language/stats/descriptives.c:108 src/ui/gui/descriptives-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1504
 #: src/language/stats/frequencies.q:113
 msgid "Skewness"
 msgstr "Asimetria"
 
-#: src/language/stats/descriptives.c:108 src/language/stats/frequencies.q:114
+#: src/language/stats/descriptives.c:109 src/language/stats/frequencies.q:114
 msgid "S.E. Skew"
 msgstr "E.E. Asim."
 
-#: src/language/stats/descriptives.c:109 src/ui/gui/descriptives-dialog.c:44
-#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/examine.q:1494
+#: src/language/stats/descriptives.c:110 src/ui/gui/descriptives-dialog.c:43
+#: src/ui/gui/frequencies-dialog.c:48 src/language/stats/examine.q:1493
 #: src/language/stats/frequencies.q:115
 msgid "Range"
 msgstr "Interval"
 
-#: src/language/stats/descriptives.c:110 src/language/stats/npar-summary.c:131
-#: src/ui/gui/descriptives-dialog.c:42 src/ui/gui/frequencies-dialog.c:43
-#: src/language/stats/examine.q:1484 src/language/stats/frequencies.q:116
-#: src/language/stats/oneway.q:400
+#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:132
+#: src/language/stats/oneway.c:701 src/ui/gui/descriptives-dialog.c:41
+#: src/ui/gui/frequencies-dialog.c:42 src/language/stats/examine.q:1483
+#: src/language/stats/frequencies.q:116
 msgid "Minimum"
 msgstr "Mínim"
 
-#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:134
-#: src/ui/gui/descriptives-dialog.c:43 src/ui/gui/frequencies-dialog.c:44
-#: src/language/stats/examine.q:1489 src/language/stats/frequencies.q:117
-#: src/language/stats/oneway.q:401
+#: src/language/stats/descriptives.c:112 src/language/stats/npar-summary.c:135
+#: src/language/stats/oneway.c:702 src/ui/gui/descriptives-dialog.c:42
+#: src/ui/gui/frequencies-dialog.c:43 src/language/stats/examine.q:1488
+#: src/language/stats/frequencies.q:117
 msgid "Maximum"
 msgstr "Màxim"
 
-#: src/language/stats/descriptives.c:112 src/ui/gui/descriptives-dialog.c:45
-#: src/ui/gui/frequencies-dialog.c:54 src/language/stats/frequencies.q:118
+#: src/language/stats/descriptives.c:113 src/ui/gui/descriptives-dialog.c:44
+#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/frequencies.q:118
 msgid "Sum"
 msgstr "Suma"
 
-#: src/language/stats/descriptives.c:343
+#: src/language/stats/descriptives.c:345
 #, c-format
 msgid "Z-score variable name %s would be a duplicate variable name."
 msgstr "el mom de variable Z %s seria un nom de variable duplicat."
 
-#: src/language/stats/descriptives.c:450
+#: src/language/stats/descriptives.c:457
 msgid "expecting statistic name: reverting to default"
 msgstr "esperant nom de l'estadístic: torna a aplicar el defecte"
 
-#: src/language/stats/descriptives.c:523
+#: src/language/stats/descriptives.c:539
 msgid "Ran out of generic names for Z-score variables.  There are only 126 generic names: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 msgstr "S'han esgotat els noms genèrics per les variables Z.  Només hi ha 126 noms genèrics: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 
-#: src/language/stats/descriptives.c:555
+#: src/language/stats/descriptives.c:568
 msgid "Mapping of variables to corresponding Z-scores."
 msgstr "Convertint variables a les puntuacions-Z corresponents."
 
-#: src/language/stats/descriptives.c:559
+#: src/language/stats/descriptives.c:572
 msgid "Source"
 msgstr "Font"
 
-#: src/language/stats/descriptives.c:560
+#: src/language/stats/descriptives.c:573
 msgid "Target"
 msgstr "Destí"
 
-#: src/language/stats/descriptives.c:670
+#: src/language/stats/descriptives.c:683
 #, c-format
 msgid "Z-score of %s"
 msgstr "puntuació-Z de %s"
 
-#: src/language/stats/descriptives.c:884
+#: src/language/stats/descriptives.c:898
 msgid "Valid N"
 msgstr "N vàlids"
 
-#: src/language/stats/descriptives.c:885
+#: src/language/stats/descriptives.c:899
 msgid "Missing N"
 msgstr "Perduts N"
 
-#: src/language/stats/descriptives.c:913
+#: src/language/stats/descriptives.c:927
 #, c-format
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr "Casos vàlids = %g; casos amb valor(s) perdut(s) = %g."
 
-#: src/language/stats/sort-cases.c:64
-msgid "Buffer limit must be at least 2."
-msgstr "El límit de la memòria intermitja ha de ser almenys de 2."
-
-#: src/language/stats/sort-criteria.c:74
-msgid "`A' or `D' expected inside parentheses."
-msgstr "S'espera `A' or `D' dins del parèntesis."
-
-#: src/language/stats/sort-criteria.c:79
-msgid "`)' expected."
-msgstr "`)' esperat."
-
-#: src/language/stats/sort-criteria.c:92
-#, c-format
-msgid "Variable %s specified twice in sort criteria."
-msgstr "La variable %s s'especifica dues vegades als criteris d'ordenació."
-
-#: src/language/stats/factor.c:803
+#: src/language/stats/factor.c:801
 msgid "Factor analysis on a single variable is not useful."
 msgstr "L'anàlisi factorial per a una única variable és inútil."
 
-#: src/language/stats/factor.c:1206
+#: src/language/stats/factor.c:1204
 msgid "Component Number"
 msgstr "Número de Component"
 
-#: src/language/stats/factor.c:1206
+#: src/language/stats/factor.c:1204
 msgid "Factor Number"
 msgstr "Número de Factor"
 
-#: src/language/stats/factor.c:1237
+#: src/language/stats/factor.c:1235
 msgid "Communalities"
 msgstr "Comunalitats"
 
-#: src/language/stats/factor.c:1243
+#: src/language/stats/factor.c:1241
 msgid "Initial"
 msgstr "Inicial"
 
-#: src/language/stats/factor.c:1246
+#: src/language/stats/factor.c:1244
 msgid "Extraction"
 msgstr "Extracció"
 
-#: src/language/stats/factor.c:1310 src/language/stats/factor.c:1437
+#: src/language/stats/factor.c:1308 src/language/stats/factor.c:1435
 msgid "Component"
 msgstr "Component"
 
-#: src/language/stats/factor.c:1315 src/language/stats/factor.c:1439
+#: src/language/stats/factor.c:1313 src/language/stats/factor.c:1437
 msgid "Factor"
 msgstr "Factor"
 
-#: src/language/stats/factor.c:1347 src/language/stats/factor.c:1495
-#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:699
-#: src/ui/gui/psppire-var-store.c:709 src/ui/gui/psppire-var-store.c:719
-#: src/ui/gui/psppire-var-store.c:825
+#: src/language/stats/factor.c:1345 src/language/stats/factor.c:1493
+#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:700
+#: src/ui/gui/psppire-var-store.c:710 src/ui/gui/psppire-var-store.c:720
+#: src/ui/gui/psppire-var-store.c:826
 #, c-format
 msgid "%d"
 msgstr "%d"
 
-#: src/language/stats/factor.c:1412
+#: src/language/stats/factor.c:1410
 msgid "Total Variance Explained"
 msgstr "Variancia Total Explicada"
 
-#: src/language/stats/factor.c:1444
+#: src/language/stats/factor.c:1442
 msgid "Initial Eigenvalues"
 msgstr "Valors propis Inicials"
 
-#: src/language/stats/factor.c:1450
+#: src/language/stats/factor.c:1448
 msgid "Extraction Sums of Squared Loadings"
 msgstr "Extracció: Sumes de Carregues al Quadrat"
 
-#: src/language/stats/factor.c:1456
+#: src/language/stats/factor.c:1454
 msgid "Rotation Sums of Squared Loadings"
 msgstr "Rotació: Sumes de Carregues al Quadrat "
 
-#: src/language/stats/factor.c:1464
+#: src/language/stats/factor.c:1462
 #, no-c-format
 msgid "% of Variance"
 msgstr "% de Variància"
 
-#: src/language/stats/factor.c:1465
+#: src/language/stats/factor.c:1463
 msgid "Cumulative %"
 msgstr "% Acumulat"
 
-#: src/language/stats/factor.c:1578
+#: src/language/stats/factor.c:1576
 msgid "Correlation Matrix"
 msgstr "Matriu de Correlació"
 
-#: src/language/stats/factor.c:1632
-msgid "Sig. 1-tailed"
-msgstr "Sig. (1-cua)"
-
-#: src/language/stats/factor.c:1666
+#: src/language/stats/factor.c:1664
 msgid "Determinant"
 msgstr "Determinant"
 
-#: src/language/stats/factor.c:1743
+#: src/language/stats/factor.c:1695
+msgid "The dataset contains no complete observations. No analysis will be performed."
+msgstr "La matriu de dades conté observacions incompletes. No es pot realitzar cap anàlisi."
+
+#: src/language/stats/factor.c:1747
 msgid "Analysis N"
 msgstr "N Anàlisis"
 
-#: src/language/stats/factor.c:1776
+#: src/language/stats/factor.c:1780
 msgid "The FACTOR criteria result in zero factors extracted. Therefore no analysis will be performed."
-msgstr "El criteri FACTOR resulta en l'extracció de cero factors. No es pot realitzar cap anàlisi."
+msgstr "El criteri FACTOR resulta en l'extracció de zero factors. No es pot realitzar cap anàlisi."
 
-#: src/language/stats/factor.c:1782
+#: src/language/stats/factor.c:1786
 msgid "The FACTOR criteria result in more factors than variables, which is not meaningful. No analysis will be performed."
 msgstr "El criteri FACTOR resulta en més factors que variables, i això no té cap sentit.  No es realitza cap anàlisi."
 
-#: src/language/stats/factor.c:1865
+#: src/language/stats/factor.c:1869
 msgid "Component Matrix"
 msgstr "Matriu de Components"
 
-#: src/language/stats/factor.c:1865
+#: src/language/stats/factor.c:1869
 msgid "Factor Matrix"
 msgstr "Matriu de Factors"
 
-#: src/language/stats/factor.c:1871
+#: src/language/stats/factor.c:1875
 msgid "Rotated Component Matrix"
 msgstr "Matriu Rotada de Components"
 
-#: src/language/stats/factor.c:1871
+#: src/language/stats/factor.c:1875
 msgid "Rotated Factor Matrix"
 msgstr "Matriu Rotada de Factors"
 
-#: src/language/stats/flip.c:98
+#: src/language/stats/flip.c:99
 msgid "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "FLIP ignora TEMPORARY.  Les transformacions temporals seran permanents."
 
-#: src/language/stats/flip.c:150
+#: src/language/stats/flip.c:151
 msgid "Could not create temporary file for FLIP."
 msgstr "No s'ha pogut crear l'arxiu temporal per a FLIP."
 
-#: src/language/stats/flip.c:327
+#: src/language/stats/flip.c:326
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr "Error reconstruint l'arxiu FLIP: %s."
 
-#: src/language/stats/flip.c:334
+#: src/language/stats/flip.c:333
 msgid "Error creating FLIP source file."
 msgstr "Error en crear l'arxiu d'origen FLIP."
 
-#: src/language/stats/flip.c:347
+#: src/language/stats/flip.c:346
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr "Error de lectura de l'arxiu FLIP: %s."
 
-#: src/language/stats/flip.c:349
+#: src/language/stats/flip.c:348
 msgid "Unexpected end of file reading FLIP file."
 msgstr "Final inesperat de la lectura d'arxiu FLIP."
 
-#: src/language/stats/flip.c:365
+#: src/language/stats/flip.c:364
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr "Error en cercar l'arxiu font FLIP: %s."
 
-#: src/language/stats/flip.c:373
+#: src/language/stats/flip.c:372
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr "Error d'escriptura de l'arxiu font FLIP: %s."
 
-#: src/language/stats/flip.c:384
-#, c-format
-msgid "Error closing FLIP source file: %s."
-msgstr "Error de tancament de l'arxiu de font FLIP: %s."
-
-#: src/language/stats/flip.c:392
+#: src/language/stats/flip.c:387
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr "Error reconstruint d'arxiu font FLIP: %s."
 
-#: src/language/stats/flip.c:426
+#: src/language/stats/flip.c:420
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr "Error de lectura de l'arxiu temporal FLIP: %s."
 
-#: src/language/stats/flip.c:429
+#: src/language/stats/flip.c:423
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr "Final inesperat de la lectura d'arxiu temporal FLIP."
 
-#: src/language/stats/npar-summary.c:141 src/language/stats/examine.q:1996
-#: src/language/stats/examine.q:2013 src/language/stats/frequencies.q:1050
+#: src/language/stats/friedman.c:227 src/language/stats/kruskal-wallis.c:242
+#: src/language/stats/mann-whitney.c:171 src/language/stats/wilcoxon.c:225
+msgid "Ranks"
+msgstr "Rangs"
+
+#: src/language/stats/friedman.c:238 src/language/stats/kruskal-wallis.c:256
+#: src/language/stats/mann-whitney.c:196 src/language/stats/wilcoxon.c:239
+msgid "Mean Rank"
+msgstr "Rang mitjà"
+
+#: src/language/stats/friedman.c:279
+msgid "Kendall's W"
+msgstr "W de Kendall"
+
+#: src/language/stats/mann-whitney.c:202 src/language/stats/wilcoxon.c:240
+msgid "Sum of Ranks"
+msgstr "Suma de Rangs"
+
+#: src/language/stats/mann-whitney.c:264
+msgid "Mann-Whitney U"
+msgstr "U de Mann-Whitney"
+
+#: src/language/stats/mann-whitney.c:265
+msgid "Wilcoxon W"
+msgstr "W de Wilcoxon"
+
+#: src/language/stats/mann-whitney.c:266 src/language/stats/runs.c:396
+#: src/language/stats/wilcoxon.c:317
+msgid "Z"
+msgstr "Z"
+
+#: src/language/stats/mann-whitney.c:267 src/language/stats/runs.c:399
+#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1237
+msgid "Asymp. Sig. (2-tailed)"
+msgstr "Sig. Asimp. (2-cues)"
+
+#: src/language/stats/mann-whitney.c:271 src/language/stats/sign.c:133
+#: src/language/stats/wilcoxon.c:322
+msgid "Exact Sig. (2-tailed)"
+msgstr "Sig. Exacta (2-cues)"
+
+#: src/language/stats/mann-whitney.c:272 src/language/stats/sign.c:139
+#: src/language/stats/wilcoxon.c:326
+msgid "Point Probability"
+msgstr "Punt de Probabilitat"
+
+#: src/language/stats/npar.c:337 src/language/stats/npar.c:364
+#, c-format
+msgid "The %s subcommand may be given only once."
+msgstr "El subcomando %s només pot ser utilitzat una vegada."
+
+#: src/language/stats/npar.c:447
+msgid "NPAR subcommand not currently implemented."
+msgstr "Actualment no está implenetat el subcomandament NPAR."
+
+#: src/language/stats/npar.c:601
+msgid "Expecting MEAN, MEDIAN, MODE or number"
+msgstr "S'espera MEAN, MEDIAN, MODE o un nombre"
+
+#: src/language/stats/npar.c:751
+#, c-format
+msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
+msgstr "El valor especificatper a HI (%d) és menor que l'especificat per a LO (%d)"
+
+#: src/language/stats/npar.c:801
+#, c-format
+msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
+msgstr "S'han proporcionat %d valors esperats, però l'interval especificat (%d-%d) requereix exactament %d valors."
+
+#: src/language/stats/npar.c:941 src/language/stats/t-test.q:384
+#, c-format
+msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
+msgstr "S'ha especificat PAIRED però el nombre de variables abans de WITH (%zu) not conicideixen amb en nombre de variables seguents (%zu)."
+
+#: src/language/stats/npar-summary.c:142 src/language/stats/examine.q:1995
+#: src/language/stats/examine.q:2012 src/language/stats/frequencies.q:1059
 #: src/ui/gui/examine.ui:345
 msgid "Percentiles"
 msgstr "Percentils"
 
-#: src/language/stats/npar-summary.c:145
+#: src/language/stats/npar-summary.c:146
 msgid "25th"
 msgstr "25è"
 
-#: src/language/stats/npar-summary.c:148
+#: src/language/stats/npar-summary.c:149
 msgid "50th (Median)"
 msgstr "50è (Mediana)"
 
-#: src/language/stats/npar-summary.c:151
+#: src/language/stats/npar-summary.c:152
 msgid "75th"
 msgstr "75è"
 
-#: src/language/stats/roc.c:932
-msgid "Area Under the Curve"
-msgstr "Àrea Sota la Corba"
+#: src/language/stats/oneway.c:542
+msgid "Number of contrast coefficients must equal the number of groups"
+msgstr "El nombre de coeficients de contrast ha de ser igual al nombre de grups."
 
-#: src/language/stats/roc.c:934
+#: src/language/stats/oneway.c:551
 #, c-format
-msgid "Area Under the Curve (%s)"
-msgstr "Àrea Sota la Corba (%s)"
+msgid "Coefficients for contrast %zu do not total zero"
+msgstr "Els coeficients per contrastar %zu no sumen cero."
 
-#: src/language/stats/roc.c:939
-msgid "Area"
-msgstr "Àrea"
+#: src/language/stats/oneway.c:592 src/language/stats/regression.q:285
+msgid "Sum of Squares"
+msgstr "Suma de Quadrats"
+
+#: src/language/stats/oneway.c:594 src/language/stats/regression.q:287
+msgid "Mean Square"
+msgstr "Rang mitjà"
+
+#: src/language/stats/oneway.c:595 src/language/stats/regression.q:288
+#: src/language/stats/t-test.q:753
+msgid "F"
+msgstr "F"
+
+#: src/language/stats/oneway.c:596 src/language/stats/oneway.c:841
+#: src/language/stats/regression.q:203 src/language/stats/regression.q:289
+msgid "Significance"
+msgstr "Significativitat"
+
+#: src/language/stats/oneway.c:614
+msgid "Between Groups"
+msgstr "Entre Grups"
+
+#: src/language/stats/oneway.c:615
+msgid "Within Groups"
+msgstr "Intra Grups"
+
+#: src/language/stats/oneway.c:648 src/language/stats/regression.q:314
+msgid "ANOVA"
+msgstr "ANOVA"
 
-#: src/language/stats/roc.c:952 src/language/stats/examine.q:1641
-#: src/language/stats/oneway.q:388 src/language/stats/oneway.q:683
-#: src/language/stats/regression.q:198
+#: src/language/stats/oneway.c:689 src/language/stats/oneway.c:1000
+#: src/language/stats/roc.c:975 src/language/stats/examine.q:1640
+#: src/language/stats/regression.q:200
 msgid "Std. Error"
 msgstr "Error Est."
 
-#: src/language/stats/roc.c:953
-msgid "Asymptotic Sig."
-msgstr "Signif. Asimpt."
+#: src/language/stats/oneway.c:695 src/language/stats/examine.q:1448
+#, c-format
+msgid "%g%% Confidence Interval for Mean"
+msgstr "Interval de Confiança de Miitjana %g%%"
 
-#: src/language/stats/roc.c:955 src/language/stats/examine.q:1455
-#: src/language/stats/oneway.q:397
+#: src/language/stats/oneway.c:698 src/language/stats/roc.c:978
+#: src/language/stats/examine.q:1454
 msgid "Lower Bound"
 msgstr "Límit Inferior"
 
-#: src/language/stats/roc.c:956 src/language/stats/examine.q:1460
-#: src/language/stats/oneway.q:398
+#: src/language/stats/oneway.c:699 src/language/stats/roc.c:979
+#: src/language/stats/examine.q:1459
 msgid "Upper Bound"
 msgstr "Límit Superior"
 
-#: src/language/stats/roc.c:960
+#: src/language/stats/oneway.c:704 src/language/stats/examine.q:1634
+#: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
+msgid "Descriptives"
+msgstr "Descriptives"
+
+#: src/language/stats/oneway.c:838
+msgid "Levene Statistic"
+msgstr "Estatístic de Levene"
+
+#: src/language/stats/oneway.c:839
+msgid "df1"
+msgstr "df1"
+
+#: src/language/stats/oneway.c:840
+msgid "df2"
+msgstr "df2"
+
+#: src/language/stats/oneway.c:843
+msgid "Test of Homogeneity of Variances"
+msgstr "Prova de Homogeneitat de variances"
+
+#: src/language/stats/oneway.c:916
+msgid "Contrast Coefficients"
+msgstr "Coeficinents de Contrast"
+
+#: src/language/stats/oneway.c:918 src/language/stats/oneway.c:998
+msgid "Contrast"
+msgstr "Contrast"
+
+#: src/language/stats/oneway.c:996
+msgid "Contrast Tests"
+msgstr "Proves de contrats"
+
+#: src/language/stats/oneway.c:999
+msgid "Value of Contrast"
+msgstr "Valor de constrast"
+
+#: src/language/stats/oneway.c:1001 src/language/stats/regression.q:202
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:926
+#: src/language/stats/t-test.q:1013
+msgid "t"
+msgstr "t"
+
+#: src/language/stats/oneway.c:1053
+msgid "Assume equal variances"
+msgstr "S'assumeix igualtat de variances"
+
+#: src/language/stats/oneway.c:1057
+msgid "Does not assume equal"
+msgstr "No s'assumeix igualtat"
+
+#: src/language/stats/reliability.c:141
+msgid "Reliability on a single variable is not useful."
+msgstr "L'anàlisi de fiabilitat d'una única variable és inútil."
+
+#: src/language/stats/reliability.c:501 src/language/stats/examine.q:1158
+msgid "Case Processing Summary"
+msgstr "Resum de processament del Casos"
+
+#: src/language/stats/reliability.c:524 src/language/stats/crosstabs.q:829
+#: src/language/stats/examine.q:1163
+msgid "Cases"
+msgstr "Casos"
+
+#: src/language/stats/reliability.c:527 src/language/stats/crosstabs.q:830
+#: src/language/stats/examine.q:1102 src/language/stats/frequencies.q:1044
+msgid "Valid"
+msgstr "Vàlid"
+
+#: src/language/stats/reliability.c:530
+msgid "Excluded"
+msgstr "Exclós"
+
+#: src/language/stats/reliability.c:538
+msgid "%"
+msgstr "%"
+
+#: src/language/stats/reliability.c:583
+msgid "Item-Total Statistics"
+msgstr "Estadístiques de total d'Items"
+
+#: src/language/stats/reliability.c:605
+msgid "Scale Mean if Item Deleted"
+msgstr "Escalar la mitjana si s'esborra l'element"
+
+#: src/language/stats/reliability.c:608
+msgid "Scale Variance if Item Deleted"
+msgstr "Escalar la variança si s'esborra l'element"
+
+#: src/language/stats/reliability.c:611
+msgid "Corrected Item-Total Correlation"
+msgstr "Correlació total-item corregida"
+
+#: src/language/stats/reliability.c:614
+msgid "Cronbach's Alpha if Item Deleted"
+msgstr "Cronbach's Alpha si s'esborra l'element"
+
+#: src/language/stats/reliability.c:688
+msgid "Reliability Statistics"
+msgstr "Estadístiques de fiabilitat"
+
+#: src/language/stats/reliability.c:728 src/language/stats/reliability.c:747
+msgid "Cronbach's Alpha"
+msgstr "Alfa de Cronbach"
+
+#: src/language/stats/reliability.c:731 src/language/stats/reliability.c:756
+#: src/language/stats/reliability.c:767
+msgid "N of Items"
+msgstr "N d'elements"
+
+#: src/language/stats/reliability.c:750
+msgid "Part 1"
+msgstr "Part 1"
+
+#: src/language/stats/reliability.c:761
+msgid "Part 2"
+msgstr "Part 2"
+
+#: src/language/stats/reliability.c:772
+msgid "Total N of Items"
+msgstr "N total d'elements"
+
+#: src/language/stats/reliability.c:775
+msgid "Correlation Between Forms"
+msgstr "Correlación entre formes"
+
+#: src/language/stats/reliability.c:779
+msgid "Spearman-Brown Coefficient"
+msgstr "Coeficient d'Spearman-Brown"
+
+#: src/language/stats/reliability.c:782
+msgid "Equal Length"
+msgstr "Ample igual"
+
+#: src/language/stats/reliability.c:785
+msgid "Unequal Length"
+msgstr "Ample desigual"
+
+#: src/language/stats/reliability.c:789
+msgid "Guttman Split-Half Coefficient"
+msgstr "Coeficient Gutman de DIvisió pel mig"
+
+#: src/language/stats/roc.c:955
+msgid "Area Under the Curve"
+msgstr "Àrea Sota la Corba"
+
+#: src/language/stats/roc.c:957
+#, c-format
+msgid "Area Under the Curve (%s)"
+msgstr "Àrea Sota la Corba (%s)"
+
+#: src/language/stats/roc.c:962
+msgid "Area"
+msgstr "Àrea"
+
+#: src/language/stats/roc.c:976
+msgid "Asymptotic Sig."
+msgstr "Signif. Asimpt."
+
+#: src/language/stats/roc.c:983
 #, c-format
 msgid "Asymp. %g%% Confidence Interval"
 msgstr " Interval de Confiança Asimp. %g%%"
 
-#: src/language/stats/roc.c:966
+#: src/language/stats/roc.c:989
 msgid "Variable under test"
 msgstr "Variable sota prova"
 
-#: src/language/stats/roc.c:1025
+#: src/language/stats/roc.c:1048
 msgid "Case Summary"
 msgstr "Resum del Cas"
 
-#: src/language/stats/roc.c:1045
+#: src/language/stats/roc.c:1068
 msgid "Unweighted"
 msgstr "No ponderat"
 
-#: src/language/stats/roc.c:1046
+#: src/language/stats/roc.c:1069
 msgid "Weighted"
 msgstr "Ponderat"
 
-#: src/language/stats/roc.c:1050
+#: src/language/stats/roc.c:1073
 msgid "Valid N (listwise)"
 msgstr "N Valid (listwise)"
 
-#: src/language/stats/roc.c:1053
+#: src/language/stats/roc.c:1076
 msgid "Positive"
 msgstr "Positiu"
 
-#: src/language/stats/roc.c:1054
+#: src/language/stats/roc.c:1077
 msgid "Negative"
 msgstr "Negatiu"
 
-#: src/language/stats/roc.c:1082
+#: src/language/stats/roc.c:1105
 msgid "Coordinates of the Curve"
 msgstr "Coordenades de la Corba"
 
-#: src/language/stats/roc.c:1084
+#: src/language/stats/roc.c:1107
 #, c-format
 msgid "Coordinates of the Curve (%s)"
 msgstr "Coordenades de la Corba (%s)"
 
-#: src/language/stats/roc.c:1092
+#: src/language/stats/roc.c:1115
 msgid "Test variable"
 msgstr "Variable de prova"
 
-#: src/language/stats/roc.c:1094
+#: src/language/stats/roc.c:1117
 msgid "Positive if greater than or equal to"
 msgstr "Positiu si és major o igual a"
 
-#: src/language/stats/roc.c:1095 src/output/charts/roc-chart-cairo.c:38
+#: src/language/stats/roc.c:1118 src/output/charts/roc-chart-cairo.c:38
 msgid "Sensitivity"
 msgstr "Sensibilitat"
 
-#: src/language/stats/roc.c:1096 src/output/charts/roc-chart-cairo.c:37
+#: src/language/stats/roc.c:1119 src/output/charts/roc-chart-cairo.c:37
 msgid "1 - Specificity"
 msgstr "1 - Especificitat"
 
-#: src/language/stats/sign.c:89
+#: src/language/stats/runs.c:167
+#, c-format
+msgid "Multiple modes exist for varible `%s'.  Using %g as the threshold value."
+msgstr "Existeixen multiples modes per la variable `%s'.  S'utilitza %g com a valor d'umbral."
+
+#: src/language/stats/runs.c:322
+msgid "Runs Test"
+msgstr "Executa prova"
+
+#: src/language/stats/runs.c:367
+msgid "Test Value"
+msgstr "Valor de prova"
+
+#: src/language/stats/runs.c:371
+msgid "Test Value (mode)"
+msgstr "Valor de prova (moda)"
+
+#: src/language/stats/runs.c:375
+msgid "Test Value (mean)"
+msgstr "Valor de prova (mitjana)"
+
+#: src/language/stats/runs.c:379
+msgid "Test Value (median)"
+msgstr "Valor de prova (mediana)"
+
+#: src/language/stats/runs.c:384
+msgid "Cases < Test Value"
+msgstr "Casos < Valor de prova"
+
+#: src/language/stats/runs.c:387
+msgid "Cases >= Test Value"
+msgstr "Casos >= Valor de prova"
+
+#: src/language/stats/runs.c:390
+msgid "Total Cases"
+msgstr "Casos Totals"
+
+#: src/language/stats/runs.c:393
+msgid "Number of Runs"
+msgstr "Nombre d'execucions"
+
+#: src/language/stats/sign.c:92
 msgid "Negative Differences"
 msgstr "Diferències Negatives"
 
-#: src/language/stats/sign.c:90
+#: src/language/stats/sign.c:93
 msgid "Positive Differences"
 msgstr "Diferències Positives"
 
-#: src/language/stats/sign.c:91 src/language/stats/wilcoxon.c:259
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:254
 msgid "Ties"
 msgstr "Lligams"
 
-#: src/language/stats/sign.c:130 src/language/stats/wilcoxon.c:327
-msgid "Exact Sig. (2-tailed)"
-msgstr "Sig. Exacta (2-cues)"
-
-#: src/language/stats/sign.c:133 src/language/stats/wilcoxon.c:328
+#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:323
 msgid "Exact Sig. (1-tailed)"
 msgstr "Sig. Exacta (1-cua)"
 
-#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:331
-msgid "Point Probability"
-msgstr "Punt de Probabilitat"
+#: src/language/stats/sort-cases.c:64
+msgid "Buffer limit must be at least 2."
+msgstr "El límit de la memòria intermitja ha de ser almenys de 2."
 
-#: src/language/stats/wilcoxon.c:230
-msgid "Ranks"
-msgstr "Rangs"
+#: src/language/stats/sort-criteria.c:74
+msgid "`A' or `D' expected inside parentheses."
+msgstr "S'espera `A' or `D' dins del parèntesis."
 
-#: src/language/stats/wilcoxon.c:244
-msgid "Mean Rank"
-msgstr "Rang mitjà"
+#: src/language/stats/sort-criteria.c:79
+msgid "`)' expected."
+msgstr "`)' esperat."
 
-#: src/language/stats/wilcoxon.c:245
-msgid "Sum of Ranks"
-msgstr "Suma de Rangs"
+#: src/language/stats/sort-criteria.c:92
+#, c-format
+msgid "Variable %s specified twice in sort criteria."
+msgstr "La variable %s s'especifica dues vegades als criteris d'ordenació."
 
-#: src/language/stats/wilcoxon.c:257
+#: src/language/stats/wilcoxon.c:252
 msgid "Negative Ranks"
 msgstr "Rangs Negatius"
 
-#: src/language/stats/wilcoxon.c:258
+#: src/language/stats/wilcoxon.c:253
 msgid "Positive Ranks"
 msgstr "Rangs Positius"
 
-#: src/language/stats/wilcoxon.c:322
-msgid "Z"
-msgstr "Z"
-
-#: src/language/stats/wilcoxon.c:323
-msgid "Asymp. Sig. (2-tailed)"
-msgstr "Sig. Asimp. (2-cues)"
-
-#: src/language/data-io/combine-files.c:210
-msgid "Cannot specify the active file since no active file has been defined."
-msgstr "No es pot especificar el fitxer actiu ja que cap fitxer actiu ha estat definit."
+#: src/language/data-io/combine-files.c:211
+msgid "Cannot specify the active dataset since none has been defined."
+msgstr "No es pot especificar l'arxiu de dades actiu ja que cap no ha estat definit."
 
-#: src/language/data-io/combine-files.c:216
-msgid "This command may not be used after TEMPORARY when the active file is an input source.  Temporary transformations will be made permanent."
-msgstr "Aquest comando no pot ser utilitzat després de TEMPORARY quan l'arxiu actiu és una font d'entrada.  Les transformacions temporals seran permanents."
+#: src/language/data-io/combine-files.c:217
+msgid "This command may not be used after TEMPORARY when the active dataset is an input source.  Temporary transformations will be made permanent."
+msgstr "Aquest comando no pot ser utilitzat després de TEMPORARY quan l'arxiu de dades actiu és una font d'entrada.  Les transformacions temporals seran permanents."
 
-#: src/language/data-io/combine-files.c:250
+#: src/language/data-io/combine-files.c:251
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr "Múltiples subcomandos IN  per a un únic FILE o TABLE."
 
-#: src/language/data-io/combine-files.c:302
+#: src/language/data-io/combine-files.c:303
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr "L'arxiu %s no té variable BY %s."
 
-#: src/language/data-io/combine-files.c:305
+#: src/language/data-io/combine-files.c:306
 #, c-format
-msgid "Active file lacks BY variable %s."
-msgstr "Arxiu actiu no té BY variable %s."
+msgid "Active dataset lacks BY variable %s."
+msgstr "Arxiu de dades actiu no té BY variable %s."
 
-#: src/language/data-io/combine-files.c:376
+#: src/language/data-io/combine-files.c:378
 msgid "The BY subcommand is required."
 msgstr "Es necessita el subcomando BY."
 
-#: src/language/data-io/combine-files.c:381
-#: src/language/data-io/combine-files.c:386
+#: src/language/data-io/combine-files.c:383
+#: src/language/data-io/combine-files.c:388
 #, c-format
 msgid "BY is required when %s is specified."
 msgstr "BY és necessari quan s'especifica %s."
 
-#: src/language/data-io/combine-files.c:513
+#: src/language/data-io/combine-files.c:521
 msgid "Combining files with incompatible encodings. String data may not be represented correctly."
 msgstr "Combinant arxius amb codificacions incompatibles. Les dades de la cadena no podran estar representades correctament."
 
-#: src/language/data-io/combine-files.c:545
+#: src/language/data-io/combine-files.c:563
 #, c-format
 msgid "Variable %s in file %s has different type or width from the same variable in earlier file."
 msgstr "La variable %s a l'arxiu %s és de tipus o amplada diferent respecte de la mateixa variable en l'arxiu anterior. "
 
-#: src/language/data-io/combine-files.c:551
+#: src/language/data-io/combine-files.c:569
 #, c-format
 msgid "In file %s, %s is numeric."
 msgstr "A l'arxiu %s, %s és numèric."
 
-#: src/language/data-io/combine-files.c:554
+#: src/language/data-io/combine-files.c:572
 #, c-format
 msgid "In file %s, %s is a string variable with width %d."
 msgstr "A l'arxiu %s, %s és una variable de cadena amb una amplada de %d."
 
-#: src/language/data-io/combine-files.c:559
+#: src/language/data-io/combine-files.c:577
 #, c-format
 msgid "In an earlier file, %s was numeric."
 msgstr "En un arxiu anterior, %s era numèric."
 
-#: src/language/data-io/combine-files.c:562
+#: src/language/data-io/combine-files.c:580
 #, c-format
 msgid "In an earlier file, %s was a string variable with width %d."
 msgstr "En un arxiu anterior, %s era una variable cadena amb una amplada de %d."
 
-#: src/language/data-io/combine-files.c:601
+#: src/language/data-io/combine-files.c:620
 #, c-format
 msgid "Variable name %s specified on %s subcommand duplicates an existing variable name."
 msgstr "Nom de la variable %s especificat al subcomando %s duplica el nom de la variable existent."
 
-#: src/language/data-io/combine-files.c:762
+#: src/language/data-io/combine-files.c:782
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr "Trobats %zu conjunts de casos duplicats a l'arxiu principal."
@@ -2888,86 +3234,91 @@ msgstr "El subcomando END només pot ser especificat una vegada."
 msgid "Only one of FIXED, FREE, or LIST may be specified."
 msgstr "Només un de FIXED, FREE, o LIST pot ser especificat."
 
-#: src/language/data-io/data-list.c:243
+#: src/language/data-io/data-list.c:244
 msgid "Encoding should not be specified for inline data. It will be ignored."
 msgstr "La codificació no ha de ser especificada per les dades en línia. Serà ignorada."
 
-#: src/language/data-io/data-list.c:254
+#: src/language/data-io/data-list.c:255
 msgid "The END subcommand may be used only with DATA LIST FIXED."
 msgstr "El subcomando END només potser utilitzat amb DATA LIST FIXED."
 
-#: src/language/data-io/data-list.c:269
+#: src/language/data-io/data-list.c:270
 msgid "At least one variable must be specified."
 msgstr "Al menys una variable ha de ser especificada."
 
-#: src/language/data-io/data-list.c:368 src/language/data-io/data-list.c:457
-#: src/language/data-io/get-data.c:530
+#: src/language/data-io/data-list.c:369 src/language/data-io/data-list.c:458
+#: src/language/data-io/get-data.c:540
 #, c-format
 msgid "%s is a duplicate variable name."
 msgstr "%s és un nom de variable duplicat."
 
-#: src/language/data-io/data-list.c:375
+#: src/language/data-io/data-list.c:376
 #, c-format
 msgid "There is already a variable %s of a different type."
 msgstr "Ja existeix una variable %s de diferent tipus."
 
-#: src/language/data-io/data-list.c:382
+#: src/language/data-io/data-list.c:383
 #, c-format
 msgid "There is already a string variable %s of a different width."
 msgstr "Ja existeix una cadena de la variable %s d'amplada diferent."
 
-#: src/language/data-io/data-list.c:390
+#: src/language/data-io/data-list.c:391
 #, c-format
 msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
 msgstr "No es pot posar la variable %s en el registre %d quan RECORDS=%d està especificat."
 
-#: src/language/data-io/data-parser.c:460
-#: src/language/data-io/data-parser.c:469
+#: src/language/data-io/data-parser.c:458
+#: src/language/data-io/data-parser.c:467
 msgid "Quoted string extends beyond end of line."
 msgstr "La cadena entre cometes s'estén més enllà del final de línia."
 
-#: src/language/data-io/data-parser.c:525
+#: src/language/data-io/data-parser.c:516
+#, c-format
+msgid "Data for variable %s is not valid as format %s: %s"
+msgstr "Les dades per a la variable %s no son vàlides com a format %s: %s"
+
+#: src/language/data-io/data-parser.c:545
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr "Casos parcials de %d de %d registres descartats."
 
-#: src/language/data-io/data-parser.c:572
+#: src/language/data-io/data-parser.c:602
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr "Cas parcial descartat.  La primera variable que faltava era %s."
 
-#: src/language/data-io/data-parser.c:610
+#: src/language/data-io/data-parser.c:644
 #, c-format
 msgid "Missing value(s) for all variables from %s onward.  These will be filled with the system-missing value or blanks, as appropriate."
 msgstr "Valor(s) perdut(s) per a totes les variables des de %st.  Aquests s'omplen amb el valor perdut del sistema o espais en blanc, segons correspongui."
 
-#: src/language/data-io/data-parser.c:630
+#: src/language/data-io/data-parser.c:664
 msgid "Record ends in data not part of any field."
 msgstr "El registre termina amb dades que no formen part de cap camp."
 
-#: src/language/data-io/data-parser.c:650 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:684 src/language/data-io/print.c:404
 msgid "Record"
 msgstr "Registre"
 
-#: src/language/data-io/data-parser.c:651 src/language/data-io/print.c:405
-#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:839
+#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:405
+#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:840
 #: src/ui/gui/crosstabs.ui:89
 msgid "Columns"
 msgstr "Columnes"
 
-#: src/language/data-io/data-parser.c:652
-#: src/language/data-io/data-parser.c:689 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:686
+#: src/language/data-io/data-parser.c:723 src/language/data-io/print.c:406
 msgid "Format"
 msgstr "Format"
 
-#: src/language/data-io/data-parser.c:670
+#: src/language/data-io/data-parser.c:704
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] "Llegint %d registre de %s."
 msgstr[1] "Llegint %d registres de %s."
 
-#: src/language/data-io/data-parser.c:704
+#: src/language/data-io/data-parser.c:738
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr "Llegint dades amb format lliure de %s."
@@ -2979,41 +3330,41 @@ msgstr "Llegint dades amb format lliure de %s."
 msgid "data file"
 msgstr "arxiu de dades"
 
-#: src/language/data-io/data-reader.c:150
+#: src/language/data-io/data-reader.c:148
 #, c-format
-msgid "Could not open \"%s\" for reading as a data file: %s."
-msgstr "No s'ha pogut obrir \"%s\" per a la lectura com un arxiu de dades: %s."
+msgid "Could not open `%s' for reading as a data file: %s."
+msgstr "No s'ha pogut obrir `%s' per a la lectura com a arxiu de dades: %s."
 
-#: src/language/data-io/data-reader.c:192
-msgid "Unexpected end-of-file while reading data in BEGIN DATA.  This probably indicates a missing or misformatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
-msgstr "Final d'arxiu inesperat durant la lectura de dades en BEGIN DATA.  Això probablement indica una pérdua o format erroni del comando END DATA.  END DATA ha d'aparèixer per si mateix en una sola línia amb exactament un espai entre les paraules."
+#: src/language/data-io/data-reader.c:198
+msgid "Missing END DATA while reading inline data.  This probably indicates a missing or incorrectly formatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
+msgstr "Manca END DATA quan es llegien dades en línia.  Això probablement indica una pérdua o format erroni del comando END DATA.  END DATA ha d'aparèixer per si mateix en una sola línia amb exactament un espai entre les paraules."
 
-#: src/language/data-io/data-reader.c:217
+#: src/language/data-io/data-reader.c:219
 #, c-format
 msgid "Error reading file %s: %s."
 msgstr "S'ha produït un error en llegir l'arxiu %s: %s."
 
-#: src/language/data-io/data-reader.c:220
+#: src/language/data-io/data-reader.c:222
 #, c-format
 msgid "Unexpected end of file reading %s."
 msgstr "Final inesperat en la lectura d'arxiu %s."
 
-#: src/language/data-io/data-reader.c:229
+#: src/language/data-io/data-reader.c:231
 #, c-format
 msgid "Unexpected end of file in partial record reading %s."
 msgstr "Fi d'arxiu inesperat en la lectura del registre parcial %s."
 
-#: src/language/data-io/data-reader.c:289
+#: src/language/data-io/data-reader.c:291
 #, c-format
 msgid "Corrupt block descriptor word at offset 0x%lx in %s."
 msgstr "Paraula descriptora de bloc malmesa en localització 0x%lx en %s."
 
-#: src/language/data-io/data-reader.c:290
+#: src/language/data-io/data-reader.c:292
 #, c-format
 msgid "Corrupt record descriptor word at offset 0x%lx in %s."
 msgstr "Paraula descriptora de registre malmesa en localització 0x%lx en %s."
 
-#: src/language/data-io/data-reader.c:303
+#: src/language/data-io/data-reader.c:305
 #, c-format
 msgid "Corrupt record size at offset 0x%lx in %s."
 msgstr "Longitud de registre malmesa en localització 0x%lx en %s."
@@ -3031,124 +3382,104 @@ msgstr "Intent llegir més enllà de la fi de l'arxiu a %s."
 msgid "Attempt to read beyond END DATA."
 msgstr "Intent de llegir més enllà de END DATA."
 
-#: src/language/data-io/data-reader.c:708
+#: src/language/data-io/data-reader.c:706
 msgid "This command is not valid here since the current input program does not access the inline file."
 msgstr "Aquesta ordre no es vàlida ja que el programa d'entrada actual no té accés a l'arxiu en línia."
 
-#: src/language/data-io/data-writer.c:74
+#: src/language/data-io/data-writer.c:73
 #, c-format
-msgid "An error occurred while opening \"%s\" for writing as a data file: %s."
-msgstr "S'ha produït un error en obrir \"%s\" per a escriure'l com un arxiu de dades: %s."
+msgid "An error occurred while opening `%s' for writing as a data file: %s."
+msgstr "S'ha produït un error en obrir `%s' per a escriure'l com a arxiu de dades: %s."
 
-#: src/language/data-io/data-writer.c:191
+#: src/language/data-io/data-writer.c:190
 #, c-format
-msgid "I/O error occurred writing data file \"%s\"."
-msgstr "I/O error en escriure les dades del fitxer \"%s\"."
+msgid "I/O error occurred writing data file `%s'."
+msgstr "Error E/S en escriure les dades de l'arxiu `%s'."
 
 #: src/language/data-io/get-data.c:64
 #, c-format
-msgid "Unsupported TYPE %s"
-msgstr "TYPE %s no admès"
+msgid "Unsupported TYPE %s."
+msgstr "TYPE %s no admès."
 
-#: src/language/data-io/get-data.c:260
+#: src/language/data-io/get-data.c:268
 #, c-format
 msgid "%s is allowed only with %s arrangement, but %s arrangement was stated or implied earlier in this command."
 msgstr "%s només es permet amb configuració %s, però prèviament en aquest comando s'ha establit la configuració %s."
 
-#: src/language/data-io/get-data.c:315
-msgid "expecting FIXED or DELIMITED"
-msgstr "esperant FIXED o DELIMITED"
-
-#: src/language/data-io/get-data.c:328
+#: src/language/data-io/get-data.c:337
 msgid "Value of FIRSTCASE must be 1 or greater."
 msgstr "Valor de FIRSTCASE ha de ser major o igual a 1."
 
-#: src/language/data-io/get-data.c:353
-msgid "expecting LINE or VARIABLES"
-msgstr "esperant LINE o VARIABLES"
-
-#: src/language/data-io/get-data.c:366
+#: src/language/data-io/get-data.c:375
 msgid "Value of FIXCASE must be at least 1."
 msgstr "Valor de FIXCASE ha de ser com a mínim 1."
 
-#: src/language/data-io/get-data.c:386
+#: src/language/data-io/get-data.c:395
 msgid "Value of FIRST must be at least 1."
 msgstr "Valor de FIRST ha de ser com a mínim 1."
 
-#: src/language/data-io/get-data.c:398
+#: src/language/data-io/get-data.c:407
 msgid "Value of PERCENT must be between 1 and 100."
 msgstr "Valor de PERCENT ha de ser entre 1 i 100."
 
-#: src/language/data-io/get-data.c:447
+#: src/language/data-io/get-data.c:458
 msgid "In compatible syntax mode, the QUALIFIER string must contain exactly one character."
 msgstr "En el mode de sintaxi compatible, la cadena QUALIFIER ha de contenir exactament un caràcter."
 
-#: src/language/data-io/get-data.c:462
-msgid "expecting VARIABLES"
-msgstr "esperant VARIABLES"
-
-#: src/language/data-io/get-data.c:484
-#: src/language/data-io/placement-parser.c:378
+#: src/language/data-io/get-data.c:493
+#: src/language/data-io/placement-parser.c:377
 #, c-format
 msgid "The record number specified, %ld, is at or before the previous record, %d.  Data fields must be listed in order of increasing record number."
 msgstr "El nombre de registre especificat, %ld, és a o abans del registre anterior, %d.  Els camps de dades han de ser llistats en ordre incremental del número de registre."
 
-#: src/language/data-io/get-data.c:493
+#: src/language/data-io/get-data.c:502
 #, c-format
 msgid "The record number specified, %ld, exceeds the number of records per case specified on FIXCASE, %d."
 msgstr "El nombre de registre especificat , %ld, excedeix el nombre de registres per cas especificats a FIXCASE, %d."
 
-#: src/language/data-io/get.c:99
-msgid "expecting COMM or TAPE"
-msgstr "esperant COMM o TAPE"
-
-#: src/language/data-io/inpt-pgm.c:130
+#: src/language/data-io/inpt-pgm.c:118
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr "Final d'arxiu inesperat dins INPUT PROGRAM."
 
-#: src/language/data-io/inpt-pgm.c:143
+#: src/language/data-io/inpt-pgm.c:131
 msgid "Input program did not create any variables."
 msgstr "El programa d'entrada no va crear cap variable."
 
-#: src/language/data-io/inpt-pgm.c:288
-msgid "COLUMN subcommand multiply specified."
-msgstr "subcomando COLUMN especificat múltiples vegades."
-
-#: src/language/data-io/inpt-pgm.c:338
+#: src/language/data-io/inpt-pgm.c:330
 msgid "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr "REREAD: Els nombres de columna han de ser nombres positius finits. La columna s'estableix en 1."
 
-#: src/language/data-io/placement-parser.c:87
+#: src/language/data-io/placement-parser.c:86
 #, c-format
 msgid "Number of variables specified (%zu) differs from number of variable formats (%zu)."
 msgstr "Nombre de variables especificades (%zu) difereix del nombre de formats de la variable (%zu)."
 
-#: src/language/data-io/placement-parser.c:97
+#: src/language/data-io/placement-parser.c:96
 msgid "SPSS-like or Fortran-like format specification expected after variable names."
 msgstr "Després del nom de les variables s'esperen especificacions en format tipus-SPSS o tipus-Fortran."
 
-#: src/language/data-io/placement-parser.c:119
+#: src/language/data-io/placement-parser.c:118
 #, c-format
 msgid "The %d columns %d-%d can't be evenly divided into %zu fields."
 msgstr "Les %d columnes %d-%d no poden ser uniformement dividides entre els camps %zu."
 
-#: src/language/data-io/placement-parser.c:305
+#: src/language/data-io/placement-parser.c:302
 msgid "Column positions for fields must be positive."
 msgstr "Les posicions de columna pels camps han de ser positives."
 
-#: src/language/data-io/placement-parser.c:307
+#: src/language/data-io/placement-parser.c:304
 msgid "Column positions for fields must not be negative."
 msgstr "Les posicions de columnes pels camps no poden ser negatives."
 
-#: src/language/data-io/placement-parser.c:344
+#: src/language/data-io/placement-parser.c:343
 msgid "The ending column for a field must be greater than the starting column."
 msgstr "La columna final d'un camp ha de ser major que la columna d'inici."
 
-#: src/language/data-io/print-space.c:116
+#: src/language/data-io/print-space.c:115
 msgid "The expression on PRINT SPACE evaluated to the system-missing value."
 msgstr "L'expressió a PRINT SPACE s'avalua pel sistema de valors perduts."
 
-#: src/language/data-io/print-space.c:119
+#: src/language/data-io/print-space.c:118
 #, c-format
 msgid "The expression on PRINT SPACE evaluated to %g."
 msgstr "L'expressió a PRINT SPACE s'avalua a %g."
@@ -3176,213 +3507,226 @@ msgid_plural "Writing %zu records."
 msgstr[0] "Escribint el registre %zu."
 msgstr[1] "Escrivint %zu registres."
 
-#: src/language/data-io/save.c:223 src/language/data-io/save.c:238
-#: src/language/data-io/save.c:266
+#: src/language/data-io/save-translate.c:165
+#: src/language/data-io/save-translate.c:180
 #, c-format
-msgid "expecting %s or %s"
-msgstr "esperant %s o %s"
+msgid "The %s string must contain exactly one character."
+msgstr "La cadena %s hauria de contenir exactament un caràcter."
+
+#: src/language/data-io/save-translate.c:250
+#, c-format
+msgid "Output file `%s' exists but REPLACE was not specified."
+msgstr "Existe un arxiu de sortida `%s' tot i que no s'ha especificat REPLACE."
 
-#: src/language/data-io/trim.c:88
+#: src/language/data-io/trim.c:89
 #, c-format
-msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, \"/RENAME (A B C=B C A)\"."
-msgstr "No es pot canviar el nom %s per %s perquè ja hi ha una variable anomenada %s.  Per canviar el nom de les variables amb noms superposats, utilitzeu el subcomando RENAME només com a \"/RENAME (A=B)(B=C)(C=A)\", o equivalentment, \"/RENAME (A B C=B C A)\"."
+msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, `/RENAME (A B C=B C A)'."
+msgstr "No es pot canviar el nom %s per %s perquè ja existeix una variable anomenada %s.  Per canviar el nom de les variables amb noms superposats, utilitzeu un únic subcomando RENAME com per exemple `/RENAME (A=B)(B=C)(C=A)', o equivalentment, `/RENAME (A B C=B C A)'."
 
-#: src/language/data-io/trim.c:114
+#: src/language/data-io/trim.c:115
 msgid "`=' expected after variable list."
 msgstr "`=' esperat després de llista de variables."
 
-#: src/language/data-io/trim.c:122
+#: src/language/data-io/trim.c:123
 #, c-format
 msgid "Number of variables on left side of `=' (%zu) does not match number of variables on right side (%zu), in parenthesized group %d of RENAME subcommand."
 msgstr "El nombre de variables en el costat esquerre de `=' (%zu) no coincideix amb el nombre de variables al costat dret (%zu), en el grup entre parèntesi %d del subcomando RENAME."
 
-#: src/language/data-io/trim.c:135
+#: src/language/data-io/trim.c:136
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr "El reanomenament demanat duplica el nom de la variable %s."
 
-#: src/language/data-io/trim.c:166
+#: src/language/data-io/trim.c:167
 msgid "Cannot DROP all variables from dictionary."
 msgstr "Impossible DROP totes les variables del diccionari."
 
-#: src/language/expressions/evaluate.c:155
+#: src/language/expressions/evaluate.c:152
 msgid "expecting number or string"
 msgstr "esperant nombre o cadena"
 
-#: src/language/expressions/evaluate.c:169
+#: src/language/expressions/evaluate.c:166
 #, c-format
 msgid "Duplicate variable name %s."
 msgstr "Nom de la variable %s duplicat."
 
-#: src/language/expressions/helpers.c:51
+#: src/language/expressions/helpers.c:41
 msgid "One of the arguments to a DATE function is not an integer.  The result will be system-missing."
 msgstr "Un dels arguments per a funció DATE no és un enter. El resultat serà perdut del sistema."
 
-#: src/language/expressions/helpers.c:73
+#: src/language/expressions/helpers.c:69
 msgid "The week argument to DATE.WKYR is not an integer.  The result will be system-missing."
 msgstr "L'argument de setmana per DATE.WKYR no és un enter. El resultat serà perdut pel sistema."
 
-#: src/language/expressions/helpers.c:79
+#: src/language/expressions/helpers.c:75
 msgid "The week argument to DATE.WKYR is outside the acceptable range of 1 to 53.  The result will be system-missing."
 msgstr "L'argument de setmana per DATE.WKYR és fora de l'interval acceptable entre 1 i 53.  El resultat serà perdut pel sistema."
 
-#: src/language/expressions/helpers.c:101
+#: src/language/expressions/helpers.c:97
 msgid "The day argument to DATE.YRDAY is not an integer.  The result will be system-missing."
 msgstr "L'argument de dia per DATE.YRDAY no és un enter.  El resultat serà perdut pel sistema."
 
-#: src/language/expressions/helpers.c:107
+#: src/language/expressions/helpers.c:103
 msgid "The day argument to DATE.YRDAY is outside the acceptable range of 1 to 366.  The result will be system-missing."
 msgstr "L'argument de dia per DATE.YRDAY és fora de l'interval acceptable entre 1 i 366. El resultat serà perdut al sistema."
 
-#: src/language/expressions/helpers.c:129
+#: src/language/expressions/helpers.c:125
 msgid "The year argument to YRMODA is greater than 47516.  The result will be system-missing."
 msgstr "L'argument d'any per YRMODA és més gran que 47516. El resultat será  perdut al sistema."
 
-#: src/language/expressions/helpers.c:182
+#. TRANSLATORS: Don't translate the the actual unit names `weeks', `days' etc
+#. They must remain in their original English.
+#: src/language/expressions/helpers.c:180
 #, c-format
-msgid "Unrecognized date unit \"%.*s\".  Valid date units are \"years\", \"quarters\", \"months\", \"weeks\", \"days\", \"hours\", \"minutes\", and \"seconds\"."
-msgstr "Unitat de dates  \"%.*s\" no reconeguda. Les unitats de data vàlides són \"anys\", \"trimestres\", \"mesos\", \"setmanes\", \"dies\", \"hores\", \"minuts\", i \"segons\"."
+msgid "Unrecognized date unit `%.*s'.  Valid date units are `years', `quarters', `months', `weeks', `days', `hours', `minutes', and `seconds'."
+msgstr "Unitat de dates `%.*s' no reconeguda. Les unitats de dates vàlides són `anys', `trimestres', `mesos' , `setmanes', `dies', `hores', `minuts', i `segons'."
 
-#: src/language/expressions/helpers.c:332
-msgid "Invalid DATESUM method.  Valid choices are \"closest\" and \"rollover\"."
-msgstr "Mètode DATESUM invàlid. Les opcions vàlides són \"propera\" i  \"acomplida\"."
+#: src/language/expressions/helpers.c:330
+msgid "Invalid DATESUM method.  Valid choices are `closest' and `rollover'."
+msgstr "Mètode DATESUM invàlid. Les opcions vàlides són `closest' i `rollover\"."
 
-#: src/language/expressions/parse.c:259
+#: src/language/expressions/parse.c:260
 #, c-format
 msgid "Type mismatch: expression has %s type, but a numeric value is required here."
 msgstr "Incompatibilitat de tipus: l'expressió té tipus %s, però aquí es demana un valor numèric."
 
-#: src/language/expressions/parse.c:271
+#: src/language/expressions/parse.c:272
 #, c-format
 msgid "Type mismatch: expression has %s type, but a string value is required here."
 msgstr "Incompatibilitat de tipus: l'expressió té tipus %s, però aquí es demana un valor de cadena."
 
-#: src/language/expressions/parse.c:427
+#: src/language/expressions/parse.c:434
 #, c-format
 msgid "Type mismatch while applying %s operator: cannot convert %s to %s."
 msgstr "Incompatibilitat dels tipus mentre que s'aplica l'operador %s: no es pot convertir %s a %s."
 
-#: src/language/expressions/parse.c:643
-msgid "Chaining relational operators (e.g. \"a < b < c\") will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. \"a < b AND b < c\").  If chaining is really intended, parentheses will disable this warning (e.g. \"(a < b) < c\".)"
-msgstr "L'encadenament d'operadors relacionals (p.e. \"a < b < c\") no produirà el resultat esperat matemàticament. Utilitzar l'operador lògic AND per solucionar el problema (p.e. \"a < b AND b < c\"). Si l'encadenament és realment intencionat, els parèntesis desactivaran aquesta alerta (p.e. \"(a < b) < c\".)"
+#: src/language/expressions/parse.c:648
+msgid "Chaining relational operators (e.g. `a < b < c') will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. `a < b AND b < c').  If chaining is really intended, parentheses will disable this warning (e.g. `(a < b) < c'.)"
+msgstr "L'encadenament d'operadors relacionals (p.e. `a < b < c') no produirà el resultat esperat matemàticament. Utilitzeu l'operador lògic AND per solucionar el problema (p.e. `a < b AND b < c'). Si l'encadenament és realment intencionat, l'ús de parèntesis desactivarà aquesta alerta (p.e. `(a < b) < c'.)"
 
-#: src/language/expressions/parse.c:744
-msgid "The exponentiation operator (\"**\") is left-associative, even though right-associative semantics are more useful.  That is, \"a**b**c\" equals \"(a**b)**c\", not as \"a**(b**c)\".  To disable this warning, insert parentheses."
-msgstr "L'operador d'exponenciació (\"**\") apareix a l'esquerra, tot i que si apareix a la dreta és més útil.  És a dir, \"a**b**c\" és igual a \"(a**b)**c\", no a \"a**(b**c)\". Per desactivar aquesta alerta, insereix parèntesis."
+#: src/language/expressions/parse.c:750
+msgid "The exponentiation operator (`**') is left-associative, even though right-associative semantics are more useful.  That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'.  To disable this warning, insert parentheses."
+msgstr "L'operador d'exponenciació (`**') apareix a l'esquerra, tot i que si apareix a la dreta és més útil.  Es a dir, `a**b**c' és igual a `(a**b)**c', i no `a**(b**c)'. Per desactivar aquesta alerta, insereix uns parèntesis."
 
-#: src/language/expressions/parse.c:809
+#: src/language/expressions/parse.c:830
 #, c-format
 msgid "Unknown system variable %s."
 msgstr "Variable de sistema desconeguda %s."
 
-#: src/language/expressions/parse.c:857
+#: src/language/expressions/parse.c:878
 #, c-format
 msgid "Unknown identifier %s."
 msgstr "Identificador desconegut %s."
 
-#: src/language/expressions/parse.c:892
-msgid "in expression"
-msgstr "en l'expressió"
-
-#: src/language/expressions/parse.c:1073
+#: src/language/expressions/parse.c:1100
 #, c-format
 msgid "%s must have at least %d arguments in list."
 msgstr "%s ha de tenir com a mínim %d arguments a la llista."
 
-#: src/language/expressions/parse.c:1082
+#: src/language/expressions/parse.c:1109
 #, c-format
-msgid "%s must have even number of arguments in list."
-msgstr "%s han de tenir un nombre parell d'arguments a la llista."
+msgid "%s must have an even number of arguments in list."
+msgstr "%s ha de tenir un nombre parell d'arguments a la llista."
 
-#: src/language/expressions/parse.c:1085
+#: src/language/expressions/parse.c:1112
 #, c-format
 msgid "%s must have multiple of %d arguments in list."
 msgstr "%s ha de tenir un múltiple de %d arguments a la llista."
 
-#: src/language/expressions/parse.c:1095
+#: src/language/expressions/parse.c:1122
 #, c-format
 msgid "%s function does not accept a minimum valid argument count."
 msgstr "la funció %s no accepta un mínim recompte d'arguments vàlids."
 
-#: src/language/expressions/parse.c:1104
+#: src/language/expressions/parse.c:1131
 #, c-format
 msgid "%s requires at least %d valid arguments in list."
 msgstr "%s requereix com a mínim %d arguments vàlids en la llista."
 
-#: src/language/expressions/parse.c:1110
+#: src/language/expressions/parse.c:1137
 #, c-format
 msgid "With %s, using minimum valid argument count of %d does not make sense when passing only %d arguments in list."
 msgstr "Amb %s, utilitzar el mínim recompte d'argument vàlid %d no té sentit quan es passen només %d arguments en la llista."
 
-#: src/language/expressions/parse.c:1164
+#: src/language/expressions/parse.c:1191
 #, c-format
 msgid "Type mismatch invoking %s as "
 msgstr "Incompatibilitats de tipus invocant %s com a"
 
-#: src/language/expressions/parse.c:1169
+#: src/language/expressions/parse.c:1196
 msgid "Function invocation "
 msgstr "Invocació de funció"
 
-#: src/language/expressions/parse.c:1171
+#: src/language/expressions/parse.c:1198
 msgid " does not match any known function.  Candidates are:"
 msgstr "no coincideix amb cap funció coneguda. Els candidats són:"
 
-#: src/language/expressions/parse.c:1201
+#: src/language/expressions/parse.c:1228
 #, c-format
 msgid "No function or vector named %s."
 msgstr "Cap funció o vector anomenat %s."
 
-#: src/language/expressions/parse.c:1244
+#: src/language/expressions/parse.c:1271
 #, c-format
 msgid "expecting `,' or `)' invoking %s function"
 msgstr "esperant `,' o `)' invocant la funció %s"
 
-#: src/language/expressions/parse.c:1264
+#: src/language/expressions/parse.c:1291
 #, c-format
 msgid "%s is a PSPP extension."
 msgstr "%s és una extensió de PSPP."
 
-#: src/language/expressions/parse.c:1273
+#: src/language/expressions/parse.c:1300
 #, c-format
 msgid "%s may not appear after TEMPORARY."
 msgstr "%s no pot aparèixer desprès de TEMPORARY."
 
-#: src/libpspp/hash.c:545
-#, c-format
-msgid "hash table:"
-msgstr "taula hash:"
+#: src/libpspp/ext-array.c:56
+msgid "failed to create temporary file"
+msgstr "error en crear l'arxiu temporal"
+
+#: src/libpspp/ext-array.c:96
+msgid "seeking in temporary file"
+msgstr "cercant en l'arxiu temporal"
+
+#: src/libpspp/ext-array.c:115
+msgid "reading temporary file"
+msgstr "llegint arxiu temporal"
+
+#: src/libpspp/ext-array.c:117
+msgid "unexpected end of file reading temporary file"
+msgstr "final de fitxer inesperat en llegir l'arxiu temporal"
 
-#: src/libpspp/message.c:128
+#: src/libpspp/ext-array.c:136
+msgid "writing to temporary file"
+msgstr "escrivint a un arxiu temporal"
+
+#: src/libpspp/message.c:172
 msgid "error"
 msgstr "error"
 
-#: src/libpspp/message.c:131
+#: src/libpspp/message.c:175
 msgid "warning"
 msgstr "avís"
 
-#: src/libpspp/message.c:135
-msgid "note"
-msgstr "anotació"
-
-#: src/libpspp/tmpfile.c:56
-msgid "failed to create temporary file"
-msgstr "error en crear l'arxiu temporal"
-
-#: src/libpspp/tmpfile.c:97
-msgid "seeking in temporary file"
-msgstr "cercant en l'arxiu temporal"
+#: src/libpspp/message.c:179
+msgid "note"
+msgstr "anotació"
 
-#: src/libpspp/tmpfile.c:116
-msgid "reading temporary file"
-msgstr "llegint arxiu temporal"
+#: src/libpspp/message.c:279
+#, c-format
+msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
+msgstr "Les anotacions (%d) han superat el límit (%d).  Es suprimeixen les posteriors."
 
-#: src/libpspp/tmpfile.c:118
-msgid "unexpected end of file reading temporary file"
-msgstr "final de fitxer inesperat en llegir l'arxiu temporal"
+#: src/libpspp/message.c:287
+#, c-format
+msgid "Warnings (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Les alertes (%d) han superat el límit (%d).  S'atura el processament de sintaxi."
 
-#: src/libpspp/tmpfile.c:137
-msgid "writing to temporary file"
-msgstr "escrivint a un arxiu temporal"
+#: src/libpspp/message.c:290
+#, c-format
+msgid "Errors (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Els errors (%d) han superat el límit (%d).  S'atura el processament de sintaxi."
 
 #: src/libpspp/zip-writer.c:91
 #, c-format
@@ -3414,60 +3758,65 @@ msgstr "Empíric"
 msgid "Empirical with averaging"
 msgstr "Empíric amb mitjanes"
 
-#: src/output/ascii.c:278
+#: src/output/ascii.c:281
 #, c-format
 msgid "%s: %s must be positive integer or `auto'"
 msgstr "%s: %s ha de ser enter positiu o `auto'"
 
-#: src/output/ascii.c:311
+#: src/output/ascii.c:314
 #, c-format
 msgid "ascii: page excluding margins and headers must be at least %d characters wide by %d lines long, but as configured is only %d characters by %d lines"
 msgstr "ascii: excloent els marges i encapçalaments la pàgina ha de tenir com a mínim %d caràcters d'ample per %d línies de llarg, però tal com està configurada, només n'hi ha %d caràcters i %d línies"
 
-#: src/output/ascii.c:360
+#: src/output/ascii.c:363
 #, c-format
-msgid "ascii: closing output file \"%s\""
-msgstr "ascii: tancant l'arxiu de sortida \"%s\""
+msgid "ascii: closing output file `%s'"
+msgstr "ascii: tancant l'arxiu de sortida `%s'"
 
-#: src/output/ascii.c:503
+#: src/output/ascii.c:506
 #, c-format
 msgid "See %s for a chart."
 msgstr "Veure %s per a gràfica."
 
-#: src/output/ascii.c:806
+#: src/output/ascii.c:833
 #, c-format
-msgid "ascii: opening output file \"%s\""
-msgstr "ascii: obrint l'arxiu de resultats \"%s\""
+msgid "ascii: opening output file `%s'"
+msgstr "ascii: obrint l'arxiu de resultats `%s'"
 
-#: src/output/ascii.c:913 src/output/cairo.c:784
+#: src/output/ascii.c:940
 #, c-format
 msgid "%s - Page %d"
 msgstr "%s - Pàgina %d"
 
-#: src/output/csv.c:87 src/output/html.c:106 src/output/journal.c:93
+#: src/output/csv.c:97 src/output/html.c:106 src/output/journal.c:93
 #: src/output/msglog.c:66
 #, c-format
-msgid "error opening output file \"%s\""
-msgstr "error obrint l'arxiu de resultats \"%s\""
+msgid "error opening output file `%s'"
+msgstr "error obrint l'arxiu de resultats `%s'"
 
-#: src/output/driver.c:330
+#. TRANSLATORS: Don't translate the words `terminal' or `listing'.
+#: src/output/driver.c:283
 #, c-format
-msgid "%s is not a valid device type (the choices are \"terminal\" and \"listing\")"
-msgstr "%s no és un tipus de dispositiu vàlid (les opcions son \"terminal\" i \"llistat\")"
+msgid "%s is not a valid device type (the choices are `terminal' and `listing')"
+msgstr "%s no és un tipus de dispositiu vàlid (les opcions son `terminal' i `listing')"
 
-#: src/output/driver.c:343
+#: src/output/driver.c:296
 #, c-format
-msgid "%s: unknown option \"%s\""
-msgstr "%s: opció desconeguda \"%s\""
+msgid "%s: unknown option `%s'"
+msgstr "%s: opció desconeguda `%s'"
 
 #: src/output/html.c:114
 msgid "PSPP Output"
 msgstr "Resultat de PSPP"
 
+#: src/output/html.c:258
+msgid "No description"
+msgstr "Sense descripció"
+
 #: src/output/journal.c:67
 #, c-format
-msgid "error writing output file \"%s\""
-msgstr "error en escriure l'arxiu de resultats \"%s\""
+msgid "error writing output file `%s'"
+msgstr "error en escriure l'arxiu de resultats `%s'"
 
 #: src/output/measure.c:65
 #, c-format
@@ -3486,110 +3835,110 @@ msgstr "tipus de paper desconegut `%.*s'"
 
 #: src/output/measure.c:248
 #, c-format
-msgid "error opening input file \"%s\""
-msgstr "error en obrir l'arxiu de dades \"%s\""
+msgid "error opening input file `%s'"
+msgstr "error en obrir l'arxiu de dades `%s'"
 
 #: src/output/measure.c:259
 #, c-format
-msgid "error reading file \"%s\""
-msgstr "error llegint l'arxiu \"%s\""
+msgid "error reading file `%s'"
+msgstr "error llegint l'arxiu `%s'"
 
 #: src/output/measure.c:276
 #, c-format
-msgid "paper size file \"%s\" does not state a paper size"
-msgstr "l'arxiu de mida de paper \"%s\" no indica una mida de paper"
+msgid "paper size file `%s' does not state a paper size"
+msgstr "l'arxiu de mida de paper `%s' no indica una mida de paper"
 
 #: src/output/options.c:113
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a Boolean value is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un valor Booleà"
+msgid "%s: `%s' is `%s' but a Boolean value is required"
+msgstr "%s: `%s' és `%s', però es requereix un valor Booleà"
 
 #: src/output/options.c:188
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but one of the following is required: %s"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un del sequents: %s "
+msgid "%s: `%s' is `%s' but one of the following is required: %s"
+msgstr "%s: `%s' és `%s', però es requereix un del sequents: %s "
 
 #: src/output/options.c:232
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a nonnegative integer is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un enter no negatiu"
+msgid "%s: `%s' is `%s' but a nonnegative integer is required"
+msgstr "%s: `%s' és `%s', però es requereix un enter no negatiu"
 
 #: src/output/options.c:236
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a positive integer is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un enter positiu"
+msgid "%s: `%s' is `%s' but a positive integer is required"
+msgstr "%s: `%s' és `%s', però es requereix un enter positiu"
 
 #: src/output/options.c:239
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but an integer is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un enter"
+msgid "%s: `%s' is `%s' but an integer is required"
+msgstr "%s: `%s' és `%s', però es requereix un enter"
 
 #: src/output/options.c:242
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but an integer greater than %d is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un enter més gran que %d"
+msgid "%s: `%s' is `%s' but an integer greater than %d is required"
+msgstr "%s: `%s' és `%s', però es requereix un enter més gran que %d"
 
 #: src/output/options.c:247
 #, c-format
-msgid "%s: \"%s\" is \"%s\"  but an integer between %d and %d is required"
-msgstr "%s: \"%s\" és \"%s\", però es requereix un enter entre %d i %d"
+msgid "%s: `%s' is `%s'  but an integer between %d and %d is required"
+msgstr "%s: `%s' és `%s', però es requereix un enter entre %d i %d"
 
 #: src/output/options.c:326
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a file name that contains \"#\" is required."
-msgstr "%s: \"%s\" és \"%s\", però es requereix un nom d'arxiu que contingui \"#\"."
+msgid "%s: `%s' is `%s' but a file name that contains `#' is required."
+msgstr "%s: `%s' és `%s', però es requereix un nom d'arxiu que contingui `#'."
 
-#: src/output/tab.c:206
+#: src/output/tab.c:207
 #, c-format
 msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) a taula de mida (%d,%d)\n"
 
-#: src/output/tab.c:244
+#: src/output/tab.c:245
 #, c-format
 msgid "bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in table size (%d,%d)\n"
 msgstr "incorrecta hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d a taula de mida (%d,%d)\n"
 
-#: src/output/tab.c:288
+#: src/output/tab.c:289
 #, c-format
 msgid "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) en taula amb mida (%d,%d)\n"
 
-#: src/output/cairo.c:295
+#: src/output/cairo.c:193
+#, c-format
+msgid "`%s': bad font specification"
+msgstr "`%s': especificació de caràcter no vàlida"
+
+#: src/output/cairo.c:357
 #, c-format
-msgid "error opening output file \"%s\": %s"
-msgstr "error obrint l'arxiu de resultats \"%s\": %s"
+msgid "error opening output file `%s': %s"
+msgstr "error obrint l'arxiu de resultats `%s': %s"
 
-#: src/output/cairo.c:312
+#: src/output/cairo.c:374
 #, c-format
 msgid "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."
 msgstr "La pàgina definida no és prou ampla com per contenir al més d'almenys %d caracters en la font per defecte.  De fet, només n'hi ha espai per %d caracters."
 
-#: src/output/cairo.c:322
+#: src/output/cairo.c:384
 #, c-format
-msgid "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."
-msgstr "La pàgina definida no és prou llarga com per contenir marges i capçaleres, a més d'almenys %d línies amb les fonts per defecte. De fet, només n'hi ha espai per %d línies."
+msgid "The defined page is not long enough to hold at least %d lines in the default font.  In fact, there's only room for %d lines."
+msgstr "La pàgina definida no és prou llarga com per contenir almenys %d línies amb les fonts per defecte. De fet, només n'hi ha espai per %d línies."
 
-#: src/output/cairo.c:376
+#: src/output/cairo.c:435
 #, c-format
 msgid "error drawing output for %s driver: %s"
-msgstr "error dibuixant resultats pel controlador %s: \"%s\""
+msgstr "error dibuixant resultats pel controlador %s: %s"
 
-#: src/output/cairo.c:864
+#: src/output/cairo.c:1073
 #, c-format
-msgid "\"%s\": bad font specification"
-msgstr "\"%s\": especificació de caràcter no vàlida"
-
-#: src/output/cairo.c:1084
-#, c-format
-msgid "error writing output file \"%s\": %s"
-msgstr "Error escribint l'arxiu de resultats \"%s\": %s."
+msgid "error writing output file `%s': %s"
+msgstr "Error escribint l'arxiu de resultats `%s': %s."
 
 #: src/output/charts/np-plot-cairo.c:37
 #, c-format
 msgid "Normal Q-Q Plot of %s"
 msgstr "Gràfica Normal Q-Q de %s"
 
-#: src/output/charts/np-plot-cairo.c:38 src/output/charts/np-plot-cairo.c:66
+#: src/output/charts/np-plot-cairo.c:38 src/output/charts/np-plot-cairo.c:65
 msgid "Observed Value"
 msgstr "Valor observat"
 
@@ -3602,7 +3951,7 @@ msgstr "Normal esperada"
 msgid "Detrended Normal Q-Q Plot of %s"
 msgstr "Gràfica Normal Detrended Q-Q de %s"
 
-#: src/output/charts/np-plot-cairo.c:67
+#: src/output/charts/np-plot-cairo.c:66
 msgid "Dev from Normal"
 msgstr "Desviació de la Normal"
 
@@ -3611,7 +3960,7 @@ msgid "HISTOGRAM"
 msgstr "HISTOGRAM"
 
 #: src/output/charts/plot-hist-cairo.c:112
-#: src/language/stats/frequencies.q:814
+#: src/language/stats/frequencies.q:824
 msgid "Frequency"
 msgstr "Freqüència"
 
@@ -3627,151 +3976,222 @@ msgstr "Grafic de Sedimentació"
 msgid "Eigenvalue"
 msgstr "Valor-propi"
 
-#: src/output/odt.c:93
+#: src/output/odt.c:94
 msgid "error creating temporary file"
 msgstr "error creant arxiu temporal"
 
-#: src/ui/source-init-opts.c:78
-msgid "Algorithm must be either \"compatible\" or \"enhanced\"."
-msgstr "Algorisme ha de ser o \"compatible\" o \"ampliat\"."
+#: src/ui/source-init-opts.c:77
+msgid "Algorithm must be either `compatible' or `enhanced'."
+msgstr "L'algoritme ha de ser o ' compatible' o `enhanced'."
 
-#: src/ui/source-init-opts.c:103
-msgid "Syntax must be either \"compatible\" or \"enhanced\"."
-msgstr "La sintaxi ha de ser o \"compatible\" o \"ampliada\"."
+#: src/ui/source-init-opts.c:104
+msgid "Syntax must be either `compatible' or `enhanced'."
+msgstr "La sintaxi ha de ser o `compatible' o `enhanced'."
+
+#: src/ui/terminal/main.c:145
+msgid "Error encountered while ERROR=STOP is effective."
+msgstr "Detectat un error mentre està actiu ERROR=STOP."
 
-#: src/ui/terminal/main.c:128
+#: src/ui/terminal/main.c:151
 msgid "Stopping syntax file processing here to avoid a cascade of dependent command failures."
 msgstr "Aturant el processament de l'arxiu de sintaxi aquí per evitar una cascada d'errors derivats."
 
-#: src/ui/terminal/msg-ui.c:127
+#: src/ui/terminal/terminal-opts.c:122
 #, c-format
-msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
-msgstr "Les anotacions (%d) han superat el límit (%d).  Es suprimeixen les posteriors."
+msgid "%s: output option missing `='"
+msgstr "%s: manca opció de resultat `='"
 
-#: src/ui/terminal/msg-ui.c:135
+#: src/ui/terminal/terminal-opts.c:129
 #, c-format
-msgid "Warnings (%d) exceed limit (%d)."
-msgstr "Avisos (%d) excedeixen el límit (%d)."
+msgid "%s: output option specified more than once"
+msgstr "%s: opció de resultat especificada més d'una vegada"
 
-#: src/ui/terminal/msg-ui.c:138
+#: src/ui/terminal/terminal-opts.c:171
 #, c-format
-msgid "Errors (%d) exceed limit (%d)."
-msgstr "Els errors (%d) excedeixen el límit (%d)."
+msgid ""
+"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"
+"  --no-output               disable default output driver\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"
+"  -b, --batch               interpret syntax in batch mode\n"
+"  -i, --interactive         interpret syntax in interactive mode\n"
+"  --syntax-encoding=ENCODING  specify encoding for syntax files\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"
+msgstr ""
+"PSPP, un programa per l'anàlisi estadistic de dades mostrals.\n"
+"Ús: %s [OPTION]... FILE...\n"
+"\n"
+"Els arguments per a opcions llargues també s'apliquen a les opcions curtes equivalents.\n"
+"\n"
+"Opcions de Sortida:\n"
+"  -o, --output=FILE         sortida cap a FILE, amb format per defecte segons el nom de FILE\n"
+"  -O format=FORMAT          sobreescritura del format previ de -o\n"
+"  -O OPTION=VALUE           estableix opcions de sortida personalitzades per a -o\n"
+"  -O device={terminal|listing}  canvia el tipus de dispositivo per a -o\n"
+"  -e, --error-file=FILE     afegeix errors, alertes i notes a FILE\n"
+"  --no-output               desactiva el dispositiu de sortida per defecte\n"
+"Formats de sortida disponibles: %s\n"
+"\n"
+"Opcions de llenguatge:\n"
+"  -I, --include=DIR         afegeix DIR a la ruta de cerca\n"
+"  -I-, --no-include         netejar la ruta de cerca\n"
+"  -r, --no-statrc           desactiva arxiu rc executant-se a l'inici\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            marcar com `compatible' si es prefereix la sortida\n"
+"                            calculada a partir d'algoritmes trencats\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            marcar com `compatible' per desactivar les extensions de PSPP\n"
+"  -b, --batch               interpretar la sintaxi en mode paquet\n"
+"  -i, --interactive         interpretar la sintaxi en mode interactiu\n"
+"  -s, --safer               no permet algunes operacions poc segures\n"
+"Ruta de cerca per defecte:%s\n"
+"\n"
+"Sortida Informativa:\n"
+"  -h, --help                mostra aquesta ajuda i surt\n"
+"  -V, --version             mostra informació sobre la versió i surt\n"
+"\n"
+"Els arguments sense opcions son interpretats com a arxius de sintaxis per executar.\n"
 
-#: src/ui/terminal/terminal.c:72
+#: src/ui/terminal/terminal.c:62
 #, c-format
 msgid "could not access definition for terminal `%s'"
 msgstr "no es pot accedir a la definició per a terminal `%s'"
 
-#: src/ui/terminal/terminal-opts.c:119
-#, c-format
-msgid "%s: output option missing `='"
-msgstr "%s: manca opció de resultat `='"
+#: src/ui/gui/aggregate-dialog.c:161
+msgid "Aggregate destination file"
+msgstr "Arxiu destinació de l'agregació"
 
-#: src/ui/terminal/terminal-opts.c:126
-#, c-format
-msgid "%s: output option specified more than once"
-msgstr "%s: opció de resultat especificada més d'una vegada"
+#: src/ui/gui/aggregate-dialog.c:172 src/ui/gui/psppire-data-window.c:400
+#: src/ui/gui/psppire-data-window.c:601
+msgid "System Files (*.sav)"
+msgstr "Arxius de Sistema (*.sav)"
+
+#: src/ui/gui/aggregate-dialog.c:178 src/ui/gui/psppire-data-window.c:406
+#: src/ui/gui/psppire-data-window.c:607
+msgid "Portable Files (*.por) "
+msgstr "Arxius Portables (*.por)"
 
-#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1213
-#: src/language/stats/crosstabs.q:1240 src/language/stats/crosstabs.q:1263
-#: src/language/stats/crosstabs.q:1287 src/language/stats/examine.q:1638
+#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1233
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1307 src/language/stats/examine.q:1637
 msgid "Statistic"
 msgstr "Estatístic"
 
-#: src/ui/gui/comments-dialog.c:58
+#: src/ui/gui/comments-dialog.c:57
 #, c-format
 msgid "Column Number: %d"
 msgstr "Número de columna: %d"
 
-#: src/ui/gui/crosstabs-dialog.c:41
+#: src/ui/gui/crosstabs-dialog.c:40
 msgid "Chisq"
 msgstr "Chisq"
 
-#: src/ui/gui/crosstabs-dialog.c:42 src/language/stats/crosstabs.q:1774
+#: src/ui/gui/crosstabs-dialog.c:41 src/language/stats/crosstabs.q:1806
 msgid "Phi"
 msgstr "Phi"
 
-#: src/ui/gui/crosstabs-dialog.c:43
+#: src/ui/gui/crosstabs-dialog.c:42
 msgid "CC"
 msgstr "CC"
 
-#: src/ui/gui/crosstabs-dialog.c:44 src/language/stats/crosstabs.q:1912
+#: src/ui/gui/crosstabs-dialog.c:43 src/language/stats/crosstabs.q:1944
 msgid "Lambda"
 msgstr "Lambda"
 
-#: src/ui/gui/crosstabs-dialog.c:45
+#: src/ui/gui/crosstabs-dialog.c:44
 msgid "UC"
 msgstr "UC"
 
-#: src/ui/gui/crosstabs-dialog.c:46
+#: src/ui/gui/crosstabs-dialog.c:45
 msgid "BTau"
 msgstr "BTau"
 
-#: src/ui/gui/crosstabs-dialog.c:47
+#: src/ui/gui/crosstabs-dialog.c:46
 msgid "CTau"
 msgstr "CTau"
 
-#: src/ui/gui/crosstabs-dialog.c:48
+#: src/ui/gui/crosstabs-dialog.c:47
 msgid "Risk"
 msgstr "Risc"
 
-#: src/ui/gui/crosstabs-dialog.c:49 src/language/stats/crosstabs.q:1779
+#: src/ui/gui/crosstabs-dialog.c:48 src/language/stats/crosstabs.q:1811
 msgid "Gamma"
 msgstr "Gamma"
 
-#: src/ui/gui/crosstabs-dialog.c:50
+#: src/ui/gui/crosstabs-dialog.c:49
 msgid "D"
 msgstr "D"
 
-#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1782
+#: src/ui/gui/crosstabs-dialog.c:50 src/language/stats/crosstabs.q:1814
 msgid "Kappa"
 msgstr "Kappa"
 
-#: src/ui/gui/crosstabs-dialog.c:52 src/language/stats/crosstabs.q:1916
+#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1948
 msgid "Eta"
 msgstr "Eta"
 
-#: src/ui/gui/crosstabs-dialog.c:53
+#: src/ui/gui/crosstabs-dialog.c:52
 msgid "Corr"
 msgstr "Corr."
 
-#: src/ui/gui/crosstabs-dialog.c:54 src/ui/gui/crosstabs-dialog.c:65
-#: src/ui/gui/crosstabs-dialog.c:100 src/ui/gui/crosstabs-dialog.c:108
-#: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
+#: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
+#: src/ui/gui/psppire-var-store.c:613 src/ui/gui/var-display.c:16
 #: src/ui/gui/variable-info-dialog.c:41
 msgid "None"
 msgstr "Cap"
 
-#: src/ui/gui/crosstabs-dialog.c:57
+#: src/ui/gui/crosstabs-dialog.c:56
 msgid "Count"
 msgstr "Recompte"
 
-#: src/ui/gui/crosstabs-dialog.c:58
+#: src/ui/gui/crosstabs-dialog.c:57
 msgid "Row"
 msgstr "Fila"
 
-#: src/ui/gui/crosstabs-dialog.c:59
+#: src/ui/gui/crosstabs-dialog.c:58
 msgid "Column"
 msgstr "Columna"
 
-#: src/ui/gui/crosstabs-dialog.c:61
+#: src/ui/gui/crosstabs-dialog.c:60
 msgid "Expected"
 msgstr "Esperat"
 
-#: src/ui/gui/crosstabs-dialog.c:63
+#: src/ui/gui/crosstabs-dialog.c:62
 msgid "Std. Residual"
 msgstr "Residu Tipificat"
 
-#: src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:63
 msgid "Adjusted Std. Residual"
 msgstr "Residu Tipificat Ajustat"
 
-#: src/ui/gui/descriptives-dialog.c:41 src/ui/gui/frequencies-dialog.c:42
-msgid "Standard deviation"
-msgstr "Desviació Estàndard"
-
-#: src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/descriptives-dialog.c:45
 msgid "Standard error"
 msgstr "Error Estàndard"
 
@@ -3780,36 +4200,32 @@ msgstr "Error Estàndard"
 msgid "Bad regular expression: %s"
 msgstr "Expressió regular incorrecta: %s"
 
-#: src/ui/gui/factor-dialog.c:344
+#: src/ui/gui/factor-dialog.c:343
 #, c-format
 msgid "Eigenvalues over %4.2f times the mean eigenvalue"
 msgstr "Valors-propis per sobre de %4.2f vegades el valor-propi mitjà"
 
-#: src/ui/gui/frequencies-dialog.c:45
+#: src/ui/gui/frequencies-dialog.c:44
 msgid "Standard error of the mean"
 msgstr "Error estàndard en la mitjana"
 
-#: src/ui/gui/frequencies-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:47
 msgid "Standard error of the skewness"
 msgstr "Error estàndard de l'asimetria"
 
-#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/frequencies.q:108
+#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/frequencies.q:108
 msgid "Mode"
 msgstr "Mode"
 
-#: src/ui/gui/frequencies-dialog.c:52
+#: src/ui/gui/frequencies-dialog.c:51
 msgid "Standard error of the kurtosis"
 msgstr "Error estàndard en la curtosi"
 
-#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/examine.q:1469
+#: src/ui/gui/frequencies-dialog.c:52 src/language/stats/examine.q:1468
 #: src/language/stats/frequencies.q:107
 msgid "Median"
 msgstr "Mediana"
 
-#: src/ui/gui/helper.c:197
-msgid "Sorry. The help system hasn't yet been implemented."
-msgstr "Disculpeu. El sistema d'ajuda encara no ha estat implementat."
-
 #: src/ui/gui/help-menu.c:67
 msgid "A program for the analysis of sampled data"
 msgstr "Un programa per a l'anàlisi de dades de mostreig"
@@ -3822,8 +4238,8 @@ msgstr "F.J. Miguel, J. Gómez, P. Payà"
 
 #: src/ui/gui/help-menu.c:98
 #, c-format
-msgid "Cannot open reference manual: %s.  The PSPP user manual is also available at http://www.gnu.org/software/pspp/documentation.html"
-msgstr "No es pot obrir el manula de referència: %s. El manual d'usuari de PSPP es tambè disponible a http://www.gnu.org/software/pspp/documentation.html"
+msgid "Cannot open reference manual: %s.  The PSPP user manual is also available at %s"
+msgstr "No es pot obrir el manual de referència: %s. El manual d'usuari de PSPP es tambè disponible a %s"
 
 #: src/ui/gui/help-menu.c:117
 msgid "_Help"
@@ -3833,6 +4249,61 @@ msgstr "Ajut"
 msgid "_Reference Manual"
 msgstr "Manual de _Referencia"
 
+#: src/ui/gui/main.c:82
+#, c-format
+msgid ""
+"PSPPIRE, a GUI for 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"
+"GUI options:\n"
+"  -q, --no-splash           don't show splash screen during startup\n"
+"\n"
+"%sLanguage options:\n"
+"  -I, --include=DIR         append DIR to search path\n"
+"  -I-, --no-include         clear search path\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"
+"A non-option argument is interpreted as a .sav or .por file to load.\n"
+msgstr ""
+"PSPPIRE, un entorn gràfic (GUI) per PSPP, programa per l'anàlisi estatistic de dades mostrals.\n"
+"Ús: %s [OPTION]... FILE\n"
+"\n"
+"Els arguments per a opcions llargues s'apliquen també a opcions curtes equivalents.\n"
+"\n"
+"Opcions de GUI:\n"
+"  -q, --no-splash           no mostrar la pantalla inicial \n"
+"\n"
+"Opcions de llenguatge %s:\n"
+"  -I, --include=DIR         afegeix DIR a la ruta de cerca\n"
+"  -I-, --no-include         netejar la ruta de cerca\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            marcar com `compatible' si es prefereix la sortida\n"
+"                            calculada a partir d'algoritmes trencats\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            maracar com `compatible' per desactivar les extensions de PSPP\n"
+"  -i, --interactive         interpretar la sintaxis en mode interactiu\n"
+"  -s, --safer               no permet algunes operacions poc segures\n"
+"Ruta de cerca per defecte:%s\n"
+"\n"
+"Sortida Informativa:\n"
+"  -h, --help                mostra aquesta ajuda i surt\n"
+"  -V, --version             mostra informació sobre la versió i surt\n"
+"\n"
+"Els arguments sense opcions son interpretats com a arxius de sintaxis per executar.\n"
+
 #: src/ui/gui/missing-val-dialog.c:113 src/ui/gui/missing-val-dialog.c:167
 msgid "Incorrect value for variable type"
 msgstr "Valor incorrecte pel tipus de variable"
@@ -3841,24 +4312,24 @@ msgstr "Valor incorrecte pel tipus de variable"
 msgid "Incorrect range specification"
 msgstr "Especificació d'interval incorrecte"
 
-#: src/ui/gui/oneway-anova-dialog.c:313
+#: src/ui/gui/oneway-anova-dialog.c:300
 #, c-format
 msgid "Contrast %d of %d"
 msgstr "Contrast %d de %d"
 
-#: src/ui/gui/psppire.c:224
+#: src/ui/gui/psppire.c:218
 msgid "_Reset"
 msgstr "_Reiniciar"
 
-#: src/ui/gui/psppire.c:225
+#: src/ui/gui/psppire.c:219
 msgid "_Select"
 msgstr "_Selecionar"
 
-#: src/ui/gui/psppire-data-editor.c:951
+#: src/ui/gui/psppire-data-editor.c:950
 msgid "Data View"
 msgstr "Vista de dades"
 
-#: src/ui/gui/psppire-data-editor.c:954
+#: src/ui/gui/psppire-data-editor.c:953
 msgid "Variable View"
 msgstr "Vista de Variables"
 
@@ -3896,256 +4367,303 @@ msgstr "Sense Ponderar:"
 msgid "Weight by %s"
 msgstr "Ponderat per %s"
 
-#: src/ui/gui/psppire-data-window.c:382
+#: src/ui/gui/psppire-data-window.c:380
 msgid "Open"
 msgstr "Obert"
 
-#: src/ui/gui/psppire-data-window.c:392
+#: src/ui/gui/psppire-data-window.c:390
 msgid "Data and Syntax Files"
 msgstr "Arxius de Dades i Sintaxi"
 
-#: src/ui/gui/psppire-data-window.c:402 src/ui/gui/psppire-data-window.c:614
-msgid "System Files (*.sav)"
-msgstr "Arxius de Sistema (*.sav)"
-
-#: src/ui/gui/psppire-data-window.c:408 src/ui/gui/psppire-data-window.c:620
-msgid "Portable Files (*.por) "
-msgstr "Arxius Portables (*.por)"
-
-#: src/ui/gui/psppire-data-window.c:414 src/ui/gui/psppire-syntax-window.c:292
+#: src/ui/gui/psppire-data-window.c:412 src/ui/gui/psppire-syntax-window.c:505
 msgid "Syntax Files (*.sps) "
 msgstr "Arxius de Sintàxi (*.sps) "
 
-#: src/ui/gui/psppire-data-window.c:420 src/ui/gui/psppire-data-window.c:626
-#: src/ui/gui/psppire-syntax-window.c:298
+#: src/ui/gui/psppire-data-window.c:418 src/ui/gui/psppire-data-window.c:613
+#: src/ui/gui/psppire-syntax-window.c:511
 msgid "All Files"
 msgstr "Tots els arxius"
 
-#: src/ui/gui/psppire-data-window.c:606
+#: src/ui/gui/psppire-data-window.c:593 src/ui/gui/aggregate.ui:448
 msgid "Save"
 msgstr "Desar"
 
-#: src/ui/gui/psppire-data-window.c:639
+#: src/ui/gui/psppire-data-window.c:626
 msgid "Portable File"
 msgstr "Arxiu Portable"
 
-#: src/ui/gui/psppire-data-window.c:776
+#: src/ui/gui/psppire-data-window.c:759
 msgid "Font Selection"
 msgstr "Selecció de font"
 
-#: src/ui/gui/psppire-data-window.c:1264
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-data-window.c:1256
+msgid "PSPP-data"
+msgstr "datos-PSPP"
+
+#: src/ui/gui/psppire-data-window.c:1257
 msgid "Data Editor"
 msgstr "Editor de Dades"
 
-#: src/ui/gui/psppire-output-window.c:458
-msgid "Export Output"
-msgstr "Exporta Resultats"
-
-#: src/ui/gui/psppire-output-window.c:466
-msgid "PDF Files (*.pdf)"
-msgstr "Arxius PDF (*.pdf)"
+#. TRANSLATORS: This string must be a valid variable name.  That means:
+#. - The string must be at most 64 bytes (not characters) long.
+#. - The string may not contain whitespace.
+#. - The first character may not be '$'
+#. - The first character may not be a digit
+#. - The final charactor may not be '.' or '_'
+#.
+#: src/ui/gui/psppire-dict.c:367
+#, c-format
+msgid "VAR%05d"
+msgstr "VAR%05d"
 
 #: src/ui/gui/psppire-output-window.c:467
-msgid "HTML Files (*.html)"
-msgstr "Arxius HTML (*.html)"
+msgid "Infer file type from extension"
+msgstr "Inferir tipus d'arxiu a partir de l'extensió"
 
 #: src/ui/gui/psppire-output-window.c:468
-msgid "OpenDocument Files (*.odt)"
-msgstr "Arxius OpenDocument (*.odt)"
+msgid "PDF (*.pdf)"
+msgstr "PDF (*.pdf)"
 
 #: src/ui/gui/psppire-output-window.c:469
-msgid "Text Files (*.txt)"
-msgstr "Arxius de Text (*.txt)"
+msgid "HTML (*.html)"
+msgstr "HTML (*.html)"
 
 #: src/ui/gui/psppire-output-window.c:470
-msgid "PostScript Files (*.ps)"
-msgstr "Arxius PostScript (*.ps)"
+msgid "OpenDocument (*.odt)"
+msgstr "OpenDocument (*.odt)"
 
 #: src/ui/gui/psppire-output-window.c:471
-msgid "Comma-Separated Value Files (*.csv)"
-msgstr "Arxius de Valors Separats per Comes (*.csv)"
+msgid "Text (*.txt)"
+msgstr "Text (*.txt)"
+
+#: src/ui/gui/psppire-output-window.c:472
+msgid "PostScript (*.ps)"
+msgstr "PostScript (*.ps)"
+
+#: src/ui/gui/psppire-output-window.c:473
+msgid "Comma-Separated Values (*.csv)"
+msgstr "Valors Separats per Comes (*.csv)"
+
+#: src/ui/gui/psppire-output-window.c:574
+msgid "Export Output"
+msgstr "Exporta Resultats"
+
+#: src/ui/gui/psppire-output-window.c:828
+msgid "failed to create temporary directory"
+msgstr "error en crear el directori temporal"
+
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-output-window.c:1059
+msgid "Output"
+msgstr "Resultats"
 
-#: src/ui/gui/psppire-output-window.c:605
+#: src/ui/gui/psppire-output-window.c:1060
 msgid "Output Viewer"
 msgstr "Vista de resultats"
 
-#: src/ui/gui/psppire-syntax-window.c:265
+#: src/ui/gui/psppire-syntax-window.c:478
 #, c-format
-msgid "Saved file \"%s\""
-msgstr "Desat com a arxiu \"%s\""
+msgid "Saved file `%s'"
+msgstr "Desat com a arxiu `%s'"
 
-#: src/ui/gui/psppire-syntax-window.c:284
+#: src/ui/gui/psppire-syntax-window.c:497
 msgid "Save Syntax"
 msgstr "Desar sintaxi"
 
-#: src/ui/gui/psppire-syntax-window.c:496
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-syntax-window.c:746
+msgid "Syntax"
+msgstr "Sintaxi"
+
+#: src/ui/gui/psppire-syntax-window.c:747
 msgid "Syntax Editor"
 msgstr "Editor de sintaxi"
 
-#: src/ui/gui/psppire-syntax-window.c:510
+#: src/ui/gui/psppire-syntax-window.c:761
 #, c-format
-msgid "Cannot load syntax file '%s'"
-msgstr "No es pot obrir l'arxiu de sintaxi \"%s\""
+msgid "Cannot load syntax file `%s'"
+msgstr "No es pot obrir l'arxiu de sintaxi `%s'"
 
-#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:833
-#: src/language/stats/crosstabs.q:1288 src/ui/gui/psppire.ui:2055
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:834
+#: src/language/stats/crosstabs.q:1308 src/ui/gui/compute.ui:599
 msgid "Type"
 msgstr "Tipus:"
 
-#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:834
-#: src/ui/gui/psppire.ui:1974
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/compute.ui:517
 msgid "Width"
 msgstr "Ample"
 
-#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:836
 msgid "Decimals"
 msgstr "Decimals"
 
-#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:838
 msgid "Values"
 msgstr "Valores"
 
-#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:838
-#: src/language/stats/crosstabs.q:822 src/language/stats/examine.q:1104
-#: src/language/stats/frequencies.q:864 src/language/stats/frequencies.q:1036
+#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:839
+#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1103
+#: src/language/stats/frequencies.q:874 src/language/stats/frequencies.q:1045
 msgid "Missing"
 msgstr "Perduts"
 
-#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:840
+#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:841
 msgid "Align"
 msgstr "Aliniament"
 
-#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:841
+#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:842
 msgid "Measure"
 msgstr "Mesura"
 
-#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/var-sheet-dialogs.ui:43
+#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.ui:43
 msgid "Comma"
 msgstr "Coma"
 
-#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.ui:59
+#: src/ui/gui/psppire-var-store.c:624 src/ui/gui/var-sheet-dialogs.ui:59
 msgid "Dot"
 msgstr "Punt"
 
-#: src/ui/gui/psppire-var-store.c:624
+#: src/ui/gui/psppire-var-store.c:625
 msgid "Scientific"
 msgstr "Científic"
 
-#: src/ui/gui/psppire-var-store.c:625 src/ui/gui/var-sheet-dialogs.ui:91
+#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.ui:91
 msgid "Date"
 msgstr "Data"
 
-#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.ui:107
+#: src/ui/gui/psppire-var-store.c:627 src/ui/gui/var-sheet-dialogs.ui:107
 msgid "Dollar"
 msgstr "Dolar"
 
-#: src/ui/gui/psppire-var-store.c:627
+#: src/ui/gui/psppire-var-store.c:628
 msgid "Custom"
 msgstr "Usuari"
 
+#: src/ui/gui/psppire-var-store.c:756
+#, c-format
+msgid "{%s,`%s'}_"
+msgstr "{%s,`%s'}_"
+
 #: src/ui/gui/psppire-window.c:97
 #, c-format
 msgid "%s %s PSPPIRE %s"
 msgstr "%s %s PSPPIRE %s"
 
-#: src/ui/gui/psppire-window.c:468
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-window.c:247
+msgid "Untitled"
+msgstr "Sense titol"
+
+#: src/ui/gui/psppire-window.c:469
 #, c-format
-msgid "Save the changes to \"%s\" before closing?"
-msgstr "Desa el canvis a \"%s\" abans de sortir?"
+msgid "Save the changes to `%s' before closing?"
+msgstr "Desa el canvis a `%s' abans de sortir?"
 
-#: src/ui/gui/psppire-window.c:475
+#: src/ui/gui/psppire-window.c:476
 #, c-format
 msgid "If you don't save, changes from the last %ld seconds will be permanently lost."
 msgstr "Si no es desa, els canvis dels darrers %ld segons es perdran permanentment."
 
-#: src/ui/gui/psppire-window.c:479
+#: src/ui/gui/psppire-window.c:480
 msgid "Close _without saving"
 msgstr "Tancar sense desar"
 
-#: src/ui/gui/recode-dialog.c:911
+#: src/ui/gui/recode-dialog.c:886
 msgid "Recode into Different Variables"
 msgstr "Recodifica en variables Diferents"
 
-#: src/ui/gui/recode-dialog.c:914 src/ui/gui/recode.ui:692
+#: src/ui/gui/recode-dialog.c:889 src/ui/gui/recode.ui:692
 msgid "Recode into Same Variables"
 msgstr "Recodifica en les Mateixes variables"
 
-#: src/ui/gui/recode-dialog.c:929 src/ui/gui/recode-dialog.c:1025
+#: src/ui/gui/recode-dialog.c:903 src/ui/gui/recode-dialog.c:999
 msgid "New"
 msgstr "Nou"
 
-#: src/ui/gui/recode-dialog.c:944 src/ui/gui/recode-dialog.c:1017
+#: src/ui/gui/recode-dialog.c:918 src/ui/gui/recode-dialog.c:991
 msgid "Old"
 msgstr "Antic"
 
-#: src/ui/gui/recode-dialog.c:1274
+#: src/ui/gui/recode-dialog.c:1236
 msgid "Recode into Different Variables: Old and New Values "
 msgstr "Recodifica en variables Diferents: Antcs y Nous valors "
 
-#: src/ui/gui/recode-dialog.c:1275
+#: src/ui/gui/recode-dialog.c:1237
 msgid "Recode into Same Variables: Old and New Values"
 msgstr "Recodifica en les mateixes variables: Antics y Nous valors"
 
-#: src/ui/gui/regression-dialog.c:42
+#: src/ui/gui/regression-dialog.c:41
 msgid "Coeff"
 msgstr "Coef."
 
-#: src/ui/gui/regression-dialog.c:43 src/language/stats/regression.q:155
+#: src/ui/gui/regression-dialog.c:42 src/language/stats/regression.q:157
 msgid "R"
 msgstr "R"
 
-#: src/ui/gui/regression-dialog.c:44
+#: src/ui/gui/regression-dialog.c:43
 msgid "Anova"
 msgstr "Anova"
 
-#: src/ui/gui/regression-dialog.c:45
+#: src/ui/gui/regression-dialog.c:44
 msgid "Bcov"
 msgstr "Bcov"
 
-#: src/ui/gui/select-cases-dialog.c:82
+#: src/ui/gui/select-cases-dialog.c:81
 #, c-format
 msgid "Approximately %3d%% of all cases."
 msgstr "Aproximadament %3d%% de tots els casos."
 
-#: src/ui/gui/select-cases-dialog.c:83
+#: src/ui/gui/select-cases-dialog.c:82
 #, c-format
 msgid "Exactly %3d cases from the first %3d cases."
 msgstr "Exactament %3d casos dels primers  %3d casos."
 
-#: src/ui/gui/select-cases-dialog.c:223
+#: src/ui/gui/select-cases-dialog.c:221
 #, c-format
 msgid "%d thru %d"
 msgstr "%d fisn a %d"
 
-#: src/ui/gui/text-data-import-dialog.c:461
+#: src/ui/gui/text-data-import-dialog.c:452
 #, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "No es pot obrir \"%s\": %s"
+msgid "Could not open `%s': %s"
+msgstr "No es pot obrir `%s': %s"
 
-#: src/ui/gui/text-data-import-dialog.c:477
+#: src/ui/gui/text-data-import-dialog.c:468
 #, c-format
-msgid "Error reading \"%s\": %s"
-msgstr "Error leyendo \"%s\": %s"
+msgid "Error reading `%s': %s"
+msgstr "Error leyendo `%s': %s"
 
-#: src/ui/gui/text-data-import-dialog.c:480
+#: src/ui/gui/text-data-import-dialog.c:471
 #, c-format
-msgid "Failed to read \"%s\", because it contains a line over %d bytes long and therefore appears not to be a text file."
-msgstr "Error en llegir \"%s\", perquè conté una linia per sobre dels %d bytes i per tant sembla que no es un arxiu de text."
+msgid "Failed to read `%s', because it contains a line over %d bytes long and therefore appears not to be a text file."
+msgstr "Error en llegir `%s', per què conté una linia per sobre dels %d bytes de llarg i, per tant, sembla que no és un arxiu de text."
 
-#: src/ui/gui/text-data-import-dialog.c:494
+#: src/ui/gui/text-data-import-dialog.c:485
 #, c-format
-msgid "\"%s\" is empty."
-msgstr "\"%s\" és buit."
+msgid "`%s' is empty."
+msgstr "`%s' és buit."
 
-#: src/ui/gui/text-data-import-dialog.c:539
+#: src/ui/gui/text-data-import-dialog.c:530
 msgid "Import Delimited Text Data"
 msgstr "Importar dades de text delimitat"
 
-#: src/ui/gui/text-data-import-dialog.c:590
+#: src/ui/gui/text-data-import-dialog.c:581
 msgid "Importing Delimited Text Data"
 msgstr "Important dades de text deliminatat"
 
-#: src/ui/gui/text-data-import-dialog.c:749
+#: src/ui/gui/text-data-import-dialog.c:730
+#, c-format
+msgid "Only the first %4d cases"
+msgstr "Només els primers %4d casos"
+
+#: src/ui/gui/text-data-import-dialog.c:740
+#, c-format
+msgid "Only the first %3d %% of file (approximately)"
+msgstr "Només els primers %3ds %% de l'arxiu (aproximadament)"
+
+#: src/ui/gui/text-data-import-dialog.c:765
 msgid ""
 "This assistant will guide you through the process of importing data into PSPP from a text file with one line per case,  in which fields are separated by tabs, commas, or other delimiters.\n"
 "\n"
@@ -4153,46 +4671,59 @@ msgstr ""
 "Aquest asistent t'acompanyarà per tot el procés d'importar dades cap al PSPP a partir d'un arxiu de text amb una linia per cas,  al qual els camps estan separats per tabuladors, comes, o altres delimitadors.\n"
 "\n"
 
-#: src/ui/gui/text-data-import-dialog.c:755
+#: src/ui/gui/text-data-import-dialog.c:771
 #, c-format
 msgid "The selected file contains %zu line of text.  "
 msgid_plural "The selected file contains %zu lines of text.  "
 msgstr[0] "L'arxiu seleccionat conté %zu linies de text.  "
 msgstr[1] "L'arxiu seleccionat conté %zu linies de text.  "
 
-#: src/ui/gui/text-data-import-dialog.c:763
+#: src/ui/gui/text-data-import-dialog.c:779
 #, c-format
 msgid "The selected file contains approximately %lu line of text.  "
 msgid_plural "The selected file contains approximately %lu lines of text.  "
 msgstr[0] "L'arxiu seleccionat conté aproximadament %lu linia de text.  "
 msgstr[1] "L'arxiu seleccionat conté aproximadament %lu linies de text.  "
 
-#: src/ui/gui/text-data-import-dialog.c:769
+#: src/ui/gui/text-data-import-dialog.c:785
 #, c-format
 msgid "Only the first %zu line of the file will be shown for preview purposes in the following screens.  "
 msgid_plural "Only the first %zu lines of the file will be shown for preview purposes in the following screens.  "
 msgstr[0] "Només les primeres %zu linies de l'arxiu es previsualitzaran a les seguents pantalles.  "
 msgstr[1] "Només les primeres %zu linies de l'arxiu es previsualitzaran a les seguents pantalles.  "
 
-#: src/ui/gui/text-data-import-dialog.c:776
+#: src/ui/gui/text-data-import-dialog.c:792
 msgid "You may choose below how much of the file should actually be imported."
 msgstr "Pots triar a continuació quina part de l'arxiu ha de ser importat."
 
-#: src/ui/gui/text-data-import-dialog.c:1523
-#: src/ui/gui/text-data-import-dialog.c:1768
+#: src/ui/gui/text-data-import-dialog.c:875
+msgid "Text"
+msgstr "Text"
+
+#: src/ui/gui/text-data-import-dialog.c:1539
+#: src/ui/gui/text-data-import-dialog.c:1785
 msgid "This input line has too few separators to fill in this field."
 msgstr "Aquesta linia d'entrada no en te prou separadors per emplenar el camp"
 
-#: src/ui/gui/text-data-import-dialog.c:1759
+#: src/ui/gui/text-data-import-dialog.c:1776
 #, c-format
-msgid "Field content \"%.*s\" cannot be parsed in format %s."
-msgstr "El contingut del camp \"%.*s\" no pot ser analitzat en format %s."
+msgid "Cannot parse field content `%.*s' as format %s: %s"
+msgstr "No es possible construïr l'arxiu de contingut `%.*s' com a format %s: %s"
+
+#: src/ui/gui/text-data-import-dialog.c:1929
+msgid "Line"
+msgstr "Linia"
 
 #: src/ui/gui/t-test-options.c:60
 #, c-format
 msgid "Confidence Interval: %2d %%"
 msgstr "Interval de Confiança: %2d %%"
 
+#: src/ui/gui/val-labs-dialog.c:515
+#, c-format
+msgid "%s = `%s'"
+msgstr "%s = `%s'"
+
 #: src/ui/gui/variable-info-dialog.c:77
 #, c-format
 msgid "Label: %s\n"
@@ -4222,428 +4753,434 @@ msgstr "Etiqueteas de valor:\n"
 msgid "%s %s\n"
 msgstr "%s %s\n"
 
-#: src/ui/gui/weight-cases-dialog.c:81 src/ui/gui/psppire.ui:52
+#: src/ui/gui/weight-cases-dialog.c:80 src/ui/gui/psppire.ui:52
 #: src/ui/gui/psppire.ui:155
 msgid "Do not weight cases"
 msgstr "No ponderar casos."
 
-#: src/ui/gui/weight-cases-dialog.c:87
+#: src/ui/gui/weight-cases-dialog.c:86
 #, c-format
 msgid "Weight cases by %s"
 msgstr "Pondera casos per %s"
 
-#: tests/dissect-sysfile.c:571
+#: tests/dissect-sysfile.c:572
 #, c-format
 msgid "Unrecognized record type 7, subtype %d."
 msgstr "Tipus de registre 7 no reconegut, subtipe %d."
 
-#: tests/dissect-sysfile.c:850
+#: tests/dissect-sysfile.c:595
+#, c-format
+msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
+msgstr "Camp de longitud (%zu) o quantitat (%zu) invàlids en el registre tipus 7, subtipus 3."
+
+#: tests/dissect-sysfile.c:626
+#, c-format
+msgid "Bad size (%zu) or count (%zu) on extension 4."
+msgstr "Longitud (%zu) o quantitat (%zu) de l'extensió 4 no vàlid."
+
+#: tests/dissect-sysfile.c:692
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record"
+msgstr "Espai perdut darrera `%c' a la posició %zu al registre MRSETS"
+
+#: tests/dissect-sysfile.c:701
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record"
+msgstr "Valor d'etiqueta no esperat `%s' darrera `E' a la posició %zu del registre MRSETS"
+
+#: tests/dissect-sysfile.c:759
+#, c-format
+msgid "Bad size %zu on extension 11."
+msgstr "Amplada no vàlida %zu en l'extensió 11."
+
+#: tests/dissect-sysfile.c:851
 #, c-format
 msgid "%s: Error parsing attribute value %s[%d]"
 msgstr "%s: Error en analitzar valor de l'atribut %s[%d]"
 
-#: tests/dissect-sysfile.c:856
+#: tests/dissect-sysfile.c:857
 #, c-format
 msgid "%s: Attribute value %s[%d] is not quoted: %s"
 msgstr "%s: El valor de l'atribut %s[%d] no esta entre cometes: %s"
 
-#: tests/dissect-sysfile.c:880
+#: tests/dissect-sysfile.c:881
 #, c-format
 msgid "Bad size %zu for extended number of cases."
 msgstr "Longitud no vàlid %zu per nombre extens de casos."
 
-#: tests/dissect-sysfile.c:886
+#: tests/dissect-sysfile.c:887
 #, c-format
 msgid "Bad count %zu for extended number of cases."
 msgstr "Recompte incorrecte %zu per nombre extens de casos."
 
-#: src/language/utilities/set.q:188
+#: tests/dissect-sysfile.c:937
+#, c-format
+msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
+msgstr "La longitud del nom de la variable al registre de l'etiqueta del valor de cadena llarga (%d) supera el límit %d-byte."
+
+#: src/language/utilities/set.q:171
 msgid "WORKSPACE must be at least 1MB"
 msgstr "WORKSPACE ha de ser com a mínim 1 Mb"
 
-#: src/language/utilities/set.q:194 src/language/utilities/set.q:196
-#: src/language/utilities/set.q:198 src/language/utilities/set.q:200
-#: src/language/utilities/set.q:202 src/language/utilities/set.q:204
-#: src/language/utilities/set.q:206 src/language/utilities/set.q:208
-#: src/language/utilities/set.q:210
+#: src/language/utilities/set.q:177 src/language/utilities/set.q:179
+#: src/language/utilities/set.q:181 src/language/utilities/set.q:183
+#: src/language/utilities/set.q:185 src/language/utilities/set.q:187
+#: src/language/utilities/set.q:189 src/language/utilities/set.q:191
+#: src/language/utilities/set.q:193
 #, c-format
 msgid "%s is obsolete."
 msgstr "%s és obsolet."
 
-#: src/language/utilities/set.q:216
+#: src/language/utilities/set.q:199
 msgid "Active file compression is not implemented."
 msgstr "La compressió d'arxius no està implementada."
 
-#: src/language/utilities/set.q:334
+#: src/language/utilities/set.q:317
 msgid "EPOCH must be 1500 or later."
 msgstr "EPOCH ha de ser 1500 o més tard."
 
-#: src/language/utilities/set.q:341
+#: src/language/utilities/set.q:324
 msgid "expecting AUTOMATIC or year"
 msgstr "esperant AUTOMATICA o any"
 
-#: src/language/utilities/set.q:369
+#: src/language/utilities/set.q:352
 msgid "LENGTH must be at least 1."
 msgstr "LENGTH ha de ser com a mínim 1."
 
-#: src/language/utilities/set.q:405
+#: src/language/utilities/set.q:388
 #, c-format
-msgid "%s is not a recognised encoding or locale name"
+msgid "%s is not a recognized encoding or locale name"
 msgstr "%s no és una codificació o un nom local reconegut"
 
-#: src/language/utilities/set.q:467
+#: src/language/utilities/set.q:449
 msgid "WIDTH must be at least 40."
 msgstr "WIDTH ha de ser com a mínim 40."
 
-#: src/language/utilities/set.q:490
+#: src/language/utilities/set.q:476
 #, c-format
 msgid "FORMAT requires numeric output format as an argument.  Specified format %s is of type string."
 msgstr "FORMAT requereix format de resultat numeric com a argument.  El format %s especificat es de tipus cadena."
 
-#: src/language/utilities/set.q:707
+#: src/language/utilities/set.q:690
 msgid "ISL (32-bit IEEE 754 single, little-endian)"
 msgstr "ISL (32-bit IEEE 754 single, little-endian)"
 
-#: src/language/utilities/set.q:710
+#: src/language/utilities/set.q:693
 msgid "ISB (32-bit IEEE 754 single, big-endian)"
 msgstr "ISB (32-bit IEEE 754 single, big-endian)"
 
-#: src/language/utilities/set.q:713
+#: src/language/utilities/set.q:696
 msgid "IDL (64-bit IEEE 754 double, little-endian)"
 msgstr "IDL (64-bit IEEE 754 double, little-endian)"
 
-#: src/language/utilities/set.q:716
+#: src/language/utilities/set.q:699
 msgid "IDB (64-bit IEEE 754 double, big-endian)"
 msgstr "IDB (64-bit IEEE 754 double, big-endian)"
 
-#: src/language/utilities/set.q:720
+#: src/language/utilities/set.q:703
 msgid "VF (32-bit VAX F, VAX-endian)"
 msgstr "VF (32-bit VAX F, VAX-endian)"
 
-#: src/language/utilities/set.q:723
+#: src/language/utilities/set.q:706
 msgid "VD (64-bit VAX D, VAX-endian)"
 msgstr "VD (64-bit VAX D, VAX-endian)"
 
-#: src/language/utilities/set.q:726
+#: src/language/utilities/set.q:709
 msgid "VG (64-bit VAX G, VAX-endian)"
 msgstr "VG (64-bit VAX G, VAX-endian)"
 
-#: src/language/utilities/set.q:730
+#: src/language/utilities/set.q:713
 msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 msgstr "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 
-#: src/language/utilities/set.q:733
+#: src/language/utilities/set.q:716
 msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 msgstr "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 
-#: src/language/utilities/set.q:835
+#: src/language/utilities/set.q:817
 #, c-format
 msgid "%s is %s."
 msgstr "%s és %s."
 
-#: src/language/stats/crosstabs.q:289
+#: src/language/utilities/set.q:920
+#, c-format
+msgid "Too many PRESERVE commands without a RESTORE: at most %d levels of saved settings are allowed."
+msgstr "Massa comandos PRESERVE sense un RESTORE: es permet, com a màxim, %d nivells de configuracions desades."
+
+#: src/language/utilities/set.q:939
+msgid "RESTORE without matching PRESERVE."
+msgstr "RESTORE sense el corresponent PRESERVE."
+
+#: src/language/stats/crosstabs.q:295
 msgid "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
 msgstr "L'INFORME de perduts no esta disponible el mode general.  S'assumeix MISSING=TABLE."
 
-#: src/language/stats/crosstabs.q:399
+#: src/language/stats/crosstabs.q:405
 msgid "Too many cross-tabulation variables or dimensions."
 msgstr "Massa variables o dimensions per a l'encreuament tabulat."
 
-#: src/language/stats/crosstabs.q:409
-msgid "expecting BY"
-msgstr "esperant BY"
-
-#: src/language/stats/crosstabs.q:466
+#: src/language/stats/crosstabs.q:472
 msgid "VARIABLES must be specified before TABLES."
 msgstr "Les VARIABLES han de ser especificades abans de TABLES."
 
-#: src/language/stats/crosstabs.q:504
+#: src/language/stats/crosstabs.q:506
 #, c-format
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr "El valor màxim (%ld) en menor que el valor mínim (%ld)."
 
-#: src/language/stats/crosstabs.q:818
+#: src/language/stats/crosstabs.q:827
 msgid "Summary."
 msgstr "Resum."
 
-#: src/language/stats/crosstabs.q:820 src/language/stats/examine.q:1164
-#: src/language/stats/reliability.q:693
-msgid "Cases"
-msgstr "Casos"
-
-#: src/language/stats/crosstabs.q:821 src/language/stats/examine.q:1103
-#: src/language/stats/frequencies.q:1035 src/language/stats/reliability.q:696
-msgid "Valid"
-msgstr "Vàlid"
-
-#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1179
-#: src/language/stats/frequencies.q:815
+#: src/language/stats/crosstabs.q:840 src/language/stats/examine.q:1178
+#: src/language/stats/frequencies.q:825
 msgid "Percent"
 msgstr "Percentatge"
 
-#: src/language/stats/crosstabs.q:1109
+#. TRANSLATORS: The %s here describes a crosstabulation.  It takes the
+#. form "var1 * var2 * var3 * ...".
+#: src/language/stats/crosstabs.q:936
+#, c-format
+msgid "Crosstabulation %s contained no non-missing cases."
+msgstr "La taula de contingencia %s no conté cap cas no-perdut."
+
+#: src/language/stats/crosstabs.q:1134
 msgid "count"
 msgstr "recompte"
 
-#: src/language/stats/crosstabs.q:1110
+#: src/language/stats/crosstabs.q:1135
 msgid "row %"
 msgstr "fila %"
 
-#: src/language/stats/crosstabs.q:1111
+#: src/language/stats/crosstabs.q:1136
 msgid "column %"
 msgstr "columna %"
 
-#: src/language/stats/crosstabs.q:1112
+#: src/language/stats/crosstabs.q:1137
 msgid "total %"
 msgstr "total %"
 
-#: src/language/stats/crosstabs.q:1113
+#: src/language/stats/crosstabs.q:1138
 msgid "expected"
 msgstr "esperat"
 
-#: src/language/stats/crosstabs.q:1114
+#: src/language/stats/crosstabs.q:1139
 msgid "residual"
 msgstr "residual"
 
-#: src/language/stats/crosstabs.q:1115
+#: src/language/stats/crosstabs.q:1140
 msgid "std. resid."
 msgstr "residu tipificat"
 
-#: src/language/stats/crosstabs.q:1116
+#: src/language/stats/crosstabs.q:1141
 msgid "adj. resid."
 msgstr "resid.ajust."
 
-#: src/language/stats/crosstabs.q:1210
+#: src/language/stats/crosstabs.q:1230
 msgid "Chi-square tests."
 msgstr "Proves Chi-quadrat."
 
-#: src/language/stats/crosstabs.q:1217
-msgid "Asymp. Sig. (2-sided)"
-msgstr "Sig. Asimp. (2-cues)"
-
-#: src/language/stats/crosstabs.q:1219
-msgid "Exact Sig. (2-sided)"
-msgstr "Sig. Exacta (2-cues)"
-
-#: src/language/stats/crosstabs.q:1221
-msgid "Exact Sig. (1-sided)"
-msgstr "Sig. Exacta (1-cua)"
-
-#: src/language/stats/crosstabs.q:1236
+#: src/language/stats/crosstabs.q:1256
 msgid "Symmetric measures."
 msgstr "Mesures simètriques."
 
-#: src/language/stats/crosstabs.q:1242 src/language/stats/crosstabs.q:1290
+#: src/language/stats/crosstabs.q:1262 src/language/stats/crosstabs.q:1310
 msgid "Asymp. Std. Error"
 msgstr "Error Est. Asimp."
 
-#: src/language/stats/crosstabs.q:1243 src/language/stats/crosstabs.q:1291
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1311
 msgid "Approx. T"
 msgstr "Aprox. T"
 
-#: src/language/stats/crosstabs.q:1244 src/language/stats/crosstabs.q:1292
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1312
 msgid "Approx. Sig."
 msgstr "Sig. Aproxim."
 
-#: src/language/stats/crosstabs.q:1258
+#: src/language/stats/crosstabs.q:1278
 msgid "Risk estimate."
 msgstr "Estimador de Risc."
 
-#: src/language/stats/crosstabs.q:1262
+#: src/language/stats/crosstabs.q:1282
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr "Interval de Confiança del 95%%"
 
-#: src/language/stats/crosstabs.q:1265 src/language/stats/t-test.q:756
-#: src/language/stats/t-test.q:920 src/language/stats/t-test.q:1013
+#: src/language/stats/crosstabs.q:1285 src/language/stats/t-test.q:760
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1017
 msgid "Lower"
 msgstr "Inferior"
 
-#: src/language/stats/crosstabs.q:1266 src/language/stats/t-test.q:757
-#: src/language/stats/t-test.q:921 src/language/stats/t-test.q:1014
+#: src/language/stats/crosstabs.q:1286 src/language/stats/t-test.q:761
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1018
 msgid "Upper"
 msgstr "Superior"
 
-#: src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1303
 msgid "Directional measures."
 msgstr "Mesures direccionals."
 
-#: src/language/stats/crosstabs.q:1708
+#: src/language/stats/crosstabs.q:1740
 msgid "Pearson Chi-Square"
 msgstr "Chi-quadrat de Pearson"
 
-#: src/language/stats/crosstabs.q:1709
+#: src/language/stats/crosstabs.q:1741
 msgid "Likelihood Ratio"
 msgstr "Raó de Similitut"
 
-#: src/language/stats/crosstabs.q:1710
+#: src/language/stats/crosstabs.q:1742
 msgid "Fisher's Exact Test"
 msgstr "Prova exacta de Fisher"
 
-#: src/language/stats/crosstabs.q:1711
+#: src/language/stats/crosstabs.q:1743
 msgid "Continuity Correction"
 msgstr "Correcció per continuitat"
 
-#: src/language/stats/crosstabs.q:1712
+#: src/language/stats/crosstabs.q:1744
 msgid "Linear-by-Linear Association"
 msgstr "Asociació linear per linear"
 
-#: src/language/stats/crosstabs.q:1747 src/language/stats/crosstabs.q:1822
-#: src/language/stats/crosstabs.q:1887
+#: src/language/stats/crosstabs.q:1779 src/language/stats/crosstabs.q:1854
+#: src/language/stats/crosstabs.q:1919
 msgid "N of Valid Cases"
 msgstr "N de casos vàlids"
 
-#: src/language/stats/crosstabs.q:1766 src/language/stats/crosstabs.q:1905
+#: src/language/stats/crosstabs.q:1798 src/language/stats/crosstabs.q:1937
 msgid "Nominal by Nominal"
 msgstr "Nominal segons Nominal"
 
-#: src/language/stats/crosstabs.q:1767 src/language/stats/crosstabs.q:1906
+#: src/language/stats/crosstabs.q:1799 src/language/stats/crosstabs.q:1938
 msgid "Ordinal by Ordinal"
 msgstr "Ordinal segons Ordinal"
 
-#: src/language/stats/crosstabs.q:1768
+#: src/language/stats/crosstabs.q:1800
 msgid "Interval by Interval"
 msgstr "Interval segons Interval"
 
-#: src/language/stats/crosstabs.q:1769
+#: src/language/stats/crosstabs.q:1801
 msgid "Measure of Agreement"
 msgstr "Mesura d'Acord"
 
-#: src/language/stats/crosstabs.q:1775
+#: src/language/stats/crosstabs.q:1807
 msgid "Cramer's V"
 msgstr "V de Cramer"
 
-#: src/language/stats/crosstabs.q:1776
+#: src/language/stats/crosstabs.q:1808
 msgid "Contingency Coefficient"
 msgstr "Coeficient de Contingencia"
 
-#: src/language/stats/crosstabs.q:1777
+#: src/language/stats/crosstabs.q:1809
 msgid "Kendall's tau-b"
 msgstr "Tau-B de Kendall"
 
-#: src/language/stats/crosstabs.q:1778
+#: src/language/stats/crosstabs.q:1810
 msgid "Kendall's tau-c"
 msgstr "Tau-C de Kendall"
 
-#: src/language/stats/crosstabs.q:1780
+#: src/language/stats/crosstabs.q:1812
 msgid "Spearman Correlation"
 msgstr "Correlació de Spearman"
 
-#: src/language/stats/crosstabs.q:1781
+#: src/language/stats/crosstabs.q:1813
 msgid "Pearson's R"
 msgstr "R de Pearson"
 
-#: src/language/stats/crosstabs.q:1860
+#: src/language/stats/crosstabs.q:1892
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
 msgstr "Raó de diferencies per a %s (%g / %g)"
 
-#: src/language/stats/crosstabs.q:1863
+#: src/language/stats/crosstabs.q:1895
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
 msgstr "Raó de diferències per a  %s (%.*s / %.*s)"
 
-#: src/language/stats/crosstabs.q:1871
+#: src/language/stats/crosstabs.q:1903
 #, c-format
 msgid "For cohort %s = %g"
 msgstr "Per cohort %s = %g"
 
-#: src/language/stats/crosstabs.q:1874
+#: src/language/stats/crosstabs.q:1906
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr "Per cohort %s = %.*s"
 
-#: src/language/stats/crosstabs.q:1907
+#: src/language/stats/crosstabs.q:1939
 msgid "Nominal by Interval"
 msgstr "Nominal segons Interval"
 
-#: src/language/stats/crosstabs.q:1913
+#: src/language/stats/crosstabs.q:1945
 msgid "Goodman and Kruskal tau"
 msgstr "Tau de Kruskal i Goodman"
 
-#: src/language/stats/crosstabs.q:1914
+#: src/language/stats/crosstabs.q:1946
 msgid "Uncertainty Coefficient"
 msgstr "Coeficient d'Incertessa"
 
-#: src/language/stats/crosstabs.q:1915
+#: src/language/stats/crosstabs.q:1947
 msgid "Somers' d"
 msgstr "D de Somers"
 
-#: src/language/stats/crosstabs.q:1921
+#: src/language/stats/crosstabs.q:1953
 msgid "Symmetric"
 msgstr "Simètric"
 
-#: src/language/stats/crosstabs.q:1922 src/language/stats/crosstabs.q:1923
+#: src/language/stats/crosstabs.q:1954 src/language/stats/crosstabs.q:1955
 #, c-format
 msgid "%s Dependent"
 msgstr "%s Dependent"
 
-#: src/language/stats/examine.q:357
+#: src/language/stats/examine.q:355
 msgid "Not creating NP plot because data set is empty."
 msgstr "No es crearà el gràfic NP perquè el conjunt de dades es buit."
 
-#: src/language/stats/examine.q:442 src/language/stats/examine.q:949
+#: src/language/stats/examine.q:441 src/language/stats/examine.q:948
 msgid "Not creating plot because data set is empty."
 msgstr "No es crea el gràfic perquè el conjunt de dades es buit."
 
-#: src/language/stats/examine.q:454
+#: src/language/stats/examine.q:453
 #, c-format
 msgid "Boxplot of %s vs. %s"
 msgstr "Diagrama de caixa de %s vs. %s"
 
-#: src/language/stats/examine.q:458
+#: src/language/stats/examine.q:457
 #, c-format
 msgid "Boxplot of %s"
 msgstr "Diagrama de caixa de %s"
 
-#: src/language/stats/examine.q:647 src/language/stats/examine.q:660
+#: src/language/stats/examine.q:646 src/language/stats/examine.q:659
 #, c-format
 msgid "%s and %s are mutually exclusive"
 msgstr "%s i %s son mutuament excloents"
 
-#: src/language/stats/examine.q:1159 src/language/stats/reliability.q:670
-msgid "Case Processing Summary"
-msgstr "Resum de processament del Casos"
-
-#: src/language/stats/examine.q:1449 src/language/stats/oneway.q:394
-#, c-format
-msgid "%g%% Confidence Interval for Mean"
-msgstr "Interval de Confiança de Miitjana %g%%"
-
-#: src/language/stats/examine.q:1464
+#: src/language/stats/examine.q:1463
 msgid "5% Trimmed Mean"
 msgstr "Mitjana retallada al 5%"
 
-#: src/language/stats/examine.q:1499
+#: src/language/stats/examine.q:1498
 msgid "Interquartile Range"
 msgstr "Interval inter-quartilic"
 
-#: src/language/stats/examine.q:1635 src/language/stats/oneway.q:404
-#: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
-msgid "Descriptives"
-msgstr "Descriptives"
-
-#: src/language/stats/examine.q:1821
+#: src/language/stats/examine.q:1820
 msgid "Highest"
 msgstr "Superior"
 
-#: src/language/stats/examine.q:1826
+#: src/language/stats/examine.q:1825
 msgid "Lowest"
 msgstr "Inferior"
 
-#: src/language/stats/examine.q:1833
+#: src/language/stats/examine.q:1832
 msgid "Extreme Values"
 msgstr "Valor extrems"
 
-#: src/language/stats/examine.q:1837 src/language/data-io/list.q:158
+#: src/language/stats/examine.q:1836 src/language/data-io/list.q:157
 msgid "Case Number"
 msgstr "Número de Cas"
 
-#: src/language/stats/examine.q:1957
+#: src/language/stats/examine.q:1956
 msgid "Tukey's Hinges"
 msgstr "Bisagras de Tukey"
 
-#: src/language/stats/examine.q:2003
+#: src/language/stats/examine.q:2002
 #, c-format
 msgid "%g"
 msgstr "%g"
@@ -4662,171 +5199,50 @@ msgstr "Per l'histograma, MAX ha de ser major o igual a MIN, però MIN s'ha espe
 msgid "MAX for pie chart must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
 msgstr "Per grafica de sectors, MAX ha de ser major o igual a MIN, però MIN s'ha especificat com a %.15g i MAX com a %.15g.  MIN i MAX seràn ignorats."
 
-#: src/language/stats/frequencies.q:703
+#: src/language/stats/frequencies.q:704
 msgid "`)' expected after GROUPED interval list."
 msgstr "`)' esperat després de la llista de variables GRUPED."
 
-#: src/language/stats/frequencies.q:723
-#, c-format
-msgid "Variables %s specified multiple times on GROUPED subcommand."
-msgstr "La variable %s s'ha especificat més d'una vegada a l'ordre GROUPED."
-
-#: src/language/stats/frequencies.q:733
-#, c-format
-msgid "Variables %s specified on GROUPED but not on VARIABLES."
-msgstr "Variables %s especificades a GROUPED però no a VARIABLES."
-
-#: src/language/stats/frequencies.q:812
-msgid "Value Label"
-msgstr "Etiqueta de Valor"
-
-#: src/language/stats/frequencies.q:816
-msgid "Valid Percent"
-msgstr "Percentatge Vàlid"
-
-#: src/language/stats/frequencies.q:817
-msgid "Cum Percent"
-msgstr "Percentatge Acumulat"
-
-#: src/language/stats/frequencies.q:1008
-#, c-format
-msgid "No valid data for variable %s; statistics not displayed."
-msgstr "No hi ha dades vàlides per a la variable %s; not es mostren estadístiques."
-
-#: src/language/stats/frequencies.q:1054
-msgid "50 (Median)"
-msgstr "50 (Mediana)"
-
-#: src/language/stats/frequencies.q:1209
-#, c-format
-msgid "Omitting pie chart for %s, which has only %d unique values."
-msgstr "S'omet grafic de sectors per a %s, que només té %d valors únics. "
-
-#: src/language/stats/frequencies.q:1212
-#, c-format
-msgid "Omitting pie chart for %s, which has over 50 unique values."
-msgstr "S'omet grafic de sectors per a %s, que té més de 50 valors únics. "
-
-#: src/language/stats/glm.q:247
-msgid "Multivariate GLM not yet supported"
-msgstr "GLM multivariable encara no disponible"
-
-#: src/language/stats/means.q:100
-msgid "Missing required subcommand TABLES."
-msgstr "Falta subordre requerida TABLES"
-
-#: src/language/stats/means.q:134
-msgid "TABLES subcommand may not appear more than once."
-msgstr "El subcomando TABLES no pot apareixer més d'una vegada."
-
-#: src/language/stats/npar.q:111
-msgid "NPAR subcommand not currently implemented."
-msgstr "Actualment no está implenetat el subcomandament NPAR."
-
-#: src/language/stats/npar.q:256
-#, c-format
-msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
-msgstr "El valor especificatper a HI (%d) és menor que l'especificat per a LO (%d)"
-
-#: src/language/stats/npar.q:311
-#, c-format
-msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
-msgstr "S'han proporcionat %d valors esperats, però l'interval especificat (%d-%d) requereix exactament %d valors."
-
-#: src/language/stats/npar.q:453 src/language/stats/t-test.q:380
-#, c-format
-msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
-msgstr "S'ha especificat PAIRED però el nombre de variables abans de WITH (%zu) not conicideixen amb en nombre de variables seguents (%zu)."
-
-#: src/language/stats/oneway.q:170
-msgid "Number of contrast coefficients must equal the number of groups"
-msgstr "El nombre de coeficients de contrast ha de ser igual al nombre de grups."
-
-#: src/language/stats/oneway.q:179
-#, c-format
-msgid "Coefficients for contrast %zu do not total zero"
-msgstr "Els coeficients per contrastar %zu no sumen cero."
-
-#: src/language/stats/oneway.q:242
-#, c-format
-msgid "`%s' is not a variable name"
-msgstr "`%s' no és un nom de variable"
-
-#: src/language/stats/oneway.q:274 src/language/stats/regression.q:283
-msgid "Sum of Squares"
-msgstr "Suma de Quadrats"
-
-#: src/language/stats/oneway.q:276 src/language/stats/regression.q:285
-msgid "Mean Square"
-msgstr "Rang mitjà"
-
-#: src/language/stats/oneway.q:277 src/language/stats/regression.q:286
-#: src/language/stats/t-test.q:749
-msgid "F"
-msgstr "F"
-
-#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:535
-#: src/language/stats/regression.q:201 src/language/stats/regression.q:287
-msgid "Significance"
-msgstr "Significativitat"
-
-#: src/language/stats/oneway.q:300
-msgid "Between Groups"
-msgstr "Entre Grups"
-
-#: src/language/stats/oneway.q:301
-msgid "Within Groups"
-msgstr "Intra Grups"
-
-#: src/language/stats/oneway.q:345 src/language/stats/regression.q:312
-msgid "ANOVA"
-msgstr "ANOVA"
-
-#: src/language/stats/oneway.q:532
-msgid "Levene Statistic"
-msgstr "Estatístic de Levene"
-
-#: src/language/stats/oneway.q:533
-msgid "df1"
-msgstr "df1"
-
-#: src/language/stats/oneway.q:534
-msgid "df2"
-msgstr "df2"
+#: src/language/stats/frequencies.q:724
+#, c-format
+msgid "Variables %s specified multiple times on GROUPED subcommand."
+msgstr "La variable %s s'ha especificat més d'una vegada a l'ordre GROUPED."
 
-#: src/language/stats/oneway.q:537
-msgid "Test of Homogeneity of Variances"
-msgstr "Prova de Homogeneitat de variances"
+#: src/language/stats/frequencies.q:734
+#, c-format
+msgid "Variables %s specified on GROUPED but not on VARIABLES."
+msgstr "Variables %s especificades a GROUPED però no a VARIABLES."
 
-#: src/language/stats/oneway.q:603
-msgid "Contrast Coefficients"
-msgstr "Coeficinents de Contrast"
+#: src/language/stats/frequencies.q:822
+msgid "Value Label"
+msgstr "Etiqueta de Valor"
 
-#: src/language/stats/oneway.q:605 src/language/stats/oneway.q:681
-msgid "Contrast"
-msgstr "Contrast"
+#: src/language/stats/frequencies.q:826
+msgid "Valid Percent"
+msgstr "Percentatge Vàlid"
 
-#: src/language/stats/oneway.q:679
-msgid "Contrast Tests"
-msgstr "Proves de contrats"
+#: src/language/stats/frequencies.q:827
+msgid "Cum Percent"
+msgstr "Percentatge Acumulat"
 
-#: src/language/stats/oneway.q:682
-msgid "Value of Contrast"
-msgstr "Valor de constrast"
+#: src/language/stats/frequencies.q:1017
+#, c-format
+msgid "No valid data for variable %s; statistics not displayed."
+msgstr "No hi ha dades vàlides per a la variable %s; not es mostren estadístiques."
 
-#: src/language/stats/oneway.q:684 src/language/stats/regression.q:200
-#: src/language/stats/t-test.q:751 src/language/stats/t-test.q:922
-#: src/language/stats/t-test.q:1009
-msgid "t"
-msgstr "t"
+#: src/language/stats/frequencies.q:1063
+msgid "50 (Median)"
+msgstr "50 (Mediana)"
 
-#: src/language/stats/oneway.q:730
-msgid "Assume equal variances"
-msgstr "S'assumeix igualtat de variances"
+#: src/language/stats/frequencies.q:1218
+#, c-format
+msgid "Omitting pie chart for %s, which has only %d unique values."
+msgstr "S'omet grafic de sectors per a %s, que només té %d valors únics. "
 
-#: src/language/stats/oneway.q:734
-msgid "Does not assume equal"
-msgstr "No s'assumeix igualtat"
+#: src/language/stats/frequencies.q:1221
+#, c-format
+msgid "Omitting pie chart for %s, which has over 50 unique values."
+msgstr "S'omet grafic de sectors per a %s, que té més de 50 valors únics. "
 
 #: src/language/stats/rank.q:220
 #, c-format
@@ -4842,342 +5258,329 @@ msgstr "%s de %s"
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr "No es pot crear la nova variable de rangs.  Tots els candidats estan en ús."
 
-#: src/language/stats/rank.q:693
+#: src/language/stats/rank.q:696
 msgid "Variables Created By RANK"
 msgstr "Variables creades per RANK"
 
-#: src/language/stats/rank.q:717
+#: src/language/stats/rank.q:720
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr "%s en %s(%s de %s utilitzant %s BY %s)"
 
-#: src/language/stats/rank.q:727
+#: src/language/stats/rank.q:730
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr "%s en %s(%s de %s BY %s)"
 
-#: src/language/stats/rank.q:740
+#: src/language/stats/rank.q:743
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr "%s en %s(%s de %s utilitzant %s)"
 
-#: src/language/stats/rank.q:749
+#: src/language/stats/rank.q:752
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr "%s en %s(%s de %s)"
 
-#: src/language/stats/rank.q:761
+#: src/language/stats/rank.q:764
 msgid "FRACTION has been specified, but NORMAL and PROPORTION rank functions have not been requested.  The FRACTION subcommand will be ignored."
 msgstr "S'ha especificat FRACTION, però no s'ahn demanat funcions de rang NORMAL o PROPORTION.  La  subordre FRACTION será ignorada."
 
-#: src/language/stats/rank.q:852
+#: src/language/stats/rank.q:855
 #, c-format
 msgid "Variable %s already exists."
 msgstr "La variable %s ja existeix."
 
-#: src/language/stats/rank.q:857
+#: src/language/stats/rank.q:860
 msgid "Too many variables in INTO clause."
 msgstr "Massa variables a la clausula INTO."
 
-#: src/language/stats/regression.q:156
+#: src/language/stats/regression.q:158
 msgid "R Square"
 msgstr "R Quadrada"
 
-#: src/language/stats/regression.q:157
+#: src/language/stats/regression.q:159
 msgid "Adjusted R Square"
 msgstr "R Quadrada Ajustada"
 
-#: src/language/stats/regression.q:158
+#: src/language/stats/regression.q:160
 msgid "Std. Error of the Estimate"
 msgstr "Error estàndard de l'Estimador"
 
-#: src/language/stats/regression.q:163
+#: src/language/stats/regression.q:165
 msgid "Model Summary"
 msgstr "Resum del model"
 
-#: src/language/stats/regression.q:197
+#: src/language/stats/regression.q:199
 msgid "B"
 msgstr "B"
 
-#: src/language/stats/regression.q:199
+#: src/language/stats/regression.q:201
 msgid "Beta"
 msgstr "Beta"
 
-#: src/language/stats/regression.q:202
+#: src/language/stats/regression.q:204
 msgid "(Constant)"
 msgstr "(Constant)"
 
-#: src/language/stats/regression.q:254
+#: src/language/stats/regression.q:256
 msgid "Coefficients"
 msgstr "Coeficients"
 
-#: src/language/stats/regression.q:289 src/ui/gui/regression.ui:7
+#: src/language/stats/regression.q:291 src/ui/gui/regression.ui:7
 msgid "Regression"
 msgstr "Regressió"
 
-#: src/language/stats/regression.q:370
+#: src/language/stats/regression.q:372
 msgid "Model"
 msgstr "Model"
 
-#: src/language/stats/regression.q:371
+#: src/language/stats/regression.q:373
 msgid "Covariances"
 msgstr "Covariància"
 
-#: src/language/stats/regression.q:386
+#: src/language/stats/regression.q:388
 msgid "Coefficient Correlations"
 msgstr "Correlacions de Coeficients"
 
-#: src/language/stats/regression.q:793
+#: src/language/stats/regression.q:787
 msgid "The dependent variable is equal to the independent variable.The least squares line is therefore Y=X.Standard errors and related statistics may be meaningless."
 msgstr "La variable dependiente es igual a la variable independiente. La línea de minimos cuadrados es por tanto Y=X. Los errores estàndard i els estadistics relacionats podríen ser irrellevants."
 
-#: src/language/stats/regression.q:891
+#: src/language/stats/regression.q:934
 msgid "REGRESSION requires numeric variables."
 msgstr "REGRESSION requereix variables numèriques."
 
-#: src/language/stats/regression.q:962
+#: src/language/stats/regression.q:1009
 msgid "No valid data found. This command was skipped."
 msgstr "No s'han trobat dades vàlides. S'gnora aquesta ordre."
 
-#: src/language/stats/reliability.q:421
-msgid "Reliability Statistics"
-msgstr "Estadístiques de fiabilitat"
-
-#: src/language/stats/reliability.q:462
-msgid "Item-Total Statistics"
-msgstr "Estadístiques de total d'Items"
-
-#: src/language/stats/reliability.q:484
-msgid "Scale Mean if Item Deleted"
-msgstr "Escalar la mitjana si s'esborra l'element"
-
-#: src/language/stats/reliability.q:487
-msgid "Scale Variance if Item Deleted"
-msgstr "Escalar la variança si s'esborra l'element"
-
-#: src/language/stats/reliability.q:490
-msgid "Corrected Item-Total Correlation"
-msgstr "Correlació total-item corregida"
-
-#: src/language/stats/reliability.q:493
-msgid "Cronbach's Alpha if Item Deleted"
-msgstr "Cronbach's Alpha si s'esborra l'element"
-
-#: src/language/stats/reliability.q:543 src/language/stats/reliability.q:562
-msgid "Cronbach's Alpha"
-msgstr "Alfa de Cronbach"
-
-#: src/language/stats/reliability.q:546 src/language/stats/reliability.q:571
-#: src/language/stats/reliability.q:582
-msgid "N of Items"
-msgstr "N d'elements"
-
-#: src/language/stats/reliability.q:565
-msgid "Part 1"
-msgstr "Part 1"
-
-#: src/language/stats/reliability.q:576
-msgid "Part 2"
-msgstr "Part 2"
-
-#: src/language/stats/reliability.q:587
-msgid "Total N of Items"
-msgstr "N total d'elements"
-
-#: src/language/stats/reliability.q:590
-msgid "Correlation Between Forms"
-msgstr "Correlación entre formes"
-
-#: src/language/stats/reliability.q:594
-msgid "Spearman-Brown Coefficient"
-msgstr "Coeficient d'Spearman-Brown"
-
-#: src/language/stats/reliability.q:597
-msgid "Equal Length"
-msgstr "Ample igual"
-
-#: src/language/stats/reliability.q:600
-msgid "Unequal Length"
-msgstr "Ample desigual"
-
-#: src/language/stats/reliability.q:604
-msgid "Guttman Split-Half Coefficient"
-msgstr "Coeficient Gutman de DIvisió pel mig"
-
-#: src/language/stats/reliability.q:699
-msgid "Excluded"
-msgstr "Exclós"
-
-#: src/language/stats/reliability.q:707
-msgid "%"
-msgstr "%"
-
-#: src/language/stats/t-test.q:190
+#: src/language/stats/t-test.q:192
 msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
 msgstr "Exactamente un dels subcomanaments TESTVAL, GROUPS y PAIRS ha d'especificarse."
 
-#: src/language/stats/t-test.q:211
+#: src/language/stats/t-test.q:213
 msgid "VARIABLES subcommand may not be used with PAIRS."
 msgstr "La subordre VARIABLES no pot se utilitzada amb PAIRS."
 
-#: src/language/stats/t-test.q:230
+#: src/language/stats/t-test.q:232
 msgid "One or more VARIABLES must be specified."
 msgstr "Una o més  VARIABLES han de ser especificades."
 
-#: src/language/stats/t-test.q:324
+#: src/language/stats/t-test.q:328
 msgid "When applying GROUPS to a string variable, two values must be specified."
 msgstr "Quan s'aplica GROUPS a una variable alfabetica, s'han d'especificar dos valors."
 
-#: src/language/stats/t-test.q:395
+#: src/language/stats/t-test.q:399
 msgid "At least two variables must be specified on PAIRS."
 msgstr "Al menys dos variables s'han d'especificar a PAIRS."
 
-#: src/language/stats/t-test.q:503
+#: src/language/stats/t-test.q:507
 msgid "One-Sample Statistics"
 msgstr "Estadisticas d'una mostra"
 
-#: src/language/stats/t-test.q:522
+#: src/language/stats/t-test.q:526
 msgid "Group Statistics"
 msgstr "Estadístiques de grup"
 
-#: src/language/stats/t-test.q:621
+#: src/language/stats/t-test.q:625
 msgid "Paired Sample Statistics"
 msgstr "Estadistiques de mostres aparellades"
 
-#: src/language/stats/t-test.q:641 src/language/stats/t-test.q:944
-#: src/language/stats/t-test.q:1111
+#: src/language/stats/t-test.q:645 src/language/stats/t-test.q:948
+#: src/language/stats/t-test.q:1115
 #, c-format
 msgid "Pair %d"
 msgstr "Parell %d"
 
-#: src/language/stats/t-test.q:737
+#: src/language/stats/t-test.q:741
 msgid "Independent Samples Test"
 msgstr "Prova per mostres independents"
 
-#: src/language/stats/t-test.q:745
+#: src/language/stats/t-test.q:749
 msgid "Levene's Test for Equality of Variances"
 msgstr "Prova de Levene per a l'igualtat de variancies"
 
-#: src/language/stats/t-test.q:747
+#: src/language/stats/t-test.q:751
 msgid "t-test for Equality of Means"
 msgstr "Prova T per l'igualtat de Mitjanes"
 
-#: src/language/stats/t-test.q:750 src/language/stats/t-test.q:1103
+#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1107
 msgid "Sig."
 msgstr "Sig."
 
-#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1012
+#: src/language/stats/t-test.q:758 src/language/stats/t-test.q:1016
 msgid "Mean Difference"
 msgstr "Diferència Mitjana"
 
-#: src/language/stats/t-test.q:755
+#: src/language/stats/t-test.q:759
 msgid "Std. Error Difference"
 msgstr "Err.Est. de la Diferència"
 
-#: src/language/stats/t-test.q:760 src/language/stats/t-test.q:914
-#: src/language/stats/t-test.q:1004
+#: src/language/stats/t-test.q:764 src/language/stats/t-test.q:918
+#: src/language/stats/t-test.q:1008
 #, c-format
 msgid "%g%% Confidence Interval of the Difference"
 msgstr "Interval de confiança de la Diferència %g%%"
 
-#: src/language/stats/t-test.q:814
+#: src/language/stats/t-test.q:818
 msgid "Equal variances assumed"
 msgstr "S'asumeix igualtat de variancies"
 
-#: src/language/stats/t-test.q:860
+#: src/language/stats/t-test.q:864
 msgid "Equal variances not assumed"
 msgstr "Igualtat de variancies no asumida"
 
-#: src/language/stats/t-test.q:904
+#: src/language/stats/t-test.q:908
 msgid "Paired Samples Test"
 msgstr "Prova de mostres aparellades"
 
-#: src/language/stats/t-test.q:907
+#: src/language/stats/t-test.q:911
 msgid "Paired Differences"
 msgstr "Diferències aparellades"
 
-#: src/language/stats/t-test.q:919
+#: src/language/stats/t-test.q:923
 msgid "Std. Error Mean"
 msgstr "Error Est. Mitjana"
 
-#: src/language/stats/t-test.q:993
+#: src/language/stats/t-test.q:997
 msgid "One-Sample Test"
 msgstr "Prova d'una mostra"
 
-#: src/language/stats/t-test.q:998
+#: src/language/stats/t-test.q:1002
 #, c-format
 msgid "Test Value = %f"
 msgstr "Valor de prova = %f"
 
-#: src/language/stats/t-test.q:1098
+#: src/language/stats/t-test.q:1102
 msgid "Paired Samples Correlations"
 msgstr "Correlacions de mostres aparellades"
 
-#: src/language/stats/t-test.q:1102
+#: src/language/stats/t-test.q:1106
 msgid "Correlation"
 msgstr "Correlació"
 
-#: src/language/stats/t-test.q:1113
+#: src/language/stats/t-test.q:1117
 #, c-format
 msgid "%s & %s"
 msgstr "%s & %s"
 
-#: src/language/data-io/file-handle.q:65
+#: src/language/data-io/file-handle.q:68
 #, c-format
 msgid "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining a file handle."
 msgstr "El manipulador d'arxiu %s ja ha esta definit.  Utilitzar CLOSE FILE HANDLE abans de redefinir un manipulador d'arxius."
 
-#: src/language/data-io/file-handle.q:120
+#: src/language/data-io/file-handle.q:123
 msgid "RECFORM must be specified with MODE=360."
 msgstr "RECFORM ha de ser espeficat amb MODE=360."
 
-#: src/language/data-io/file-handle.q:131
+#: src/language/data-io/file-handle.q:134
 #, c-format
 msgid "The specified file mode requires LRECL.  Assuming %zu-character records."
 msgstr "El mode d'arxiu especificat requereix LRECL.  S'asumeix registres de %zu caracters."
 
-#: src/language/data-io/file-handle.q:135
+#: src/language/data-io/file-handle.q:138
 #, c-format
 msgid "Record length (%ld) must be between 1 and %lu bytes.  Assuming %d-character records."
 msgstr "L'amplada de registre (%ld) ha d'estar entre  1 i %lu bytes.  S'asumeix %d-registres de caracter."
 
-#: src/language/data-io/file-handle.q:177
+#: src/language/data-io/file-handle.q:182
 msgid "file"
 msgstr "arxiu"
 
-#: src/language/data-io/file-handle.q:179
+#: src/language/data-io/file-handle.q:184
 msgid "inline file"
 msgstr "arxiu en linia"
 
-#: src/language/data-io/file-handle.q:205
+#: src/language/data-io/file-handle.q:210
 msgid "expecting a file name or handle name"
 msgstr "experant un nom d'arxiu o un manipulador"
 
-#: src/language/data-io/file-handle.q:225
+#: src/language/data-io/file-handle.q:231
 #, c-format
 msgid "Handle for %s not allowed here."
 msgstr "Aquí no està permès un manipulador per a %s."
 
-#: src/language/data-io/list.q:99
+#: src/language/data-io/list.q:98
 #, c-format
 msgid "The first case (%ld) specified precedes the last case (%ld) specified.  The values will be swapped."
 msgstr "El primer cas (%ld) especificat precedeix a l'ultim cas (%ld) especificat.  Els valors s'intercanviaran."
 
-#: src/language/data-io/list.q:107
+#: src/language/data-io/list.q:106
 #, c-format
 msgid "The first case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "EL primer cas (%ld) per llistar es menor que 1.  El valor es retorna a 1."
 
-#: src/language/data-io/list.q:113
+#: src/language/data-io/list.q:112
 #, c-format
 msgid "The last case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "L'últim cas (%ld) per llistar es menor que 1.  El valor es restaura a 1.."
 
-#: src/language/data-io/list.q:119
+#: src/language/data-io/list.q:118
 #, c-format
 msgid "The step value %ld is less than 1.  The value is being reset to 1."
 msgstr "El valor del pas %ld es menor que 1.  el valor es retorna a 1."
 
+#: src/ui/gui/aggregate.ui:7
+msgid "Aggregate Data"
+msgstr "Dades Agregades"
+
+#: src/ui/gui/aggregate.ui:100
+msgid "_Break variable(s)"
+msgstr "Variable(s) de Tall"
+
+#: src/ui/gui/aggregate.ui:136
+msgid "Variable Name: "
+msgstr " Variable:"
+
+#: src/ui/gui/aggregate.ui:161
+msgid "Variable Label: "
+msgstr "Etiqueta de variable: "
+
+#: src/ui/gui/aggregate.ui:190
+msgid "Function: "
+msgstr "Funció: "
+
+#: src/ui/gui/aggregate.ui:253
+msgid "Argument 1: "
+msgstr "Argument 1: "
+
+#: src/ui/gui/aggregate.ui:282
+msgid "Argument 2: "
+msgstr "Argument 2: "
+
+#: src/ui/gui/aggregate.ui:328
+msgid "Aggregated variables"
+msgstr "Variables agregades"
+
+#: src/ui/gui/aggregate.ui:362
+msgid "_Add aggregated variables to the active dataset"
+msgstr "_Afegeix variables agregades al conjunt de dades actiu"
+
+#: src/ui/gui/aggregate.ui:376
+msgid "_Replace the current dataset with the aggregated variables"
+msgstr "_Reemplaça el conjunt de dades actual amb les variables agregades"
+
+#: src/ui/gui/aggregate.ui:391
+msgid "_Write a new data file containing only the aggregated variables"
+msgstr "Escriu un nou arxiu de dades que contingui només les variables agregades"
+
+#: src/ui/gui/aggregate.ui:428
+msgid "label"
+msgstr "etiqueta"
+
+#: src/ui/gui/aggregate.ui:472
+msgid "File is _already sorted on break variable(s)"
+msgstr "L'arxiu j_a está ordenat per le(s) variable(s) de tall"
+
+#: src/ui/gui/aggregate.ui:487
+msgid "Sort file before a_ggregating"
+msgstr "Ordenar l'arxiu abans de l'a_gregació"
+
+#: src/ui/gui/aggregate.ui:508
+msgid "Options for very large datasets"
+msgstr "Opcions per conjunts de dades grans"
+
 #: src/ui/gui/binomial.ui:57 src/ui/gui/chi-square.ui:57
 msgid "_Test Variable List:"
 msgstr "Lista de Variable _Test:"
@@ -5198,6 +5601,43 @@ msgstr "Defineix Dicotomia"
 msgid "Test _Proportion:"
 msgstr "Test _Proporció:"
 
+#: src/ui/gui/compute.ui:8
+msgid "Compute Variable"
+msgstr "Calcular Variable"
+
+#: src/ui/gui/compute.ui:41
+msgid "Target Variable:"
+msgstr "Variable objectiu:"
+
+#: src/ui/gui/compute.ui:70
+msgid "Type & Label"
+msgstr "Tipus y Etiquetes"
+
+#: src/ui/gui/compute.ui:117
+msgid "="
+msgstr "="
+
+#: src/ui/gui/compute.ui:171
+msgid "Numeric Expressions:"
+msgstr "Expressions Numeriques:"
+
+#: src/ui/gui/compute.ui:233
+msgid "Functions:"
+msgstr "Funcions:"
+
+#: src/ui/gui/compute.ui:298 src/ui/gui/recode.ui:741
+#: src/ui/gui/select-cases.ui:378
+msgid "If..."
+msgstr "si..."
+
+#: src/ui/gui/compute.ui:351
+msgid "Compute Variable: Type and Label"
+msgstr "Calcular Variable: Tipus i Etiqueta"
+
+#: src/ui/gui/compute.ui:386
+msgid "Use expression as label"
+msgstr "Utilitza l'expressio com a etiqueta"
+
 #: src/ui/gui/correlation.ui:7
 msgid "Bivariate Correlations"
 msgstr "Correlacions Bivariades"
@@ -5402,91 +5842,107 @@ msgstr "Repetir valors"
 msgid "Missing Values"
 msgstr "Valors perduts"
 
-#: src/ui/gui/factor.ui:21
+#: src/ui/gui/goto-case.ui:8
+msgid "Goto Case"
+msgstr "Anar a Cas"
+
+#: src/ui/gui/goto-case.ui:26
+msgid "Goto Case Number:"
+msgstr "Anar al cas número:"
+
+#: src/ui/gui/factor.ui:22
+msgid "Principal Components Analysis"
+msgstr "Anàlisi de Components Principals"
+
+#: src/ui/gui/factor.ui:26
+msgid "Principal Axis Factoring"
+msgstr "Factors pels eixos principals"
+
+#: src/ui/gui/factor.ui:29
 msgid "Factor Analysis"
 msgstr "Anàlisi Factorial"
 
-#: src/ui/gui/factor.ui:47
+#: src/ui/gui/factor.ui:55
 msgid "_Descriptives..."
 msgstr "_Descriptius..."
 
-#: src/ui/gui/factor.ui:60
+#: src/ui/gui/factor.ui:68
 msgid "_Extraction..."
 msgstr "_Extracció..."
 
-#: src/ui/gui/factor.ui:74
+#: src/ui/gui/factor.ui:82
 msgid "_Rotations..."
 msgstr "Rotacions..."
 
-#: src/ui/gui/factor.ui:192
+#: src/ui/gui/factor.ui:200
 msgid "Factor Analysis: Extraction"
 msgstr "Anàlisi Factorial: Extracció"
 
-#: src/ui/gui/factor.ui:216
+#: src/ui/gui/factor.ui:224
 msgid "Method: "
 msgstr "Mètode: "
 
-#: src/ui/gui/factor.ui:266
+#: src/ui/gui/factor.ui:274
 msgid "Correlation matrix"
 msgstr "Matriu de Correlació"
 
-#: src/ui/gui/factor.ui:280
+#: src/ui/gui/factor.ui:288
 msgid "Covariance matrix"
 msgstr "Matriu de Covariància"
 
-#: src/ui/gui/factor.ui:300
-msgid "Analyse"
+#: src/ui/gui/factor.ui:308
+msgid "Analyze"
 msgstr "Analitzar"
 
-#: src/ui/gui/factor.ui:324
-msgid "Unrotatated factor solution"
-msgstr "Solució factorial no rotada"
+#: src/ui/gui/factor.ui:332
+msgid "Unrotated factor solution"
+msgstr "Solució factorial sense rotació"
 
-#: src/ui/gui/factor.ui:338
+#: src/ui/gui/factor.ui:346
 msgid "Scree plot"
 msgstr "Gràfic de sedimentació"
 
-#: src/ui/gui/factor.ui:357 src/ui/gui/roc.ui:286
+#: src/ui/gui/factor.ui:365 src/ui/gui/roc.ui:286
 msgid "Display"
 msgstr "Contingut"
 
-#: src/ui/gui/factor.ui:430
+#: src/ui/gui/factor.ui:438
 msgid "Number of factors:"
 msgstr "Nombre de factors:"
 
-#: src/ui/gui/factor.ui:460
+#: src/ui/gui/factor.ui:468
 msgid "Extract"
 msgstr "Extracció"
 
-#: src/ui/gui/factor.ui:475 src/ui/gui/factor.ui:665
+#: src/ui/gui/factor.ui:483 src/ui/gui/factor.ui:673
 msgid "Maximum iterations for convergence:"
 msgstr "Iteracions màximes per convergència:"
 
-#: src/ui/gui/factor.ui:538
+#: src/ui/gui/factor.ui:546
 msgid "Factor Analysis: Rotation"
 msgstr "Anàlisi Factorial: Rotació"
 
-#: src/ui/gui/factor.ui:571
+#: src/ui/gui/factor.ui:579
 msgid "_None"
 msgstr "_No res"
 
-#: src/ui/gui/factor.ui:582
+#: src/ui/gui/factor.ui:590
 msgid "_Varimax"
 msgstr "_Varimax"
 
-#: src/ui/gui/factor.ui:598
+#: src/ui/gui/factor.ui:606
 msgid "_Quartimax"
 msgstr "_Quartimax"
 
-#: src/ui/gui/factor.ui:614
+#: src/ui/gui/factor.ui:622
 msgid "_Equimax"
 msgstr "_Equimax"
 
-#: src/ui/gui/factor.ui:637
+#: src/ui/gui/factor.ui:645
 msgid "Method"
 msgstr "Mètode"
 
-#: src/ui/gui/factor.ui:648
+#: src/ui/gui/factor.ui:656
 msgid "_Display rotated solution"
 msgstr "Mostra solució rotada"
 
@@ -5632,6 +6088,30 @@ msgstr "Incloure sectors pels valors perduts"
 msgid "<b>Pie Charts</b>"
 msgstr "<b>Gràfiques de Sectors</b>"
 
+#: src/ui/gui/k-related.ui:7
+msgid "Tests for Several Related Samples"
+msgstr "Prova per Múltiples Mostres Aparellades"
+
+#: src/ui/gui/k-related.ui:94
+msgid "_Test Variables:"
+msgstr "Variables de prova:"
+
+#: src/ui/gui/k-related.ui:122
+msgid "_Friedman"
+msgstr "_Friedman"
+
+#: src/ui/gui/k-related.ui:136
+msgid "_Kendall's W"
+msgstr " W de Kendall"
+
+#: src/ui/gui/k-related.ui:150
+msgid "_Cochran's Q"
+msgstr "Q de Cochran"
+
+#: src/ui/gui/k-related.ui:169
+msgid "Test Type"
+msgstr "Tipus de Test"
+
 #: src/ui/gui/oneway.ui:8
 msgid "One-Way ANOVA"
 msgstr "ANOVA d'un factor"
@@ -5644,7 +6124,7 @@ msgstr "_Factor:"
 msgid "Dependent _Variable(s):"
 msgstr "_Variable(s) Depenents:"
 
-#: src/ui/gui/oneway.ui:184 src/ui/gui/data-editor.ui:328
+#: src/ui/gui/oneway.ui:184 src/ui/gui/data-editor.ui:332
 msgid "_Descriptives"
 msgstr "_Descriptives"
 
@@ -5652,219 +6132,66 @@ msgstr "_Descriptives"
 msgid "_Homogeneity"
 msgstr "_Homogeneitat"
 
-#: src/ui/gui/oneway.ui:238
-msgid "_Contrasts..."
-msgstr "_Contrasts..."
-
-#: src/ui/gui/oneway.ui:292
-msgid "One-Way ANOVA: Contrasts"
-msgstr "ANOVA d'un factor: Contrasts"
-
-#: src/ui/gui/oneway.ui:369
-msgid "_Coefficients:"
-msgstr "_Coeficients:"
-
-#: src/ui/gui/oneway.ui:416
-msgid "Coefficient Total: "
-msgstr "Coeficient Total: "
-
-#: src/ui/gui/oneway.ui:452
-msgid "Contrast 1 of 1"
-msgstr "Contrast 1 de 1"
-
-#: src/ui/gui/psppire.ui:7
-msgid "Weight Cases"
-msgstr "Ponderar Cassos"
-
-#: src/ui/gui/psppire.ui:66
-msgid "Weight cases by"
-msgstr "Pondera cassos per"
-
-#: src/ui/gui/psppire.ui:102
-msgid "Frequency Variable"
-msgstr "Variable de Freqüència"
-
-#: src/ui/gui/psppire.ui:145
-msgid "Current Status: "
-msgstr "Estatus actual: "
-
-#: src/ui/gui/psppire.ui:195
-msgid "Transpose"
-msgstr "Trasposar"
-
-#: src/ui/gui/psppire.ui:247
-msgid "Name Variable:"
-msgstr "Nom de Variable:"
-
-#: src/ui/gui/psppire.ui:383
-msgid "Split File"
-msgstr "Divideix Arxiu"
-
-#: src/ui/gui/psppire.ui:443
-msgid "Analyze all cases.  Do not create groups."
-msgstr "Analitzar tots els casos.  No crear grups."
-
-#: src/ui/gui/psppire.ui:459
-msgid "Compare groups."
-msgstr "Comparar grups."
-
-#: src/ui/gui/psppire.ui:475
-msgid "Organize output by groups."
-msgstr "Organitzar els resultats per grups."
-
-#: src/ui/gui/psppire.ui:533
-msgid "Groups based on:"
-msgstr "Grups basats en:"
-
-#: src/ui/gui/psppire.ui:592
-msgid "Sort the file by grouping variables."
-msgstr "Ordena l'arxiu per variables d'agrupació."
-
-#: src/ui/gui/psppire.ui:609
-msgid "File is already sorted."
-msgstr "L'arxiu ja está ordenat."
-
-#: src/ui/gui/psppire.ui:662
-msgid "Current Status : "
-msgstr "Estatus actual : "
-
-#: src/ui/gui/psppire.ui:673
-msgid "Analysis by groups is off"
-msgstr "L'anàlisi per grups està activat"
-
-#: src/ui/gui/psppire.ui:709
-msgid "Compute Variable"
-msgstr "Calcular Variable"
-
-#: src/ui/gui/psppire.ui:742
-msgid "Target Variable:"
-msgstr "Variable objectiu:"
-
-#: src/ui/gui/psppire.ui:771
-msgid "Type & Label"
-msgstr "Tipus y Etiquetes"
-
-#: src/ui/gui/psppire.ui:818
-msgid "="
-msgstr "="
-
-#: src/ui/gui/psppire.ui:872
-msgid "Numeric Expressions:"
-msgstr "Expressions Numeriques:"
-
-#: src/ui/gui/psppire.ui:934
-msgid "Functions:"
-msgstr "Funcions:"
-
-#: src/ui/gui/psppire.ui:999 src/ui/gui/psppire.ui:1422
-#: src/ui/gui/recode.ui:741
-msgid "If..."
-msgstr "si..."
-
-#: src/ui/gui/psppire.ui:1052
-msgid "Select Cases"
-msgstr "Seleccionar casos"
-
-#: src/ui/gui/psppire.ui:1240
-msgid "Use filter variable"
-msgstr "Utilitzar variable de filtre"
+#: src/ui/gui/oneway.ui:238
+msgid "_Contrasts..."
+msgstr "_Contrasts..."
 
-#: src/ui/gui/psppire.ui:1299
-msgid "Based on time or case range"
-msgstr "Basat en interval de temps o casos"
+#: src/ui/gui/oneway.ui:292
+msgid "One-Way ANOVA: Contrasts"
+msgstr "ANOVA d'un factor: Contrasts"
 
-#: src/ui/gui/psppire.ui:1311
-msgid "Range..."
-msgstr "Interval..."
+#: src/ui/gui/oneway.ui:369
+msgid "_Coefficients:"
+msgstr "_Coeficients:"
 
-#: src/ui/gui/psppire.ui:1355
-msgid "Random sample of cases"
-msgstr "Mostra aleatoria de casos"
+#: src/ui/gui/oneway.ui:416
+msgid "Coefficient Total: "
+msgstr "Coeficient Total: "
 
-#: src/ui/gui/psppire.ui:1368
-msgid "Sample..."
-msgstr "Mostra..."
+#: src/ui/gui/oneway.ui:452
+msgid "Contrast 1 of 1"
+msgstr "Contrast 1 de 1"
 
-#: src/ui/gui/psppire.ui:1410
-msgid "If condition is satisfied"
-msgstr "si la condició es satisfà"
+#: src/ui/gui/psppire.ui:7
+msgid "Weight Cases"
+msgstr "Ponderar Cassos"
 
-#: src/ui/gui/psppire.ui:1462
-msgid "All Cases"
-msgstr "Tots els Casos:"
+#: src/ui/gui/psppire.ui:66
+msgid "Weight cases by"
+msgstr "Pondera cassos per"
 
-#: src/ui/gui/psppire.ui:1477
-msgid "Select"
-msgstr "Selecciona"
+#: src/ui/gui/psppire.ui:102
+msgid "Frequency Variable"
+msgstr "Variable de Freqüència"
 
-#: src/ui/gui/psppire.ui:1504
-msgid "Filtered"
-msgstr "Filtrat"
+#: src/ui/gui/psppire.ui:145
+msgid "Current Status: "
+msgstr "Estatus actual: "
 
-#: src/ui/gui/psppire.ui:1520
-msgid "Deleted"
-msgstr "Eliminat"
+#: src/ui/gui/psppire.ui:195
+msgid "Transpose"
+msgstr "Trasposar"
 
-#: src/ui/gui/psppire.ui:1543
-msgid "Unselected Cases Are"
-msgstr "Els casos no seleccionats son"
+#: src/ui/gui/psppire.ui:247
+msgid "Name Variable:"
+msgstr "Nom de Variable:"
 
-#: src/ui/gui/psppire.ui:1585
+#: src/ui/gui/psppire.ui:383
 msgid "Data File Comments"
 msgstr "Comentaris de l'arxiu de dades"
 
-#: src/ui/gui/psppire.ui:1609
+#: src/ui/gui/psppire.ui:407
 msgid "Comments:"
 msgstr "Comentaris:"
 
-#: src/ui/gui/psppire.ui:1650
+#: src/ui/gui/psppire.ui:448
 msgid "Display comments in output"
 msgstr "Mostra comentaris al resultat"
 
-#: src/ui/gui/psppire.ui:1669
+#: src/ui/gui/psppire.ui:467
 msgid "Column Number: 0"
 msgstr "Columna Numero: 0"
 
-#: src/ui/gui/psppire.ui:1703
-msgid "Select Cases: Range"
-msgstr "Seleccionar casos: Rang"
-
-#: src/ui/gui/psppire.ui:1750
-msgid "First case"
-msgstr "Primer cas"
-
-#: src/ui/gui/psppire.ui:1763
-msgid "Last case"
-msgstr "Últim cas"
-
-#: src/ui/gui/psppire.ui:1776
-msgid "Observation"
-msgstr "Observació"
-
-#: src/ui/gui/psppire.ui:1808
-msgid "Compute Variable: Type and Label"
-msgstr "Calcular Variable: Tipus i Etiqueta"
-
-#: src/ui/gui/psppire.ui:1843
-msgid "Use expression as label"
-msgstr "Utilitza l'expressio com a etiqueta"
-
-#: src/ui/gui/psppire.ui:2088
-msgid "Goto Case"
-msgstr "Anar a Cas"
-
-#: src/ui/gui/psppire.ui:2106
-msgid "Goto Case Number:"
-msgstr "Anar al cas número:"
-
-#: src/ui/gui/psppire.ui:2149
-msgid "Select Cases: Random Sample"
-msgstr "Seleccionar casos: Mostra aleatoria"
-
-#: src/ui/gui/psppire.ui:2247
-msgid "Sample Size"
-msgstr "Grandaria de mostra"
-
 #: src/ui/gui/rank.ui:8
 msgid "Rank Cases"
 msgstr "Rang de cassos"
@@ -5899,7 +6226,7 @@ msgstr "Vincles..."
 
 #: src/ui/gui/rank.ui:346
 msgid "Rank Cases: Types"
-msgstr "Rang de cassos: Tipus"
+msgstr "Rang de casos: Tipus"
 
 #: src/ui/gui/rank.ui:366
 msgid "Sum of case weights"
@@ -5955,7 +6282,7 @@ msgstr "Formula d'estimació de Porporcións"
 
 #: src/ui/gui/rank.ui:625
 msgid "Rank Cases: Ties"
-msgstr "Rang de cassos: Vincles"
+msgstr "Rang de casos: Vincles"
 
 #: src/ui/gui/rank.ui:651
 msgid "_Mean"
@@ -5993,6 +6320,42 @@ msgstr "Descendent"
 msgid "Sort Order"
 msgstr "Ordre"
 
+#: src/ui/gui/split-file.ui:8
+msgid "Split File"
+msgstr "Divideix Arxiu"
+
+#: src/ui/gui/split-file.ui:68
+msgid "Analyze all cases.  Do not create groups."
+msgstr "Analitzar tots els casos.  No crear grups."
+
+#: src/ui/gui/split-file.ui:84
+msgid "Compare groups."
+msgstr "Comparar grups."
+
+#: src/ui/gui/split-file.ui:100
+msgid "Organize output by groups."
+msgstr "Organitzar els resultats per grups."
+
+#: src/ui/gui/split-file.ui:158
+msgid "Groups based on:"
+msgstr "Grups basats en:"
+
+#: src/ui/gui/split-file.ui:217
+msgid "Sort the file by grouping variables."
+msgstr "Ordena l'arxiu per variables d'agrupació."
+
+#: src/ui/gui/split-file.ui:234
+msgid "File is already sorted."
+msgstr "L'arxiu ja está ordenat."
+
+#: src/ui/gui/split-file.ui:287
+msgid "Current Status : "
+msgstr "Estatus actual : "
+
+#: src/ui/gui/split-file.ui:298
+msgid "Analysis by groups is off"
+msgstr "L'anàlisi per grups està activat"
+
 #: src/ui/gui/recode.ui:185 src/ui/gui/recode.ui:467
 msgid "System Missing"
 msgstr "Perdut del Sistema"
@@ -6038,8 +6401,8 @@ msgid "New Value"
 msgstr "Nou Valor"
 
 #: src/ui/gui/recode.ui:596
-msgid "Convert numeric strings to numbers ('5' -> 5)"
-msgstr "Convertir cadenes numériques a números ('5' -> 5)"
+msgid "Convert numeric strings to numbers (`5' -> 5)"
+msgstr "Convertir cadenes numèriques a nombres (`5' -> 5)"
 
 #: src/ui/gui/recode.ui:614
 msgid "Output variables are strings"
@@ -6083,7 +6446,7 @@ msgstr "Independent"
 
 #: src/ui/gui/regression.ui:236
 msgid "Regression: Save"
-msgstr "Regressió: Desar"
+msgstr "Regresió: Desar"
 
 #: src/ui/gui/regression.ui:250
 msgid "Predicted values"
@@ -6097,22 +6460,26 @@ msgstr "Residuals"
 msgid "Regression: Statistics"
 msgstr "Regresió: Estadìstics"
 
-#: src/ui/gui/reliability.ui:27
+#: src/ui/gui/reliability.ui:26
 msgid "Reliability Analysis"
 msgstr "Anàlsisi de fiabilitat"
 
-#: src/ui/gui/reliability.ui:114
+#: src/ui/gui/reliability.ui:124
 msgid "_Items:"
 msgstr "_Items:"
 
-#: src/ui/gui/reliability.ui:136
+#: src/ui/gui/reliability.ui:141
 msgid "Model:\t"
 msgstr "Model:\t"
 
-#: src/ui/gui/reliability.ui:175
+#: src/ui/gui/reliability.ui:180
 msgid "Variables in first split:"
 msgstr "Variables a primera divissió:"
 
+#: src/ui/gui/reliability.ui:217
+msgid "Show descriptives for scale if _item is deleted"
+msgstr "Mostrar descriptius per escala si l'_item és esborrat"
+
 #: src/ui/gui/roc.ui:115
 msgid "_Test Variable:"
 msgstr "Variable de prova:"
@@ -6141,6 +6508,78 @@ msgstr "_Error típic i Interval de Confiança"
 msgid "_Coordinate points of the ROC Curve"
 msgstr "_Coordenades de la Corba ROC"
 
+#: src/ui/gui/select-cases.ui:8
+msgid "Select Cases"
+msgstr "Seleccionar casos"
+
+#: src/ui/gui/select-cases.ui:196
+msgid "Use filter variable"
+msgstr "Utilitzar variable de filtre"
+
+#: src/ui/gui/select-cases.ui:255
+msgid "Based on time or case range"
+msgstr "Basat en interval de temps o casos"
+
+#: src/ui/gui/select-cases.ui:267
+msgid "Range..."
+msgstr "Interval..."
+
+#: src/ui/gui/select-cases.ui:311
+msgid "Random sample of cases"
+msgstr "Mostra aleatoria de casos"
+
+#: src/ui/gui/select-cases.ui:324
+msgid "Sample..."
+msgstr "Mostra..."
+
+#: src/ui/gui/select-cases.ui:366
+msgid "If condition is satisfied"
+msgstr "si la condició es satisfà"
+
+#: src/ui/gui/select-cases.ui:418
+msgid "All Cases"
+msgstr "Tots els Casos:"
+
+#: src/ui/gui/select-cases.ui:433
+msgid "Select"
+msgstr "Selecciona"
+
+#: src/ui/gui/select-cases.ui:460
+msgid "Filtered"
+msgstr "Filtrat"
+
+#: src/ui/gui/select-cases.ui:476
+msgid "Deleted"
+msgstr "Eliminat"
+
+#: src/ui/gui/select-cases.ui:499
+msgid "Unselected Cases Are"
+msgstr "Els casos no seleccionats son"
+
+#: src/ui/gui/select-cases.ui:541
+msgid "Select Cases: Range"
+msgstr "Seleccionar casos: Rang"
+
+#: src/ui/gui/select-cases.ui:590
+msgid "First case"
+msgstr "Primer cas"
+
+#: src/ui/gui/select-cases.ui:603
+msgid "Last case"
+msgstr "Últim cas"
+
+#: src/ui/gui/select-cases.ui:616
+msgid "Observation"
+msgstr "Observació"
+
+#: src/ui/gui/select-cases.ui:648
+msgid "Select Cases: Random Sample"
+msgstr "Seleccionar casos: Mostra aleatoria"
+
+#: src/ui/gui/select-cases.ui:746
+msgid "Sample Size"
+msgstr "Grandaria de mostra"
+
 #: src/ui/gui/t-test.ui:8
 msgid "Independent-Samples T Test"
 msgstr "Prova T per mostres Independents"
@@ -6203,115 +6642,103 @@ msgstr ""
 "\n"
 "L'arxiu seleccionat conté N linies de text.  Només les primeres M seran mostrades per previsualització a les pantalles seguents.  Pots triar a continuació quina part de l'arxiu ha de ser importat."
 
-#: src/ui/gui/text-data-import.ui:52
+#: src/ui/gui/text-data-import.ui:95
 msgid "All cases"
 msgstr "Tots els casos"
 
-#: src/ui/gui/text-data-import.ui:71 src/ui/gui/text-data-import.ui:128
-msgid "Only first "
-msgstr "Només el primer"
-
-#: src/ui/gui/text-data-import.ui:106
-msgid " cases"
-msgstr " cassos"
-
-#: src/ui/gui/text-data-import.ui:162
-msgid "% of file (approximately)"
-msgstr "% de l'arxiu (aproximadament)"
-
-#: src/ui/gui/text-data-import.ui:183
+#: src/ui/gui/text-data-import.ui:116
 msgid "<b>Amount to Import</b>"
 msgstr "<b>Quantitat a importar</b>"
 
-#: src/ui/gui/text-data-import.ui:202
+#: src/ui/gui/text-data-import.ui:135
 msgid "Select Data to Import"
 msgstr "Selecionar dades per a importar"
 
-#: src/ui/gui/text-data-import.ui:213
+#: src/ui/gui/text-data-import.ui:146
 msgid "Select the first line of the data file that contains data."
 msgstr "Seleccionar la primera linia del'arxiu que conté dades."
 
-#: src/ui/gui/text-data-import.ui:241
+#: src/ui/gui/text-data-import.ui:174
 msgid "Line above selected line contains variable names"
 msgstr "La linia sobre la linia seleccionada contè els noms de les variables"
 
-#: src/ui/gui/text-data-import.ui:259
+#: src/ui/gui/text-data-import.ui:192
 msgid "Choose Separators"
 msgstr "Triar els separadors"
 
-#: src/ui/gui/text-data-import.ui:305
+#: src/ui/gui/text-data-import.ui:238
 msgid "C_ustom"
 msgstr "_Usuari"
 
-#: src/ui/gui/text-data-import.ui:320
+#: src/ui/gui/text-data-import.ui:253
 msgid "Slas_h (/)"
 msgstr "Barra (/)"
 
-#: src/ui/gui/text-data-import.ui:337
+#: src/ui/gui/text-data-import.ui:270
 msgid "Semicolo_n (;)"
 msgstr "Punt i coma (;)"
 
-#: src/ui/gui/text-data-import.ui:354
+#: src/ui/gui/text-data-import.ui:287
 msgid "P_ipe (|)"
 msgstr "Tub (|)"
 
-#: src/ui/gui/text-data-import.ui:369
+#: src/ui/gui/text-data-import.ui:302
 msgid "H_yphen (-)"
 msgstr "Guionet (-)"
 
-#: src/ui/gui/text-data-import.ui:386
+#: src/ui/gui/text-data-import.ui:319
 msgid "Co_mma (,)"
 msgstr "Coma (,)"
 
-#: src/ui/gui/text-data-import.ui:403
+#: src/ui/gui/text-data-import.ui:336
 msgid "_Colon (:)"
 msgstr "Dos punts (:)"
 
-#: src/ui/gui/text-data-import.ui:418
+#: src/ui/gui/text-data-import.ui:351
 msgid "Ban_g (!)"
 msgstr "Exclamació (!)"
 
-#: src/ui/gui/text-data-import.ui:433
+#: src/ui/gui/text-data-import.ui:366
 msgid "Ta_b"
 msgstr "Tabulador"
 
-#: src/ui/gui/text-data-import.ui:448
+#: src/ui/gui/text-data-import.ui:381
 msgid "_Space"
 msgstr "E-spai"
 
-#: src/ui/gui/text-data-import.ui:465
+#: src/ui/gui/text-data-import.ui:398
 msgid "<b>Separators</b>"
 msgstr "<b>Separadors</b>"
 
-#: src/ui/gui/text-data-import.ui:495
+#: src/ui/gui/text-data-import.ui:428
 msgid "Doubled quote mark treated as escape"
 msgstr "La marca \" es tractada con a ESCAPE"
 
-#: src/ui/gui/text-data-import.ui:524
+#: src/ui/gui/text-data-import.ui:457
 msgid "Quote separator characters with"
 msgstr "Separar caracters amb comilla"
 
-#: src/ui/gui/text-data-import.ui:544
+#: src/ui/gui/text-data-import.ui:477
 msgid "<b>Quoting</b>"
 msgstr "<b>Comilles</b>"
 
-#: src/ui/gui/text-data-import.ui:592
+#: src/ui/gui/text-data-import.ui:525
 msgid "<b>Fields Preview</b>"
 msgstr "<b>Previsualitza camps</b>"
 
-#: src/ui/gui/text-data-import.ui:607
+#: src/ui/gui/text-data-import.ui:540
 msgid "Adjust Variable Formats"
 msgstr "Ajustar formats de variables"
 
-#: src/ui/gui/text-data-import.ui:618
+#: src/ui/gui/text-data-import.ui:551
 msgid "Check the data formats displayed below and fix any that are incorrect.  You may set other variable properties now or later."
 msgstr "Comprovar les formats de les dades mostrades a continuació i corregir els problemes.  Es pot asignar altres propietats de les variables ara o més tard."
 
-#: src/ui/gui/text-data-import.ui:662
+#: src/ui/gui/text-data-import.ui:595
 msgid "<b>Variables</b>"
 msgstr "<b>Variables</b>"
 
-#: src/ui/gui/text-data-import.ui:705
+#: src/ui/gui/text-data-import.ui:638
 msgid "<b>Data Preview</b>"
 msgstr "<b>Previsualització de dades</b>"
 
@@ -6383,306 +6810,302 @@ msgstr "Valor perdut discreto ocpional d'interval més un"
 msgid "Variable Information:"
 msgstr "Informació de la Variable"
 
-#: src/ui/gui/data-editor.ui:9
-msgid "Sort Ascending"
-msgstr "Ordenació ascendent"
-
-#: src/ui/gui/data-editor.ui:15
-msgid "Sort Descending"
-msgstr "Ordenació descendent"
-
-#: src/ui/gui/data-editor.ui:26 src/ui/gui/output-viewer.ui:9
+#: src/ui/gui/data-editor.ui:23 src/ui/gui/output-viewer.ui:9
 #: src/ui/gui/syntax-editor.ui:10
 msgid "_File"
 msgstr "_Arxiu"
 
-#: src/ui/gui/data-editor.ui:38 src/ui/gui/syntax-editor.ui:22
+#: src/ui/gui/data-editor.ui:35 src/ui/gui/syntax-editor.ui:22
 #: src/ui/gui/syntax-editor.ui:40
 msgid "_Syntax"
 msgstr "_Sintaxi"
 
-#: src/ui/gui/data-editor.ui:44 src/ui/gui/data-editor.ui:217
-#: src/ui/gui/data-editor.ui:229 src/ui/gui/syntax-editor.ui:28
+#: src/ui/gui/data-editor.ui:41 src/ui/gui/data-editor.ui:214
+#: src/ui/gui/data-editor.ui:226 src/ui/gui/syntax-editor.ui:28
 #: src/ui/gui/syntax-editor.ui:46
 msgid "_Data"
 msgstr "_Dades"
 
-#: src/ui/gui/data-editor.ui:56
+#: src/ui/gui/data-editor.ui:53
 msgid "_Import Delimited Text Data"
 msgstr "_Importar dades de text delimitat"
 
-#: src/ui/gui/data-editor.ui:75
+#: src/ui/gui/data-editor.ui:72
 msgid "D_isplay Data File Information"
 msgstr "Mostra _informació de l'arxiu de dades"
 
-#: src/ui/gui/data-editor.ui:81
+#: src/ui/gui/data-editor.ui:79
 msgid "Working File"
 msgstr "Arxius de treball"
 
-#: src/ui/gui/data-editor.ui:87
+#: src/ui/gui/data-editor.ui:85
 msgid "External File"
 msgstr "Arxiu extern"
 
-#: src/ui/gui/data-editor.ui:93
+#: src/ui/gui/data-editor.ui:91
 msgid "Recently Used Da_ta"
 msgstr "Dades usades recentment"
 
-#: src/ui/gui/data-editor.ui:99
+#: src/ui/gui/data-editor.ui:97
 msgid "Recently Used _Files"
 msgstr "Arxius utilitzats recentment"
 
-#: src/ui/gui/data-editor.ui:111 src/ui/gui/output-viewer.ui:28
+#: src/ui/gui/data-editor.ui:109 src/ui/gui/output-viewer.ui:28
 #: src/ui/gui/syntax-editor.ui:70
 msgid "_Edit"
 msgstr "_Editar"
 
-#: src/ui/gui/data-editor.ui:117
+#: src/ui/gui/data-editor.ui:115
 msgid "Insert Variable"
 msgstr "Insertar Variable"
 
-#: src/ui/gui/data-editor.ui:118
+#: src/ui/gui/data-editor.ui:116
 msgid "Create a new variable at the current position"
 msgstr "Crear una nova variable a la posició seleccionada"
 
-#: src/ui/gui/data-editor.ui:125
+#: src/ui/gui/data-editor.ui:123
 msgid "Insert Cases"
 msgstr "Insertar Casos"
 
-#: src/ui/gui/data-editor.ui:126
+#: src/ui/gui/data-editor.ui:124
 msgid "Create a new case at the current position"
 msgstr "Crear un nou cas a la posició actual"
 
-#: src/ui/gui/data-editor.ui:132
+#: src/ui/gui/data-editor.ui:130
 msgid "Go To Case"
 msgstr "Anar a"
 
-#: src/ui/gui/data-editor.ui:134
+#: src/ui/gui/data-editor.ui:132
 msgid "Jump to a case in the data sheet"
 msgstr "Anar a un cas a la matriu de Dades"
 
-#: src/ui/gui/data-editor.ui:160
+#: src/ui/gui/data-editor.ui:158
 msgid "Cl_ear Variables"
 msgstr "_Eliminar Variables:"
 
-#: src/ui/gui/data-editor.ui:161
+#: src/ui/gui/data-editor.ui:159
 msgid "Delete the variables at the selected position(s)"
 msgstr "Esborra les variables a la posició(ns) selecconada(es)"
 
-#: src/ui/gui/data-editor.ui:169
+#: src/ui/gui/data-editor.ui:167
 msgid "_Clear Cases"
 msgstr "_Eliminar Casos"
 
-#: src/ui/gui/data-editor.ui:170
+#: src/ui/gui/data-editor.ui:168
 msgid "Delete the cases at the selected position(s)"
 msgstr "Esborra els casos a la(es) posició(ns) seleccionada(es)"
 
-#: src/ui/gui/data-editor.ui:182
+#: src/ui/gui/data-editor.ui:180
 msgid "_View"
 msgstr "_Veure"
 
-#: src/ui/gui/data-editor.ui:189
+#: src/ui/gui/data-editor.ui:187
 msgid "_Status Bar"
 msgstr "Barra d'E_stat"
 
-#: src/ui/gui/data-editor.ui:195
-msgid "_Fonts"
-msgstr "_Fonts"
-
-#: src/ui/gui/data-editor.ui:203
+#: src/ui/gui/data-editor.ui:200
 msgid "_Grid Lines"
 msgstr "_Linies divisories"
 
-#: src/ui/gui/data-editor.ui:209
+#: src/ui/gui/data-editor.ui:206
 msgid "Value _Labels"
 msgstr "Etiquetes de _Valors"
 
-#: src/ui/gui/data-editor.ui:210
+#: src/ui/gui/data-editor.ui:207
 msgid "Show/hide value labels"
 msgstr "Mostra/Oculta etiquetes de valor"
 
-#: src/ui/gui/data-editor.ui:223 src/ui/gui/data-editor.ui:430
+#: src/ui/gui/data-editor.ui:220 src/ui/gui/data-editor.ui:440
 msgid "_Variables"
 msgstr "_Variables:"
 
-#: src/ui/gui/data-editor.ui:234
+#: src/ui/gui/data-editor.ui:231
 msgid "_Sort Cases"
 msgstr "_Ordenar Casos"
 
-#: src/ui/gui/data-editor.ui:237
-msgid "Sort cases in the active file"
-msgstr "Ordenar casos a l'arxiu actiu"
+#: src/ui/gui/data-editor.ui:234
+msgid "Sort cases in the active dataset"
+msgstr "Ordenar casos a l'arxiu de dades actiu"
 
-#: src/ui/gui/data-editor.ui:244
+#: src/ui/gui/data-editor.ui:241
 msgid "_Transpose"
 msgstr "_Transposar"
 
-#: src/ui/gui/data-editor.ui:245
+#: src/ui/gui/data-editor.ui:242
 msgid "Transpose the cases with the variables"
 msgstr "Transposar casos i variables"
 
-#: src/ui/gui/data-editor.ui:251
+#: src/ui/gui/data-editor.ui:249
+msgid "_Aggregate"
+msgstr "_Agregar"
+
+#: src/ui/gui/data-editor.ui:255
 msgid "S_plit File"
 msgstr "Divideix Arxiu"
 
-#: src/ui/gui/data-editor.ui:252
-msgid "Split the active file"
-msgstr "Dividir l'arxius actiu"
+#: src/ui/gui/data-editor.ui:256
+msgid "Split the active dataset"
+msgstr "Dividir l'arxiu de dades actiu"
 
-#: src/ui/gui/data-editor.ui:259
+#: src/ui/gui/data-editor.ui:263
 msgid "Select _Cases"
 msgstr "Seleccionar _Casos"
 
-#: src/ui/gui/data-editor.ui:265
+#: src/ui/gui/data-editor.ui:269
 msgid "_Weight Cases"
 msgstr "Pondera Cassos"
 
-#: src/ui/gui/data-editor.ui:266
+#: src/ui/gui/data-editor.ui:270
 msgid "Weight cases by variable"
 msgstr "Pondera casos per la variable"
 
-#: src/ui/gui/data-editor.ui:273
+#: src/ui/gui/data-editor.ui:277
 msgid "_Transform"
 msgstr "_Transformar"
 
-#: src/ui/gui/data-editor.ui:279
+#: src/ui/gui/data-editor.ui:283
 msgid "_Compute"
 msgstr "_Calcular"
 
-#: src/ui/gui/data-editor.ui:285
+#: src/ui/gui/data-editor.ui:289
 msgid "Ran_k Cases"
 msgstr "Rang de casos"
 
-#: src/ui/gui/data-editor.ui:291
+#: src/ui/gui/data-editor.ui:295
 msgid "Recode into _Same Variables"
 msgstr "Recodificar a les Mateixe_s Variables"
 
-#: src/ui/gui/data-editor.ui:297
+#: src/ui/gui/data-editor.ui:301
 msgid "Recode into _Different Variables"
 msgstr "Recodificar a variables _Diferents"
 
-#: src/ui/gui/data-editor.ui:303
+#: src/ui/gui/data-editor.ui:307
 msgid "_Run Pending Transforms"
 msgstr "Executa_r Transformacions pendents"
 
-#: src/ui/gui/data-editor.ui:310
+#: src/ui/gui/data-editor.ui:314
 msgid "_Analyze"
 msgstr "_Analitzar"
 
-#: src/ui/gui/data-editor.ui:316
+#: src/ui/gui/data-editor.ui:320
 msgid "_Descriptive Statistics"
 msgstr "Estadística _Descriptiva"
 
-#: src/ui/gui/data-editor.ui:322
+#: src/ui/gui/data-editor.ui:326
 msgid "_Frequencies"
 msgstr "_Freqüències"
 
-#: src/ui/gui/data-editor.ui:334
+#: src/ui/gui/data-editor.ui:338
 msgid "_Explore"
 msgstr "_Explorar"
 
-#: src/ui/gui/data-editor.ui:340
+#: src/ui/gui/data-editor.ui:344
 msgid "_Crosstabs"
 msgstr "_Creuaments tabulars"
 
-#: src/ui/gui/data-editor.ui:346
+#: src/ui/gui/data-editor.ui:350
 msgid "Compare _Means"
 msgstr "Comparar _Mitjanes"
 
-#: src/ui/gui/data-editor.ui:352
+#: src/ui/gui/data-editor.ui:356
 msgid "_One Sample T Test"
 msgstr "Prova T per una mostra"
 
-#: src/ui/gui/data-editor.ui:358
+#: src/ui/gui/data-editor.ui:362
 msgid "_Independent Samples T Test"
 msgstr "Prova T per mostres _Independents"
 
-#: src/ui/gui/data-editor.ui:364
+#: src/ui/gui/data-editor.ui:368
 msgid "_Paired Samples T Test"
 msgstr "Prova T per mostres A_parellades"
 
-#: src/ui/gui/data-editor.ui:370
+#: src/ui/gui/data-editor.ui:374
 msgid "One Way _ANOVA"
 msgstr "_ANOVA d'un factor"
 
-#: src/ui/gui/data-editor.ui:376
+#: src/ui/gui/data-editor.ui:380
 msgid "Bivariate _Correlation..."
 msgstr "_Correlació Bivariada..."
 
-#: src/ui/gui/data-editor.ui:382
+#: src/ui/gui/data-editor.ui:386
 msgid "Factor _Analysis"
 msgstr "_Anàlisi Factorial"
 
-#: src/ui/gui/data-editor.ui:388
+#: src/ui/gui/data-editor.ui:392
 msgid "Re_liability"
 msgstr "Fiabi_litat"
 
-#: src/ui/gui/data-editor.ui:394
+#: src/ui/gui/data-editor.ui:398
 msgid "Linear _Regression"
 msgstr "_Regressió Linear"
 
-#: src/ui/gui/data-editor.ui:400
+#: src/ui/gui/data-editor.ui:404
 msgid "_Non-Parametric Statistics"
 msgstr "Proves _No-Paramétriques"
 
-#: src/ui/gui/data-editor.ui:406
+#: src/ui/gui/data-editor.ui:410
 msgid "_Chi-Square"
 msgstr "_Chi-quadrat"
 
-#: src/ui/gui/data-editor.ui:412
+#: src/ui/gui/data-editor.ui:416
 msgid "_Binomial"
 msgstr "_Binomial"
 
-#: src/ui/gui/data-editor.ui:418
+#: src/ui/gui/data-editor.ui:422
+msgid "K Related _Samples"
+msgstr "K mostres aparellades"
+
+#: src/ui/gui/data-editor.ui:428
 msgid "ROC Cur_ve..."
 msgstr "Corba ROC..."
 
-#: src/ui/gui/data-editor.ui:424
+#: src/ui/gui/data-editor.ui:434
 msgid "_Utilities"
 msgstr "_Utilitats"
 
-#: src/ui/gui/data-editor.ui:431
+#: src/ui/gui/data-editor.ui:441
 msgid "Jump to variable"
 msgstr "Anar a la variable"
 
-#: src/ui/gui/data-editor.ui:438
+#: src/ui/gui/data-editor.ui:448
 msgid "Data File _Comments"
 msgstr "_Comentaris arxiu de dades"
 
-#: src/ui/gui/data-editor.ui:444 src/ui/gui/output-viewer.ui:40
-#: src/ui/gui/syntax-editor.ui:131
+#: src/ui/gui/data-editor.ui:454 src/ui/gui/output-viewer.ui:46
+#: src/ui/gui/syntax-editor.ui:135
 msgid "_Windows"
 msgstr "Finestres"
 
-#: src/ui/gui/data-editor.ui:450 src/ui/gui/output-viewer.ui:46
-#: src/ui/gui/syntax-editor.ui:137
+#: src/ui/gui/data-editor.ui:460 src/ui/gui/output-viewer.ui:52
+#: src/ui/gui/syntax-editor.ui:141
 msgid "_Minimize All Windows"
 msgstr "_Minimitza totes les finestres"
 
-#: src/ui/gui/data-editor.ui:456
+#: src/ui/gui/data-editor.ui:466
 msgid "_Split"
 msgstr "Divideix"
 
-#: src/ui/gui/data-editor.ui:630
+#: src/ui/gui/data-editor.ui:642
 msgid "Information Area"
 msgstr "Àrea d'Informació"
 
-#: src/ui/gui/data-editor.ui:652
+#: src/ui/gui/data-editor.ui:664
 msgid "Processor Area"
 msgstr "Area del processador"
 
-#: src/ui/gui/data-editor.ui:677
+#: src/ui/gui/data-editor.ui:689
 msgid "Case Counter Area"
 msgstr "Area del Recompte"
 
-#: src/ui/gui/data-editor.ui:702
+#: src/ui/gui/data-editor.ui:714
 msgid "Filter Use Status Area"
 msgstr "Area del Filtre"
 
-#: src/ui/gui/data-editor.ui:728
+#: src/ui/gui/data-editor.ui:740
 msgid "Weight Status Area"
 msgstr "Area de Ponderació"
 
-#: src/ui/gui/data-editor.ui:754
+#: src/ui/gui/data-editor.ui:766
 msgid "Split File Status Area"
 msgstr "Area de Divisió"
 
@@ -6690,26 +7113,248 @@ msgstr "Area de Divisió"
 msgid "_Export"
 msgstr "_Exportar"
 
-#: src/ui/gui/syntax-editor.ui:100
+#: src/ui/gui/syntax-editor.ui:104
 msgid "_Run"
 msgstr "Executa_r"
 
-#: src/ui/gui/syntax-editor.ui:106
+#: src/ui/gui/syntax-editor.ui:110
 msgid "All"
 msgstr "Tots"
 
-#: src/ui/gui/syntax-editor.ui:112
+#: src/ui/gui/syntax-editor.ui:116
 msgid "Selection"
 msgstr "Selecció"
 
-#: src/ui/gui/syntax-editor.ui:118
+#: src/ui/gui/syntax-editor.ui:122
 msgid "Current Line"
 msgstr "Linia actual"
 
-#: src/ui/gui/syntax-editor.ui:125
+#: src/ui/gui/syntax-editor.ui:129
 msgid "To End"
 msgstr "Fins al final"
 
+#~ msgid "Cannot create variable name from %s"
+#~ msgstr "No es pot crear el nom de la variable des de %s"
+
+#~ msgid "Duplicate variable name %s in position %d."
+#~ msgstr "Nom de la variable %s duplicat en la posició %d."
+
+#~ msgid "Recoded variable name duplicates an existing `%s' within system file."
+#~ msgstr "El nom de la variable recodificada duplica `%s' existent dins de l'arxiu de sistema."
+
+#~ msgid "Variable name begins with invalid character `%c'."
+#~ msgstr "El nom de la variable  comença amb el caràctar invàlid `%c'."
+
+#~ msgid "Duplicate variable name `%s' within system file."
+#~ msgstr "Nom de variable '%s' duplicat dins de l'arxiu de sistema."
+
+#~ msgid "Document line contains null byte."
+#~ msgstr "Una línia del document conté un byte nul."
+
+#~ msgid "Duplicate long variable name `%s' within system file."
+#~ msgstr "Nom de la variable llarga '%s' duplicat dins de l'arxiu de sistema."
+
+#~ msgid "Invalid number of labels: %d.  Ignoring labels."
+#~ msgstr "Nombre d'etiquetes invàlid: %d. Ignorant etiquetes."
+
+#~ msgid "Reading `%s': %s."
+#~ msgstr "Llegint `%s': %s."
+
+#~ msgid "Closing `%s': %s."
+#~ msgstr "Tancant `%s': %s."
+
+#~ msgid "%s does not form a valid number."
+#~ msgstr "%s no constitueix un número vàlid."
+
+#~ msgid "binary"
+#~ msgstr "binari"
+
+#~ msgid "octal"
+#~ msgstr "octal"
+
+#~ msgid "hex"
+#~ msgstr "hexadecimal"
+
+#~ msgid "Unexpected end of file in string concatenation."
+#~ msgstr "Final d'arxiu inesperat a la concatenació de cadenes."
+
+#~ msgid "incorrect use of TO convention"
+#~ msgstr "ús incorrecte de la convenció TO"
+
+#~ msgid "DO REPEAT without END REPEAT."
+#~ msgstr "DO REPEAT sense END REPEAT."
+
+#~ msgid "DO REPEAT may not nest in compatibility mode."
+#~ msgstr "DO REPEAT no pot usar-se recursivament en mode de comptabilitat."
+
+#~ msgid "%s is too long for a variable name."
+#~ msgstr "%s és massa llarg per un nom de variable."
+
+#~ msgid "%zu-byte string needed but %zu-byte string supplied."
+#~ msgstr "Es necessita cadena de %zu-byte però s'han subministrat de %zu-byte."
+
+#~ msgid "Hexadecimal floating constant too long."
+#~ msgstr "Constant hexadecimal flotant massa llarga."
+
+#~ msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
+#~ msgstr "conversió %s de %s desde %s a %s s'hauria d'haver produït %s però actualment ha produït %s."
+
+#~ msgid "Too many values in single command."
+#~ msgstr "Massa valors en el comandament únic."
+
+#~ msgid "Unexpected token: `%s'."
+#~ msgstr "Testimoni inesperat: `%s'."
+
+#~ msgid "Unable to open `%s': %s."
+#~ msgstr "No es pot obrir `%s': %s."
+
+#~ msgid "Multivariate analysis is not yet implemented"
+#~ msgstr "L'analisi multivariat encara no està implementat."
+
+#~ msgid "Tests of Between-Subjects Effects"
+#~ msgstr "Contraste de Efectos Inter-Sujetos"
+
+#~ msgid "Type %s Sum of Squares"
+#~ msgstr "Suma de Quadrats tipus %s"
+
+#~ msgid "Corrected Model"
+#~ msgstr "Model corregit"
+
+#~ msgid "Intercept"
+#~ msgstr "Constant"
+
+#~ msgid "Error"
+#~ msgstr "Error"
+
+#~ msgid "Corrected Total"
+#~ msgstr "Total Corregit"
+
+#~ msgid "Analyse"
+#~ msgstr "Analitzar"
+
+#~ msgid "column %d"
+#~ msgstr "columna %d"
+
+#~ msgid "columns %d-%d"
+#~ msgstr "columnes %d-%d"
+
+#~ msgid "%s field) "
+#~ msgstr "%s camp)"
+
+#~ msgid "%s: Creating temporary file: %s."
+#~ msgstr "%s: Creant arxiu temporal: %s"
+
+#~ msgid "%s: Creating file: %s."
+#~ msgstr "%s: Creant arxiu: %s"
+
+#~ msgid "Missing space following 'E' at offset %zu in MRSETS record"
+#~ msgstr "Espai perdut darrera 'E' en la possició %zu a registre MRSETS"
+
+#~ msgid "Syntax error %s at %s."
+#~ msgstr "Error de sintaxi %s a %s."
+
+#~ msgid "String exceeds 255 characters in length (%zu characters)."
+#~ msgstr "La cadena supera els 255 caràcters de longitud (%zu caràcters)."
+
+#~ msgid "expecting ATTRIBUTE= or DELETE="
+#~ msgstr "esperant ATTRIBUTE= o DELETE="
+
+#~ msgid "expecting `('"
+#~ msgstr "esperant `('"
+
+#~ msgid "String expected for variable label."
+#~ msgstr "S'espera una cadena com a etiqueta de variable."
+
+#~ msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
+#~ msgstr "Esperant BATCH o INTERACTIVE després de SYNTAX."
+
+#~ msgid "Expecting YES or NO after CD."
+#~ msgstr "Esperant YES o NO després del CD."
+
+#~ msgid "Expecting CONTINUE or STOP after ERROR."
+#~ msgstr "Esperant CONTINUE o bé STOP després de l'ERROR."
+
+#~ msgid "while expecting COLUMNWISE"
+#~ msgstr "mentrestant esperant COLUMNWISE"
+
+#~ msgid "expecting BREAK"
+#~ msgstr "esperant BREAK"
+
+#~ msgid "expecting `)'"
+#~ msgstr "esperant `)'"
+
+#~ msgid "Sig. 1-tailed"
+#~ msgstr "Sig. (1-cua)"
+
+#~ msgid "Error closing FLIP source file: %s."
+#~ msgstr "Error de tancament de l'arxiu de font FLIP: %s."
+
+#~ msgid "expecting FIXED or DELIMITED"
+#~ msgstr "esperant FIXED o DELIMITED"
+
+#~ msgid "expecting LINE or VARIABLES"
+#~ msgstr "esperant LINE o VARIABLES"
+
+#~ msgid "expecting VARIABLES"
+#~ msgstr "esperant VARIABLES"
+
+#~ msgid "expecting COMM or TAPE"
+#~ msgstr "esperant COMM o TAPE"
+
+#~ msgid "COLUMN subcommand multiply specified."
+#~ msgstr "subcomando COLUMN especificat múltiples vegades."
+
+#~ msgid "in expression"
+#~ msgstr "en l'expressió"
+
+#~ msgid "hash table:"
+#~ msgstr "taula hash:"
+
+#~ msgid "Warnings (%d) exceed limit (%d)."
+#~ msgstr "Avisos (%d) excedeixen el límit (%d)."
+
+#~ msgid "Errors (%d) exceed limit (%d)."
+#~ msgstr "Els errors (%d) excedeixen el límit (%d)."
+
+#~ msgid "Field content \"%.*s\" cannot be parsed in format %s."
+#~ msgstr "El contingut del camp \"%.*s\" no pot ser analitzat en format %s."
+
+#~ msgid "expecting BY"
+#~ msgstr "esperant BY"
+
+#~ msgid "Asymp. Sig. (2-sided)"
+#~ msgstr "Sig. Asimp. (2-cues)"
+
+#~ msgid "Exact Sig. (2-sided)"
+#~ msgstr "Sig. Exacta (2-cues)"
+
+#~ msgid "Exact Sig. (1-sided)"
+#~ msgstr "Sig. Exacta (1-cua)"
+
+#~ msgid "Multivariate GLM not yet supported"
+#~ msgstr "GLM multivariable encara no disponible"
+
+#~ msgid "Missing required subcommand TABLES."
+#~ msgstr "Falta subordre requerida TABLES"
+
+#~ msgid "TABLES subcommand may not appear more than once."
+#~ msgstr "El subcomando TABLES no pot apareixer més d'una vegada."
+
+#~ msgid "`%s' is not a variable name"
+#~ msgstr "`%s' no és un nom de variable"
+
+#~ msgid " cases"
+#~ msgstr " cassos"
+
+#~ msgid "Sort Ascending"
+#~ msgstr "Ordenació ascendent"
+
+#~ msgid "Sort Descending"
+#~ msgstr "Ordenació descendent"
+
+#~ msgid "_Fonts"
+#~ msgstr "_Fonts"
+
 #~ msgid "Buttons"
 #~ msgstr "Botons"
 
@@ -6800,9 +7445,6 @@ msgstr "Fins al final"
 #~ msgid "expected end of file"
 #~ msgstr "fi d'arxiu esperat"
 
-#~ msgid "syntax error expecting end of line"
-#~ msgstr "error de sintaxi en esperar el final de línia"
-
 #~ msgid "number out of valid range"
 #~ msgstr "número fora de l'interval vàlid"
 
@@ -6881,9 +7523,6 @@ msgstr "Fins al final"
 #~ msgid "reading \"%s\""
 #~ msgstr "llegint \"%s\""
 
-#~ msgid "syntax error"
-#~ msgstr "error de sintaxi"
-
 #~ msgid "error closing \"%s\""
 #~ msgstr "error en tancar \"%s\""
 
@@ -7095,9 +7734,6 @@ msgstr "Fins al final"
 #~ msgid "Import text data file"
 #~ msgstr "Importar arxiu de  text"
 
-#~ msgid "Save data to file"
-#~ msgstr "Desar dades a arxiu"
-
 #~ msgid "Select cases from the active file"
 #~ msgstr "Seleccionar cassos de l'arxiu actiu"
 
@@ -7248,6 +7884,3 @@ msgstr "Fins al final"
 
 #~ msgid "`/FORMAT WEIGHT' specified, but weighting is not on."
 #~ msgstr "`/FORMAT WEIGHT' especificat, però la ponderació no està activada."
-
-#~ msgid "Line"
-#~ msgstr "Linea"
index e45dbf14a8277ae61da33bb7ca19c85d6d11aec0..d32753099d0e3bb53e159e829261dc201c23826a 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.7.6\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2010-10-17 16:50+0200\n"
+"POT-Creation-Date: 2010-10-23 10:53+0200\n"
 "PO-Revision-Date: 2010-10-17 16:51+0200\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -504,7 +504,7 @@ msgstr ""
 #: src/data/por-file-reader.c:543
 #, c-format
 msgid "Unrecognized version code `%c'."
-msgstr "Unrecognised version code `%c'."
+msgstr "Unrecognised version code ‘%c’."
 
 #: src/data/por-file-reader.c:552
 #, c-format
@@ -807,6 +807,8 @@ msgid ""
 "Unrecognized record type 7, subtype %d.  Please send a copy of this file, "
 "and the syntax which created it to %s"
 msgstr ""
+"Unrecognised record type 7, subtype %d.  Please send a copy of this file, "
+"and the syntax which created it to %s"
 
 #: src/data/sys-file-reader.c:919 tests/dissect-sysfile.c:595
 #, c-format
@@ -1284,7 +1286,7 @@ msgid "Syntax error at `%s'"
 msgstr "Syntax error at ‘%s’"
 
 #: src/language/lexer/lexer.c:457 src/language/xforms/select-if.c:60
-#: src/language/stats/autorecode.c:161 src/language/stats/npar.c:310
+#: src/language/stats/autorecode.c:161 src/language/stats/npar.c:350
 #: src/language/data-io/print-space.c:73
 msgid "expecting end of command"
 msgstr ""
@@ -1344,18 +1346,18 @@ msgstr ""
 msgid "String expected following `+'."
 msgstr "String expected following ‘+’."
 
-#: src/language/lexer/format-parser.c:88
+#: src/language/lexer/format-parser.c:79
 msgid "expecting valid format specifier"
 msgstr ""
 
-#: src/language/lexer/format-parser.c:107
-#: src/language/lexer/format-parser.c:126
+#: src/language/lexer/format-parser.c:118
+#: src/language/lexer/format-parser.c:138
 #: src/language/data-io/placement-parser.c:226
 #, c-format
 msgid "Unknown format type `%s'."
 msgstr "Unknown format type ‘%s’."
 
-#: src/language/lexer/format-parser.c:121
+#: src/language/lexer/format-parser.c:133
 msgid "expecting format type"
 msgstr ""
 
@@ -1737,7 +1739,7 @@ msgstr ""
 #: src/language/dictionary/modify-variables.c:301
 #, c-format
 msgid "Unrecognized subcommand name `%s'."
-msgstr "Unrecognised subcommand name `%s'."
+msgstr "Unrecognised subcommand name ‘%s’."
 
 #: src/language/dictionary/modify-variables.c:303
 msgid "Subcommand name expected."
@@ -2491,7 +2493,7 @@ msgid "Category"
 msgstr ""
 
 #: src/language/stats/binomial.c:256 src/language/stats/correlations.c:119
-#: src/language/stats/correlations.c:227
+#: src/language/stats/correlations.c:227 src/language/stats/friedman.c:260
 #: src/language/stats/kruskal-wallis.c:259
 #: src/language/stats/npar-summary.c:120 src/language/stats/oneway.c:692
 #: src/language/stats/reliability.c:541 src/language/stats/sign.c:72
@@ -2541,24 +2543,28 @@ msgstr ""
 msgid "Frequencies"
 msgstr ""
 
-#: src/language/stats/chisquare.c:249 src/language/stats/kruskal-wallis.c:312
-#: src/language/stats/sign.c:112 src/language/stats/wilcoxon.c:304
+#: src/language/stats/chisquare.c:249 src/language/stats/friedman.c:257
+#: src/language/stats/kruskal-wallis.c:312 src/language/stats/sign.c:112
+#: src/language/stats/wilcoxon.c:304
 msgid "Test Statistics"
 msgstr ""
 
-#: src/language/stats/chisquare.c:263 src/language/stats/kruskal-wallis.c:315
+#: src/language/stats/chisquare.c:263 src/language/stats/friedman.c:263
+#: src/language/stats/kruskal-wallis.c:315
 msgid "Chi-Square"
 msgstr ""
 
-#: src/language/stats/chisquare.c:264 src/language/stats/glm.c:308
-#: src/language/stats/kruskal-wallis.c:318 src/language/stats/oneway.c:599
-#: src/language/stats/oneway.c:1008 src/language/stats/crosstabs.q:1207
-#: src/language/stats/regression.q:284 src/language/stats/t-test.q:752
-#: src/language/stats/t-test.q:923 src/language/stats/t-test.q:1010
+#: src/language/stats/chisquare.c:264 src/language/stats/friedman.c:266
+#: src/language/stats/glm.c:308 src/language/stats/kruskal-wallis.c:318
+#: src/language/stats/oneway.c:599 src/language/stats/oneway.c:1008
+#: src/language/stats/crosstabs.q:1207 src/language/stats/regression.q:284
+#: src/language/stats/t-test.q:752 src/language/stats/t-test.q:923
+#: src/language/stats/t-test.q:1010
 msgid "df"
 msgstr ""
 
-#: src/language/stats/chisquare.c:265 src/language/stats/kruskal-wallis.c:321
+#: src/language/stats/chisquare.c:265 src/language/stats/friedman.c:269
+#: src/language/stats/kruskal-wallis.c:321
 msgid "Asymp. Sig."
 msgstr ""
 
@@ -2832,6 +2838,16 @@ msgstr ""
 msgid "Rotated Factor Matrix"
 msgstr ""
 
+#: src/language/stats/friedman.c:214 src/language/stats/kruskal-wallis.c:244
+#: src/language/stats/wilcoxon.c:225
+msgid "Ranks"
+msgstr ""
+
+#: src/language/stats/friedman.c:225 src/language/stats/kruskal-wallis.c:258
+#: src/language/stats/wilcoxon.c:239
+msgid "Mean Rank"
+msgstr ""
+
 #: src/language/stats/flip.c:98
 msgid ""
 "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
@@ -2928,37 +2944,33 @@ msgstr ""
 msgid "Corrected Total"
 msgstr ""
 
-#: src/language/stats/kruskal-wallis.c:244 src/language/stats/wilcoxon.c:225
-msgid "Ranks"
-msgstr ""
-
-#: src/language/stats/kruskal-wallis.c:258 src/language/stats/wilcoxon.c:239
-msgid "Mean Rank"
-msgstr ""
-
-#: src/language/stats/npar.c:233 src/language/stats/npar.c:260
+#: src/language/stats/npar.c:273 src/language/stats/npar.c:300
 #, c-format
 msgid "The %s subcommand may be given only once."
 msgstr ""
 
-#: src/language/stats/npar.c:343
+#: src/language/stats/npar.c:383
 msgid "NPAR subcommand not currently implemented."
 msgstr ""
 
-#: src/language/stats/npar.c:496
+#: src/language/stats/npar.c:537
+msgid "Expecting MEAN, MEDIAN, MODE or number"
+msgstr ""
+
+#: src/language/stats/npar.c:624
 #, c-format
 msgid ""
 "The specified value of HI (%d) is lower than the specified value of LO (%d)"
 msgstr ""
 
-#: src/language/stats/npar.c:551
+#: src/language/stats/npar.c:679
 #, c-format
 msgid ""
 "%d expected values were given, but the specified range (%d-%d) requires "
 "exactly %d values."
 msgstr ""
 
-#: src/language/stats/npar.c:690 src/language/stats/t-test.q:380
+#: src/language/stats/npar.c:818 src/language/stats/t-test.q:380
 #, c-format
 msgid ""
 "PAIRED was specified but the number of variables preceding WITH (%zu) did "
@@ -3086,7 +3098,7 @@ msgid "Does not assume equal"
 msgstr ""
 
 #: src/language/stats/reliability.c:146
-msgid "Reliabilty on a single variable is not useful."
+msgid "Reliability on a single variable is not useful."
 msgstr ""
 
 #: src/language/stats/reliability.c:506 src/language/stats/examine.q:1159
@@ -3251,6 +3263,58 @@ msgstr ""
 msgid "1 - Specificity"
 msgstr ""
 
+#: src/language/stats/runs.c:168
+#, c-format
+msgid ""
+"Multiple modes exist for varible `%s'.  Using %g as the threshold value."
+msgstr ""
+"Multiple modes exist for varible ‘%s’.  Using %g as the threshold value."
+
+#: src/language/stats/runs.c:324
+msgid "Runs Test"
+msgstr ""
+
+#: src/language/stats/runs.c:369
+msgid "Test Value"
+msgstr ""
+
+#: src/language/stats/runs.c:373
+msgid "Test Value (mode)"
+msgstr ""
+
+#: src/language/stats/runs.c:377
+msgid "Test Value (mean)"
+msgstr ""
+
+#: src/language/stats/runs.c:381
+msgid "Test Value (median)"
+msgstr ""
+
+#: src/language/stats/runs.c:386
+msgid "Cases < Test Value"
+msgstr ""
+
+#: src/language/stats/runs.c:389
+msgid "Cases >= Test Value"
+msgstr "Cases ≥ Test Value"
+
+#: src/language/stats/runs.c:392
+msgid "Total Cases"
+msgstr ""
+
+#: src/language/stats/runs.c:395
+msgid "Number of Runs"
+msgstr ""
+
+#: src/language/stats/runs.c:398 src/language/stats/wilcoxon.c:317
+msgid "Z"
+msgstr ""
+
+#: src/language/stats/runs.c:401 src/language/stats/wilcoxon.c:318
+#: src/language/stats/crosstabs.q:1209
+msgid "Asymp. Sig. (2-tailed)"
+msgstr ""
+
 #: src/language/stats/sign.c:90
 msgid "Negative Differences"
 msgstr ""
@@ -3304,14 +3368,6 @@ msgstr ""
 msgid "Positive Ranks"
 msgstr ""
 
-#: src/language/stats/wilcoxon.c:317
-msgid "Z"
-msgstr ""
-
-#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1209
-msgid "Asymp. Sig. (2-tailed)"
-msgstr ""
-
 #: src/language/data-io/combine-files.c:210
 msgid "Cannot specify the active file since no active file has been defined."
 msgstr ""
@@ -3509,8 +3565,8 @@ msgstr "Could not open ‘%s’ for reading as a data file: %s."
 #: src/language/data-io/data-reader.c:191
 msgid ""
 "Unexpected end-of-file while reading data in BEGIN DATA.  This probably "
-"indicates a missing or misformatted END DATA command.  END DATA must appear "
-"by itself on a single line with exactly one space between words."
+"indicates a missing or miss-formatted END DATA command.  END DATA must "
+"appear by itself on a single line with exactly one space between words."
 msgstr ""
 
 #: src/language/data-io/data-reader.c:216
@@ -3725,7 +3781,7 @@ msgid ""
 "variables on right side (%zu), in parenthesized group %d of RENAME "
 "subcommand."
 msgstr ""
-"Number of variables on left side of `=' (%zu) does not match number of \n"
+"Number of variables on left side of ‘=’ (%zu) does not match number of \n"
 "variables on right side (%zu), in parenthesised group %d of RENAME \n"
 "subcommand."
 
@@ -3791,8 +3847,8 @@ msgid ""
 "Unrecognized date unit `%.*s'.  Valid date units are `years', `quarters', "
 "`months', `weeks', `days', `hours', `minutes', and `seconds'."
 msgstr ""
-"Unrecognised date unit `%.*s'.  Valid date units are `years', `quarters', "
-"`months', `weeks', `days', `hours', `minutes', and `seconds'."
+"Unrecognised date unit ‘%.*s’.  Valid date units are ‘years’, ‘quarters’, "
+"‘months’, ‘weeks’, ‘days’, ‘hours’, ‘minutes’, and ‘seconds’."
 
 #: src/language/expressions/helpers.c:327
 msgid "Invalid DATESUM method.  Valid choices are `closest' and `rollover'."
@@ -4999,8 +5055,8 @@ msgstr ""
 
 #: src/language/utilities/set.q:405
 #, c-format
-msgid "%s is not a recognised encoding or locale name"
-msgstr ""
+msgid "%s is not a recognized encoding or locale name"
+msgstr "%s is not a recognised encoding or locale name"
 
 #: src/language/utilities/set.q:467
 msgid "WIDTH must be at least 40."
@@ -6054,11 +6110,11 @@ msgid "Covariance matrix"
 msgstr ""
 
 #: src/ui/gui/factor.ui:308
-msgid "Analyse"
-msgstr ""
+msgid "Analyze"
+msgstr "Analyse"
 
 #: src/ui/gui/factor.ui:332
-msgid "Unrotatated factor solution"
+msgid "Unrotated factor solution"
 msgstr ""
 
 #: src/ui/gui/factor.ui:346
index e4d1e2a6213934a5c900d9710893b7ce322b543d..a7ff31ba0b36e68ab477e1153686117ab88d5a08 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -5,21 +5,25 @@
 # Palmira Payá Sanchez, 2009.
 # Javier Gómez Serrano, 2009.
 # Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>, 2010.
-#
-#
+# Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>, 2011.
 msgid ""
 msgstr ""
-"Project-Id-Version: pspp-0.7.5\n"
+"Project-Id-Version: pspp-0.7.7\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2010-05-21 16:40-0700\n"
-"PO-Revision-Date: 2010-10-13 13:30+0200\n"
+"POT-Creation-Date: 2011-03-24 20:36-0700\n"
+"PO-Revision-Date: 2011-05-03 01:49+0200\n"
 "Last-Translator: Francesc Josep Miguel Quesada <Miguel.Quesada@uab.cat>\n"
 "Language-Team: Spanish <es@li.org>\n"
+"Language: es\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms:  nplurals=2; plural=(n != 1);\n"
 
+#: src/ui/gui/helper.c:194
+msgid "Sorry. The help system hasn't yet been implemented."
+msgstr "Disculpas. El sistema de ayuda todavía no ha sido implementado."
+
 #: src/ui/gui/psppire-buttonbox.c:275 src/ui/gui/psppire-buttonbox.c:437
 msgid "Continue"
 msgstr "Continuar"
@@ -49,12 +53,12 @@ msgid "Paste"
 msgstr "Pegar"
 
 #: src/ui/gui/psppire-dictview.c:466 src/language/dictionary/split-file.c:82
-#: src/language/dictionary/sys-file-info.c:150
-#: src/language/dictionary/sys-file-info.c:340
-#: src/language/dictionary/sys-file-info.c:664
-#: src/language/stats/descriptives.c:881
-#: src/language/data-io/data-parser.c:649
-#: src/language/data-io/data-parser.c:688 src/language/data-io/print.c:403
+#: src/language/dictionary/sys-file-info.c:149
+#: src/language/dictionary/sys-file-info.c:334
+#: src/language/dictionary/sys-file-info.c:658
+#: src/language/stats/descriptives.c:895
+#: src/language/data-io/data-parser.c:683
+#: src/language/data-io/data-parser.c:722 src/language/data-io/print.c:403
 msgid "Variable"
 msgstr "Variable"
 
@@ -67,31 +71,31 @@ msgstr "Prefiero las etiquetas de variable"
 msgid "Var%d"
 msgstr "Var%d"
 
-#: src/data/any-reader.c:56
+#: src/data/any-reader.c:60
 #, c-format
-msgid "An error occurred while opening \"%s\": %s."
-msgstr "Se ha producido un error en abrir \"%s\": %s."
+msgid "An error occurred while opening `%s': %s."
+msgstr "Se ha producido un error al abrir `%s': %s."
 
-#: src/data/any-reader.c:101
+#: src/data/any-reader.c:105
 #, c-format
-msgid "\"%s\" is not a system or portable file."
-msgstr "\"%s\" no es un archivo del sistema o portátil."
+msgid "`%s' is not a system or portable file."
+msgstr "`%s' no es un archivo del sistema o portátil."
 
-#: src/data/any-reader.c:107 src/data/any-writer.c:63
+#: src/data/any-reader.c:111 src/data/any-writer.c:67
 msgid "The inline file is not allowed here."
 msgstr "El archivo en línea no está permitido aquí."
 
-#: src/data/calendar.c:81
+#: src/data/calendar.c:100
 #, c-format
 msgid "Month %d is not in acceptable range of 0 to 13."
 msgstr "El mes %d no está en el intervalo válido de 0 a 13."
 
-#: src/data/calendar.c:89
+#: src/data/calendar.c:110
 #, c-format
 msgid "Day %d is not in acceptable range of 0 to 31."
 msgstr "El día %d no está en el intervalo válido de 0 a 31."
 
-#: src/data/calendar.c:96
+#: src/data/calendar.c:119
 #, c-format
 msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
 msgstr "La fecha %04d-%d-%d es anterior a la fecha aceptada más antigua, 1582-10-15."
@@ -100,127 +104,141 @@ msgstr "La fecha %04d-%d-%d es anterior a la fecha aceptada más antigua, 1582-1
 msgid "At least one case in the data read had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
 msgstr "Al menos un caso en la lectura de datos tenia un valor de ponderación que es perdido del usuari, del sistema, cero o negativo. Este(os) caso(s) fueron ignorado(s)."
 
-#: src/data/data-in.c:274 src/data/data-in.c:464
+#. TRANSLATORS: this fragment will be interpolated into messages in fh_lock()
+#. that identify types of files.
+#: src/data/csv-file-writer.c:154
+msgid "CSV file"
+msgstr "archivo CSV"
+
+#: src/data/csv-file-writer.c:163 src/data/sys-file-writer.c:219
+#, c-format
+msgid "Error opening `%s' for writing as a system file: %s."
+msgstr "Error al abrir `%s' para grabar como archivo de sistema: %s."
+
+#: src/data/csv-file-writer.c:464
+#, c-format
+msgid "An I/O error occurred writing CSV file `%s'."
+msgstr "Error de E/S al guardar el archivo de sistema `%s'."
+
+#: src/data/data-in.c:171
+#, c-format
+msgid "Data is not valid as format %s: %s"
+msgstr "Los datos no son válidos como formato %s: %s."
+
+#: src/data/data-in.c:376 src/data/data-in.c:552
 msgid "Field contents are not numeric."
 msgstr "El contenido del campo no es numérico."
 
-#: src/data/data-in.c:276 src/data/data-in.c:466
+#: src/data/data-in.c:378 src/data/data-in.c:554
 msgid "Number followed by garbage."
 msgstr "Número seguido por desecho."
 
-#: src/data/data-in.c:287
+#: src/data/data-in.c:391
 msgid "Invalid numeric syntax."
 msgstr "Sintaxis numérica no válida."
 
-#: src/data/data-in.c:296 src/data/data-in.c:479
+#: src/data/data-in.c:399 src/data/data-in.c:570
 msgid "Too-large number set to system-missing."
 msgstr "Número demasiado grande definido como perdido del sistema."
 
-#: src/data/data-in.c:301 src/data/data-in.c:484
+#: src/data/data-in.c:405 src/data/data-in.c:576
 msgid "Too-small number set to zero."
 msgstr "Número demasiado pequeño definido como cero."
 
-#: src/data/data-in.c:327
+#: src/data/data-in.c:425
 msgid "All characters in field must be digits."
 msgstr "Todos los carácteres del campo tienen que ser dígitos."
 
-#: src/data/data-in.c:350
+#: src/data/data-in.c:444
 msgid "Unrecognized character in field."
 msgstr "Carácter no reconocido en el campo."
 
-#: src/data/data-in.c:374 src/data/data-in.c:650
+#: src/data/data-in.c:465 src/data/data-in.c:728
 msgid "Field must have even length."
 msgstr "Campo debe tener la anchura divisible por 2 (par)."
 
-#: src/data/data-in.c:379 src/data/data-in.c:661
+#: src/data/data-in.c:467 src/data/data-in.c:731
 msgid "Field must contain only hex digits."
 msgstr "Campo debe contener únicamente dígitos hexadecimales."
 
-#: src/data/data-in.c:700 src/data/data-in.c:747
+#: src/data/data-in.c:543
+msgid "Invalid zoned decimal syntax."
+msgstr "Sintaxis decimal no válida."
+
+#: src/data/data-in.c:643 src/data/data-in.c:649
+msgid "Invalid syntax for P field."
+msgstr "Sintaxis numérica no válida para campo P."
+
+#: src/data/data-in.c:767 src/data/data-in.c:813
 msgid "Syntax error in date field."
 msgstr "Error sintáctico en el campo de datos."
 
-#: src/data/data-in.c:716
+#: src/data/data-in.c:782
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr "Día (%ld) debe estar entre 1 y 31."
 
-#: src/data/data-in.c:763
+#: src/data/data-in.c:827
 msgid "Delimiter expected between fields in date."
 msgstr "En la fecha se espera un delimitador entre los campos."
 
-#: src/data/data-in.c:837
+#: src/data/data-in.c:901
 msgid "Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names."
 msgstr "Formato de mes no reconocido. Los meses pueden ser especificados como números Arábicos o Romanos, o como mínimo 3 letras de sus nombres en Inglés."
 
-#: src/data/data-in.c:864
+#: src/data/data-in.c:928
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr "Año (%ld) debe estar entre 1582 y 19999."
 
-#: src/data/data-in.c:876
+#: src/data/data-in.c:939
 #, c-format
-msgid "Trailing garbage \"%.*s\" following date."
-msgstr "Basura \"%.*s\" detrás de la fecha."
+msgid "Trailing garbage `%.*s' following date."
+msgstr "Basura `%.*s' detrás de la fecha."
 
-#: src/data/data-in.c:892
+#: src/data/data-in.c:953
 msgid "Julian day must have exactly three digits."
 msgstr "Un Día Juliano debe tener exactamente tres dígitos."
 
-#: src/data/data-in.c:897
+#: src/data/data-in.c:955
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr "El Día Juliano (%ld) debe estar entre 1 y 366."
 
-#: src/data/data-in.c:921
+#: src/data/data-in.c:979
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr "Trimestre (%ld) debe estar entre 1 y 4."
 
-#: src/data/data-in.c:941
+#: src/data/data-in.c:1000
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr "Semana (%ld) debe estar entre 1 y 53."
 
-#: src/data/data-in.c:954
+#: src/data/data-in.c:1012
 msgid "Delimiter expected between fields in time."
 msgstr "Se espera un delimitador entre campos de tiempo."
 
-#: src/data/data-in.c:974
+#: src/data/data-in.c:1032
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr "Minuto (%ld) debe estar entre 0 y 59."
 
-#: src/data/data-in.c:1014
+#: src/data/data-in.c:1070
 msgid "Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified."
 msgstr "Día de la semana no reconocido. Al menos se deben especificar las dos primeras letras del nombre en inglés."
 
-#: src/data/data-in.c:1152
+#: src/data/data-in.c:1196
 #, c-format
 msgid "`%c' expected in date field."
 msgstr "Se espera `%c' en un campo de datos."
 
-#: src/data/data-in.c:1193
-#, c-format
-msgid "column %d"
-msgstr "columna %d"
-
-#: src/data/data-in.c:1195
-#, c-format
-msgid "columns %d-%d"
-msgstr "columnas %d-%d"
-
-#: src/data/data-in.c:1199
-#, c-format
-msgid "%s field) "
-msgstr "%s campo)"
-
-#: src/data/data-out.c:481
+#: src/data/data-out.c:546
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr "Número del día de la semana %f no está entre 1 y 7."
 
-#: src/data/data-out.c:502
+#: src/data/data-out.c:571
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr "Número del mes %f no está entre 1 y 12."
@@ -235,28 +253,28 @@ msgstr "sistema"
 
 #: src/data/dict-class.c:56
 msgid "scratch"
-msgstr "cero"
+msgstr "borrador"
 
-#: src/data/dictionary.c:980
+#: src/data/dictionary.c:1007
 msgid "At least one case in the data file had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
 msgstr "Al menos un caso del archivo de datos tenía un valor de ponderación perdido de usuario, de sistema, cero o negativo. Estos caso(s) fueron ignorado(s)."
 
-#: src/data/dictionary.c:1283
+#: src/data/dictionary.c:1333
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr "Linea de documento truncada a  %d bytes."
 
-#: src/data/file-handle-def.c:462
+#: src/data/file-handle-def.c:469
 #, c-format
 msgid "Can't read from %s as a %s because it is already being read as a %s."
 msgstr "No se puede leer de %s como una %s porque ya esta siendo leída como una %s."
 
-#: src/data/file-handle-def.c:466
+#: src/data/file-handle-def.c:473
 #, c-format
 msgid "Can't write to %s as a %s because it is already being written as a %s."
 msgstr "No se puede escribir en %s como una %s porque ya esta siendo escrita como una %s."
 
-#: src/data/file-handle-def.c:473
+#: src/data/file-handle-def.c:480
 #, c-format
 msgid "Can't re-open %s as a %s."
 msgstr "No se puede re-abrir %s como %s."
@@ -266,86 +284,86 @@ msgstr "No se puede re-abrir %s como %s."
 msgid "Not opening pipe file `%s' because SAFER option set."
 msgstr "No abrir el archivo de transferencia '%s' porque la opción SAFER esta activada."
 
-#: src/data/format.c:235
+#: src/data/format.c:320
 msgid "Input format"
 msgstr "Formato de entrada"
 
-#: src/data/format.c:235
+#: src/data/format.c:320
 msgid "Output format"
 msgstr "Formato de salida"
 
-#: src/data/format.c:244
+#: src/data/format.c:329
 #, c-format
 msgid "Format %s may not be used for input."
 msgstr "Formato %s no puede ser utilizado como entrada."
 
-#: src/data/format.c:251
+#: src/data/format.c:336
 #, c-format
 msgid "%s specifies width %d, but %s requires an even width."
 msgstr "%s especifica %d anchura, pero %s requiere una anchura par."
 
-#: src/data/format.c:260
+#: src/data/format.c:345
 #, c-format
 msgid "%s %s specifies width %d, but %s requires a width between %d and %d."
 msgstr "%s %s especifica anchura %d, pero %s requiere una anchura entre %d y %d."
 
-#: src/data/format.c:269
+#: src/data/format.c:354
 #, c-format
 msgid "%s %s specifies %d decimal place, but %s does not allow any decimals."
 msgid_plural "%s %s specifies %d decimal places, but %s does not allow any decimals."
 msgstr[0] "%s %s especifica %d lugar decimal, pero %s no permite ninguno."
 msgstr[1] "%s %s especifica %d lugares decimales, pero %s no permite ninguno."
 
-#: src/data/format.c:280
+#: src/data/format.c:365
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width allows at most %d decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width allows at most %d decimals."
 msgstr[0] "%s %s especifica %d lugar decimal, pero la anchura dada permite como mucho %d decimales."
 msgstr[1] "%s %s especifica %d lugares decimales, pero la anchura dada permite como mucho %d decimales."
 
-#: src/data/format.c:287
+#: src/data/format.c:372
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width does not allow for any decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width does not allow for any decimals."
 msgstr[0] "%s %s especifica %d lugar decimal, pero la anchura dada no permite ninguno."
 msgstr[1] "%s %s especifica %d lugares decimales, pero la anchura dada no permite ninguno."
 
-#: src/data/format.c:326
+#: src/data/format.c:411
 #, c-format
 msgid "%s variables are not compatible with %s format %s."
 msgstr "Las variables %s no son compatibles con %s formato %s."
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:752
-#: src/ui/gui/psppire-var-store.c:628 src/ui/gui/psppire.ui:1960
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:629 src/ui/gui/compute.ui:503
 #: src/ui/gui/var-sheet-dialogs.ui:139
 msgid "String"
 msgstr "Cadena"
 
-#: src/data/format.c:327 src/data/sys-file-reader.c:752
-#: src/ui/gui/psppire-var-store.c:621 src/ui/gui/psppire.ui:2040
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/compute.ui:584
 #: src/ui/gui/var-sheet-dialogs.ui:27
 msgid "Numeric"
 msgstr "Numérico"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:493
-#: src/language/xforms/recode.c:494 src/language/xforms/recode.c:506
-#: src/language/xforms/recode.c:507
+#: src/data/format.c:413 src/data/sys-file-reader.c:1663
+#: src/data/sys-file-reader.c:1665 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
-#: src/language/dictionary/apply-dictionary.c:79
 msgid "numeric"
 msgstr "numérico"
 
-#: src/data/format.c:328 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:493
-#: src/language/xforms/recode.c:494 src/language/xforms/recode.c:506
-#: src/language/xforms/recode.c:507
+#: src/data/format.c:413 src/data/sys-file-reader.c:1663
+#: src/data/sys-file-reader.c:1665 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
-#: src/language/dictionary/apply-dictionary.c:79
 msgid "string"
 msgstr "cadena"
 
-#: src/data/format.c:346
+#: src/data/format.c:431
 #, c-format
 msgid "String variable with width %d is not compatible with format %s."
 msgstr "Variable de cadena con ancho %d no es compatible con el formato %s."
@@ -354,259 +372,273 @@ msgstr "Variable de cadena con ancho %d no es compatible con el formato %s."
 msgid "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr "Soporte para archivos Gnumeric no fue compilado en esta instalación de PSPP"
 
-#: src/data/gnumeric-reader.c:364
+#: src/data/gnumeric-reader.c:363
+#, c-format
+msgid "Error opening `%s' for reading as a Gnumeric file: %s."
+msgstr "Error al abrir `%s' para la lectura como archivo Gnumeric: %s."
+
+#: src/data/gnumeric-reader.c:383
+#, c-format
+msgid "Invalid cell range `%s'"
+msgstr "Intervalo de celda `%s' inválido"
+
+#: src/data/gnumeric-reader.c:522
 #, c-format
-msgid "Error opening \"%s\" for reading as a Gnumeric file: %s."
-msgstr "Error en abrir \"%s\" para la lectura como archivo Gnumeric: %s."
+msgid "Selected sheet or range of spreadsheet `%s' is empty."
+msgstr "La hoja o el intervalo de hojas de cálculo seleccionadas `%s' está vacía."
 
-#: src/data/gnumeric-reader.c:384
+#: src/data/identifier2.c:60
 #, c-format
-msgid "Invalid cell range \"%s\""
-msgstr "Intervalo de celda \"%s\" inválido"
+msgid "Identifier `%s' exceeds %d-byte limit."
+msgstr "El identificador `%s' supera el límite de %d-bytes."
+
+#: src/data/identifier2.c:84
+msgid "Identifier cannot be empty string."
+msgstr "El identificador no puede ser una cadena vacía."
 
-#: src/data/gnumeric-reader.c:516 src/data/psql-reader.c:187
+#: src/data/identifier2.c:92
 #, c-format
-msgid "Cannot create variable name from %s"
-msgstr "No se puede crear el nombre de la variable desde %s"
+msgid "`%s' may not be used as an identifier because it is a reserved word."
+msgstr "`%s' no puede ser utilizado como identificador porque es una palabra reservada."
 
-#: src/data/gnumeric-reader.c:528
+#: src/data/identifier2.c:103
 #, c-format
-msgid "Selected sheet or range of spreadsheet \"%s\" is empty."
-msgstr "La hoja o el intervalo de hojas de cálculo seleccionadas \"%s\" está vacía."
+msgid "`%s' may not be used as an identifier because it contains ill-formed UTF-8 at byte offset %tu."
+msgstr "`%s' no puede ser utilizado como identificador porque contiene UTF-8 malformado en la posición %tu."
 
-#: src/data/make-file.c:68
+#: src/data/identifier2.c:114
 #, c-format
-msgid "%s: Creating temporary file: %s."
-msgstr "%s: Creando archivo temporal: %s."
+msgid "Character %s (in `%s') may not appear as the first character in a identifier."
+msgstr "Carácter %s (en `%s') no puede aparecer como el primer carácter en un identificador."
 
-#: src/data/make-file.c:110
+#: src/data/identifier2.c:126
 #, c-format
-msgid "%s: Creating file: %s."
-msgstr "%s: Creando archivo: %s."
+msgid "Character %s (in `%s') may not appear in an identifier."
+msgstr "El carácter %s (en `%s') no puede aparecer en un identificador."
 
-#: src/data/make-file.c:148
+#: src/data/make-file.c:71
 #, c-format
 msgid "Opening %s for writing: %s."
 msgstr "Abriendo %s para escribir: %s."
 
-#: src/data/make-file.c:157
+#: src/data/make-file.c:80
 #, c-format
 msgid "Opening stream for %s: %s."
 msgstr "Abriendo flujo para %s: %s."
 
-#: src/data/make-file.c:186
+#: src/data/make-file.c:109
 #, c-format
 msgid "Creating temporary file to replace %s: %s."
 msgstr "Creando archivo temporal para sustituir %s: %s."
 
-#: src/data/make-file.c:197
+#: src/data/make-file.c:120
 #, c-format
 msgid "Creating temporary file %s: %s."
 msgstr "Creando archivo temporal %s: %s."
 
-#: src/data/make-file.c:209
+#: src/data/make-file.c:132
 #, c-format
 msgid "Opening stream for temporary file %s: %s."
 msgstr "Abriendo flujo para el archivo temporal %s: %s."
 
-#: src/data/make-file.c:250
+#: src/data/make-file.c:173
 #, c-format
 msgid "Replacing %s by %s: %s."
 msgstr "Sustituyendo %s por %s: %s."
 
-#: src/data/make-file.c:278
+#: src/data/make-file.c:201
 #, c-format
 msgid "Removing %s: %s."
 msgstr "Eliminando %s: %s."
 
-#: src/data/por-file-reader.c:99
+#: src/data/mrset.c:83
+#, c-format
+msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
+msgstr "%s no es un nombre válido de variable para un conjunto de respuesta múltiple. Los conjuntos de respuesta múltiple han de comenzar con `$'."
+
+#: src/data/por-file-reader.c:100
 #, c-format
 msgid "portable file %s corrupt at offset 0x%llx: "
 msgstr "el archivo portátil %s está corrupto en la posición 0x%llx: "
 
-#: src/data/por-file-reader.c:128
+#: src/data/por-file-reader.c:132
 #, c-format
 msgid "reading portable file %s at offset 0x%llx: "
 msgstr "leyendo el archivo portátil %s en la posición 0x%llx: "
 
-#: src/data/por-file-reader.c:156
+#: src/data/por-file-reader.c:163
 #, c-format
-msgid "Error closing portable file \"%s\": %s."
-msgstr "Error en cerrar el archivo portátil \"%s\": %s."
+msgid "Error closing portable file `%s': %s."
+msgstr "Error cerrando el archivo portátil `%s': %s."
 
-#: src/data/por-file-reader.c:208
+#: src/data/por-file-reader.c:215
 msgid "unexpected end of file"
 msgstr "fin de archivo inesperado"
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:267 src/data/por-file-writer.c:149
+#: src/data/por-file-reader.c:274 src/data/por-file-writer.c:148
 msgid "portable file"
 msgstr "archivo portátil"
 
-#: src/data/por-file-reader.c:275
+#: src/data/por-file-reader.c:282
 #, c-format
-msgid "An error occurred while opening \"%s\" for reading as a portable file: %s."
-msgstr "Error en abrir \"%s\" para la lectura como archivo portátil: %s."
+msgid "An error occurred while opening `%s' for reading as a portable file: %s."
+msgstr "Error abriendo `%s' para la lectura como archivo portátil: %s."
 
-#: src/data/por-file-reader.c:296
+#: src/data/por-file-reader.c:303
 msgid "Data record expected."
 msgstr "Registro de datos esperado."
 
-#: src/data/por-file-reader.c:378
+#: src/data/por-file-reader.c:385
 msgid "Number expected."
 msgstr "Número esperado."
 
-#: src/data/por-file-reader.c:406
+#: src/data/por-file-reader.c:413
 msgid "Missing numeric terminator."
 msgstr "Falta la terminación numérica."
 
-#: src/data/por-file-reader.c:429
+#: src/data/por-file-reader.c:436
 msgid "Invalid integer."
 msgstr "Número entero inválido."
 
-#: src/data/por-file-reader.c:440 src/data/por-file-reader.c:460
+#: src/data/por-file-reader.c:447 src/data/por-file-reader.c:467
 #, c-format
 msgid "Bad string length %d."
 msgstr "Longitud de cadena %d inválida."
 
-#: src/data/por-file-reader.c:523
+#: src/data/por-file-reader.c:530
 #, c-format
 msgid "%s: Not a portable file."
 msgstr "%s: No es un archivo portátil."
 
-#: src/data/por-file-reader.c:540
+#: src/data/por-file-reader.c:547
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr "Código de versión no reconocido `%c'."
 
-#: src/data/por-file-reader.c:549
+#: src/data/por-file-reader.c:556
 #, c-format
 msgid "Bad date string length %zu."
 msgstr "Longitud de cadena de datos %zu inválida."
 
-#: src/data/por-file-reader.c:551
+#: src/data/por-file-reader.c:558
 #, c-format
 msgid "Bad time string length %zu."
 msgstr "Longitud de cadena de tiempo %zu inválida."
 
-#: src/data/por-file-reader.c:593
+#: src/data/por-file-reader.c:600
 #, c-format
 msgid "%s: Bad format specifier byte (%d).  Variable will be assigned a default format."
 msgstr "%s: Byte especificador de formato inválido (%d). Se asignará formato predeterminado a la variable."
 
-#: src/data/por-file-reader.c:614
+#: src/data/por-file-reader.c:621
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr "La variable numérica %s tiene una especificación de formato inválida %s."
 
-#: src/data/por-file-reader.c:618
+#: src/data/por-file-reader.c:625
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr "La variable en cadena %s con longitud %d tiene una especificación de formato inválida %s."
 
-#: src/data/por-file-reader.c:642
+#: src/data/por-file-reader.c:649
 msgid "Expected variable count record."
 msgstr "Registro de recuento de variables esperado."
 
-#: src/data/por-file-reader.c:646
+#: src/data/por-file-reader.c:653
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr "Número inválido de variables: %d."
 
-#: src/data/por-file-reader.c:655
+#: src/data/por-file-reader.c:662
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr "Nombre de la variable ponderada (%s) truncado."
 
-#: src/data/por-file-reader.c:670
+#: src/data/por-file-reader.c:677
 msgid "Expected variable record."
 msgstr "Registro de variable esperado."
 
-#: src/data/por-file-reader.c:674
+#: src/data/por-file-reader.c:681
 #, c-format
 msgid "Invalid variable width %d."
 msgstr "Ancho de variable inválida %d."
 
-#: src/data/por-file-reader.c:681
+#: src/data/por-file-reader.c:689
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr "Nombre de la variable inválido `%s' en la posición %d."
 
-#: src/data/por-file-reader.c:685 src/data/sys-file-reader.c:606
+#: src/data/por-file-reader.c:693 src/data/sys-file-reader.c:963
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr "Ancho %d incorrecto para la variable %s."
 
-#: src/data/por-file-reader.c:700
-#, c-format
-msgid "Duplicate variable name %s in position %d."
-msgstr "Nombre de la variable %s duplicado en la posición %d."
-
-#: src/data/por-file-reader.c:701
+#: src/data/por-file-reader.c:707
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr "Nombre de la variable %s duplicado en la posición %d se ha renombrado a %s."
 
-#: src/data/por-file-reader.c:750
+#: src/data/por-file-reader.c:756
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr "La variable de ponderación %s no está en el diccionario."
 
-#: src/data/por-file-reader.c:794
+#: src/data/por-file-reader.c:800
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr "Variable %s desconocida mientras se analizaban las etiquetas de valor."
 
-#: src/data/por-file-reader.c:797
+#: src/data/por-file-reader.c:803
 #, c-format
 msgid "Cannot assign value labels to %s and %s, which have different variable types."
 msgstr "No se puede asignar etiquetas de valor a %s y %s, que tienen diferentes tipos de variables."
 
-#: src/data/por-file-writer.c:141
+#: src/data/por-file-writer.c:140
 #, c-format
 msgid "Invalid decimal digits count %d.  Treating as %d."
 msgstr "Recuento de dígitos decimales %d inválido. Se tratarà como %d."
 
-#: src/data/por-file-writer.c:161
+#: src/data/por-file-writer.c:160
 #, c-format
-msgid "Error opening \"%s\" for writing as a portable file: %s."
-msgstr "Error en abrir \"%s\" para escribir como archivo portátil: %s."
+msgid "Error opening `%s' for writing as a portable file: %s."
+msgstr "Error abriendo `%s' para escribir como archivo portátil: %s."
 
-#: src/data/por-file-writer.c:506
+#: src/data/por-file-writer.c:502
 #, c-format
-msgid "An I/O error occurred writing portable file \"%s\"."
-msgstr "Error I/O en escribir el archivo portátil \"%s\"."
+msgid "An I/O error occurred writing portable file `%s'."
+msgstr "Error I/O al escribir el archivo portátil `%s'."
 
 #: src/data/psql-reader.c:46
 msgid "Support for reading postgres databases was not compiled into this installation of PSPP"
 msgstr "El soporte para la lectura de las bases de datos postgres no fue compilado en esta instalación de PSPP"
 
-#: src/data/psql-reader.c:242
+#: src/data/psql-reader.c:239
 msgid "Memory error whilst opening psql source"
 msgstr "Error de memoria en abrir la fuente psql"
 
-#: src/data/psql-reader.c:248
+#: src/data/psql-reader.c:245
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr "Error abriendo la fuente psql: %s."
 
-#: src/data/psql-reader.c:263
+#: src/data/psql-reader.c:260
 #, c-format
 msgid "Postgres server is version %s. Reading from versions earlier than 8.0 is not supported."
 msgstr "La versión del servidor Postgres es la %s. No es posible la lectura desde versiones anteriores a la 8.0."
 
-#: src/data/psql-reader.c:283
+#: src/data/psql-reader.c:280
 msgid "Connection is unencrypted, but unencrypted connections have not been permitted."
 msgstr "La conexión no está cifrada, pero las conexiones sin cifrar no están permitidas."
 
-#: src/data/psql-reader.c:322 src/data/psql-reader.c:347
-#: src/data/psql-reader.c:357
+#: src/data/psql-reader.c:318 src/data/psql-reader.c:343
+#: src/data/psql-reader.c:353
 #, c-format
 msgid "Error from psql source: %s."
 msgstr "Error desde la fuente psql: %s."
 
-#: src/data/psql-reader.c:452
+#: src/data/psql-reader.c:448
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr "OID %d no admitido. Valores SYSMIS serán insertados."
@@ -618,11 +650,20 @@ msgstr "El manipulador de archivos de trabajo %s aún no se ha escrito, utilizan
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:181
+#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:186
 msgid "scratch file"
 msgstr "archivo de trabajo"
 
-#: src/data/settings.c:608
+#: src/data/settings.c:384
+msgid "MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."
+msgstr "MXWARNS colocado a cero.  NIngún aviso se mostrará en lo sucesivo aunque se den situaciones problemáticas."
+
+#: src/data/settings.c:391
+#, c-format
+msgid "Warnings re-enabled. %d warnings will be issued before aborting syntax processing."
+msgstr "Avisos re-activados. %d avisos se mostraran antes de abortar el procesamiento de sintaxis."
+
+#: src/data/settings.c:599
 #, c-format
 msgid "%s: Custom currency string `%s' does not contain exactly three periods or commas (or it contains both)."
 msgstr "%s: La cadena de moneda personalizada '%s' no contiene exactamente tres puntos o comas (o contiene ambos)."
@@ -631,373 +672,366 @@ msgstr "%s: La cadena de moneda personalizada '%s' no contiene exactamente tres
 msgid "Variable suffix too large."
 msgstr "Sufijo de la variable demasiado grande."
 
-#: src/data/sys-file-reader.c:226
-#, c-format
-msgid "Recoded variable name duplicates an existing `%s' within system file."
-msgstr "El nombre de la variable recodificada duplica `%s' existente dentro del archivo del sistema."
-
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:290 src/data/sys-file-writer.c:207
+#: src/data/sys-file-reader.c:323 src/data/sys-file-writer.c:207
 msgid "system file"
 msgstr "archivo de sistema"
 
-#: src/data/sys-file-reader.c:297
+#: src/data/sys-file-reader.c:330
 #, c-format
-msgid "Error opening \"%s\" for reading as a system file: %s."
-msgstr "Error en abrir \"%s\" para la lectura como archivo de sistema: %s."
+msgid "Error opening `%s' for reading as a system file: %s."
+msgstr "Error abriendo `%s' para la lectura como archivo de sistema: %s."
 
-#: src/data/sys-file-reader.c:336 tests/dissect-sysfile.c:154
+#: src/data/sys-file-reader.c:387 tests/dissect-sysfile.c:155
 msgid "Misplaced type 4 record."
 msgstr "Registro de tipo 4 fuera de lugar."
 
-#: src/data/sys-file-reader.c:347 tests/dissect-sysfile.c:165
+#: src/data/sys-file-reader.c:391
+msgid "Duplicate type 6 (document) record."
+msgstr "Registros de tipo 6 (document) duplicados."
+
+#: src/data/sys-file-reader.c:400 src/data/sys-file-reader.c:900
+#, c-format
+msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Registro de tipo 7, subtipo %d , no reconocido. Por favor envíe una copia de este archivo, así como de la sintaxis que lo creó a %s."
+
+#: src/data/sys-file-reader.c:409
+#, c-format
+msgid "Record type 7, subtype %d found here has the same type as the record found near offset 0x%llx.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Registro de tipo 7, subtipo %d encontrado aquí del mismo tipo que el registro encontrado cerca de la posición 0x%llx. Por favor envíe una copia de este archivo y de la sintaxis que lo creó a %s."
+
+#: src/data/sys-file-reader.c:422 tests/dissect-sysfile.c:166
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr "Tipo de registro %d no reconocido."
 
-#: src/data/sys-file-reader.c:388
+#: src/data/sys-file-reader.c:467
+#, c-format
+msgid "Weighting variable must be numeric (not string variable `%s')."
+msgstr "Variable de ponderación tiene que ser numérica (no cadena textual `%s')."
+
+#: src/data/sys-file-reader.c:502
 #, c-format
 msgid "File header claims %d variable positions but %d were read from file."
 msgstr "Cabecera del archivo requiere %d posiciones de variable, per se han leído %d desde el archivo."
 
-#: src/data/sys-file-reader.c:428
+#: src/data/sys-file-reader.c:542
 #, c-format
-msgid "Error closing system file \"%s\": %s."
-msgstr "Error en cerrar el archivo de sistema \"%s\": %s."
+msgid "Error closing system file `%s': %s."
+msgstr "Error cerrando el archivo de sistema `%s': %s."
 
-#: src/data/sys-file-reader.c:493 src/data/sys-file-reader.c:503
-#: tests/dissect-sysfile.c:202 tests/dissect-sysfile.c:212
+#: src/data/sys-file-reader.c:604 src/data/sys-file-reader.c:614
+#: tests/dissect-sysfile.c:203 tests/dissect-sysfile.c:213
 msgid "This is not an SPSS system file."
 msgstr "Esto no es un archivo de sistema de SPSS."
 
-#: src/data/sys-file-reader.c:525 tests/dissect-sysfile.c:227
+#: src/data/sys-file-reader.c:636 tests/dissect-sysfile.c:228
 msgid "Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format."
 msgstr "El sesgo de compresión no es el valor habitual de 100, o el archivo de sistema utiliza un formato de punto flotante no reconocido."
 
-#: src/data/sys-file-reader.c:602
-#, c-format
-msgid "Invalid variable name `%s'."
-msgstr "Nombre de variable '%s' no válido."
-
-#: src/data/sys-file-reader.c:610
-#, c-format
-msgid "Duplicate variable name `%s' within system file."
-msgstr "Nombre de variable '%s' duplicado dentro del archivo de sistema."
-
-#: src/data/sys-file-reader.c:618 tests/dissect-sysfile.c:356
+#: src/data/sys-file-reader.c:712 tests/dissect-sysfile.c:357
 msgid "Variable label indicator field is not 0 or 1."
 msgstr "Campo indicador de etiqueta de variable no es 0 o 1."
 
-#: src/data/sys-file-reader.c:649 tests/dissect-sysfile.c:387
+#: src/data/sys-file-reader.c:722 tests/dissect-sysfile.c:388
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr "Campo de indicador de valores perdidos numéricos no es -3, -2, 0, 1, 2 o 3."
 
-#: src/data/sys-file-reader.c:667 tests/dissect-sysfile.c:402
+#: src/data/sys-file-reader.c:729 tests/dissect-sysfile.c:403
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr "Campo de indicador de valores perdidos de cadena no es 0, 1, 2 o 3."
 
-#: src/data/sys-file-reader.c:699
+#: src/data/sys-file-reader.c:749
+#, c-format
+msgid "Invalid number of labels %zu."
+msgstr "Número inválido de etiquetas %zu."
+
+#: src/data/sys-file-reader.c:774 tests/dissect-sysfile.c:469
+msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
+msgstr "Registro de índice de variable (tipo 4) no está seguido inmediatament, como debería, por el registro de etiquetas de valores (tipo 3) ."
+
+#: src/data/sys-file-reader.c:782
+#, c-format
+msgid "Number of variables associated with a value label (%d) is not between 1 and the number of variables (%zu)."
+msgstr "Número de variables asociadas con una etiqueta de valores (%d) no está entre 1 y el número de variables (%zu)."
+
+#: src/data/sys-file-reader.c:803
+#, c-format
+msgid "Number of document lines (%d) must be greater than 0 and less than %d."
+msgstr "Número de líneas de documento (%d) tiene que ser mayor que 0 y menor que %d."
+
+#: src/data/sys-file-reader.c:876
+#, c-format
+msgid "Record type 7, subtype %d has bad size %zu (expected %d)."
+msgstr "Registro de tipo 7, subtipo %d tiene medida incorrecta %zu (se espera %d)."
+
+#: src/data/sys-file-reader.c:880
+#, c-format
+msgid "Record type 7, subtype %d has bad count %zu (expected %d)."
+msgstr "Registro de tipo 7, subtipo %d tiene recuento incorrecto %zu (se espera %d)."
+
+#: src/data/sys-file-reader.c:959
+#, c-format
+msgid "Invalid variable name `%s'."
+msgstr "Nombre de variable '%s' no válido."
+
+#: src/data/sys-file-reader.c:967
+#, c-format
+msgid "Duplicate variable name `%s'."
+msgstr "Nombre de variable `%s' duplicado."
+
+#: src/data/sys-file-reader.c:1038
 msgid "Missing string continuation record."
 msgstr "Falta de registro de continuación de cadena."
 
-#: src/data/sys-file-reader.c:733
+#: src/data/sys-file-reader.c:1059
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr "Formato de variable %<PRIu8> desconocido."
 
-#: src/data/sys-file-reader.c:751
+#: src/data/sys-file-reader.c:1077
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr "%s variable %s con formato %s no válido %s."
 
-#: src/data/sys-file-reader.c:754
+#: src/data/sys-file-reader.c:1080
 msgid "print"
 msgstr "imprimir"
 
-#: src/data/sys-file-reader.c:754
+#: src/data/sys-file-reader.c:1080
 msgid "write"
 msgstr "escribir"
 
-#: src/data/sys-file-reader.c:758
+#: src/data/sys-file-reader.c:1084
 msgid "Suppressing further invalid format warnings."
 msgstr "Se desactivan las alertas posteriores de formato no válido."
 
-#: src/data/sys-file-reader.c:776
-msgid "Weighting variable must be numeric."
-msgstr "Variable de ponderación tiene que ser numérica."
-
-#: src/data/sys-file-reader.c:790
-msgid "Multiple type 6 (document) records."
-msgstr "Múltiples registros de tipo 6 (document)."
-
-#: src/data/sys-file-reader.c:794
-#, c-format
-msgid "Number of document lines (%d) must be greater than 0."
-msgstr "Número de líneas de documento (%d) tiene que ser mayor que 0."
-
-#: src/data/sys-file-reader.c:802
-msgid "Document line contains null byte."
-msgstr "Una línea del documento contiene un byte nulo."
-
-#: src/data/sys-file-reader.c:893
-#, c-format
-msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s"
-msgstr "Registro de tipo 7, subtipo %d , no reconocido. Por favor envíe una copia de este archivo, así como de la sintaxis que lo creó en %s"
-
-#: src/data/sys-file-reader.c:920 tests/dissect-sysfile.c:594
-#, c-format
-msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
-msgstr "Campo de longitud (%zu) o cantidad (%zu) inválidos en el registro tipo 7, subtipo 3."
-
-#: src/data/sys-file-reader.c:940
+#: src/data/sys-file-reader.c:1136
 #, c-format
 msgid "Floating-point representation indicated by system file (%d) differs from expected (%d)."
 msgstr "Representación del punto flotante indicado por el archivo de sistema (%d) difiere de lo esperado (%d)."
 
-#: src/data/sys-file-reader.c:953 src/language/dictionary/sys-file-info.c:110
-msgid "Little Endian"
-msgstr "Tipo Little-Endian"
-
-#: src/data/sys-file-reader.c:953 src/language/dictionary/sys-file-info.c:109
-msgid "Big Endian"
-msgstr "Tipo Big-Endian."
-
-#: src/data/sys-file-reader.c:954
+#: src/data/sys-file-reader.c:1150
 #, c-format
-msgid "Integer format indicated by system file (%s) differs from expected (%s)."
-msgstr "Formato entero indicado por el archivo de sistema  (%s) difiere de lo esperado (%s)."
-
-#: src/data/sys-file-reader.c:1011 tests/dissect-sysfile.c:625
-#, c-format
-msgid "Bad size (%zu) or count (%zu) on extension 4."
-msgstr "Longitud (%zu) o cantidad (%zu) de la extensión 4 no válida."
+msgid "Integer format indicated by system file (%d) differs from expected (%d)."
+msgstr "El formato entero indicado por el archivo de sistema (%d) difiere de lo esperado (%d)."
 
-#: src/data/sys-file-reader.c:1015 src/data/sys-file-reader.c:1019
-#: src/data/sys-file-reader.c:1023 tests/dissect-sysfile.c:630
-#: tests/dissect-sysfile.c:635 tests/dissect-sysfile.c:640
+#: src/data/sys-file-reader.c:1211 src/data/sys-file-reader.c:1215
+#: src/data/sys-file-reader.c:1219 tests/dissect-sysfile.c:631
+#: tests/dissect-sysfile.c:636 tests/dissect-sysfile.c:641
 #, c-format
 msgid "File specifies unexpected value %g as %s."
 msgstr "El archivo especifica un valor inesperado %g como %s."
 
-#: src/data/sys-file-reader.c:1056
+#: src/data/sys-file-reader.c:1252
 #, c-format
-msgid "Missing space following 'C' at offset %zu in MRSETS record"
-msgstr "Espacio perdido tras 'C' en la posición %zu del registro MRSETS"
+msgid "`%s' does not begin with `$' at UTF-8 offset %zu in MRSETS record."
+msgstr "`%s' no comienza con `$' en la posición UTF-8 %zu de un registro MRSETS."
 
-#: src/data/sys-file-reader.c:1074 tests/dissect-sysfile.c:691
+#: src/data/sys-file-reader.c:1263 src/data/sys-file-reader.c:1282
 #, c-format
-msgid "Missing space following 'E' at offset %zu in MRSETS record"
-msgstr "Espacio perdido tras 'E' en la posición %zu del registro MRSETS"
+msgid "Missing space following `%c' at UTF-8 offset %zu in MRSETS record."
+msgstr "Espacio perdido tras `%c' en la posición UTF-8 %zu del registro MRSETS."
 
-#: src/data/sys-file-reader.c:1083 tests/dissect-sysfile.c:700
+#: src/data/sys-file-reader.c:1292
 #, c-format
-msgid "Unexpected label source value \"%s\" following 'E' at offset %zu in MRSETS record"
-msgstr "Etiqueta de valor fuente inesperada \"%s\" tras 'E' en la posición %zu del registro MRSETS"
+msgid "Unexpected label source value `%s' following `E' at UTF-8 offset %zu in MRSETS record."
+msgstr "Etiqueta de valor fuente inesperada `%s' tras 'E' en la posición UTF-8 %zu del registro MRSETS."
 
-#: src/data/sys-file-reader.c:1089
+#: src/data/sys-file-reader.c:1299
 #, c-format
-msgid "Missing 'C', 'D', or 'E' at offset %zu in MRSETS record."
-msgstr "Falta 'C', 'D' o 'E' en la posición %zu del registro MRSETS"
+msgid "Missing `C', `D', or `E' at UTF-8 offset %zu in MRSETS record."
+msgstr "Falta `C', `D' o `E' en la posición UTF-8 %zu del registro MRSETS."
 
-#: src/data/sys-file-reader.c:1118
+#: src/data/sys-file-reader.c:1329
 #, c-format
-msgid "Missing new-line parsing variable names at offset %zu in MRSETS record."
-msgstr "Falta el nombre de variable de nueva línea en la posición %zu del registro MRSETS"
+msgid "Missing new-line parsing variable names at UTF-8 offset %zu in MRSETS record."
+msgstr "Faltan nombres de variables de la nueva línea en la posición UTF-8 %zu del registro MRSETS."
 
-#: src/data/sys-file-reader.c:1129
+#: src/data/sys-file-reader.c:1341
 #, c-format
-msgid "Duplicate variable name %s at offset %zu in MRSETS record."
-msgstr "Nombre de la variable %s duplicado en la posición %zu en registro MRSETS."
+msgid "Duplicate variable name %s at UTF-8 offset %zu in MRSETS record."
+msgstr "Nombre de la variable %s duplicado en la posición UTF-8 %zu en registro MRSETS."
 
-#: src/data/sys-file-reader.c:1142
+#: src/data/sys-file-reader.c:1355
 #, c-format
 msgid "MRSET %s contains both string and numeric variables."
 msgstr "MRSET %s contiene tanto variables textuales como numéricas."
 
-#: src/data/sys-file-reader.c:1157
+#: src/data/sys-file-reader.c:1371
 #, c-format
 msgid "MRSET %s has only %zu variables."
 msgstr "MRSET %s tiene sólo %zu variables."
 
-#: src/data/sys-file-reader.c:1194 tests/dissect-sysfile.c:758
-#, c-format
-msgid "Bad size %zu on extension 11."
-msgstr "Longitud no válida %zu en la extensión 11."
-
-#: src/data/sys-file-reader.c:1206 tests/dissect-sysfile.c:770
+#: src/data/sys-file-reader.c:1417 tests/dissect-sysfile.c:771
 #, c-format
 msgid "Extension 11 has bad count %zu (for %zu variables)."
 msgstr "Extensión 11 tiene un recuento inválido %zu (para %zu variables)."
 
-#: src/data/sys-file-reader.c:1227
+#: src/data/sys-file-reader.c:1451
 #, c-format
 msgid "Invalid variable display parameters for variable %zu (%s).  Default parameters substituted."
 msgstr "Parámetros de visualización de variable no válidos para la variable %zu (%s). Sustitución de parámetros por defecto."
 
-#: src/data/sys-file-reader.c:1271
+#: src/data/sys-file-reader.c:1548
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr "Identificación de variable larga desde %s hacia un nombre de variable inválido '%s'."
 
-#: src/data/sys-file-reader.c:1281
+#: src/data/sys-file-reader.c:1559
 #, c-format
-msgid "Duplicate long variable name `%s' within system file."
-msgstr "Nombre de la variable larga '%s' duplicada dentro del archivo de sistema."
+msgid "Duplicate long variable name `%s'."
+msgstr "Nombre largo de la variable `%s' duplicado."
 
-#: src/data/sys-file-reader.c:1334
+#: src/data/sys-file-reader.c:1592
 #, c-format
-msgid "%s listed as string of invalid length %s in very length string record."
+msgid "%s listed as string of invalid length %s in very long string record."
 msgstr "%s figura como cadena de longitud no válida %s en un registro de cadena muy largo."
 
-#: src/data/sys-file-reader.c:1344
+#: src/data/sys-file-reader.c:1603
 #, c-format
 msgid "%s listed in very long string record with width %s, which requires only one segment."
 msgstr "%s figura en el registro de cadena muy larga con longitud %s, que requiere solo un segmento."
 
-#: src/data/sys-file-reader.c:1350
+#: src/data/sys-file-reader.c:1610
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr "Cadena muy larga %s desborda el diccionario."
 
-#: src/data/sys-file-reader.c:1364
+#: src/data/sys-file-reader.c:1625
 #, c-format
-msgid "Very long string with width %ld has segment %d of width %d (expected %d)"
-msgstr "Cadena muy larga con una longitud de %ld tiene un segmento %d de longitud %d (se espera %d)"
-
-#: src/data/sys-file-reader.c:1410
-#, c-format
-msgid "Invalid number of labels: %d.  Ignoring labels."
-msgstr "Número de etiquetas inválido: %d. Ignorando etiquetas."
-
-#: src/data/sys-file-reader.c:1441 tests/dissect-sysfile.c:468
-msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
-msgstr "Registro de índice de variable (tipo 4) no está seguido inmediatament, como debería, por el registro de etiquetas de valores (tipo 3) ."
+msgid "Very long string with width %ld has segment %d of width %d (expected %d)."
+msgstr "Cadena muy larga con una longitud %ld tiene un segmento %d de longitud %d (se espera %d)"
 
-#: src/data/sys-file-reader.c:1448
+#: src/data/sys-file-reader.c:1659
 #, c-format
-msgid "Number of variables associated with a value label (%d) is not between 1 and the number of variables (%zu)."
-msgstr "Número de variables asociadas con una etiqueta de valores (%d) no está entre 1 y el número de variables (%zu)."
+msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
+msgstr "Las variables asociadas con etiqueta de valores no son todas del mismo tipo.  La variable %s es %s, pero la variable %s es %s."
 
-#: src/data/sys-file-reader.c:1459
+#: src/data/sys-file-reader.c:1676
 #, c-format
 msgid "Value labels may not be added to long string variables (e.g. %s) using records types 3 and 4."
 msgstr "No se pueden añadir etiquetas de valor a las variables de cadena larga (e.g. %s) utilizando los tipos de registro 3 y 4."
 
-#: src/data/sys-file-reader.c:1468
-#, c-format
-msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
-msgstr "Las variables asociadas con etiqueta de valores no son todas del mismo tipo.  La variable %s es %s, pero la variable %s es %s."
-
-#: src/data/sys-file-reader.c:1502
+#: src/data/sys-file-reader.c:1695
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr "Etiqueta de valor duplicad para %g en %s."
 
-#: src/data/sys-file-reader.c:1505 src/data/sys-file-reader.c:1686
+#: src/data/sys-file-reader.c:1699 src/data/sys-file-reader.c:1941
 #, c-format
-msgid "Duplicate value label for \"%.*s\" on %s."
-msgstr "Etiqueta de valor duplicada para \"%.*s\" en %s."
+msgid "Duplicate value label for `%.*s' on %s."
+msgstr "Etiqueta de valor duplicada para `%.*s' en %s."
 
-#: src/data/sys-file-reader.c:1543
+#: src/data/sys-file-reader.c:1724
 #, c-format
-msgid "Error parsing attribute value %s[%d]"
-msgstr "Error al analizar el valor del atributo %s[%d]"
+msgid "Variable index %d not in valid range 1...%d."
+msgstr "Índice de la variable %d no en el intervalo válido de 1...%d."
 
-#: src/data/sys-file-reader.c:1557
+#: src/data/sys-file-reader.c:1733
 #, c-format
-msgid "Attribute value %s[%d] is not quoted: %s"
-msgstr "El valor del atributo %s[%d] no está entre comillas: %s"
+msgid "Variable index %d refers to long string continuation."
+msgstr "Índice de la variable %d se refiere a una continuación de cadena larga."
 
-#: src/data/sys-file-reader.c:1620 tests/dissect-sysfile.c:936
+#: src/data/sys-file-reader.c:1769
 #, c-format
-msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
-msgstr "La longitud del nombre de la variable en el registro de la etiqueta del valor de cadena larga (%d) supera el límite %d-byte."
+msgid "Error parsing attribute value %s[%d]."
+msgstr "Error al analizar el valor del atributo %s[%d]"
+
+#: src/data/sys-file-reader.c:1783
+#, c-format
+msgid "Attribute value %s[%d] is not quoted: %s."
+msgstr "El valor del atributo %s[%d] no está entre comillas: %s."
+
+#: src/data/sys-file-reader.c:1836
+msgid "Long string value label record ends unexpectedly."
+msgstr "Etiqueta de valor de un registro de texto muy largo finaliza inesperadamente."
 
-#: src/data/sys-file-reader.c:1630
+#: src/data/sys-file-reader.c:1875
 #, c-format
 msgid "Ignoring long string value record for unknown variable %s."
 msgstr "Ignorando el registro del valor de cadena larga para la variable desconocida %s."
 
-#: src/data/sys-file-reader.c:1637
+#: src/data/sys-file-reader.c:1880
 #, c-format
 msgid "Ignoring long string value record for numeric variable %s."
 msgstr "Ignorando el registro del valor de cadena larga para la variable numérica %s."
 
-#: src/data/sys-file-reader.c:1644
+#: src/data/sys-file-reader.c:1887
 #, c-format
-msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)"
-msgstr "Ignorando el registro del valor de cadena larga %s ya que el ancho del registro (%d) no coincide con el ancho de la variable (%d)"
+msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)."
+msgstr "Ignorando el registro del valor de cadena larga %s ya que el ancho del registro (%d) no coincide con el ancho de la variable (%d)."
 
-#: src/data/sys-file-reader.c:1666
+#: src/data/sys-file-reader.c:1916
 #, c-format
 msgid "Ignoring long string value %zu for variable %s, with width %d, that has bad value width %zu."
 msgstr "Ignorando el valor de cadena larga %zu para la variable %s, de ancho %d, que tiene un ancho de valor incorrecto %zu."
 
-#: src/data/sys-file-reader.c:1781
+#: src/data/sys-file-reader.c:2020
 msgid "File ends in partial case."
 msgstr "El archivo acaba en un caso parcial."
 
-#: src/data/sys-file-reader.c:1789
+#: src/data/sys-file-reader.c:2028
 #, c-format
 msgid "Error reading case from file %s."
 msgstr "Error leyendo un caso del archivo %s."
 
-#: src/data/sys-file-reader.c:1890
+#: src/data/sys-file-reader.c:2130
 msgid "Possible compressed data corruption: compressed spaces appear in numeric field."
 msgstr "Posible corrupción de datos comprimidos: aparecen espacios comprimidos en un campo numérico."
 
-#: src/data/sys-file-reader.c:1943
+#: src/data/sys-file-reader.c:2184
 #, c-format
-msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)"
+msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)."
 msgstr "Posible corrupción de datos comprimidos: una cadena textual contiene un entero comprimido (opcode %d)."
 
-#: src/data/sys-file-reader.c:2035
-#, c-format
-msgid "Variable index %d not in valid range 1...%d."
-msgstr "Índice de la variable %d no en el intervalo válido de 1...%d."
-
-#: src/data/sys-file-reader.c:2040
-#, c-format
-msgid "Variable index %d refers to long string continuation."
-msgstr "Índice de la variable %d se refiere a una continuación de cadena larga."
-
-#: src/data/sys-file-reader.c:2108
+#: src/data/sys-file-reader.c:2273
 #, c-format
 msgid "Suppressed %d additional related warnings."
 msgstr "Suprimidas %d advertencias adicionales."
 
-#: src/data/sys-file-reader.c:2153 src/data/sys-file-reader.c:2170
+#: src/data/sys-file-reader.c:2318 src/data/sys-file-reader.c:2335
 #, c-format
 msgid "Dictionary record refers to unknown variable %s."
 msgstr "El registro diccionario se refiere a una variable desconocida %s."
 
-#: src/data/sys-file-reader.c:2231
+#: src/data/sys-file-reader.c:2397
+#, c-format
+msgid "Expecting digit at UTF-8 offset %zu in MRSETS record."
+msgstr "Se espera un dígito en la posición UTF-8 %zu del registro MRSETS."
+
+#: src/data/sys-file-reader.c:2405
+#, c-format
+msgid "Expecting space at UTF-8 offset %zu in MRSETS record."
+msgstr "Se espera un espacio en la posición UTF-8 %zu del registre MRSETS."
+
+#: src/data/sys-file-reader.c:2413
 #, c-format
-msgid "Expecting digit at offset %zu in MRSETS record."
-msgstr "Se espera un dígito en la posición %zu del registro MRSETS."
+msgid "%zu-byte string starting at UTF-8 offset %zu exceeds record length %zu."
+msgstr "Un texto de %zu-bytes que comienza en la posición UTF-8 %zu excede la longitud del registro %zu. "
 
-#: src/data/sys-file-reader.c:2238
+#: src/data/sys-file-reader.c:2423
 #, c-format
-msgid "Expecting space at offset %zu in MRSETS record."
-msgstr "Se espera un espacio en la posición %zu del registre MRSETS."
+msgid "Expecting space at UTF-8 offset %zu following %zu-byte string."
+msgstr "Se espera un espacio en la posición UTF-8 %zu tras un texto de %zu-bytes."
 
-#: src/data/sys-file-reader.c:2245
+#: src/data/sys-file-reader.c:2465
 #, c-format
-msgid "%zu-byte string starting at offset %zu exceeds record length %zu."
-msgstr "El texto de %zu-bytes que comienza en la posición %zu excede la longitud del registro %zu. "
+msgid "`%s' near offset 0x%llx: "
+msgstr "`%s' cerca de la posición 0x%llx: "
 
-#: src/data/sys-file-reader.c:2255
+#: src/data/sys-file-reader.c:2468
 #, c-format
-msgid "Expecting space at offset %zu following %zu-byte string."
-msgstr "Se espera un espacio en la posición %zu tras un texto de %zu-byte."
+msgid "`%s': "
+msgstr "`%s': "
 
-#: src/data/sys-file-reader.c:2347 tests/dissect-sysfile.c:1341
+#: src/data/sys-file-reader.c:2525 tests/dissect-sysfile.c:1356
 #, c-format
 msgid "System error: %s."
 msgstr "Error de sistema: %s."
 
-#: src/data/sys-file-reader.c:2349 tests/dissect-sysfile.c:1343
+#: src/data/sys-file-reader.c:2527 tests/dissect-sysfile.c:1358
 msgid "Unexpected end of file."
 msgstr "Final de archivo inesperado."
 
@@ -1006,386 +1040,343 @@ msgstr "Final de archivo inesperado."
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr "Versión de archivo de sistema %d desconocida.Se tratará como versión %d."
 
-#: src/data/sys-file-writer.c:219
-#, c-format
-msgid "Error opening \"%s\" for writing as a system file: %s."
-msgstr "Error al abrir \"%s\" para grabar com archivo de sistema: %s."
-
-#: src/data/sys-file-writer.c:989
-#, c-format
-msgid "An I/O error occurred writing system file \"%s\"."
-msgstr "Error de E/S al guardar el archivo de sistema \"%s\"."
-
-#: src/data/variable.c:206
-#, c-format
-msgid "Character `%c' (in %s) may not appear as the first character in a variable name."
-msgstr "Carácter '%c' (en %s) no puede aparecer como el primer carácter en un nombre de variable."
-
-#: src/data/variable.c:218
-#, c-format
-msgid "Character `%c' (in %s) may not appear in a variable name."
-msgstr "Carácter '%c' (en %s) no puede aparecer en un nombre de variable."
-
-#: src/data/variable.c:244
-msgid "Variable name cannot be empty string."
-msgstr "El nombre de la variable no puede ser una cadena vacía."
-
-#: src/data/variable.c:250
-#, c-format
-msgid "Variable name %s exceeds %d-character limit."
-msgstr "El nombre de la variable %s supera el límite de %d caracteres."
-
-#: src/data/variable.c:258
-#, c-format
-msgid "`%s' may not be used as a variable name because it is a reserved word."
-msgstr "'%s' no puede ser utilizado como nombre de variable porque es una palabra reservada."
-
-#: src/language/syntax-file.c:95
-#, c-format
-msgid "Opening `%s': %s."
-msgstr "Abriendo `%s': %s."
-
-#: src/language/syntax-file.c:109
+#: src/data/sys-file-writer.c:997
 #, c-format
-msgid "Reading `%s': %s."
-msgstr "Leyendo `%s': %s."
+msgid "An I/O error occurred writing system file `%s'."
+msgstr "Error de E/S al guardar el archivo de sistema `%s'."
 
-#: src/language/syntax-file.c:126
+#: src/data/variable.c:599
 #, c-format
-msgid "Closing `%s': %s."
-msgstr "Cerrando `%s': %s."
+msgid "Truncating variable label for variable `%s' to %d bytes."
+msgstr "Truncando la etiqueta de la variable `%s' a %d bytes."
 
-#: src/language/command.c:205 src/language/expressions/parse.c:1267
-#: src/language/utilities/set.q:213
+#: src/language/command.c:193 src/language/expressions/parse.c:1294
+#: src/language/utilities/set.q:196
 #, c-format
 msgid "%s is not yet implemented."
 msgstr "%s aún no está implementado."
 
-#: src/language/command.c:210
+#: src/language/command.c:198
 #, c-format
 msgid "%s may be used only in testing mode."
 msgstr "%s sólo puede ser utilizado en el modo de prueba."
 
-#: src/language/command.c:215
+#: src/language/command.c:203
 #, c-format
 msgid "%s may be used only in enhanced syntax mode."
 msgstr "%s sólo puede ser utilizado en modo de sintaxis ampliado."
 
-#: src/language/command.c:239
-msgid "Error encountered while ERROR=STOP is effective."
-msgstr "Error detectado mientras está activo ERROR=STOP."
-
-#: src/language/command.c:484
+#: src/language/command.c:331
 msgid "expecting command name"
 msgstr "esperando nombre de comando"
 
-#: src/language/command.c:498
+#: src/language/command.c:333
 #, c-format
-msgid "Unknown command %s."
-msgstr "Comando %s desconocido."
+msgid "Unknown command `%s'."
+msgstr "Comando `%s' desconocido."
 
-#: src/language/command.c:623
+#: src/language/command.c:366
 #, c-format
-msgid "%s is allowed only before the active file has been defined."
-msgstr "%s sólo se permite antes que el archivo activo se ha definido."
+msgid "%s is allowed only before the active dataset has been defined."
+msgstr "%s sólo se permite antes de que el archivo de datos activo se haya definido."
 
-#: src/language/command.c:627
+#: src/language/command.c:370
 #, c-format
-msgid "%s is allowed only after the active file has been defined."
-msgstr "%s sólo se permite después que el archivo activo se ha definido."
+msgid "%s is allowed only after the active dataset has been defined."
+msgstr "%s sólo se permite después que el archivo de datos activo se haya definido."
 
-#: src/language/command.c:631
+#: src/language/command.c:374
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM."
 msgstr "%s sólo se permite dentro de INPUT PROGRAM."
 
-#: src/language/command.c:635
+#: src/language/command.c:378
 #, c-format
 msgid "%s is allowed only inside FILE TYPE."
 msgstr "%s sólo se permite dentro de FILE TYPE."
 
-#: src/language/command.c:642
+#: src/language/command.c:385
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s sólo se permite antes que el archivo activo se ha definido, o dentro de INPUT PROGRAM."
+msgid "%s is allowed only before the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s sólo se permite antes que el archivo de datos activo se haya definido o dentro de INPUT PROGRAM."
 
-#: src/language/command.c:646
+#: src/language/command.c:389
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside FILE TYPE."
-msgstr "%s sólo se permite antes que el archivo activo se ha definido, o dentro de FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined or inside FILE TYPE."
+msgstr "%s sólo se permite antes que el archivo de datos activo se haya definido o dentro de FILE TYPE."
 
-#: src/language/command.c:650
+#: src/language/command.c:393
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s sólo se permite después que el archivo activo se ha definido, o dentro de INPUT PROGRAM."
+msgid "%s is allowed only after the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s sólo se permite después que el archivo de datos activo se ha definido o dentro de INPUT PROGRAM."
 
-#: src/language/command.c:654
+#: src/language/command.c:397
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside FILE TYPE."
-msgstr "%s sólo se permite después que el archivo activo se ha definido, o dentro de FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined or inside FILE TYPE."
+msgstr "%s sólo se permite después que el archivo de datos activo se ha definido o dentro de FILE TYPE."
 
-#: src/language/command.c:658
+#: src/language/command.c:401
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM or inside FILE TYPE."
 msgstr "%s sólo se permite dentro de INPUT PROGRAM o FILE TYPE."
 
-#: src/language/command.c:664
+#: src/language/command.c:407
 #, c-format
-msgid "%s is allowed only after the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s sólo se permite después que el archivo activo se ha definido, dentro de INPUT PROGRAM, o FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s sólo se permite después que el archivo de datos activo se ha definido, dentro de INPUT PROGRAM, o de FILE TYPE."
 
-#: src/language/command.c:669
+#: src/language/command.c:412
 #, c-format
-msgid "%s is allowed only before the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s sólo se permite antes que el archivo activo se ha definido, dentro de INPUT PROGRAM, o FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s sólo se permite antes que el archivo de datos activo se haya definido, dentro de INPUT PROGRAM, o de FILE TYPE."
 
-#: src/language/command.c:687 src/language/command.c:689
+#: src/language/command.c:430 src/language/command.c:433
 #, c-format
 msgid "%s is not allowed inside %s."
 msgstr "%s no está permitido dentro de %s."
 
-#: src/language/command.c:768 src/language/command.c:876
-#: src/language/utilities/permissions.c:98
+#: src/language/command.c:515 src/language/utilities/host.c:130
+#: src/language/utilities/permissions.c:104
 msgid "This command not allowed when the SAFER option is set."
 msgstr "Esta orden no está permitida cuando la opción SAFER está activa."
 
-#: src/language/command.c:780
+#: src/language/command.c:531
 #, c-format
 msgid "Error removing `%s': %s."
 msgstr "Error de eliminación de '%s' : %s."
 
-#: src/language/command.c:830
-#, c-format
-msgid "Couldn't fork: %s."
-msgstr "Imposible crear fork: %s."
-
-#: src/language/command.c:845
-msgid "Interactive shell not supported on this platform."
-msgstr "Intérprete de órdenes interactivo no disponible para esta plataforma."
-
-#: src/language/command.c:857
-msgid "Command shell not supported on this platform."
-msgstr "Intérprete de órdenes no disponible para esta plataforma."
-
-#: src/language/command.c:863
-#, c-format
-msgid "Error executing command: %s."
-msgstr "Error de ejecución del comando: %s."
-
-#: src/language/lexer/lexer.c:284
-#, c-format
-msgid "%s does not form a valid number."
-msgstr "%s no constituye un número vàlido."
-
-#: src/language/lexer/lexer.c:390
-#, c-format
-msgid "Bad character in input: `%s'."
-msgstr "Carácter erróneo en la entrada: `%s'."
-
-#: src/language/lexer/lexer.c:427
+#: src/language/lexer/lexer.c:276
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr "Subcomando %s sólo se puede especificar una vez."
 
-#: src/language/lexer/lexer.c:435
+#: src/language/lexer/lexer.c:284
 #, c-format
 msgid "missing required subcommand %s"
 msgstr "suborden requerida %s ausente"
 
-#: src/language/lexer/lexer.c:464
-#, c-format
-msgid "Syntax error %s at %s."
-msgstr "Error de sintaxis %s en %s."
-
-#: src/language/lexer/lexer.c:467
-#, c-format
-msgid "Syntax error at %s."
-msgstr "Error de sintaxis en %s."
+#: src/language/lexer/lexer.c:302
+msgid "Syntax error at end of input"
+msgstr "Error de sintaxis al final de la entrada"
 
-#: src/language/lexer/lexer.c:479 src/language/xforms/select-if.c:60
-#: src/language/stats/autorecode.c:144 src/language/data-io/print-space.c:73
+#: src/language/lexer/lexer.c:323 src/language/xforms/select-if.c:60
+#: src/language/stats/autorecode.c:162 src/language/stats/npar.c:414
+#: src/language/data-io/print-space.c:72
 msgid "expecting end of command"
 msgstr "se espera el final de la orden"
 
-#: src/language/lexer/lexer.c:601 src/language/lexer/lexer.c:618
+#: src/language/lexer/lexer.c:494 src/language/lexer/lexer.c:511
 #, c-format
 msgid "expecting `%s'"
 msgstr "esperando '%s'"
 
-#: src/language/lexer/lexer.c:632
+#: src/language/lexer/lexer.c:525
 msgid "expecting string"
 msgstr "esperando cadena"
 
-#: src/language/lexer/lexer.c:646
+#: src/language/lexer/lexer.c:539
 msgid "expecting integer"
 msgstr "esperando entero"
 
-#: src/language/lexer/lexer.c:659
+#: src/language/lexer/lexer.c:552
 msgid "expecting number"
 msgstr "esperando número"
 
-#: src/language/lexer/lexer.c:671
+#: src/language/lexer/lexer.c:564
 msgid "expecting identifier"
 msgstr "esperando identificador"
 
-#: src/language/lexer/lexer.c:1065
-msgid "binary"
-msgstr "binario"
+#: src/language/lexer/lexer.c:1187
+msgid "Syntax error at end of command"
+msgstr "Error de sintaxis al final del comando"
+
+#: src/language/lexer/lexer.c:1196
+#, c-format
+msgid "Syntax error at `%s'"
+msgstr "Error de sintaxis en `%s'."
+
+#: src/language/lexer/lexer.c:1199
+msgid "Syntax error"
+msgstr "Error de sintaxis"
+
+#: src/language/lexer/lexer.c:1358
+#, c-format
+msgid "String of hex digits has %d characters, which is not a multiple of 2"
+msgstr "La cadena hexadecimal tiene %d caracteres, que no es un múltiplo de 2."
 
-#: src/language/lexer/lexer.c:1070
-msgid "octal"
-msgstr "octal"
+#: src/language/lexer/lexer.c:1365
+#, c-format
+msgid "`%c' is not a valid hex digit"
+msgstr "`%c' no es un dígito hexadecimal válido."
 
-#: src/language/lexer/lexer.c:1075
-msgid "hex"
-msgstr "hexadecimal"
+#: src/language/lexer/lexer.c:1370
+#, c-format
+msgid "Unicode string contains %d bytes, which is not in the valid range of 1 to 8 bytes"
+msgstr "Cadena Unicode contiene %d bytes, lo que está fuera del rango válido entre 1 y 8 bytes"
 
-#: src/language/lexer/lexer.c:1085
+#: src/language/lexer/lexer.c:1376
 #, c-format
-msgid "String of %s digits has %zu characters, which is not a multiple of %d."
-msgstr "La cadena de %s dígitos tiene %zu caracteres, que no es un múltiplo de %d."
+msgid "U+%04X is not a valid Unicode code point"
+msgstr "U+%04X no es un punto de código Unicode válido"
 
-#: src/language/lexer/lexer.c:1114
+#: src/language/lexer/lexer.c:1381
+msgid "Unterminated string constant"
+msgstr "Constante de cadena inacabada"
+
+#: src/language/lexer/lexer.c:1385
 #, c-format
-msgid "`%c' is not a valid %s digit."
-msgstr "'%c' no es un dígito %s válido."
+msgid "Missing exponent following `%s'"
+msgstr "Falta el exponente a continuación de `%s'"
+
+#: src/language/lexer/lexer.c:1390
+msgid "Unexpected `.' in middle of command"
+msgstr "`.' inesperado en mitad de un comando"
 
-#: src/language/lexer/lexer.c:1148
-msgid "Unterminated string constant."
-msgstr "Constante de cadena inacabada."
+#: src/language/lexer/lexer.c:1396
+#, c-format
+msgid "Bad character %s in input"
+msgstr "Caracter erróneo `%s' en la entrada"
 
-#: src/language/lexer/lexer.c:1202
-msgid "Unexpected end of file in string concatenation."
-msgstr "Final de archivo inesperado en la concatenación de cadenas."
+#: src/language/lexer/lexer.c:1490
+#, c-format
+msgid "Opening `%s': %s."
+msgstr "Abriendo `%s': %s."
 
-#: src/language/lexer/lexer.c:1210
-msgid "String expected following `+'."
-msgstr "Se espera una cadena seguida de `+'."
+#: src/language/lexer/lexer.c:1520
+#, c-format
+msgid "Error reading `%s': %s."
+msgstr "Error leyendo `%s': %s."
 
-#: src/language/lexer/lexer.c:1223
+#: src/language/lexer/lexer.c:1534
 #, c-format
-msgid "String exceeds 255 characters in length (%zu characters)."
-msgstr "La cadena supera los 255 carácteres de longitud (%zu carácteres)."
+msgid "Error closing `%s': %s."
+msgstr "Error cerrando '%s' : %s."
 
-#: src/language/lexer/format-parser.c:88
+#: src/language/lexer/format-parser.c:79
 msgid "expecting valid format specifier"
 msgstr "esperando especificador de formato válido"
 
-#: src/language/lexer/format-parser.c:107
-#: src/language/lexer/format-parser.c:126
-#: src/language/data-io/placement-parser.c:226
+#: src/language/lexer/format-parser.c:118
+#: src/language/lexer/format-parser.c:138
+#: src/language/data-io/placement-parser.c:225
 #, c-format
-msgid "Unknown format type \"%s\"."
-msgstr "Tipo de formato \"%s\" desconocido."
+msgid "Unknown format type `%s'."
+msgstr "Tipo de formato `%s' desconocido."
 
-#: src/language/lexer/format-parser.c:121
+#: src/language/lexer/format-parser.c:133
 msgid "expecting format type"
 msgstr "esperando el tipo de formato"
 
-#: src/language/lexer/value-parser.c:60
+#: src/language/lexer/value-parser.c:65
 #, c-format
 msgid "Low end of range (%g) is below high end (%g).  The range will be treated as reversed."
 msgstr "El límite inferior del intervalo (%g) está por debajo del límite superior (%g). El intervalo será invertido."
 
-#: src/language/lexer/value-parser.c:68
+#: src/language/lexer/value-parser.c:73
 #, c-format
 msgid "Ends of range are equal (%g)."
 msgstr "Los límites del intervalo son iguales (%g)."
 
-#: src/language/lexer/value-parser.c:76
+#: src/language/lexer/value-parser.c:81
 msgid "LO or LOWEST must be part of a range."
 msgstr "LO o LOWEST tienen que ser parte del intervalo."
 
-#: src/language/lexer/value-parser.c:109
+#: src/language/lexer/value-parser.c:117
 msgid "System-missing value is not valid here."
 msgstr "Valor perdido del sistema no es válido aquí."
 
-#: src/language/lexer/value-parser.c:117
+#: src/language/lexer/value-parser.c:125
 msgid "expecting number or data string"
 msgstr "esperando nombre o cadena de datos"
 
-#: src/language/lexer/variable-parser.c:65
+#: src/language/lexer/variable-parser.c:67
 msgid "expecting variable name"
 msgstr "esperando nombre de la variable"
 
-#: src/language/lexer/variable-parser.c:75
+#: src/language/lexer/variable-parser.c:77
 #, c-format
 msgid "%s is not a variable name."
 msgstr "%s no es un nombre de variable."
 
-#: src/language/lexer/variable-parser.c:178
+#: src/language/lexer/variable-parser.c:180
 #, c-format
 msgid "%s is not a numeric variable.  It will not be included in the variable list."
 msgstr "%s no es una variable numérica. No será incluida en la lista de variables."
 
-#: src/language/lexer/variable-parser.c:181
+#: src/language/lexer/variable-parser.c:183
 #, c-format
 msgid "%s is not a string variable.  It will not be included in the variable list."
 msgstr "%s no es una variable de cadena. No será incluida en la lista de variables."
 
-#: src/language/lexer/variable-parser.c:185
+#: src/language/lexer/variable-parser.c:187
 #, c-format
 msgid "Scratch variables (such as %s) are not allowed here."
 msgstr "Las variables de trabajol  (como %s) no están permitidas aquí."
 
-#: src/language/lexer/variable-parser.c:189
+#: src/language/lexer/variable-parser.c:191
 #, c-format
 msgid "%s and %s are not the same type.  All variables in this variable list must be of the same type.  %s will be omitted from the list."
 msgstr "%s y %s no son del mismo tipo. Todas las variables de esta lista tienen que ser del mismo tipo. %s será omitida de la lista."
 
-#: src/language/lexer/variable-parser.c:195
+#: src/language/lexer/variable-parser.c:197
 #, c-format
 msgid "%s and %s are string variables with different widths.  All variables in this variable list must have the same width.  %s will be omitted from the list."
 msgstr "%s y %s son variables de cadena con tamaños diferentes. Todas las variables de esta lista deben tener el mismo tamaño. %s será omitida de la lista."
 
-#: src/language/lexer/variable-parser.c:200
-#: src/language/lexer/variable-parser.c:496
+#: src/language/lexer/variable-parser.c:202
+#: src/language/lexer/variable-parser.c:404
 #, c-format
 msgid "Variable %s appears twice in variable list."
 msgstr "La variable %s aparece dos veces en la lista de variables."
 
-#: src/language/lexer/variable-parser.c:313
+#: src/language/lexer/variable-parser.c:315
 #, c-format
 msgid "%s TO %s is not valid syntax since %s precedes %s in the dictionary."
 msgstr "%s TO %s no es una sintaxis válida debido a que %s precede %s en el diccionario."
 
-#: src/language/lexer/variable-parser.c:321
+#: src/language/lexer/variable-parser.c:323
 #, c-format
 msgid "When using the TO keyword to specify several variables, both variables must be from the same variable dictionaries, of either ordinary, scratch, or system variables.  %s is a %s variable, whereas %s is %s."
 msgstr "Cuando se utiliza la palabra clave TO para especificar diversas variables, ambas tienen que ser del mismo diccionario de variables, ya sean ordinales, scratch, o variables de sistema. %s es una variable %s, debido a que %s es %s."
 
-#: src/language/lexer/variable-parser.c:395
-msgid "incorrect use of TO convention"
-msgstr "uso incorrecto de la convención TO"
+#: src/language/lexer/variable-parser.c:381
+#, c-format
+msgid "`%s' cannot be used with TO because it does not end in a digit."
+msgstr "`%s' no puede ser utilitzado con TO por que no acaba con un dígito."
+
+#: src/language/lexer/variable-parser.c:389
+#, c-format
+msgid "Numeric suffix on `%s' is larger than supported with TO."
+msgstr "Sufijo numérico en `%s' es más largo de lo soportado con TO."
 
-#: src/language/lexer/variable-parser.c:450
+#: src/language/lexer/variable-parser.c:465
 msgid "Scratch variables not allowed here."
 msgstr "Las variables de trabajo no están permitidas aquí."
 
-#: src/language/lexer/variable-parser.c:472
+#: src/language/lexer/variable-parser.c:497
 msgid "Prefixes don't match in use of TO convention."
 msgstr "Los prefijos no coinciden en el uso de la convención TO."
 
-#: src/language/lexer/variable-parser.c:477
+#: src/language/lexer/variable-parser.c:502
 msgid "Bad bounds in use of TO convention."
 msgstr "Límites incorrectos en el uso de la convención TO."
 
-#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:203
+#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:204
 #, c-format
 msgid "When executing COMPUTE: SYSMIS is not a valid value as an index into vector %s."
 msgstr "Cuando se ejecuta COMPUTE: SYSMIS no es un valor válido como índice en el vector %s."
 
-#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:210
+#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:211
 #, c-format
 msgid "When executing COMPUTE: %g is not a valid value as an index into vector %s."
 msgstr "Cuando se ejecuta COMPUTE: %g no es un valor válid como índice en el vector %s."
 
-#: src/language/xforms/compute.c:353
+#: src/language/xforms/compute.c:355
 #, c-format
 msgid "There is no vector named %s."
 msgstr "No hay ningún vector llamado %s."
 
-#: src/language/xforms/count.c:123
+#: src/language/xforms/count.c:125
 msgid "Destination cannot be a string variable."
 msgstr "El destino no puede ser una variable de cadena."
 
@@ -1398,38 +1389,38 @@ msgstr "El factor de mostreo tiene que estar exclusivamente entre 0 y 1."
 msgid "Cannot sample %d observations from a population of %d."
 msgstr "No se puede hacer una muestra de %d observaciones de una población de %d."
 
-#: src/language/xforms/recode.c:248
+#: src/language/xforms/recode.c:255
 msgid "Inconsistent target variable types.  Target variables must be all numeric or all string."
 msgstr "Tipo inconsistente de variables objetivo.  Las variables objetivo tienen que ser todas, o bien de cadena o bien numéricas."
 
-#: src/language/xforms/recode.c:269
+#: src/language/xforms/recode.c:276
 msgid "CONVERT requires string input values and numeric output values."
 msgstr "CONVERT requiere valores de entrada de cadena y valores de salida numéricos."
 
-#: src/language/xforms/recode.c:324
+#: src/language/xforms/recode.c:333
 msgid "THRU is not allowed with string variables."
 msgstr "THRU no es permitido con variables de cadena."
 
-#: src/language/xforms/recode.c:403
+#: src/language/xforms/recode.c:416
 msgid "expecting output value"
 msgstr "esperando el valor de salida"
 
-#: src/language/xforms/recode.c:460
+#: src/language/xforms/recode.c:473
 #, c-format
 msgid "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same number of variables as source and target variables."
 msgstr "%zu variable(s) no pueden ser recodificadas en %zu variable(s).  Especifique el mismo número de variables como origen y destino."
 
-#: src/language/xforms/recode.c:475
+#: src/language/xforms/recode.c:488
 #, c-format
 msgid "There is no variable named %s.  (All string variables specified on INTO must already exist.  Use the STRING command to create a string variable.)"
 msgstr "No existe ninguna variable llamada %s. (Todas las variables de cadena especificadas en INTO tienen que existir. Utilice el comando STRING para crear una variable de cadena.)"
 
-#: src/language/xforms/recode.c:491
+#: src/language/xforms/recode.c:504
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr "INTO es necesario con %s valores de entrada y %s valores de salida."
 
-#: src/language/xforms/recode.c:504
+#: src/language/xforms/recode.c:517
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr "Desajuste de tipo. No se puede almacenar %s datos en %s variable %s."
@@ -1446,17 +1437,17 @@ msgstr "La variable de filtro tiene que ser numérica."
 msgid "The filter variable may not be scratch."
 msgstr "La variable de filtro no puede ser cero."
 
-#: src/language/control/control-stack.c:27
+#: src/language/control/control-stack.c:31
 #, c-format
 msgid "%s without %s."
 msgstr "%s sin %s."
 
-#: src/language/control/control-stack.c:55
+#: src/language/control/control-stack.c:59
 #, c-format
 msgid "This command must appear inside %s...%s, without intermediate %s...%s."
 msgstr "Esta orden tiene que aparecer dentro de %s...%s, sin intermediarios %s...%s."
 
-#: src/language/control/control-stack.c:72
+#: src/language/control/control-stack.c:76
 #, c-format
 msgid "This command cannot appear outside %s...%s."
 msgstr "Este comando no puede aparecer fuera de %s...%s."
@@ -1469,61 +1460,65 @@ msgstr "Este comando no puede seguir ELSE en DO IF...END IF."
 msgid "Only one index clause may be specified."
 msgstr "Únicamente puede ser especificada una cláusula del índice."
 
-#: src/language/control/temporary.c:46
-msgid "This command may only appear once between procedures and procedure-like commands."
-msgstr "Esta orden únicamente puede aparecer una vez entre las órdenes de procedimientos y casi-procedimientos."
-
-#: src/language/control/repeat.c:172
+#: src/language/control/repeat.c:115
 #, c-format
-msgid "Dummy variable name \"%s\" hides dictionary variable \"%s\"."
-msgstr "El nombre de la variable ficticia \"%s\" oculta la variable de diccionario \"%s\"."
+msgid "Dummy variable name `%s' hides dictionary variable `%s'."
+msgstr "El nombre de la variable ficticia `%s' oculta la variable de diccionario `%s'."
 
-#: src/language/control/repeat.c:177
+#: src/language/control/repeat.c:119
 #, c-format
-msgid "Dummy variable name \"%s\" is given twice."
-msgstr "El nombre de la variable ficticia \"%s\" se da dos veces."
+msgid "Dummy variable name `%s' is given twice."
+msgstr "El nombre de la variable ficticia `%s' se da dos veces."
 
-#: src/language/control/repeat.c:223
+#: src/language/control/repeat.c:162
 #, c-format
-msgid "Dummy variable \"%.*s\" had %d substitutions, so \"%.*s\" must also, but %d were specified."
-msgstr "Una variable ficticia \"%.*s\" tiene %d substituciones, de forma tal que \"%.*s\" también tendría que tenerlas, pero se especificaron %d."
-
-# recursivamente? recurridamente? repetidamente?
-#: src/language/control/repeat.c:335
-msgid "DO REPEAT may not nest in compatibility mode."
-msgstr "DO REPEAT no puede usarse recursivamente en modo compatibilidad."
+msgid "Dummy variable `%s' had %d substitutions, so `%s' must also, but %d were specified."
+msgstr "La variable ficticia `%s' tiene %d substituciones, así que `%s' también tendría que tenerlas, pero se especificaron %d."
 
-#: src/language/control/repeat.c:437
-msgid "Ranges may only have integer bounds"
-msgstr "Los intervalos únicamente pueden tener límites enteros"
+#: src/language/control/repeat.c:366
+msgid "Ranges may only have integer bounds."
+msgstr "Los intervalos únicamente pueden tener límites enteros."
 
-#: src/language/control/repeat.c:446
+#: src/language/control/repeat.c:380
 #, c-format
-msgid "%g TO %g is an invalid range."
-msgstr "%g TO %g es un intervalo inválido."
+msgid "%ld TO %ld is an invalid range."
+msgstr "%ld TO %ld es un intervalo inválido."
 
-#: src/language/control/repeat.c:481
+#: src/language/control/repeat.c:414
 msgid "String expected."
 msgstr "Cadena esperada."
 
-#: src/language/control/repeat.c:500
+#: src/language/control/repeat.c:431
 msgid "No matching DO REPEAT."
 msgstr "DO REPEAT no coincide."
 
-#: src/language/dictionary/attributes.c:108
+#: src/language/control/temporary.c:45
+msgid "This command may only appear once between procedures and procedure-like commands."
+msgstr "Esta orden únicamente puede aparecer una vez entre las órdenes de procedimientos y casi-procedimientos."
+
+#: src/language/dictionary/attributes.c:104
 msgid "Attribute array index must be between 1 and 65535."
 msgstr "El índice de la tabla de atributos tiene que estar entre 1 y 65535."
 
-#: src/language/dictionary/attributes.c:189
-msgid "expecting ATTRIBUTE= or DELETE="
-msgstr "esperando ATTRIBUTE= o DELETE="
+#: src/language/dictionary/attributes.c:200
+#: src/language/data-io/get-data.c:324 src/language/data-io/get-data.c:362
+#: src/language/data-io/get.c:99 src/language/data-io/save-translate.c:118
+#: src/language/data-io/save-translate.c:135
+#: src/language/data-io/save-translate.c:148
+#: src/language/data-io/save-translate.c:196
+#: src/language/data-io/save-translate.c:210
+#: src/language/data-io/save-translate.c:228 src/language/data-io/save.c:216
+#: src/language/data-io/save.c:231 src/language/data-io/save.c:259
+#, c-format
+msgid "expecting %s or %s"
+msgstr "esperando %s o %s"
 
-#: src/language/dictionary/apply-dictionary.c:75
+#: src/language/dictionary/apply-dictionary.c:74
 #, c-format
 msgid "Variable %s is %s in target file, but %s in source file."
 msgstr "La variable %s es %s en el archivo de destino, pero %s en el archivo de origen."
 
-#: src/language/dictionary/apply-dictionary.c:115
+#: src/language/dictionary/apply-dictionary.c:111
 msgid "No matching variables found between the source and target files."
 msgstr "No se han encontrado coincidencias de variables entre los archivos de origen y de destino."
 
@@ -1531,59 +1526,55 @@ msgstr "No se han encontrado coincidencias de variables entre los archivos de or
 msgid "DELETE VARIABLES may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "DELETE VARIABLES no puede ser utilizado después de TEMPORARY. Las transformaciones temporales serán permanentes."
 
-#: src/language/dictionary/delete-variables.c:48
-msgid "DELETE VARIABLES may not be used to delete all variables from the active file dictionary.  Use NEW FILE instead."
-msgstr "DELETE VARIABLES no puede ser utilizado para borrar todas las variables del archivo de diccionario activo. Utilizar NEW FILE en su lugar."
+#: src/language/dictionary/delete-variables.c:47
+msgid "DELETE VARIABLES may not be used to delete all variables from the active dataset dictionary.  Use NEW FILE instead."
+msgstr "DELETE VARIABLES no puede ser utilizado para borrar todas las variables del archivo de datos de diccionario activo. Utilizar NEW FILE en su lugar."
 
 #: src/language/dictionary/formats.c:90
 msgid "`(' expected after variable list."
 msgstr "`(' esperado después de la lista de variables."
 
-#: src/language/dictionary/formats.c:100 src/language/dictionary/numeric.c:74
+#: src/language/dictionary/formats.c:100 src/language/dictionary/numeric.c:75
 msgid "`)' expected after output format."
 msgstr "`)' esperado después del formato de resultados."
 
-#: src/language/dictionary/missing-values.c:56
-#: src/language/stats/aggregate.c:459
-msgid "expecting `('"
-msgstr "esperando `('"
-
-#: src/language/dictionary/missing-values.c:72
+#: src/language/dictionary/missing-values.c:70
 #, c-format
 msgid "Cannot mix numeric variables (e.g. %s) and string variables (e.g. %s) within a single list."
 msgstr "No se pueden mezclar las variables numéricas (e.g. %s) y las variables de cadena (e.g. %s) dentro de una lista única."
 
-#: src/language/dictionary/missing-values.c:116
+#: src/language/dictionary/missing-values.c:119
 #, c-format
 msgid "Truncating missing value to maximum acceptable length (%d bytes)."
 msgstr "Truncando el valor perdido a la longitud máxima aceptable (%d bytes)."
 
-#: src/language/dictionary/missing-values.c:138
+#: src/language/dictionary/missing-values.c:142
 #, c-format
 msgid "Missing values provided are too long to assign to variable of width %d."
 msgstr "Los valores perdidos proporcionados son demasiado largos para asignar a una variable de ancho %d."
 
-#: src/language/dictionary/modify-variables.c:92
+#: src/language/dictionary/modify-variables.c:91
 msgid "MODIFY VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "MODIFY VARS no puede ser utilizado después de TEMPORARY. Las transformaciones temporales serán permanentes."
 
-#: src/language/dictionary/modify-variables.c:114
+#: src/language/dictionary/modify-variables.c:113
 #: src/language/dictionary/modify-variables.c:177
+#: src/language/data-io/inpt-pgm.c:280
 #, c-format
 msgid "%s subcommand may be given at most once."
 msgstr "El subcomando %s sólo puede utilizarse una vez."
 
-#: src/language/dictionary/modify-variables.c:137
+#: src/language/dictionary/modify-variables.c:136
 msgid "Cannot specify ALL after specifying a set of variables."
 msgstr "No se puede especificar ALL después de la especificación de un conjunto de variables."
 
-#: src/language/dictionary/modify-variables.c:147
+#: src/language/dictionary/modify-variables.c:146
 #: src/language/dictionary/modify-variables.c:190
 #, c-format
 msgid "`(' expected on %s subcommand."
 msgstr "Se espera `(' en el subcomando %s."
 
-#: src/language/dictionary/modify-variables.c:159
+#: src/language/dictionary/modify-variables.c:158
 msgid "`)' expected following variable names on REORDER subcommand."
 msgstr "`)' se esperaba seguido de los nombres de la variable en el subcomando REORDER."
 
@@ -1601,182 +1592,177 @@ msgstr "Diferente número de variables en la lista de nombres antigua (%zu) y en
 msgid "`)' expected after variable lists on RENAME subcommand."
 msgstr "`)' esperado después de las listas de variables en el subcomando RENAME."
 
-#: src/language/dictionary/modify-variables.c:233
+#: src/language/dictionary/modify-variables.c:234
 msgid "KEEP subcommand may be given at most once.  It may not be given in conjunction with the DROP subcommand."
 msgstr "El subcomando KEEP puede ser emitido más de una vez. Puede ser que no sea facilitado en relación con el subcomando DROP."
 
-#: src/language/dictionary/modify-variables.c:276
+#: src/language/dictionary/modify-variables.c:277
 msgid "DROP subcommand may be given at most once.  It may not be given in conjunction with the KEEP subcommand."
 msgstr "El subcomando DROP puede ser utilizado únicamente una vez. No puede ser utilizado juntamente con el subcomando KEEP."
 
-#: src/language/dictionary/modify-variables.c:302
+#: src/language/dictionary/modify-variables.c:303
 #, c-format
 msgid "Unrecognized subcommand name `%s'."
 msgstr "Nombre del subcomando no reconocido '%s'."
 
-#: src/language/dictionary/modify-variables.c:304
+#: src/language/dictionary/modify-variables.c:305
 msgid "Subcommand name expected."
 msgstr "Nombre del subcomando esperado."
 
-#: src/language/dictionary/modify-variables.c:312
+#: src/language/dictionary/modify-variables.c:313
 msgid "`/' or `.' expected."
 msgstr "'/' o '.' esperado."
 
-#: src/language/dictionary/mrsets.c:98
-#, c-format
-msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
-msgstr "%s no es un nombre válido de variable para un conjunto de respuesta múltiple. Los conjuntos de respuesta múltiple han de comenzar con `$'."
-
-#: src/language/dictionary/mrsets.c:120
+#: src/language/dictionary/mrsets.c:116
 #, c-format
 msgid "VARIABLES specified only variable %s on %s, but at least two variables are required."
 msgstr "VARIABLES especifica sólo la variable %s en %s, pero se requieren al menos dos variables."
 
-#: src/language/dictionary/mrsets.c:153
+#: src/language/dictionary/mrsets.c:149
 msgid "Numeric VALUE must be an integer."
 msgstr "VALUE numérico debe ser un entero."
 
-#: src/language/dictionary/mrsets.c:207 src/language/dictionary/mrsets.c:213
-#: src/language/dictionary/mrsets.c:223
+#: src/language/dictionary/mrsets.c:208 src/language/dictionary/mrsets.c:214
+#: src/language/dictionary/mrsets.c:224
 #, c-format
 msgid "Required %s specification missing from %s subcommand."
 msgstr "Falta la especificación %s requerida para el subcomando %s."
 
-#: src/language/dictionary/mrsets.c:231 src/language/dictionary/mrsets.c:269
+#: src/language/dictionary/mrsets.c:232 src/language/dictionary/mrsets.c:270
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies a string VALUE, but the variables specified for this group are numeric."
 msgstr "El subcomando MDGROUPS para el grupo %s especifica un VALUE textual, pero las variables especificadas por este grupo son numéricas."
 
-#: src/language/dictionary/mrsets.c:255
+#: src/language/dictionary/mrsets.c:256
 #, c-format
 msgid "VALUE string on MDGROUP subcommand for group %s is %d bytes long, but it must be no longer than the narrowest variable in the group, which is %s with a width of %d bytes."
 msgstr "El VALUE textual del subcomando MDGROUP para el grupo %s tiene %d bytes, pero no puede ser más largo que la variable más corta del grupo, que es %s con longitud %d bytes."
 
-#: src/language/dictionary/mrsets.c:281
+#: src/language/dictionary/mrsets.c:282
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies LABELSOURCE=VARLABEL but not CATEGORYLABELS=COUNTEDVALUES.  Ignoring LABELSOURCE."
 msgstr "El subcomando MDGROUP para el grupo %s espeficifica LABELSOURCE=VARLABEL pero no CATEGORYLABELS=COUNTEDVALUES. Se ignorará LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:287
+#: src/language/dictionary/mrsets.c:288
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies both LABEL and LABELSOURCE, but only one of these subcommands may be used at a time.  Ignoring LABELSOURCE."
 msgstr "El subcomando MDGROUP para el grupo %s espeficifica LABEL i LABELSOURCE, pero sólo uno de estos subcomandos puede ser utilitzado a la vez. Se ignorará LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:327
+#: src/language/dictionary/mrsets.c:328
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s have the same variable label.  Categories represented by these variables will not be distinguishable in output."
 msgstr "Las variables %s y %s especificadas como parte del grupo dicotomico múltiple %s tienen la misma etiqueta de variable. Las categorias representadas por estas variables no seran distingibles en los resultados."
 
-#: src/language/dictionary/mrsets.c:357
+#: src/language/dictionary/mrsets.c:358
 #, c-format
 msgid "Variable %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) has no value label for its counted value.  This category will not be distinguishable in output."
 msgstr "La variable %s especificada como parte del grupe dicotomico múltiple %s (que tiene CATEGORYLABELS=COUNTEDVALUES) no tiene etiqueta de valor para su valor de recuento. Esta categoria no será distingible en los resultados."
 
-#: src/language/dictionary/mrsets.c:370
+#: src/language/dictionary/mrsets.c:371
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) have the same value label for the the group's counted value.  These categories will not be distinguishable in output."
 msgstr "Las variables %s y %s especificadas como parte del grupo dicotomico múltiple %s (que tiene CATEGORYLABELS=COUNTEDVALUES) no tiene etiqueta de valor para su valor de recuento. Esta categoria no será distingible en los resultados."
 
-#: src/language/dictionary/mrsets.c:427
+#: src/language/dictionary/mrsets.c:428
 #, c-format
 msgid "Variables specified on MCGROUP should have the same categories, but %s and %s (and possibly others) in multiple category group %s have different value labels for value %s."
 msgstr "La variables especificadas en MDGROUP deben tener las mismas categorias, pero %s y %s (y posiblemente otras) del grupo de caterorias múltiples %s tiene diferentes etiquetas de valores para el valor %s."
 
-#: src/language/dictionary/mrsets.c:484
+#: src/language/dictionary/mrsets.c:486
 #, c-format
 msgid "No multiple response set named %s."
 msgstr "Ningún conjunto multirespuesta llamado %s."
 
-#: src/language/dictionary/mrsets.c:538
-msgid "The active file dictionary does not contain any multiple response sets."
-msgstr "El diccionario del fichero activo no contiene ningún conjunto de multi-respuesta. "
+#: src/language/dictionary/mrsets.c:540
+msgid "The active dataset dictionary does not contain any multiple response sets."
+msgstr "El diccionario del fichero de datos activo no contiene ningún conjunto de multi-respuesta. "
 
-#: src/language/dictionary/mrsets.c:548
+#: src/language/dictionary/mrsets.c:550
 msgid "Multiple Response Sets"
 msgstr "Conjuntos Multi-Respuesta"
 
-#: src/language/dictionary/mrsets.c:549 src/ui/gui/psppire-var-sheet.c:534
-#: src/ui/gui/psppire-var-store.c:832
+#: src/language/dictionary/mrsets.c:551 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:833
 msgid "Name"
 msgstr "Nombre"
 
-#: src/language/dictionary/mrsets.c:550 src/ui/gui/variable-info.ui:8
+#: src/language/dictionary/mrsets.c:552 src/ui/gui/variable-info.ui:8
 msgid "Variables"
 msgstr "Variables"
 
-#: src/language/dictionary/mrsets.c:551
+#: src/language/dictionary/mrsets.c:553
 msgid "Details"
 msgstr "Detalles"
 
-#: src/language/dictionary/mrsets.c:565
+#: src/language/dictionary/mrsets.c:567
 msgid "Multiple dichotomy set"
 msgstr "Conjunto de Dicotomias Múltiples"
 
-#: src/language/dictionary/mrsets.c:566
+#: src/language/dictionary/mrsets.c:568
 msgid "Multiple category set"
 msgstr "Conjunto de Categorias Múltiples"
 
-#: src/language/dictionary/mrsets.c:568
+#: src/language/dictionary/mrsets.c:570
 #: src/language/dictionary/split-file.c:84
-#: src/language/dictionary/sys-file-info.c:344
-#: src/language/dictionary/sys-file-info.c:583
-#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:836
-#: src/ui/gui/crosstabs.ui:292 src/ui/gui/psppire.ui:1924
+#: src/language/dictionary/sys-file-info.c:338
+#: src/language/dictionary/sys-file-info.c:577
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/compute.ui:467 src/ui/gui/crosstabs.ui:292
 msgid "Label"
 msgstr "Etiqueta"
 
-#: src/language/dictionary/mrsets.c:572
+#: src/language/dictionary/mrsets.c:574
 msgid "Label source"
 msgstr "Fuente de etiquetas"
 
-#: src/language/dictionary/mrsets.c:574
+#: src/language/dictionary/mrsets.c:576
 msgid "First variable label among variables"
 msgstr "Primera etiqueta de variable entre las variables"
 
-#: src/language/dictionary/mrsets.c:575
+#: src/language/dictionary/mrsets.c:577
 msgid "Provided by user"
 msgstr "Proporcionado por el usuario"
 
-#: src/language/dictionary/mrsets.c:576
+#: src/language/dictionary/mrsets.c:578
 msgid "Counted value"
 msgstr "Valor de recuento"
 
-#: src/language/dictionary/mrsets.c:582
+#: src/language/dictionary/mrsets.c:584
 msgid "Category label source"
 msgstr "Fuente de etiquetas de categoria"
 
-#: src/language/dictionary/mrsets.c:584
+#: src/language/dictionary/mrsets.c:586
 msgid "Variable labels"
 msgstr "Etiquetas de variable"
 
-#: src/language/dictionary/mrsets.c:585
+#: src/language/dictionary/mrsets.c:587
 msgid "Value labels of counted value"
 msgstr "Etiquetas de valor del valor de recuento"
 
-#: src/language/dictionary/numeric.c:67
+#: src/language/dictionary/numeric.c:68
 #, c-format
 msgid "Format type %s may not be used with a numeric variable."
 msgstr "Tipo de formato %s no puede ser utilizado con una variable numérica."
 
-#: src/language/dictionary/numeric.c:86 src/language/dictionary/numeric.c:155
+#: src/language/dictionary/numeric.c:87 src/language/dictionary/numeric.c:157
 #, c-format
 msgid "There is already a variable named %s."
 msgstr "Ya existe una variable con nombre %s."
 
-#: src/language/dictionary/numeric.c:140
+#: src/language/dictionary/numeric.c:142
 #, c-format
 msgid "Format type %s may not be used with a string variable."
 msgstr "El tipo de formato %s no puede utilizarse con variable de cadena."
 
-#: src/language/dictionary/rename-variables.c:49
+#: src/language/dictionary/rename-variables.c:48
 msgid "RENAME VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "RENAME VARS no puede ser utilizado después de TEMPORARY.  Las transformaciones temporales serán permanentes."
 
-#: src/language/dictionary/rename-variables.c:59
+#: src/language/dictionary/rename-variables.c:58
 msgid "`(' expected."
 msgstr "'(' esperado."
 
-#: src/language/dictionary/rename-variables.c:67
+#: src/language/dictionary/rename-variables.c:66
 msgid "`=' expected between lists of new and old variable names."
 msgstr "`=' esperado entre listas de nuevos y antiguos nombres de la variable."
 
@@ -1790,268 +1776,265 @@ msgid "Renaming would duplicate variable name %s."
 msgstr "Cambiar el nombre duplicaría el nombre de la variable %s."
 
 #: src/language/dictionary/split-file.c:83
-#: src/language/dictionary/sys-file-info.c:429
-#: src/language/dictionary/sys-file-info.c:582
-#: src/language/stats/crosstabs.q:1214 src/language/stats/crosstabs.q:1241
-#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1289
-#: src/language/stats/examine.q:1841 src/language/stats/frequencies.q:813
-#: src/language/stats/reliability.q:568 src/language/stats/reliability.q:579
+#: src/language/dictionary/sys-file-info.c:423
+#: src/language/dictionary/sys-file-info.c:576
+#: src/language/stats/cochran.c:170 src/language/stats/reliability.c:753
+#: src/language/stats/reliability.c:764 src/language/stats/crosstabs.q:1234
+#: src/language/stats/crosstabs.q:1261 src/language/stats/crosstabs.q:1284
+#: src/language/stats/crosstabs.q:1309 src/language/stats/examine.q:1840
+#: src/language/stats/frequencies.q:823
 msgid "Value"
 msgstr "Valor"
 
-#: src/language/dictionary/sys-file-info.c:95
+#: src/language/dictionary/sys-file-info.c:94
 msgid "File:"
 msgstr "Archivo:"
 
-#: src/language/dictionary/sys-file-info.c:97 src/ui/gui/psppire.ui:1862
+#: src/language/dictionary/sys-file-info.c:96 src/ui/gui/compute.ui:405
 #: src/ui/gui/recode.ui:859
 msgid "Label:"
 msgstr "Etiqueta:"
 
-#: src/language/dictionary/sys-file-info.c:101
+#: src/language/dictionary/sys-file-info.c:100
 msgid "No label."
 msgstr "Sin etiqueta."
 
-#: src/language/dictionary/sys-file-info.c:104
+#: src/language/dictionary/sys-file-info.c:103
 msgid "Created:"
 msgstr "Creado:"
 
-#: src/language/dictionary/sys-file-info.c:107
+#: src/language/dictionary/sys-file-info.c:106
 msgid "Integer Format:"
 msgstr "Formato Entero:"
 
-#: src/language/dictionary/sys-file-info.c:111
-#: src/language/dictionary/sys-file-info.c:119
-#: src/language/dictionary/sys-file-info.c:124
-#: src/language/dictionary/sys-file-info.c:143
+#: src/language/dictionary/sys-file-info.c:108
+msgid "Big Endian"
+msgstr "Tipo Big-Endian."
+
+#: src/language/dictionary/sys-file-info.c:109
+msgid "Little Endian"
+msgstr "Tipo Little-Endian"
+
+#: src/language/dictionary/sys-file-info.c:110
+#: src/language/dictionary/sys-file-info.c:118
+#: src/language/dictionary/sys-file-info.c:123
+#: src/language/dictionary/sys-file-info.c:142
 msgid "Unknown"
 msgstr "Desconocido"
 
-#: src/language/dictionary/sys-file-info.c:112
+#: src/language/dictionary/sys-file-info.c:111
 msgid "Real Format:"
 msgstr "Formato Real:"
 
-#: src/language/dictionary/sys-file-info.c:114
+#: src/language/dictionary/sys-file-info.c:113
 msgid "IEEE 754 LE."
 msgstr "IEEE 754 LE."
 
-#: src/language/dictionary/sys-file-info.c:115
+#: src/language/dictionary/sys-file-info.c:114
 msgid "IEEE 754 BE."
 msgstr "IEE 754 BE."
 
-#: src/language/dictionary/sys-file-info.c:116
+#: src/language/dictionary/sys-file-info.c:115
 msgid "VAX D."
 msgstr "VAX D."
 
-#: src/language/dictionary/sys-file-info.c:117
+#: src/language/dictionary/sys-file-info.c:116
 msgid "VAX G."
 msgstr "VAX G."
 
-#: src/language/dictionary/sys-file-info.c:118
+#: src/language/dictionary/sys-file-info.c:117
 msgid "IBM 390 Hex Long."
 msgstr "IBM 390 Hex Long."
 
-#: src/language/dictionary/sys-file-info.c:120 src/ui/gui/descriptives.ui:85
-#: src/ui/gui/factor.ui:173 src/ui/gui/recode.ui:960
+#: src/language/dictionary/sys-file-info.c:119 src/ui/gui/descriptives.ui:85
+#: src/ui/gui/factor.ui:181 src/ui/gui/recode.ui:960
 msgid "Variables:"
 msgstr "Variables:"
 
-#: src/language/dictionary/sys-file-info.c:122
+#: src/language/dictionary/sys-file-info.c:121
 msgid "Cases:"
 msgstr "Casos:"
 
-#: src/language/dictionary/sys-file-info.c:127
+#: src/language/dictionary/sys-file-info.c:126
 msgid "Type:"
 msgstr "Tipo:"
 
-#: src/language/dictionary/sys-file-info.c:128
-#: src/ui/gui/psppire-data-window.c:634
+#: src/language/dictionary/sys-file-info.c:127
+#: src/ui/gui/psppire-data-window.c:621
 msgid "System File"
 msgstr "Archivo de Sistema"
 
-#: src/language/dictionary/sys-file-info.c:129
+#: src/language/dictionary/sys-file-info.c:128
 msgid "Weight:"
 msgstr "Peso:"
 
-#: src/language/dictionary/sys-file-info.c:134
+#: src/language/dictionary/sys-file-info.c:133
 msgid "Not weighted."
 msgstr "No ponderado."
 
-#: src/language/dictionary/sys-file-info.c:136
+#: src/language/dictionary/sys-file-info.c:135
 msgid "Mode:"
 msgstr "Modo:"
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 #, c-format
 msgid "Compression %s."
 msgstr "Compresión %s."
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 msgid "on"
 msgstr "activado"
 
-#: src/language/dictionary/sys-file-info.c:138
+#: src/language/dictionary/sys-file-info.c:137
 msgid "off"
 msgstr "desactivado"
 
-#: src/language/dictionary/sys-file-info.c:141
+#: src/language/dictionary/sys-file-info.c:140
 msgid "Charset:"
 msgstr "Conjunto de carácteres:"
 
-#: src/language/dictionary/sys-file-info.c:151
-#: src/language/dictionary/sys-file-info.c:344
+#: src/language/dictionary/sys-file-info.c:150
+#: src/language/dictionary/sys-file-info.c:338
 msgid "Description"
 msgstr "Descripción"
 
-#: src/language/dictionary/sys-file-info.c:152
-#: src/language/dictionary/sys-file-info.c:346
-#: src/language/dictionary/sys-file-info.c:663
+#: src/language/dictionary/sys-file-info.c:151
+#: src/language/dictionary/sys-file-info.c:340
+#: src/language/dictionary/sys-file-info.c:657
 msgid "Position"
 msgstr "Posición"
 
-#: src/language/dictionary/sys-file-info.c:199
-msgid "The active file does not have a file label."
-msgstr "El archivo activo no tiene etiqueta de archivo."
+#: src/language/dictionary/sys-file-info.c:198
+msgid "The active dataset does not have a file label."
+msgstr "El archivo de datos activo no tiene etiqueta de archivo."
 
-#: src/language/dictionary/sys-file-info.c:202
+#: src/language/dictionary/sys-file-info.c:201
 msgid "File label:"
 msgstr "Etiqueta de archivo:"
 
-#: src/language/dictionary/sys-file-info.c:277
+#: src/language/dictionary/sys-file-info.c:276
 msgid "No variables to display."
 msgstr "Ninguna variable para mostrar."
 
-#: src/language/dictionary/sys-file-info.c:291
+#: src/language/dictionary/sys-file-info.c:290
 msgid "Macros not supported."
 msgstr "Macros no disponibles."
 
-#: src/language/dictionary/sys-file-info.c:300
-msgid "The active file dictionary does not contain any documents."
-msgstr "El diccionario del archivo activo no contiene ningún documento."
+#: src/language/dictionary/sys-file-info.c:299
+msgid "The active dataset dictionary does not contain any documents."
+msgstr "El diccionario del archivo de datos activo no contiene ningún documento."
 
-#: src/language/dictionary/sys-file-info.c:308
-msgid "Documents in the active file:"
-msgstr "Documentos en el archivo activo:"
+#: src/language/dictionary/sys-file-info.c:306
+msgid "Documents in the active dataset:"
+msgstr "Documentos en el archivo de datos activo:"
 
-#: src/language/dictionary/sys-file-info.c:428
+#: src/language/dictionary/sys-file-info.c:422
 msgid "Attribute"
 msgstr "Atributo"
 
-#: src/language/dictionary/sys-file-info.c:484
+#: src/language/dictionary/sys-file-info.c:478
 #, c-format
 msgid "Format: %s"
 msgstr "Formato: %s"
 
-#: src/language/dictionary/sys-file-info.c:491
+#: src/language/dictionary/sys-file-info.c:485
 #, c-format
 msgid "Print Format: %s"
 msgstr "Formato de Impresión: %s"
 
-#: src/language/dictionary/sys-file-info.c:495
+#: src/language/dictionary/sys-file-info.c:489
 #, c-format
 msgid "Write Format: %s"
 msgstr "Formato de Escritura: %s"
 
-#: src/language/dictionary/sys-file-info.c:508
+#: src/language/dictionary/sys-file-info.c:502
 #, c-format
 msgid "Measure: %s"
 msgstr "Medida: %s"
 
-#: src/language/dictionary/sys-file-info.c:509
+#: src/language/dictionary/sys-file-info.c:503
 #: src/ui/gui/psppire-var-sheet.c:111
 msgid "Nominal"
 msgstr "Nominal"
 
-#: src/language/dictionary/sys-file-info.c:510
+#: src/language/dictionary/sys-file-info.c:504
 #: src/ui/gui/psppire-var-sheet.c:112
 msgid "Ordinal"
 msgstr "Ordinal"
 
-#: src/language/dictionary/sys-file-info.c:511
+#: src/language/dictionary/sys-file-info.c:505
 #: src/ui/gui/psppire-var-sheet.c:113
 msgid "Scale"
 msgstr "Escala"
 
-#: src/language/dictionary/sys-file-info.c:514
+#: src/language/dictionary/sys-file-info.c:508
 #, c-format
 msgid "Display Alignment: %s"
 msgstr "Alineación de la muestra: %s"
 
-#: src/language/dictionary/sys-file-info.c:515
+#: src/language/dictionary/sys-file-info.c:509
 #: src/ui/gui/psppire-var-sheet.c:104
 msgid "Left"
 msgstr "Izquierda"
 
-#: src/language/dictionary/sys-file-info.c:516
+#: src/language/dictionary/sys-file-info.c:510
 #: src/ui/gui/psppire-var-sheet.c:106
 msgid "Center"
 msgstr "Centro"
 
-#: src/language/dictionary/sys-file-info.c:517
+#: src/language/dictionary/sys-file-info.c:511
 #: src/ui/gui/psppire-var-sheet.c:105
 msgid "Right"
 msgstr "Derecha"
 
-#: src/language/dictionary/sys-file-info.c:520
+#: src/language/dictionary/sys-file-info.c:514
 #, c-format
 msgid "Display Width: %d"
 msgstr "Ancho de la muestra: %d"
 
-#: src/language/dictionary/sys-file-info.c:534
+#: src/language/dictionary/sys-file-info.c:528
 msgid "Missing Values: "
 msgstr "Valores perdidos: "
 
-#: src/language/dictionary/sys-file-info.c:643
+#: src/language/dictionary/sys-file-info.c:637
 msgid "No vectors defined."
 msgstr "Vectores no definidos."
 
-#: src/language/dictionary/sys-file-info.c:662
+#: src/language/dictionary/sys-file-info.c:656
 msgid "Vector"
 msgstr "Vector"
 
-#: src/language/dictionary/sys-file-info.c:665
+#: src/language/dictionary/sys-file-info.c:659
 msgid "Print Format"
 msgstr "Formato de Impresión"
 
-#: src/language/dictionary/value-labels.c:150
-msgid "Truncating value label to 60 characters."
-msgstr "Truncando etiqueta de valor a 60 caracteres."
-
-#: src/language/dictionary/variable-label.c:51
-msgid "String expected for variable label."
-msgstr "Se espera una cadena como etiqueta de variable."
-
-#: src/language/dictionary/variable-label.c:59
-msgid "Truncating variable label to 255 characters."
-msgstr "Truncando la etiqueta de variable a 255 caracteres."
+#: src/language/dictionary/value-labels.c:154
+#, c-format
+msgid "Truncating value label to %d bytes."
+msgstr "Truncando etiqueta de valor a %d caracteres."
 
-#: src/language/dictionary/vector.c:64
+#: src/language/dictionary/vector.c:65
 #, c-format
 msgid "A vector named %s already exists."
 msgstr "Un vector llamado %s ya existe."
 
-#: src/language/dictionary/vector.c:72
+#: src/language/dictionary/vector.c:73
 #, c-format
 msgid "Vector name %s is given twice."
 msgstr "El nombre del vector %s se da dos veces."
 
-#: src/language/dictionary/vector.c:96
+#: src/language/dictionary/vector.c:97
 msgid "A slash must separate each vector specification in VECTOR's long form."
 msgstr "Una barra debe separar cada especificación de vector en la forma larga de VECTOR."
 
-#: src/language/dictionary/vector.c:129
+#: src/language/dictionary/vector.c:130
 msgid "Vectors must have at least one element."
 msgstr "Los vectores deben tener al menos un elemento."
 
-#: src/language/dictionary/vector.c:150
+#: src/language/dictionary/vector.c:151
 msgid "expecting vector length"
 msgstr "esperando longitud del vector"
 
-#: src/language/dictionary/vector.c:166
-#, c-format
-msgid "%s is too long for a variable name."
-msgstr "%s es demasiado largo para un nombre de variable."
-
 #: src/language/dictionary/vector.c:171
 #, c-format
 msgid "%s is an existing variable name."
@@ -2069,201 +2052,268 @@ msgstr "La variable de ponderación debe ser numérica."
 msgid "The weighting variable may not be scratch."
 msgstr "La variable de ponderación no puede ser cero."
 
-#: src/language/tests/float-format.c:124
-#, c-format
-msgid "%zu-byte string needed but %zu-byte string supplied."
-msgstr "Se necesita cadena de %zu-byte pero se han suministrado de %zu-byte."
-
-#: src/language/tests/float-format.c:136
-msgid "Hexadecimal floating constant too long."
-msgstr "Constante hexadecimal flotante demasiado larga."
-
-#: src/language/tests/float-format.c:201
-#, c-format
-msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
-msgstr "conversión %s de %s desde %s en %s debería haber producido %s pero actualmente ha producido %s."
-
-#: src/language/tests/float-format.c:247
-msgid "Too many values in single command."
-msgstr "Demasiados valores en un sólo comando."
-
-#: src/language/tests/moments-test.c:47
+#: src/language/tests/moments-test.c:50
 msgid "expecting weight value"
 msgstr "esperando valor de ponderación"
 
-#: src/language/utilities/cd.c:41
+#: src/language/utilities/cd.c:45
 #, c-format
 msgid "Cannot change directory to %s:  %s "
 msgstr "No se puede cambiar el directorio para %s: %s"
 
-#: src/language/utilities/date.c:32
+#: src/language/utilities/date.c:33
 msgid "Only USE ALL is currently implemented."
 msgstr "Sólo USE ALL se está aplicando actualmente."
 
-#: src/language/utilities/title.c:103
+#: src/language/utilities/host.c:87
 #, c-format
-msgid "   (Entered %s)"
-msgstr "   (Introducido %s)"
+msgid "Couldn't fork: %s."
+msgstr "Imposible crear fork: %s."
 
-#: src/language/utilities/include.c:95
-msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
-msgstr "Esperando BATCH o INTERACTIVE después de SYNTAX."
+#: src/language/utilities/host.c:102
+msgid "Interactive shell not supported on this platform."
+msgstr "Intérprete de órdenes interactivo no disponible para esta plataforma."
 
-#: src/language/utilities/include.c:112
-msgid "Expecting YES or NO after CD."
-msgstr "Esperando YES o NO después del CD."
+#: src/language/utilities/host.c:114
+msgid "Command shell not supported on this platform."
+msgstr "Intérprete de órdenes no disponible para esta plataforma."
 
-#: src/language/utilities/include.c:129
-msgid "Expecting CONTINUE or STOP after ERROR."
-msgstr "Esperando CONTINUE o bien STOP después del ERROR."
+#: src/language/utilities/host.c:120
+#, c-format
+msgid "Error executing command: %s."
+msgstr "Error de ejecución del comando: %s."
 
-#: src/language/utilities/include.c:136
+#: src/language/utilities/title.c:97
 #, c-format
-msgid "Unexpected token: `%s'."
-msgstr "Testimonio inesperado: `%s'."
+msgid "   (Entered %s)"
+msgstr "   (Introducido %s)"
 
-#: src/language/utilities/include.c:181
+#: src/language/utilities/include.c:64
 msgid "expecting file name"
 msgstr "esperando nombre de archivo"
 
-#: src/language/utilities/include.c:193
+#: src/language/utilities/include.c:74
 #, c-format
 msgid "Can't find `%s' in include file search path."
 msgstr "No se puede encontrar `%s' en la ruta de búsqueda del archivo de inclusión."
 
-#: src/language/utilities/include.c:201
+#: src/language/utilities/include.c:107
+#, c-format
+msgid "expecting %s, %s, or %s after %s"
+msgstr "esperando %s, %s, o %s tras %s"
+
+#: src/language/utilities/include.c:125 src/language/utilities/include.c:143
 #, c-format
-msgid "Unable to open `%s': %s."
-msgstr "No se puede abrir `%s': %s."
+msgid "expecting %s or %s after %s"
+msgstr "esperando %s o %s tras %s"
 
-#: src/language/utilities/permissions.c:73
+#: src/language/utilities/permissions.c:78
 #, c-format
 msgid "Expecting %s or %s."
 msgstr "Esperando %s o bien %s."
 
-#: src/language/utilities/permissions.c:106
+#: src/language/utilities/permissions.c:113
 #, c-format
 msgid "Cannot stat %s: %s"
 msgstr "No se puede decir que %s: %s"
 
-#: src/language/utilities/permissions.c:119
+#: src/language/utilities/permissions.c:127
 #, c-format
 msgid "Cannot change mode of %s: %s"
 msgstr "No se puede cambiar el modo de %s: %s"
 
-#: src/language/stats/aggregate.c:220
-msgid "while expecting COLUMNWISE"
-msgstr "mientras tanto esperando COLUMNWISE"
+#: src/language/stats/aggregate.c:95
+msgid "Sum of values"
+msgstr "Suma de valores"
+
+#: src/language/stats/aggregate.c:96
+msgid "Mean average"
+msgstr "Media promedio"
+
+#: src/language/stats/aggregate.c:97
+msgid "Median average"
+msgstr "Mediana Promedio"
+
+#: src/language/stats/aggregate.c:98 src/ui/gui/descriptives-dialog.c:40
+#: src/ui/gui/frequencies-dialog.c:41
+msgid "Standard deviation"
+msgstr "Desviación Estándar"
+
+#: src/language/stats/aggregate.c:99
+msgid "Maximum value"
+msgstr "Valor Máximo"
+
+#: src/language/stats/aggregate.c:100
+msgid "Minimum value"
+msgstr "Valor Mínimo"
+
+#: src/language/stats/aggregate.c:101
+msgid "Percentage greater than"
+msgstr "Porcentaje mayor que"
+
+#: src/language/stats/aggregate.c:102
+msgid "Percentage less than"
+msgstr "Porcentaje menor que"
+
+#: src/language/stats/aggregate.c:103
+msgid "Percentage included in range"
+msgstr "Porcentaje incluido en rango"
+
+#: src/language/stats/aggregate.c:104
+msgid "Percentage excluded from range"
+msgstr "Porcentaje excluido del rango"
+
+#: src/language/stats/aggregate.c:105
+msgid "Fraction greater than"
+msgstr "Fracción mayor que"
+
+#: src/language/stats/aggregate.c:106
+msgid "Fraction less than"
+msgstr "Fracción menor que"
 
-#: src/language/stats/aggregate.c:247
-msgid "expecting BREAK"
-msgstr "esperando BREAK"
+#: src/language/stats/aggregate.c:107
+msgid "Fraction included in range"
+msgstr "Fracción incluida en rango"
 
-#: src/language/stats/aggregate.c:252
+#: src/language/stats/aggregate.c:108
+msgid "Fraction excluded from range"
+msgstr "Fracción excluida del rango"
+
+#: src/language/stats/aggregate.c:109
+msgid "Number of cases"
+msgstr "Número de casos"
+
+#: src/language/stats/aggregate.c:110
+msgid "Number of cases (unweighted)"
+msgstr "Número de casos (sin ponderar)"
+
+#: src/language/stats/aggregate.c:111
+msgid "Number of missing values"
+msgstr "Número de valores perdidos"
+
+#: src/language/stats/aggregate.c:112
+msgid "Number of missing values (unweighted)"
+msgstr "Número de valores perdidos (sin ponderar)"
+
+#: src/language/stats/aggregate.c:113
+msgid "First non-missing value"
+msgstr "Primer valor no-perdido"
+
+#: src/language/stats/aggregate.c:114
+msgid "Last non-missing value"
+msgstr "Último valor no-perdido"
+
+#: src/language/stats/aggregate.c:226 src/language/data-io/get-data.c:473
+#, c-format
+msgid "expecting %s"
+msgstr "esperando %s"
+
+#: src/language/stats/aggregate.c:257
 msgid "When PRESORTED is specified, specifying sorting directions with (A) or (D) has no effect.  Output data will be sorted the same way as the input data."
 msgstr "Cuando se especifica PRESORTED, dar directivas de ordenación con (A) o (D) no tiene efecto. Los datos de salida serán ordenados de la misma manera que los de entrada."
 
-#: src/language/stats/aggregate.c:424
+#: src/language/stats/aggregate.c:447
 msgid "expecting aggregation function"
 msgstr "esperando una función agregadora"
 
-#: src/language/stats/aggregate.c:442
+#: src/language/stats/aggregate.c:459
 #, c-format
 msgid "Unknown aggregation function %s."
 msgstr "Función agregadora desconocida %s."
 
-#: src/language/stats/aggregate.c:498
+#: src/language/stats/aggregate.c:513
 #, c-format
 msgid "Missing argument %zu to %s."
 msgstr "Argumento perdido %zu para %s."
 
-#: src/language/stats/aggregate.c:507
+#: src/language/stats/aggregate.c:522
 #, c-format
 msgid "Arguments to %s must be of same type as source variables."
 msgstr "Los argumentos para %s deben ser del mismo tipo que las variables de origen."
 
-#: src/language/stats/aggregate.c:517 src/language/expressions/parse.c:885
-msgid "expecting `)'"
-msgstr "esperando ')'"
-
-#: src/language/stats/aggregate.c:529
+#: src/language/stats/aggregate.c:541
 #, c-format
 msgid "Number of source variables (%zu) does not match number of target variables (%zu)."
 msgstr "Número de variables de origen (%zu) no coincide con el número de variables de destino (%zu)."
 
-#: src/language/stats/aggregate.c:545
+#: src/language/stats/aggregate.c:557
 #, c-format
 msgid "The value arguments passed to the %s function are out-of-order.  They will be treated as if they had been specified in the correct order."
 msgstr "El valor de los argumentos pasados en la función %s están fuera de orden. Serán tratatos como si hubieran sido especificados en el orden correcto."
 
-#: src/language/stats/aggregate.c:615
+#: src/language/stats/aggregate.c:631
 #, c-format
 msgid "Variable name %s is not unique within the aggregate file dictionary, which contains the aggregate variables and the break variables."
 msgstr "El nombre de variable %s no es único dentro del archivo de diccionario agregado, que contiene las variables agregadas y las variables de corte."
 
-#: src/language/stats/autorecode.c:116
+#: src/language/stats/autorecode.c:128
 #, c-format
 msgid "Source variable count (%zu) does not match target variable count (%zu)."
 msgstr "El recuento de la variable de origen (%zu) no coincide con el recuento de la variable de destino (%zu)."
 
-#: src/language/stats/autorecode.c:128
+#: src/language/stats/autorecode.c:140
 #, c-format
 msgid "Target variable %s duplicates existing variable %s."
 msgstr "Variable de destino %s duplica una variable existente %s."
 
-#: src/language/stats/binomial.c:141
+#: src/language/stats/binomial.c:136
 #, c-format
 msgid "Variable %s is not dichotomous"
 msgstr "La variable %s no es dicotómica"
 
-#: src/language/stats/binomial.c:192 src/ui/gui/binomial.ui:13
+#: src/language/stats/binomial.c:187 src/ui/gui/binomial.ui:13
 msgid "Binomial Test"
 msgstr "Prueba Binomial"
 
-#: src/language/stats/binomial.c:222
+#: src/language/stats/binomial.c:217
 msgid "Group1"
 msgstr "Grupo 1"
 
-#: src/language/stats/binomial.c:223
+#: src/language/stats/binomial.c:218
 msgid "Group2"
 msgstr "Grupo 2"
 
-#: src/language/stats/binomial.c:224 src/language/stats/chisquare.c:177
-#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1462
-#: src/language/stats/sign.c:92 src/language/stats/wilcoxon.c:260
-#: src/ui/gui/crosstabs-dialog.c:60 src/language/stats/crosstabs.q:823
-#: src/language/stats/crosstabs.q:1151 src/language/stats/crosstabs.q:1528
-#: src/language/stats/examine.q:1105 src/language/stats/frequencies.q:871
-#: src/language/stats/oneway.q:302 src/language/stats/oneway.q:472
-#: src/language/stats/regression.q:291 src/language/stats/reliability.q:702
+#: src/language/stats/binomial.c:219 src/language/stats/chisquare.c:177
+#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1460
+#: src/language/stats/kruskal-wallis.c:292
+#: src/language/stats/mann-whitney.c:188 src/language/stats/oneway.c:616
+#: src/language/stats/oneway.c:786 src/language/stats/reliability.c:533
+#: src/language/stats/sign.c:95 src/language/stats/wilcoxon.c:255
+#: src/ui/gui/crosstabs-dialog.c:59 src/language/stats/crosstabs.q:832
+#: src/language/stats/crosstabs.q:1176 src/language/stats/crosstabs.q:1560
+#: src/language/stats/examine.q:1104 src/language/stats/frequencies.q:881
+#: src/language/stats/regression.q:293
 msgid "Total"
 msgstr "Total"
 
-#: src/language/stats/binomial.c:257 src/language/stats/chisquare.c:199
-#: src/language/stats/crosstabs.q:1239 src/language/stats/crosstabs.q:1286
+#: src/language/stats/binomial.c:252 src/language/stats/chisquare.c:199
+#: src/language/stats/crosstabs.q:1259 src/language/stats/crosstabs.q:1306
 msgid "Category"
 msgstr "Categoría"
 
-#: src/language/stats/binomial.c:258 src/language/stats/correlations.c:119
-#: src/language/stats/correlations.c:227 src/language/stats/npar-summary.c:122
-#: src/language/stats/sign.c:72 src/language/stats/wilcoxon.c:243
-#: src/language/stats/crosstabs.q:830 src/language/stats/examine.q:1176
-#: src/language/stats/frequencies.q:1034 src/language/stats/oneway.q:385
-#: src/language/stats/reliability.q:705 src/language/stats/t-test.q:505
-#: src/language/stats/t-test.q:525 src/language/stats/t-test.q:625
-#: src/language/stats/t-test.q:1101
+#: src/language/stats/binomial.c:253 src/language/stats/cochran.c:211
+#: src/language/stats/correlations.c:120 src/language/stats/correlations.c:228
+#: src/language/stats/friedman.c:275 src/language/stats/kruskal-wallis.c:257
+#: src/language/stats/mann-whitney.c:190 src/language/stats/npar-summary.c:123
+#: src/language/stats/oneway.c:686 src/language/stats/reliability.c:536
+#: src/language/stats/sign.c:74 src/language/stats/wilcoxon.c:238
+#: src/language/stats/crosstabs.q:839 src/language/stats/examine.q:1175
+#: src/language/stats/frequencies.q:1043 src/language/stats/t-test.q:509
+#: src/language/stats/t-test.q:529 src/language/stats/t-test.q:629
+#: src/language/stats/t-test.q:1105
 msgid "N"
 msgstr "N"
 
-#: src/language/stats/binomial.c:259
+#: src/language/stats/binomial.c:254
 msgid "Observed Prop."
 msgstr "Prop. Observada"
 
-#: src/language/stats/binomial.c:260
+#: src/language/stats/binomial.c:255
 msgid "Test Prop."
 msgstr "Prop. Test"
 
-#: src/language/stats/binomial.c:263
+#: src/language/stats/binomial.c:258 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1241
 #, c-format
 msgid "Exact Sig. (%d-tailed)"
 msgstr "Sig. Exact.(%d-tailed)"
@@ -2282,598 +2332,892 @@ msgid "Expected N"
 msgstr "N esperado"
 
 #: src/language/stats/chisquare.c:163 src/language/stats/chisquare.c:202
-#: src/ui/gui/crosstabs-dialog.c:62 src/language/stats/regression.q:290
+#: src/ui/gui/crosstabs-dialog.c:61 src/language/stats/regression.q:292
 msgid "Residual"
 msgstr "Residual"
 
-#: src/language/stats/chisquare.c:195 src/language/stats/sign.c:60
-#: src/ui/gui/frequencies.ui:9 src/ui/gui/frequencies.ui:669
+#: src/language/stats/chisquare.c:195 src/language/stats/cochran.c:159
+#: src/language/stats/sign.c:62 src/ui/gui/frequencies.ui:9
+#: src/ui/gui/frequencies.ui:669
 msgid "Frequencies"
 msgstr "Frecuencias"
 
-#: src/language/stats/chisquare.c:249 src/language/stats/sign.c:111
-#: src/language/stats/wilcoxon.c:309
+#: src/language/stats/chisquare.c:249 src/language/stats/cochran.c:208
+#: src/language/stats/friedman.c:272 src/language/stats/kruskal-wallis.c:310
+#: src/language/stats/mann-whitney.c:251 src/language/stats/sign.c:114
+#: src/language/stats/wilcoxon.c:304
 msgid "Test Statistics"
 msgstr "Pruebas Estadísticas"
 
-#: src/language/stats/chisquare.c:263
+#: src/language/stats/chisquare.c:263 src/language/stats/friedman.c:282
+#: src/language/stats/kruskal-wallis.c:313
 msgid "Chi-Square"
 msgstr "Chi-cuadrado"
 
-#: src/language/stats/chisquare.c:264 src/language/stats/crosstabs.q:1215
-#: src/language/stats/oneway.q:275 src/language/stats/oneway.q:685
-#: src/language/stats/regression.q:284 src/language/stats/t-test.q:752
-#: src/language/stats/t-test.q:923 src/language/stats/t-test.q:1010
+#: src/language/stats/chisquare.c:264 src/language/stats/cochran.c:217
+#: src/language/stats/friedman.c:285 src/language/stats/kruskal-wallis.c:316
+#: src/language/stats/oneway.c:593 src/language/stats/oneway.c:1002
+#: src/language/stats/crosstabs.q:1235 src/language/stats/regression.q:286
+#: src/language/stats/t-test.q:756 src/language/stats/t-test.q:927
+#: src/language/stats/t-test.q:1014
 msgid "df"
 msgstr "df"
 
-#: src/language/stats/chisquare.c:265
+#: src/language/stats/chisquare.c:265 src/language/stats/cochran.c:220
+#: src/language/stats/friedman.c:288 src/language/stats/kruskal-wallis.c:319
 msgid "Asymp. Sig."
 msgstr "Sign. Asint."
 
-#: src/language/stats/correlations.c:96 src/language/stats/factor.c:1720
-#: src/language/stats/npar-summary.c:108
+#: src/language/stats/cochran.c:109
+msgid "More than two values encountered.  Cochran Q test will not be run."
+msgstr "Más de dos valores encontrados.  El test Q de Cochran Q no se ejecutará."
+
+#: src/language/stats/cochran.c:172
+#, c-format
+msgid "Success (%g)"
+msgstr "Éxito (%g)"
+
+#: src/language/stats/cochran.c:173
+#, c-format
+msgid "Failure (%g)"
+msgstr "Fracaso (%g)"
+
+#: src/language/stats/cochran.c:214
+msgid "Cochran's Q"
+msgstr "Q de Cochran"
+
+#: src/language/stats/correlations.c:97 src/language/stats/factor.c:1724
+#: src/language/stats/npar-summary.c:109
 msgid "Descriptive Statistics"
 msgstr "Estadísticos Descriptivos"
 
-#: src/language/stats/correlations.c:117 src/language/stats/descriptives.c:101
-#: src/language/stats/factor.c:1741 src/language/stats/npar-summary.c:125
-#: src/ui/gui/descriptives-dialog.c:40 src/ui/gui/frequencies-dialog.c:41
-#: src/language/stats/examine.q:1444 src/language/stats/frequencies.q:105
-#: src/language/stats/oneway.q:386 src/language/stats/t-test.q:506
-#: src/language/stats/t-test.q:526 src/language/stats/t-test.q:624
-#: src/language/stats/t-test.q:917
+#: src/language/stats/correlations.c:118 src/language/stats/descriptives.c:102
+#: src/language/stats/factor.c:1745 src/language/stats/npar-summary.c:126
+#: src/language/stats/oneway.c:687 src/ui/gui/descriptives-dialog.c:39
+#: src/ui/gui/frequencies-dialog.c:40 src/language/stats/examine.q:1443
+#: src/language/stats/frequencies.q:105 src/language/stats/t-test.q:510
+#: src/language/stats/t-test.q:530 src/language/stats/t-test.q:628
+#: src/language/stats/t-test.q:921
 msgid "Mean"
 msgstr "Media"
 
-#: src/language/stats/correlations.c:118 src/language/stats/factor.c:1742
-#: src/language/stats/npar-summary.c:128 src/language/stats/examine.q:1479
-#: src/language/stats/oneway.q:387 src/language/stats/t-test.q:507
-#: src/language/stats/t-test.q:527 src/language/stats/t-test.q:626
-#: src/language/stats/t-test.q:918
+#: src/language/stats/correlations.c:119 src/language/stats/factor.c:1746
+#: src/language/stats/npar-summary.c:129 src/language/stats/oneway.c:688
+#: src/language/stats/examine.q:1478 src/language/stats/t-test.q:511
+#: src/language/stats/t-test.q:531 src/language/stats/t-test.q:630
+#: src/language/stats/t-test.q:922
 msgid "Std. Deviation"
 msgstr "Desviación Estándar"
 
-#: src/language/stats/correlations.c:190 src/language/stats/factor.c:1620
+#: src/language/stats/correlations.c:191 src/language/stats/factor.c:1618
 msgid "Correlations"
 msgstr "Correlaciones"
 
-#: src/language/stats/correlations.c:216
+#: src/language/stats/correlations.c:217
 msgid "Pearson Correlation"
 msgstr "Correlación de Pearson"
 
-#: src/language/stats/correlations.c:218 src/language/stats/oneway.q:686
-#: src/language/stats/t-test.q:753 src/language/stats/t-test.q:924
-#: src/language/stats/t-test.q:1011
+#: src/language/stats/correlations.c:219 src/language/stats/oneway.c:1003
+#: src/language/stats/t-test.q:757 src/language/stats/t-test.q:928
+#: src/language/stats/t-test.q:1015
 msgid "Sig. (2-tailed)"
 msgstr "Sign. (2-colas)"
 
-#: src/language/stats/correlations.c:218
+#: src/language/stats/correlations.c:219 src/language/stats/factor.c:1630
 msgid "Sig. (1-tailed)"
 msgstr "Sig. (1-cola)"
 
-#: src/language/stats/correlations.c:222
+#: src/language/stats/correlations.c:223
 msgid "Cross-products"
 msgstr "Productos-cruzados"
 
-#: src/language/stats/correlations.c:223
+#: src/language/stats/correlations.c:224
 msgid "Covariance"
 msgstr "Covarianza"
 
-#: src/language/stats/correlations.c:454 src/language/stats/descriptives.c:361
-#: src/language/data-io/list.q:91
+#: src/language/stats/correlations.c:456 src/language/stats/descriptives.c:363
+#: src/language/data-io/list.q:90
 msgid "No variables specified."
 msgstr "Variables no especificadas."
 
-#: src/language/stats/descriptives.c:102 src/language/stats/frequencies.q:106
-#: src/language/stats/t-test.q:508 src/language/stats/t-test.q:528
-#: src/language/stats/t-test.q:627
+#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:106
+#: src/language/stats/t-test.q:512 src/language/stats/t-test.q:532
+#: src/language/stats/t-test.q:631
 msgid "S.E. Mean"
 msgstr "Err.Est.Media"
 
-#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:109
+#: src/language/stats/descriptives.c:104 src/language/stats/frequencies.q:109
 msgid "Std Dev"
 msgstr "Desv Std"
 
-#: src/language/stats/descriptives.c:104 src/ui/gui/descriptives-dialog.c:47
-#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1474
+#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/frequencies-dialog.c:45 src/language/stats/examine.q:1473
 #: src/language/stats/frequencies.q:110
 msgid "Variance"
 msgstr "Varianza"
 
-#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:48
-#: src/ui/gui/frequencies-dialog.c:51 src/language/stats/examine.q:1510
+#: src/language/stats/descriptives.c:106 src/ui/gui/descriptives-dialog.c:47
+#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/examine.q:1509
 #: src/language/stats/frequencies.q:111
 msgid "Kurtosis"
 msgstr "Curtosis"
 
-#: src/language/stats/descriptives.c:106 src/language/stats/frequencies.q:112
+#: src/language/stats/descriptives.c:107 src/language/stats/frequencies.q:112
 msgid "S.E. Kurt"
 msgstr "Err.Est.Curt."
 
-#: src/language/stats/descriptives.c:107 src/ui/gui/descriptives-dialog.c:49
-#: src/ui/gui/frequencies-dialog.c:47 src/language/stats/examine.q:1505
+#: src/language/stats/descriptives.c:108 src/ui/gui/descriptives-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1504
 #: src/language/stats/frequencies.q:113
 msgid "Skewness"
 msgstr "Asimetría"
 
-#: src/language/stats/descriptives.c:108 src/language/stats/frequencies.q:114
+#: src/language/stats/descriptives.c:109 src/language/stats/frequencies.q:114
 msgid "S.E. Skew"
 msgstr "Err.Est.Asim."
 
-#: src/language/stats/descriptives.c:109 src/ui/gui/descriptives-dialog.c:44
-#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/examine.q:1494
+#: src/language/stats/descriptives.c:110 src/ui/gui/descriptives-dialog.c:43
+#: src/ui/gui/frequencies-dialog.c:48 src/language/stats/examine.q:1493
 #: src/language/stats/frequencies.q:115
 msgid "Range"
 msgstr "Intervalo"
 
-#: src/language/stats/descriptives.c:110 src/language/stats/npar-summary.c:131
-#: src/ui/gui/descriptives-dialog.c:42 src/ui/gui/frequencies-dialog.c:43
-#: src/language/stats/examine.q:1484 src/language/stats/frequencies.q:116
-#: src/language/stats/oneway.q:400
+#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:132
+#: src/language/stats/oneway.c:701 src/ui/gui/descriptives-dialog.c:41
+#: src/ui/gui/frequencies-dialog.c:42 src/language/stats/examine.q:1483
+#: src/language/stats/frequencies.q:116
 msgid "Minimum"
 msgstr "Mínimo"
 
-#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:134
-#: src/ui/gui/descriptives-dialog.c:43 src/ui/gui/frequencies-dialog.c:44
-#: src/language/stats/examine.q:1489 src/language/stats/frequencies.q:117
-#: src/language/stats/oneway.q:401
+#: src/language/stats/descriptives.c:112 src/language/stats/npar-summary.c:135
+#: src/language/stats/oneway.c:702 src/ui/gui/descriptives-dialog.c:42
+#: src/ui/gui/frequencies-dialog.c:43 src/language/stats/examine.q:1488
+#: src/language/stats/frequencies.q:117
 msgid "Maximum"
 msgstr "Máximo"
 
-#: src/language/stats/descriptives.c:112 src/ui/gui/descriptives-dialog.c:45
-#: src/ui/gui/frequencies-dialog.c:54 src/language/stats/frequencies.q:118
+#: src/language/stats/descriptives.c:113 src/ui/gui/descriptives-dialog.c:44
+#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/frequencies.q:118
 msgid "Sum"
 msgstr "Suma"
 
-#: src/language/stats/descriptives.c:343
+#: src/language/stats/descriptives.c:345
 #, c-format
 msgid "Z-score variable name %s would be a duplicate variable name."
 msgstr "el nombre de variable Z %s sería un nombre de variable duplicado."
 
-#: src/language/stats/descriptives.c:450
+#: src/language/stats/descriptives.c:457
 msgid "expecting statistic name: reverting to default"
 msgstr "esperando nombre del estadístico: vuelve a aplicar el defecto"
 
-#: src/language/stats/descriptives.c:523
+#: src/language/stats/descriptives.c:539
 msgid "Ran out of generic names for Z-score variables.  There are only 126 generic names: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 msgstr "Se han agotado los nombres genéricos para las variables Z.  Sólo hay 126 nombres genéricos: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 
-#: src/language/stats/descriptives.c:555
+#: src/language/stats/descriptives.c:568
 msgid "Mapping of variables to corresponding Z-scores."
 msgstr "Convirtiendo variables a las puntuaciones-Z correspondientes."
 
-#: src/language/stats/descriptives.c:559
+#: src/language/stats/descriptives.c:572
 msgid "Source"
 msgstr "Fuente"
 
-#: src/language/stats/descriptives.c:560
+#: src/language/stats/descriptives.c:573
 msgid "Target"
 msgstr "Destino"
 
-#: src/language/stats/descriptives.c:670
+#: src/language/stats/descriptives.c:683
 #, c-format
 msgid "Z-score of %s"
 msgstr "puntuación-Z de %s"
 
-#: src/language/stats/descriptives.c:884
+#: src/language/stats/descriptives.c:898
 msgid "Valid N"
 msgstr "N válido"
 
-#: src/language/stats/descriptives.c:885
+#: src/language/stats/descriptives.c:899
 msgid "Missing N"
 msgstr "N Perdidos"
 
-#: src/language/stats/descriptives.c:913
+#: src/language/stats/descriptives.c:927
 #, c-format
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr "Casos válidos = %g; casos con valor(es) perdido(s) = %g."
 
-#: src/language/stats/sort-cases.c:64
-msgid "Buffer limit must be at least 2."
-msgstr "El límite de la memoria intermedia debe ser al menos de 2."
-
-#: src/language/stats/sort-criteria.c:74
-msgid "`A' or `D' expected inside parentheses."
-msgstr "Se espera `A' o `D' dentro del paréntesis."
-
-#: src/language/stats/sort-criteria.c:79
-msgid "`)' expected."
-msgstr "`)' esperado."
-
-#: src/language/stats/sort-criteria.c:92
-#, c-format
-msgid "Variable %s specified twice in sort criteria."
-msgstr "La variable %s se especifica dos veces en los criterios de ordenación."
-
-#: src/language/stats/factor.c:803
+#: src/language/stats/factor.c:801
 msgid "Factor analysis on a single variable is not useful."
 msgstr "El análisis factorial para una única variable es inútil."
 
-#: src/language/stats/factor.c:1206
+#: src/language/stats/factor.c:1204
 msgid "Component Number"
 msgstr "Número de Componente"
 
-#: src/language/stats/factor.c:1206
+#: src/language/stats/factor.c:1204
 msgid "Factor Number"
 msgstr "Número de Factores"
 
-#: src/language/stats/factor.c:1237
+#: src/language/stats/factor.c:1235
 msgid "Communalities"
 msgstr "Comunalidades"
 
-#: src/language/stats/factor.c:1243
+#: src/language/stats/factor.c:1241
 msgid "Initial"
 msgstr "Inicial"
 
-#: src/language/stats/factor.c:1246
+#: src/language/stats/factor.c:1244
 msgid "Extraction"
 msgstr "Extracción"
 
-#: src/language/stats/factor.c:1310 src/language/stats/factor.c:1437
+#: src/language/stats/factor.c:1308 src/language/stats/factor.c:1435
 msgid "Component"
 msgstr "Componente"
 
-#: src/language/stats/factor.c:1315 src/language/stats/factor.c:1439
+#: src/language/stats/factor.c:1313 src/language/stats/factor.c:1437
 msgid "Factor"
 msgstr "Factor"
 
-#: src/language/stats/factor.c:1347 src/language/stats/factor.c:1495
-#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:699
-#: src/ui/gui/psppire-var-store.c:709 src/ui/gui/psppire-var-store.c:719
-#: src/ui/gui/psppire-var-store.c:825
+#: src/language/stats/factor.c:1345 src/language/stats/factor.c:1493
+#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:700
+#: src/ui/gui/psppire-var-store.c:710 src/ui/gui/psppire-var-store.c:720
+#: src/ui/gui/psppire-var-store.c:826
 #, c-format
 msgid "%d"
 msgstr "%d"
 
-#: src/language/stats/factor.c:1412
+#: src/language/stats/factor.c:1410
 msgid "Total Variance Explained"
 msgstr "Varianza Total Explicada"
 
-#: src/language/stats/factor.c:1444
+#: src/language/stats/factor.c:1442
 msgid "Initial Eigenvalues"
 msgstr "Valores propios Iniciales"
 
-#: src/language/stats/factor.c:1450
+#: src/language/stats/factor.c:1448
 msgid "Extraction Sums of Squared Loadings"
 msgstr "Sumas de Pesos al Cuadrado de la Extracción"
 
-#: src/language/stats/factor.c:1456
+#: src/language/stats/factor.c:1454
 msgid "Rotation Sums of Squared Loadings"
 msgstr "Rotación: Sumas de Pesos al Cuadrado "
 
-#: src/language/stats/factor.c:1464
+#: src/language/stats/factor.c:1462
 #, no-c-format
 msgid "% of Variance"
 msgstr "% de Varianza"
 
-#: src/language/stats/factor.c:1465
+#: src/language/stats/factor.c:1463
 msgid "Cumulative %"
 msgstr "% Acumulado"
 
-#: src/language/stats/factor.c:1578
+#: src/language/stats/factor.c:1576
 msgid "Correlation Matrix"
 msgstr "Matriz de Correlación"
 
-#: src/language/stats/factor.c:1632
-msgid "Sig. 1-tailed"
-msgstr "Sig. (1-cola)"
-
-#: src/language/stats/factor.c:1666
+#: src/language/stats/factor.c:1664
 msgid "Determinant"
 msgstr "Determinante"
 
-#: src/language/stats/factor.c:1743
+#: src/language/stats/factor.c:1695
+msgid "The dataset contains no complete observations. No analysis will be performed."
+msgstr "El conjunto de datos no contiene observaciones completas. No se realizará ningún análisis."
+
+#: src/language/stats/factor.c:1747
 msgid "Analysis N"
 msgstr "Análisis N"
 
-#: src/language/stats/factor.c:1776
+#: src/language/stats/factor.c:1780
 msgid "The FACTOR criteria result in zero factors extracted. Therefore no analysis will be performed."
 msgstr "El criterio FACTOR resulta en la extracción de cero factores. No se puede realizar ningún análisis."
 
-#: src/language/stats/factor.c:1782
+#: src/language/stats/factor.c:1786
 msgid "The FACTOR criteria result in more factors than variables, which is not meaningful. No analysis will be performed."
 msgstr "El criterio FACTOR resulta en más factores que variables, y esto no tiene ningún sentido."
 
-#: src/language/stats/factor.c:1865
+#: src/language/stats/factor.c:1869
 msgid "Component Matrix"
 msgstr "Matriz de Componentes"
 
-#: src/language/stats/factor.c:1865
+#: src/language/stats/factor.c:1869
 msgid "Factor Matrix"
 msgstr "Matriz de Factores"
 
-#: src/language/stats/factor.c:1871
+#: src/language/stats/factor.c:1875
 msgid "Rotated Component Matrix"
 msgstr "Matriz Rotada de Componentes"
 
-#: src/language/stats/factor.c:1871
+#: src/language/stats/factor.c:1875
 msgid "Rotated Factor Matrix"
 msgstr "Matriz Rotada de Factores"
 
-#: src/language/stats/flip.c:98
+#: src/language/stats/flip.c:99
 msgid "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "FLIP ignora TEMPORARY.  Las transformaciones temporales serán permanentes."
 
-#: src/language/stats/flip.c:150
+#: src/language/stats/flip.c:151
 msgid "Could not create temporary file for FLIP."
 msgstr "No se ha podido crear el archivo temporal para FLIP."
 
-#: src/language/stats/flip.c:327
+#: src/language/stats/flip.c:326
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr "Error reconstruyendo el archivo FLIP: %s."
 
-#: src/language/stats/flip.c:334
+#: src/language/stats/flip.c:333
 msgid "Error creating FLIP source file."
 msgstr "Error al crear el archivo de origen FLIP."
 
-#: src/language/stats/flip.c:347
+#: src/language/stats/flip.c:346
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr "Error de lectura del archivo FLIP: %s."
 
-#: src/language/stats/flip.c:349
+#: src/language/stats/flip.c:348
 msgid "Unexpected end of file reading FLIP file."
 msgstr "Final inesperado de la lectura del archivo FLIP."
 
-#: src/language/stats/flip.c:365
+#: src/language/stats/flip.c:364
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr "Error al buscar el archivo fuente FLIP: %s."
 
-#: src/language/stats/flip.c:373
+#: src/language/stats/flip.c:372
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr "Error de escritura del archivo fuente FLIP: %s."
 
-#: src/language/stats/flip.c:384
-#, c-format
-msgid "Error closing FLIP source file: %s."
-msgstr "Error de cierre del archivo de fuente FLIP: %s."
-
-#: src/language/stats/flip.c:392
+#: src/language/stats/flip.c:387
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr "Error reconstruyendo el archivo fuente FLIP: %s."
 
-#: src/language/stats/flip.c:426
+#: src/language/stats/flip.c:420
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr "Error de lectura del archivo temporal FLIP: %s."
 
-#: src/language/stats/flip.c:429
+#: src/language/stats/flip.c:423
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr "Final inesperado de la lectura del archivo temporal FLIP."
 
-#: src/language/stats/npar-summary.c:141 src/language/stats/examine.q:1996
-#: src/language/stats/examine.q:2013 src/language/stats/frequencies.q:1050
+#: src/language/stats/friedman.c:227 src/language/stats/kruskal-wallis.c:242
+#: src/language/stats/mann-whitney.c:171 src/language/stats/wilcoxon.c:225
+msgid "Ranks"
+msgstr "Rangos"
+
+#: src/language/stats/friedman.c:238 src/language/stats/kruskal-wallis.c:256
+#: src/language/stats/mann-whitney.c:196 src/language/stats/wilcoxon.c:239
+msgid "Mean Rank"
+msgstr " Rango medio"
+
+#: src/language/stats/friedman.c:279
+msgid "Kendall's W"
+msgstr "W de Kendall"
+
+#: src/language/stats/mann-whitney.c:202 src/language/stats/wilcoxon.c:240
+msgid "Sum of Ranks"
+msgstr "Suma de Rangos"
+
+#: src/language/stats/mann-whitney.c:264
+msgid "Mann-Whitney U"
+msgstr "U de Mann-Whitney"
+
+#: src/language/stats/mann-whitney.c:265
+msgid "Wilcoxon W"
+msgstr "W de Wilcoxon"
+
+#: src/language/stats/mann-whitney.c:266 src/language/stats/runs.c:396
+#: src/language/stats/wilcoxon.c:317
+msgid "Z"
+msgstr "Z"
+
+#: src/language/stats/mann-whitney.c:267 src/language/stats/runs.c:399
+#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1237
+msgid "Asymp. Sig. (2-tailed)"
+msgstr "Sig. Asint. (2-colas)"
+
+#: src/language/stats/mann-whitney.c:271 src/language/stats/sign.c:133
+#: src/language/stats/wilcoxon.c:322
+msgid "Exact Sig. (2-tailed)"
+msgstr "Sig. Exacta (2-colas)"
+
+#: src/language/stats/mann-whitney.c:272 src/language/stats/sign.c:139
+#: src/language/stats/wilcoxon.c:326
+msgid "Point Probability"
+msgstr "Punto de Probabilidad"
+
+#: src/language/stats/npar.c:337 src/language/stats/npar.c:364
+#, c-format
+msgid "The %s subcommand may be given only once."
+msgstr "El subcomando %s sólo puede utilizarse una vez."
+
+#: src/language/stats/npar.c:447
+msgid "NPAR subcommand not currently implemented."
+msgstr "Actualmente no está implementado el subcomando NPAR."
+
+#: src/language/stats/npar.c:601
+msgid "Expecting MEAN, MEDIAN, MODE or number"
+msgstr "Se espera MEAN, MEDIAN, MODE o un número."
+
+#: src/language/stats/npar.c:751
+#, c-format
+msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
+msgstr "El valor especificado para HI (%d) es menor que el especificado para LO (%d)"
+
+#: src/language/stats/npar.c:801
+#, c-format
+msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
+msgstr "Se han proporcionado %d valores esperados, pero el intervalo especificado (%d-%d) requiere exactamente %d valores."
+
+#: src/language/stats/npar.c:941 src/language/stats/t-test.q:384
+#, c-format
+msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
+msgstr "Se ha especificado PAIRED pero el número de variables antes de WITH (%zu) no coincide con el número de variables posterior (%zu)."
+
+#: src/language/stats/npar-summary.c:142 src/language/stats/examine.q:1995
+#: src/language/stats/examine.q:2012 src/language/stats/frequencies.q:1059
 #: src/ui/gui/examine.ui:345
 msgid "Percentiles"
 msgstr "Percentiles"
 
-#: src/language/stats/npar-summary.c:145
+#: src/language/stats/npar-summary.c:146
 msgid "25th"
 msgstr "25º"
 
-#: src/language/stats/npar-summary.c:148
+#: src/language/stats/npar-summary.c:149
 msgid "50th (Median)"
 msgstr "50º (Mediana)"
 
-#: src/language/stats/npar-summary.c:151
+#: src/language/stats/npar-summary.c:152
 msgid "75th"
 msgstr "75º"
 
-#: src/language/stats/roc.c:932
-msgid "Area Under the Curve"
-msgstr "Área Bajo la Curva"
+#: src/language/stats/oneway.c:542
+msgid "Number of contrast coefficients must equal the number of groups"
+msgstr "El número de coeficientes de contraste debe ser igual al número de grupos"
 
-#: src/language/stats/roc.c:934
+#: src/language/stats/oneway.c:551
 #, c-format
-msgid "Area Under the Curve (%s)"
-msgstr "Área Bajo la Curva (%s)"
+msgid "Coefficients for contrast %zu do not total zero"
+msgstr "Los coeficientes para contrastar %zu no suman cero"
 
-#: src/language/stats/roc.c:939
-msgid "Area"
-msgstr "Área"
+#: src/language/stats/oneway.c:592 src/language/stats/regression.q:285
+msgid "Sum of Squares"
+msgstr "Suma de Cuadrados"
+
+#: src/language/stats/oneway.c:594 src/language/stats/regression.q:287
+msgid "Mean Square"
+msgstr "Cuadrado medio"
+
+#: src/language/stats/oneway.c:595 src/language/stats/regression.q:288
+#: src/language/stats/t-test.q:753
+msgid "F"
+msgstr "F"
+
+#: src/language/stats/oneway.c:596 src/language/stats/oneway.c:841
+#: src/language/stats/regression.q:203 src/language/stats/regression.q:289
+msgid "Significance"
+msgstr "Significatividad"
+
+#: src/language/stats/oneway.c:614
+msgid "Between Groups"
+msgstr "Entre Grupos"
+
+#: src/language/stats/oneway.c:615
+msgid "Within Groups"
+msgstr "Intra Grupos"
 
-#: src/language/stats/roc.c:952 src/language/stats/examine.q:1641
-#: src/language/stats/oneway.q:388 src/language/stats/oneway.q:683
-#: src/language/stats/regression.q:198
+#: src/language/stats/oneway.c:648 src/language/stats/regression.q:314
+msgid "ANOVA"
+msgstr "ANOVA"
+
+#: src/language/stats/oneway.c:689 src/language/stats/oneway.c:1000
+#: src/language/stats/roc.c:975 src/language/stats/examine.q:1640
+#: src/language/stats/regression.q:200
 msgid "Std. Error"
 msgstr "Error Estándar"
 
-#: src/language/stats/roc.c:953
-msgid "Asymptotic Sig."
-msgstr "Sig. Asintótica"
+#: src/language/stats/oneway.c:695 src/language/stats/examine.q:1448
+#, c-format
+msgid "%g%% Confidence Interval for Mean"
+msgstr "Intervalo de Confianza %g%% para la Media"
 
-#: src/language/stats/roc.c:955 src/language/stats/examine.q:1455
-#: src/language/stats/oneway.q:397
+#: src/language/stats/oneway.c:698 src/language/stats/roc.c:978
+#: src/language/stats/examine.q:1454
 msgid "Lower Bound"
 msgstr "Límite Inferior"
 
-#: src/language/stats/roc.c:956 src/language/stats/examine.q:1460
-#: src/language/stats/oneway.q:398
+#: src/language/stats/oneway.c:699 src/language/stats/roc.c:979
+#: src/language/stats/examine.q:1459
 msgid "Upper Bound"
 msgstr "Límite Superior"
 
-#: src/language/stats/roc.c:960
+#: src/language/stats/oneway.c:704 src/language/stats/examine.q:1634
+#: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
+msgid "Descriptives"
+msgstr "Descriptivos"
+
+#: src/language/stats/oneway.c:838
+msgid "Levene Statistic"
+msgstr "Estadístico de Levene"
+
+#: src/language/stats/oneway.c:839
+msgid "df1"
+msgstr "df1"
+
+#: src/language/stats/oneway.c:840
+msgid "df2"
+msgstr "df2"
+
+#: src/language/stats/oneway.c:843
+msgid "Test of Homogeneity of Variances"
+msgstr "Prueba de Homogeneidad de Varianzas"
+
+#: src/language/stats/oneway.c:916
+msgid "Contrast Coefficients"
+msgstr "Coeficientes de Contraste"
+
+#: src/language/stats/oneway.c:918 src/language/stats/oneway.c:998
+msgid "Contrast"
+msgstr "Contraste"
+
+#: src/language/stats/oneway.c:996
+msgid "Contrast Tests"
+msgstr "Pruebas de contrate"
+
+#: src/language/stats/oneway.c:999
+msgid "Value of Contrast"
+msgstr "Valor de constraste"
+
+#: src/language/stats/oneway.c:1001 src/language/stats/regression.q:202
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:926
+#: src/language/stats/t-test.q:1013
+msgid "t"
+msgstr "t"
+
+#: src/language/stats/oneway.c:1053
+msgid "Assume equal variances"
+msgstr "Se asume igualdad de varianzas"
+
+#: src/language/stats/oneway.c:1057
+msgid "Does not assume equal"
+msgstr "No se asume igualdad"
+
+#: src/language/stats/reliability.c:141
+msgid "Reliability on a single variable is not useful."
+msgstr "El análisis factorial para una única variable es inútil."
+
+#: src/language/stats/reliability.c:501 src/language/stats/examine.q:1158
+msgid "Case Processing Summary"
+msgstr "Resumen del proceso de casos"
+
+#: src/language/stats/reliability.c:524 src/language/stats/crosstabs.q:829
+#: src/language/stats/examine.q:1163
+msgid "Cases"
+msgstr "Casos"
+
+#: src/language/stats/reliability.c:527 src/language/stats/crosstabs.q:830
+#: src/language/stats/examine.q:1102 src/language/stats/frequencies.q:1044
+msgid "Valid"
+msgstr "Válido"
+
+#: src/language/stats/reliability.c:530
+msgid "Excluded"
+msgstr "Excluido"
+
+#: src/language/stats/reliability.c:538
+msgid "%"
+msgstr "%"
+
+#: src/language/stats/reliability.c:583
+msgid "Item-Total Statistics"
+msgstr "Estadísticas de total de Ítems"
+
+#: src/language/stats/reliability.c:605
+msgid "Scale Mean if Item Deleted"
+msgstr "Escalar la mediana si se borra el elemento"
+
+#: src/language/stats/reliability.c:608
+msgid "Scale Variance if Item Deleted"
+msgstr "Escalar la varianza si se borra el elemento"
+
+#: src/language/stats/reliability.c:611
+msgid "Corrected Item-Total Correlation"
+msgstr "Correlación total-ítem corregida"
+
+#: src/language/stats/reliability.c:614
+msgid "Cronbach's Alpha if Item Deleted"
+msgstr "Alfa de Cronbach si se borra el elemento"
+
+#: src/language/stats/reliability.c:688
+msgid "Reliability Statistics"
+msgstr "Estadísticas de fiabilidad"
+
+#: src/language/stats/reliability.c:728 src/language/stats/reliability.c:747
+msgid "Cronbach's Alpha"
+msgstr "Alfa de Cronbach"
+
+#: src/language/stats/reliability.c:731 src/language/stats/reliability.c:756
+#: src/language/stats/reliability.c:767
+msgid "N of Items"
+msgstr "N de elementos"
+
+#: src/language/stats/reliability.c:750
+msgid "Part 1"
+msgstr "Parte 1"
+
+#: src/language/stats/reliability.c:761
+msgid "Part 2"
+msgstr "Parte 2"
+
+#: src/language/stats/reliability.c:772
+msgid "Total N of Items"
+msgstr "N total de elementos"
+
+#
+#: src/language/stats/reliability.c:775
+msgid "Correlation Between Forms"
+msgstr "Correlación entre formas"
+
+#: src/language/stats/reliability.c:779
+msgid "Spearman-Brown Coefficient"
+msgstr "Coeficiente de Spearman-Brown"
+
+#: src/language/stats/reliability.c:782
+msgid "Equal Length"
+msgstr "Ancho igual"
+
+#: src/language/stats/reliability.c:785
+msgid "Unequal Length"
+msgstr "Ancho desigual"
+
+#: src/language/stats/reliability.c:789
+msgid "Guttman Split-Half Coefficient"
+msgstr "Coeficiente Guttman de División en Mitades"
+
+#: src/language/stats/roc.c:955
+msgid "Area Under the Curve"
+msgstr "Área Bajo la Curva"
+
+#: src/language/stats/roc.c:957
+#, c-format
+msgid "Area Under the Curve (%s)"
+msgstr "Área Bajo la Curva (%s)"
+
+#: src/language/stats/roc.c:962
+msgid "Area"
+msgstr "Área"
+
+#: src/language/stats/roc.c:976
+msgid "Asymptotic Sig."
+msgstr "Sig. Asintótica"
+
+#: src/language/stats/roc.c:983
 #, c-format
 msgid "Asymp. %g%% Confidence Interval"
 msgstr "Asymp. %g%% Intervalo de Confianza"
 
-#: src/language/stats/roc.c:966
+#: src/language/stats/roc.c:989
 msgid "Variable under test"
 msgstr "Variable a prueba"
 
-#: src/language/stats/roc.c:1025
+#: src/language/stats/roc.c:1048
 msgid "Case Summary"
 msgstr "Resumen del Caso"
 
-#: src/language/stats/roc.c:1045
+#: src/language/stats/roc.c:1068
 msgid "Unweighted"
 msgstr "No ponderado"
 
-#: src/language/stats/roc.c:1046
+#: src/language/stats/roc.c:1069
 msgid "Weighted"
 msgstr "Ponderado"
 
-#: src/language/stats/roc.c:1050
+#: src/language/stats/roc.c:1073
 msgid "Valid N (listwise)"
 msgstr "N Válido (listwise)"
 
-#: src/language/stats/roc.c:1053
+#: src/language/stats/roc.c:1076
 msgid "Positive"
 msgstr "Positivo"
 
-#: src/language/stats/roc.c:1054
+#: src/language/stats/roc.c:1077
 msgid "Negative"
 msgstr "Negativo"
 
-#: src/language/stats/roc.c:1082
+#: src/language/stats/roc.c:1105
 msgid "Coordinates of the Curve"
 msgstr "Coordenadas de la Curva"
 
-#: src/language/stats/roc.c:1084
+#: src/language/stats/roc.c:1107
 #, c-format
 msgid "Coordinates of the Curve (%s)"
 msgstr "Coordenadas de la Curva (%s)"
 
-#: src/language/stats/roc.c:1092
+#: src/language/stats/roc.c:1115
 msgid "Test variable"
 msgstr "Variable de prueba"
 
-#: src/language/stats/roc.c:1094
+#: src/language/stats/roc.c:1117
 msgid "Positive if greater than or equal to"
 msgstr "Positivo si es mayor o igual a"
 
-#: src/language/stats/roc.c:1095 src/output/charts/roc-chart-cairo.c:38
+#: src/language/stats/roc.c:1118 src/output/charts/roc-chart-cairo.c:38
 msgid "Sensitivity"
 msgstr "Sensibilidad"
 
-#: src/language/stats/roc.c:1096 src/output/charts/roc-chart-cairo.c:37
+#: src/language/stats/roc.c:1119 src/output/charts/roc-chart-cairo.c:37
 msgid "1 - Specificity"
 msgstr "1 - Especificitado"
 
-#: src/language/stats/sign.c:89
+#: src/language/stats/runs.c:167
+#, c-format
+msgid "Multiple modes exist for varible `%s'.  Using %g as the threshold value."
+msgstr "Existen múltiples modos para la variable `%s'.  Se utiliza %g como valor de umbral."
+
+#: src/language/stats/runs.c:322
+msgid "Runs Test"
+msgstr "Ejecuta Test"
+
+#: src/language/stats/runs.c:367
+msgid "Test Value"
+msgstr "Valor del Test"
+
+#: src/language/stats/runs.c:371
+msgid "Test Value (mode)"
+msgstr "Valor de Test (moda)"
+
+#: src/language/stats/runs.c:375
+msgid "Test Value (mean)"
+msgstr "Valor de Test (media)"
+
+#: src/language/stats/runs.c:379
+msgid "Test Value (median)"
+msgstr "Valor de Test (mediana)"
+
+#: src/language/stats/runs.c:384
+msgid "Cases < Test Value"
+msgstr "Casos < Valor de Test"
+
+#: src/language/stats/runs.c:387
+msgid "Cases >= Test Value"
+msgstr "Casos >= Valor de Test"
+
+#: src/language/stats/runs.c:390
+msgid "Total Cases"
+msgstr "Casos Totales"
+
+#: src/language/stats/runs.c:393
+msgid "Number of Runs"
+msgstr "Número de ejecuciones"
+
+#: src/language/stats/sign.c:92
 msgid "Negative Differences"
 msgstr "Diferencias Negativas"
 
-#: src/language/stats/sign.c:90
+#: src/language/stats/sign.c:93
 msgid "Positive Differences"
 msgstr "Diferencias Positivas"
 
-#: src/language/stats/sign.c:91 src/language/stats/wilcoxon.c:259
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:254
 msgid "Ties"
 msgstr "Vínculos"
 
-#: src/language/stats/sign.c:130 src/language/stats/wilcoxon.c:327
-msgid "Exact Sig. (2-tailed)"
-msgstr "Sig. Exacta (2-colas)"
-
-#: src/language/stats/sign.c:133 src/language/stats/wilcoxon.c:328
+#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:323
 msgid "Exact Sig. (1-tailed)"
 msgstr "Sig. Exacta (1-cola)"
 
-#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:331
-msgid "Point Probability"
-msgstr "Punto de Probabilidad"
+#: src/language/stats/sort-cases.c:64
+msgid "Buffer limit must be at least 2."
+msgstr "El límite de la memoria intermedia debe ser al menos de 2."
 
-#: src/language/stats/wilcoxon.c:230
-msgid "Ranks"
-msgstr "Rangos"
+#: src/language/stats/sort-criteria.c:74
+msgid "`A' or `D' expected inside parentheses."
+msgstr "Se espera `A' o `D' dentro del paréntesis."
 
-#: src/language/stats/wilcoxon.c:244
-msgid "Mean Rank"
-msgstr " Rango medio"
+#: src/language/stats/sort-criteria.c:79
+msgid "`)' expected."
+msgstr "`)' esperado."
 
-#: src/language/stats/wilcoxon.c:245
-msgid "Sum of Ranks"
-msgstr "Suma de Rangos"
+#: src/language/stats/sort-criteria.c:92
+#, c-format
+msgid "Variable %s specified twice in sort criteria."
+msgstr "La variable %s se especifica dos veces en los criterios de ordenación."
 
-#: src/language/stats/wilcoxon.c:257
+#: src/language/stats/wilcoxon.c:252
 msgid "Negative Ranks"
 msgstr "Rangos Negativos"
 
-#: src/language/stats/wilcoxon.c:258
+#: src/language/stats/wilcoxon.c:253
 msgid "Positive Ranks"
 msgstr "Rangos Positivos"
 
-#: src/language/stats/wilcoxon.c:322
-msgid "Z"
-msgstr "Z"
-
-#: src/language/stats/wilcoxon.c:323
-msgid "Asymp. Sig. (2-tailed)"
-msgstr "Sig. Asint. (2-colas)"
-
-#: src/language/data-io/combine-files.c:210
-msgid "Cannot specify the active file since no active file has been defined."
-msgstr "No se puede especificar el fichero activo ya que ningún fichero activo ha sido definido."
+#: src/language/data-io/combine-files.c:211
+msgid "Cannot specify the active dataset since none has been defined."
+msgstr "No se puede especificar el fichero de datos activo ya que ningún fichero activo ha sido definido."
 
-#: src/language/data-io/combine-files.c:216
-msgid "This command may not be used after TEMPORARY when the active file is an input source.  Temporary transformations will be made permanent."
-msgstr "Este comando no puede ser utilizado después de TEMPORARY cuando el archivo activo es una fuente de entrada. Las transformaciones temporales serán permanentes."
+#: src/language/data-io/combine-files.c:217
+msgid "This command may not be used after TEMPORARY when the active dataset is an input source.  Temporary transformations will be made permanent."
+msgstr "Este comando no puede ser utilizado después de TEMPORARY cuando el archivo de datos activo es una fuente de entrada.  Las transformaciones temporales serán permanentes."
 
-#: src/language/data-io/combine-files.c:250
+#: src/language/data-io/combine-files.c:251
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr "Múltiples subcomandos IN  per a un único FILE o TABLE."
 
-#: src/language/data-io/combine-files.c:302
+#: src/language/data-io/combine-files.c:303
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr "El archivo %s no tiene variable BY %s."
 
-#: src/language/data-io/combine-files.c:305
+#: src/language/data-io/combine-files.c:306
 #, c-format
-msgid "Active file lacks BY variable %s."
-msgstr "Archivo activo no tiene BY variable %s."
+msgid "Active dataset lacks BY variable %s."
+msgstr "Archivo de datos activo no tiene BY variable %s."
 
-#: src/language/data-io/combine-files.c:376
+#: src/language/data-io/combine-files.c:378
 msgid "The BY subcommand is required."
 msgstr "Se necesita el subcomando BY."
 
-#: src/language/data-io/combine-files.c:381
-#: src/language/data-io/combine-files.c:386
+#: src/language/data-io/combine-files.c:383
+#: src/language/data-io/combine-files.c:388
 #, c-format
 msgid "BY is required when %s is specified."
 msgstr "BY es necesario cuando se especifica %s."
 
-#: src/language/data-io/combine-files.c:513
+#: src/language/data-io/combine-files.c:521
 msgid "Combining files with incompatible encodings. String data may not be represented correctly."
 msgstr "Combinando archivos con codificaciones incompatibles. Los datos de la cadena no podrán estar representados correctamente."
 
-#: src/language/data-io/combine-files.c:545
+#: src/language/data-io/combine-files.c:563
 #, c-format
 msgid "Variable %s in file %s has different type or width from the same variable in earlier file."
 msgstr "La variable %s en el archivo %s es de tipo o tamaño diferente respecto de la misma variable en un archivo anterior."
 
-#: src/language/data-io/combine-files.c:551
+#: src/language/data-io/combine-files.c:569
 #, c-format
 msgid "In file %s, %s is numeric."
 msgstr "En el archivo %s, %s es numérico."
 
-#: src/language/data-io/combine-files.c:554
+#: src/language/data-io/combine-files.c:572
 #, c-format
 msgid "In file %s, %s is a string variable with width %d."
 msgstr "En el archivo %s, %s es una variable de cadena con ancho %d."
 
-#: src/language/data-io/combine-files.c:559
+#: src/language/data-io/combine-files.c:577
 #, c-format
 msgid "In an earlier file, %s was numeric."
 msgstr "En un archivo anterior, %s era numérico."
 
-#: src/language/data-io/combine-files.c:562
+#: src/language/data-io/combine-files.c:580
 #, c-format
 msgid "In an earlier file, %s was a string variable with width %d."
 msgstr "En un archivo anterior, %s era una variable de cadena con un tamaño de %d."
 
-#: src/language/data-io/combine-files.c:601
+#: src/language/data-io/combine-files.c:620
 #, c-format
 msgid "Variable name %s specified on %s subcommand duplicates an existing variable name."
 msgstr "Nombre de la variable %s especificado en el subcomando %s duplica el nombre de la variable existente."
 
-#: src/language/data-io/combine-files.c:762
+#: src/language/data-io/combine-files.c:782
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr "Encontrados %zu conjuntos de casos duplicados en el archivo principal."
@@ -2890,86 +3234,91 @@ msgstr "El subcomando END sólo puede ser especificado una vez."
 msgid "Only one of FIXED, FREE, or LIST may be specified."
 msgstr "Sólo uno de FIXED, FREE, o LIST puede ser especificado."
 
-#: src/language/data-io/data-list.c:243
+#: src/language/data-io/data-list.c:244
 msgid "Encoding should not be specified for inline data. It will be ignored."
 msgstr "La codificación no debe ser especificada por los datos en línea. Será ignorada."
 
-#: src/language/data-io/data-list.c:254
+#: src/language/data-io/data-list.c:255
 msgid "The END subcommand may be used only with DATA LIST FIXED."
 msgstr "El subcomando END sólo puede ser utilizado con DATA LIST FIXED."
 
-#: src/language/data-io/data-list.c:269
+#: src/language/data-io/data-list.c:270
 msgid "At least one variable must be specified."
 msgstr "Al menos una variable debe ser especificada."
 
-#: src/language/data-io/data-list.c:368 src/language/data-io/data-list.c:457
-#: src/language/data-io/get-data.c:530
+#: src/language/data-io/data-list.c:369 src/language/data-io/data-list.c:458
+#: src/language/data-io/get-data.c:540
 #, c-format
 msgid "%s is a duplicate variable name."
 msgstr "%s es un nombre de variable duplicado."
 
-#: src/language/data-io/data-list.c:375
+#: src/language/data-io/data-list.c:376
 #, c-format
 msgid "There is already a variable %s of a different type."
 msgstr "Ya existe una variable %s de diferente tipo."
 
-#: src/language/data-io/data-list.c:382
+#: src/language/data-io/data-list.c:383
 #, c-format
 msgid "There is already a string variable %s of a different width."
 msgstr "Existe ya una variable de cadena %s con ancho diferente."
 
-#: src/language/data-io/data-list.c:390
+#: src/language/data-io/data-list.c:391
 #, c-format
 msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
 msgstr "No se puede poner la variable %s en el registro %d cuando RECORDS=%d está especificado."
 
-#: src/language/data-io/data-parser.c:460
-#: src/language/data-io/data-parser.c:469
+#: src/language/data-io/data-parser.c:458
+#: src/language/data-io/data-parser.c:467
 msgid "Quoted string extends beyond end of line."
 msgstr "La cadena entre comillas se extiende más allá del final de línea."
 
-#: src/language/data-io/data-parser.c:525
+#: src/language/data-io/data-parser.c:516
+#, c-format
+msgid "Data for variable %s is not valid as format %s: %s"
+msgstr "Los datos para la variable %s no es válido como formato %s: %s"
+
+#: src/language/data-io/data-parser.c:545
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr "Casos parciales de %d de %d registros descartados."
 
-#: src/language/data-io/data-parser.c:572
+#: src/language/data-io/data-parser.c:602
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr "Caso parcial descartado.  La primera variable que faltaba era %s."
 
-#: src/language/data-io/data-parser.c:610
+#: src/language/data-io/data-parser.c:644
 #, c-format
 msgid "Missing value(s) for all variables from %s onward.  These will be filled with the system-missing value or blanks, as appropriate."
 msgstr "Valor(es) perdido(s) para todas las variables desde %st.  Éstos se llenan con el valor perdido del sistema o espacios en blanco, según corresponda."
 
-#: src/language/data-io/data-parser.c:630
+#: src/language/data-io/data-parser.c:664
 msgid "Record ends in data not part of any field."
 msgstr "El registro termina con datos que no forman parte de ningún campo."
 
-#: src/language/data-io/data-parser.c:650 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:684 src/language/data-io/print.c:404
 msgid "Record"
 msgstr "Registro"
 
-#: src/language/data-io/data-parser.c:651 src/language/data-io/print.c:405
-#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:839
+#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:405
+#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:840
 #: src/ui/gui/crosstabs.ui:89
 msgid "Columns"
 msgstr "Columnas"
 
-#: src/language/data-io/data-parser.c:652
-#: src/language/data-io/data-parser.c:689 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:686
+#: src/language/data-io/data-parser.c:723 src/language/data-io/print.c:406
 msgid "Format"
 msgstr "Formato"
 
-#: src/language/data-io/data-parser.c:670
+#: src/language/data-io/data-parser.c:704
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] "Leyendo %d registro de %s."
 msgstr[1] "Leyendo %d registros de %s."
 
-#: src/language/data-io/data-parser.c:704
+#: src/language/data-io/data-parser.c:738
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr "Leyendo datos con formato libre de %s."
@@ -2981,41 +3330,41 @@ msgstr "Leyendo datos con formato libre de %s."
 msgid "data file"
 msgstr "archivo de datos"
 
-#: src/language/data-io/data-reader.c:150
+#: src/language/data-io/data-reader.c:148
 #, c-format
-msgid "Could not open \"%s\" for reading as a data file: %s."
-msgstr "No se ha podido abrir \"%s\" para la lectura como un archivo de datos: %s."
+msgid "Could not open `%s' for reading as a data file: %s."
+msgstr "No se ha podido abrir `%s' para la lectura como un archivo de datos: %s."
 
-#: src/language/data-io/data-reader.c:192
-msgid "Unexpected end-of-file while reading data in BEGIN DATA.  This probably indicates a missing or misformatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
-msgstr "Final de archivo inesperado durante la lectura de datos en BEGIN DATA.  Esto probablemente indica una pérdida o formato erróneo del comando END DATA.  END DATA debe aparecer por sí misma en una sola línea con exactamente un espacio entre las palabras."
+#: src/language/data-io/data-reader.c:198
+msgid "Missing END DATA while reading inline data.  This probably indicates a missing or incorrectly formatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
+msgstr "Falta END DATA durante la lectura de datos en línea.  Esto probablemente indica una pérdida o formato erróneo del comando END DATA.  END DATA debe aparecer por sí misma en una sola línea con exactamente un espacio entre las palabras."
 
-#: src/language/data-io/data-reader.c:217
+#: src/language/data-io/data-reader.c:219
 #, c-format
 msgid "Error reading file %s: %s."
 msgstr "Se ha producido un error al leer el archivo %s: %s."
 
-#: src/language/data-io/data-reader.c:220
+#: src/language/data-io/data-reader.c:222
 #, c-format
 msgid "Unexpected end of file reading %s."
 msgstr "Final inesperado en la lectura de archivo %s."
 
-#: src/language/data-io/data-reader.c:229
+#: src/language/data-io/data-reader.c:231
 #, c-format
 msgid "Unexpected end of file in partial record reading %s."
 msgstr "Final de archivo inesperado en la lectura del registro parcial %s."
 
-#: src/language/data-io/data-reader.c:289
+#: src/language/data-io/data-reader.c:291
 #, c-format
 msgid "Corrupt block descriptor word at offset 0x%lx in %s."
 msgstr "Palabra descriptiva de bloque dañada en localización 0x%lx en %s."
 
-#: src/language/data-io/data-reader.c:290
+#: src/language/data-io/data-reader.c:292
 #, c-format
 msgid "Corrupt record descriptor word at offset 0x%lx in %s."
 msgstr "Palabra descriptora de registro dañada en localización 0x%lx en %s."
 
-#: src/language/data-io/data-reader.c:303
+#: src/language/data-io/data-reader.c:305
 #, c-format
 msgid "Corrupt record size at offset 0x%lx in %s."
 msgstr "Longitud de registro dañada en localización 0x%lx en %s."
@@ -3033,124 +3382,104 @@ msgstr "Intento de leer más allá del final de archivo en %s."
 msgid "Attempt to read beyond END DATA."
 msgstr "Intento de leer más allá de END DATA."
 
-#: src/language/data-io/data-reader.c:708
+#: src/language/data-io/data-reader.c:706
 msgid "This command is not valid here since the current input program does not access the inline file."
 msgstr "Esta orden no es válida ya que el programa de entrada actual no tiene acceso al archivo en línea."
 
-#: src/language/data-io/data-writer.c:74
+#: src/language/data-io/data-writer.c:73
 #, c-format
-msgid "An error occurred while opening \"%s\" for writing as a data file: %s."
-msgstr "Se ha producido un error al abrir \"%s\" para escribirlo como un archivo de datos: %s."
+msgid "An error occurred while opening `%s' for writing as a data file: %s."
+msgstr "Se ha producido un error al abrir `%s' para escribir en él como un archivo de datos: %s."
 
-#: src/language/data-io/data-writer.c:191
+#: src/language/data-io/data-writer.c:190
 #, c-format
-msgid "I/O error occurred writing data file \"%s\"."
-msgstr "I/O error al escribir los datos del fichero \"%s\"."
+msgid "I/O error occurred writing data file `%s'."
+msgstr "Error de E/S al escribir los datos del fichero `%s'."
 
 #: src/language/data-io/get-data.c:64
 #, c-format
-msgid "Unsupported TYPE %s"
-msgstr "TYPE %s no admitido"
+msgid "Unsupported TYPE %s."
+msgstr "TYPE %s no admitido."
 
-#: src/language/data-io/get-data.c:260
+#: src/language/data-io/get-data.c:268
 #, c-format
 msgid "%s is allowed only with %s arrangement, but %s arrangement was stated or implied earlier in this command."
 msgstr "%s sólo se permite con configuración %s, pero previamente en este comando se ha establecido la configuración %s."
 
-#: src/language/data-io/get-data.c:315
-msgid "expecting FIXED or DELIMITED"
-msgstr "esperando FIXED o DELIMITED"
-
-#: src/language/data-io/get-data.c:328
+#: src/language/data-io/get-data.c:337
 msgid "Value of FIRSTCASE must be 1 or greater."
 msgstr "Valor de FIRSTCASE debe ser mayor o igual a 1."
 
-#: src/language/data-io/get-data.c:353
-msgid "expecting LINE or VARIABLES"
-msgstr "esperando LINE o VARIABLES"
-
-#: src/language/data-io/get-data.c:366
+#: src/language/data-io/get-data.c:375
 msgid "Value of FIXCASE must be at least 1."
 msgstr "Valor de FIXCASE debe ser como mínimo 1."
 
-#: src/language/data-io/get-data.c:386
+#: src/language/data-io/get-data.c:395
 msgid "Value of FIRST must be at least 1."
 msgstr "Valor de FIRST debe ser como mínimo 1."
 
-#: src/language/data-io/get-data.c:398
+#: src/language/data-io/get-data.c:407
 msgid "Value of PERCENT must be between 1 and 100."
 msgstr "Valor de PERCENT debe estar entre 1 y 100."
 
-#: src/language/data-io/get-data.c:447
+#: src/language/data-io/get-data.c:458
 msgid "In compatible syntax mode, the QUALIFIER string must contain exactly one character."
 msgstr "En el modo de sintaxis compatible, la cadena QUALIFIER debe contener exactamente un carácter."
 
-#: src/language/data-io/get-data.c:462
-msgid "expecting VARIABLES"
-msgstr "esperando VARIABLES"
-
-#: src/language/data-io/get-data.c:484
-#: src/language/data-io/placement-parser.c:378
+#: src/language/data-io/get-data.c:493
+#: src/language/data-io/placement-parser.c:377
 #, c-format
 msgid "The record number specified, %ld, is at or before the previous record, %d.  Data fields must be listed in order of increasing record number."
 msgstr "El número de registro especificado, %ld, es en o antes del registro anterior, %d.  Los campos de datos deben ser listados en orden incremental del número de registro."
 
-#: src/language/data-io/get-data.c:493
+#: src/language/data-io/get-data.c:502
 #, c-format
 msgid "The record number specified, %ld, exceeds the number of records per case specified on FIXCASE, %d."
 msgstr "El número de registro especificado, %ld, excede el número de registros para casos especificados en FIXCASE, %d."
 
-#: src/language/data-io/get.c:99
-msgid "expecting COMM or TAPE"
-msgstr "esperando COMM o TAPE"
-
-#: src/language/data-io/inpt-pgm.c:130
+#: src/language/data-io/inpt-pgm.c:118
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr "Final de archivo inesperado dentro de INPUT PROGRAM."
 
-#: src/language/data-io/inpt-pgm.c:143
+#: src/language/data-io/inpt-pgm.c:131
 msgid "Input program did not create any variables."
 msgstr "El programa de entrada no creó ninguna variable."
 
-#: src/language/data-io/inpt-pgm.c:288
-msgid "COLUMN subcommand multiply specified."
-msgstr "subcomando COLUMN especificado múltiples veces."
-
-#: src/language/data-io/inpt-pgm.c:338
+#: src/language/data-io/inpt-pgm.c:330
 msgid "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr "REREAD: Los números de columna tienen que ser números positivos finitos. La columna se establece en 1."
 
-#: src/language/data-io/placement-parser.c:87
+#: src/language/data-io/placement-parser.c:86
 #, c-format
 msgid "Number of variables specified (%zu) differs from number of variable formats (%zu)."
 msgstr "Número de variables especificadas (%zu) difiere del número de formatos de la variable (%zu)."
 
-#: src/language/data-io/placement-parser.c:97
+#: src/language/data-io/placement-parser.c:96
 msgid "SPSS-like or Fortran-like format specification expected after variable names."
 msgstr "Después del nombre de las variables se esperan especificaciones en formato tipo-SPSS o tipo-Fortran."
 
-#: src/language/data-io/placement-parser.c:119
+#: src/language/data-io/placement-parser.c:118
 #, c-format
 msgid "The %d columns %d-%d can't be evenly divided into %zu fields."
 msgstr "Las %d columnas %d-%d no pueden ser uniformemente dividas entre los campos %zu."
 
-#: src/language/data-io/placement-parser.c:305
+#: src/language/data-io/placement-parser.c:302
 msgid "Column positions for fields must be positive."
 msgstr "Las posiciones de columna para los campos tienen que ser positivas."
 
-#: src/language/data-io/placement-parser.c:307
+#: src/language/data-io/placement-parser.c:304
 msgid "Column positions for fields must not be negative."
 msgstr "Las posiciones de columnas para los campos no pueden ser negativas."
 
-#: src/language/data-io/placement-parser.c:344
+#: src/language/data-io/placement-parser.c:343
 msgid "The ending column for a field must be greater than the starting column."
 msgstr "La columna final de un campo tiene que ser mayor que la columna de inicio."
 
-#: src/language/data-io/print-space.c:116
+#: src/language/data-io/print-space.c:115
 msgid "The expression on PRINT SPACE evaluated to the system-missing value."
 msgstr "La expresión en PRINT SPACE se evalúa por el sistema de valores perdidos."
 
-#: src/language/data-io/print-space.c:119
+#: src/language/data-io/print-space.c:118
 #, c-format
 msgid "The expression on PRINT SPACE evaluated to %g."
 msgstr "La expresión en PRINT SPACE se evalúa en %g."
@@ -3178,214 +3507,227 @@ msgid_plural "Writing %zu records."
 msgstr[0] "Escribiendo el registro %zu."
 msgstr[1] "Escribiendo %zu registros."
 
-#: src/language/data-io/save.c:223 src/language/data-io/save.c:238
-#: src/language/data-io/save.c:266
+#: src/language/data-io/save-translate.c:165
+#: src/language/data-io/save-translate.c:180
 #, c-format
-msgid "expecting %s or %s"
-msgstr "esperando %s o %s"
+msgid "The %s string must contain exactly one character."
+msgstr "La cadena %s debe contener exactamente un carácter."
+
+#: src/language/data-io/save-translate.c:250
+#, c-format
+msgid "Output file `%s' exists but REPLACE was not specified."
+msgstr "El archivo de salida `%s' existe pero no ha sido especificado REPLACE."
 
-#: src/language/data-io/trim.c:88
+#: src/language/data-io/trim.c:89
 #, c-format
-msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, \"/RENAME (A B C=B C A)\"."
-msgstr "No se puede cambiar el nombre %s por %s porque ya hay una variable nombrada %s.  Para cambiar el nombre de las variables con nombre superpuesto, utilitce el subcomando RENAME únicamente como \"/RENAME (A=B)(B=C)(C=A)\", o equivalentemente, \"/RENAME (A B C=B C A)\"."
+msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, `/RENAME (A B C=B C A)'."
+msgstr "No se puede cambiar el nombre %s por %s porque ya existe una variable denominada %s.  Para renombrar variables con nombres coincidentes, utilice un sólo subcomando RENAME como `/RENAME (A=B)(B=C)(C=A)', o equivalentemente, `/RENAME (A B C=B C A)'."
 
-#: src/language/data-io/trim.c:114
+#: src/language/data-io/trim.c:115
 msgid "`=' expected after variable list."
 msgstr "`=' esperado después de lista de variables."
 
-#: src/language/data-io/trim.c:122
+#: src/language/data-io/trim.c:123
 #, c-format
 msgid "Number of variables on left side of `=' (%zu) does not match number of variables on right side (%zu), in parenthesized group %d of RENAME subcommand."
 msgstr "El número de variables en el lado izquierdo de `=' (%zu) no coincide con el número de variables en el lado derecho (%zu), en el grupo entre paréntesis %d del subcomando RENAME."
 
-#: src/language/data-io/trim.c:135
+#: src/language/data-io/trim.c:136
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr "El renombramiento pedido duplica el nombre de la variable %s."
 
-#: src/language/data-io/trim.c:166
+#: src/language/data-io/trim.c:167
 msgid "Cannot DROP all variables from dictionary."
 msgstr "Imposible DROP todas las variables del diccionario."
 
-#: src/language/expressions/evaluate.c:155
+#: src/language/expressions/evaluate.c:152
 msgid "expecting number or string"
 msgstr "esperando número o cadena"
 
-#: src/language/expressions/evaluate.c:169
+#: src/language/expressions/evaluate.c:166
 #, c-format
 msgid "Duplicate variable name %s."
 msgstr "Nombre de la variable %s duplicado."
 
-#: src/language/expressions/helpers.c:51
+#: src/language/expressions/helpers.c:41
 msgid "One of the arguments to a DATE function is not an integer.  The result will be system-missing."
 msgstr "Uno de los argumentos para función DATE no es un entero.  El resultado será perdido por el sistema."
 
-#: src/language/expressions/helpers.c:73
+#: src/language/expressions/helpers.c:69
 msgid "The week argument to DATE.WKYR is not an integer.  The result will be system-missing."
 msgstr "El argumento de semana para DATE.WKYR no es un entero. El resultado será perdido del sistema."
 
-#: src/language/expressions/helpers.c:79
+#: src/language/expressions/helpers.c:75
 msgid "The week argument to DATE.WKYR is outside the acceptable range of 1 to 53.  The result will be system-missing."
 msgstr "El argumento de semana para DATE.WKYR está fuera del intervalo aceptable entre 1 y 53.  El resultado será perdido del sistema."
 
-#: src/language/expressions/helpers.c:101
+#: src/language/expressions/helpers.c:97
 msgid "The day argument to DATE.YRDAY is not an integer.  The result will be system-missing."
 msgstr "El argumento de día para DATE.YRDAY no es un entero.  El resultado será perdido del sistema."
 
-#: src/language/expressions/helpers.c:107
+#: src/language/expressions/helpers.c:103
 msgid "The day argument to DATE.YRDAY is outside the acceptable range of 1 to 366.  The result will be system-missing."
 msgstr "El argumento de día para DATE.YRDAY está fuera del intervalo aceptable entre 1 y 366. El resultado será perdido del sistema."
 
-#: src/language/expressions/helpers.c:129
+#: src/language/expressions/helpers.c:125
 msgid "The year argument to YRMODA is greater than 47516.  The result will be system-missing."
 msgstr "El argumento año para YRMODA es más grande que 47516. El resultado será perdido del sistema."
 
-#: src/language/expressions/helpers.c:182
+#. TRANSLATORS: Don't translate the the actual unit names `weeks', `days' etc
+#. They must remain in their original English.
+#: src/language/expressions/helpers.c:180
 #, c-format
-msgid "Unrecognized date unit \"%.*s\".  Valid date units are \"years\", \"quarters\", \"months\", \"weeks\", \"days\", \"hours\", \"minutes\", and \"seconds\"."
-msgstr "Unidad de fecha \"%.*s\" no reconocida. Las unidades de fecha válidas son \"años\", \"trimestres\", \"meses\", \"semanas\", \"días\", \"horas\", \"minutos\", y \"segundos\"."
+msgid "Unrecognized date unit `%.*s'.  Valid date units are `years', `quarters', `months', `weeks', `days', `hours', `minutes', and `seconds'."
+msgstr "Unidad de fecha `%.*s' no reconocida. Las unidades de fecha válidas son `años', `trimestres', `meses', `semanas', `días', `horas', `minutos', y `segundos'."
 
-#: src/language/expressions/helpers.c:332
-msgid "Invalid DATESUM method.  Valid choices are \"closest\" and \"rollover\"."
-msgstr "Método DATESUM inválido. Las opciones válidas son \"cercana\" y  \"cumplida\"."
+#: src/language/expressions/helpers.c:330
+msgid "Invalid DATESUM method.  Valid choices are `closest' and `rollover'."
+msgstr "Método DATESUM inválido.  Las opciones válidas son `cercana' y `cumplida'."
 
-#: src/language/expressions/parse.c:259
+#: src/language/expressions/parse.c:260
 #, c-format
 msgid "Type mismatch: expression has %s type, but a numeric value is required here."
 msgstr "Incompatibilidad de tipo: la expresión tiene tipo %s, pero aquí se pide un valor numérico."
 
-#: src/language/expressions/parse.c:271
+#: src/language/expressions/parse.c:272
 #, c-format
 msgid "Type mismatch: expression has %s type, but a string value is required here."
 msgstr "Incompatibilidad de tipo: la expresión tiene tipo %s, pero aquí se pide un valor de cadena."
 
-#: src/language/expressions/parse.c:427
+#: src/language/expressions/parse.c:434
 #, c-format
 msgid "Type mismatch while applying %s operator: cannot convert %s to %s."
 msgstr "Incompatibilidad de los tipos mientras se aplica el operador %s: no se puede convertir %s en %s."
 
-#: src/language/expressions/parse.c:643
-msgid "Chaining relational operators (e.g. \"a < b < c\") will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. \"a < b AND b < c\").  If chaining is really intended, parentheses will disable this warning (e.g. \"(a < b) < c\".)"
-msgstr "El encadenamiento de operadores relacionales (p.e. \"a < b < c\") no producirà el resultado esperado matemáticamente. Utilizar el operador lógico AND para solucionar el problema (p.e. \"a < b AND b < c\"). Si el encadenamiento es realmente intencionado, los paréntesis desactivaran esta alerta (p.e. \"(a < b) < c\".)"
+#: src/language/expressions/parse.c:648
+msgid "Chaining relational operators (e.g. `a < b < c') will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. `a < b AND b < c').  If chaining is really intended, parentheses will disable this warning (e.g. `(a < b) < c'.)"
+msgstr "Los operadores relacionales de encadenamiento (p.e. `a < b < c') no produciran el resultado esperado matemáticamente. Utilizar el operador lógico AND para solucionar el problema (p.e. `a < b AND b < c'). Si el encadenamiento es realmente intencionado, los paréntesis desactivaran esta alerta (p.e. `(a < b) < c'.)"
 
-#: src/language/expressions/parse.c:744
-msgid "The exponentiation operator (\"**\") is left-associative, even though right-associative semantics are more useful.  That is, \"a**b**c\" equals \"(a**b)**c\", not as \"a**(b**c)\".  To disable this warning, insert parentheses."
-msgstr "El operador de exponenciación (\"**\") aparece a la izquierda, aunque si aparece a la derecha es más útil.  Es decir, \"a**b**c\" es igual a \"(a**b)**c\", no a \"a**(b**c)\". Para desactivar esta alerta, insertar paréntesis."
+#: src/language/expressions/parse.c:750
+msgid "The exponentiation operator (`**') is left-associative, even though right-associative semantics are more useful.  That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'.  To disable this warning, insert parentheses."
+msgstr "El operador de exponenciación (`**') aparece a la izquierda, aunque si aparece a la derecha es más útil.  Es decir, `a**b**c' equivale a `(a**b)**c', no a `a**(b**c)'. Para desactivar esta alerta, insertar paréntesis."
 
-#: src/language/expressions/parse.c:809
+#: src/language/expressions/parse.c:830
 #, c-format
 msgid "Unknown system variable %s."
 msgstr "Variable de sistema desconocida %s."
 
-#: src/language/expressions/parse.c:857
+#: src/language/expressions/parse.c:878
 #, c-format
 msgid "Unknown identifier %s."
 msgstr "Identificador desconocido %s."
 
-#: src/language/expressions/parse.c:892
-msgid "in expression"
-msgstr "en la expresión"
-
-#: src/language/expressions/parse.c:1073
+#: src/language/expressions/parse.c:1100
 #, c-format
 msgid "%s must have at least %d arguments in list."
 msgstr "%s debe tener como mínimo %d argumentos en la lista."
 
-#: src/language/expressions/parse.c:1082
+#: src/language/expressions/parse.c:1109
 #, c-format
-msgid "%s must have even number of arguments in list."
-msgstr "%s tienen que tener un número par de argumentos en la lista."
+msgid "%s must have an even number of arguments in list."
+msgstr "%s tiene que tener un número par de argumentos en la lista."
 
-#: src/language/expressions/parse.c:1085
+#: src/language/expressions/parse.c:1112
 #, c-format
 msgid "%s must have multiple of %d arguments in list."
 msgstr "%s tiene que tener un múltiplo de %d argumentos en la lista."
 
-#: src/language/expressions/parse.c:1095
+#: src/language/expressions/parse.c:1122
 #, c-format
 msgid "%s function does not accept a minimum valid argument count."
 msgstr "la función %s no acepta un mínimo recuento de argumentos válidos."
 
-#: src/language/expressions/parse.c:1104
+#: src/language/expressions/parse.c:1131
 #, c-format
 msgid "%s requires at least %d valid arguments in list."
 msgstr "%s requiere como mínimo %d argumentos válidos en la lista."
 
-#: src/language/expressions/parse.c:1110
+#: src/language/expressions/parse.c:1137
 #, c-format
 msgid "With %s, using minimum valid argument count of %d does not make sense when passing only %d arguments in list."
 msgstr "Con %s, no tiene sentido utilizar %d como recuento mínimo de argumento válido si se pasan únicamente %d argumentos en la lista."
 
-#: src/language/expressions/parse.c:1164
+#: src/language/expressions/parse.c:1191
 #, c-format
 msgid "Type mismatch invoking %s as "
 msgstr "Incompatibilidad de tipo al invocar %s como"
 
-#: src/language/expressions/parse.c:1169
+#: src/language/expressions/parse.c:1196
 msgid "Function invocation "
 msgstr "Invocación de función"
 
-#: src/language/expressions/parse.c:1171
+#: src/language/expressions/parse.c:1198
 msgid " does not match any known function.  Candidates are:"
 msgstr "no coincide con ninguna función conocida. Los candidatos son:"
 
-#: src/language/expressions/parse.c:1201
+#: src/language/expressions/parse.c:1228
 #, c-format
 msgid "No function or vector named %s."
 msgstr "Ninguna función o vector nombrado %s."
 
-#: src/language/expressions/parse.c:1244
+#: src/language/expressions/parse.c:1271
 #, c-format
 msgid "expecting `,' or `)' invoking %s function"
 msgstr "esperando `,' o `)' al invocar la función %s"
 
-#: src/language/expressions/parse.c:1264
+#: src/language/expressions/parse.c:1291
 #, c-format
 msgid "%s is a PSPP extension."
 msgstr "%s es una extensión de PSPP."
 
-#: src/language/expressions/parse.c:1273
+#: src/language/expressions/parse.c:1300
 #, c-format
 msgid "%s may not appear after TEMPORARY."
 msgstr "%s no puede aparecer después de TEMPORARY."
 
-#: src/libpspp/hash.c:545
-#, c-format
-msgid "hash table:"
-msgstr "tabla hash:"
-
-#: src/libpspp/message.c:128
-msgid "error"
-msgstr "error"
-
-#: src/libpspp/message.c:131
-msgid "warning"
-msgstr "aviso"
-
-#: src/libpspp/message.c:135
-msgid "note"
-msgstr "anotación"
-
-#: src/libpspp/tmpfile.c:56
+#: src/libpspp/ext-array.c:56
 msgid "failed to create temporary file"
 msgstr "error en crear el archivo temporal"
 
-#: src/libpspp/tmpfile.c:97
+#: src/libpspp/ext-array.c:96
 msgid "seeking in temporary file"
 msgstr "buscando en el archivo temporal"
 
-#: src/libpspp/tmpfile.c:116
+#: src/libpspp/ext-array.c:115
 msgid "reading temporary file"
 msgstr "leyendo archivo temporal"
 
-#: src/libpspp/tmpfile.c:118
+#: src/libpspp/ext-array.c:117
 msgid "unexpected end of file reading temporary file"
 msgstr "final de fichero inesperado en leer el archivo temporal"
 
-#: src/libpspp/tmpfile.c:137
+#: src/libpspp/ext-array.c:136
 msgid "writing to temporary file"
 msgstr "escribiendo en un archivo temporal"
 
+#: src/libpspp/message.c:172
+msgid "error"
+msgstr "error"
+
+#: src/libpspp/message.c:175
+msgid "warning"
+msgstr "aviso"
+
+#: src/libpspp/message.c:179
+msgid "note"
+msgstr "anotación"
+
+#: src/libpspp/message.c:279
+#, c-format
+msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
+msgstr "Las notas (%d) han superado el límite (%d). Se suprimen las posteriores notas."
+
+#: src/libpspp/message.c:287
+#, c-format
+msgid "Warnings (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Las advertencias (%d) han superado el límite (%d). Se detiene el procesamiento de sintaxis."
+
+#: src/libpspp/message.c:290
+#, c-format
+msgid "Errors (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Los errores (%d) han superado el límite (%d). Se detiene el procesamiento de sintaxis."
+
 #: src/libpspp/zip-writer.c:91
 #, c-format
 msgid "%s: error opening output file"
@@ -3416,60 +3758,65 @@ msgstr "Empírico"
 msgid "Empirical with averaging"
 msgstr "Empírico promediado"
 
-#: src/output/ascii.c:278
+#: src/output/ascii.c:281
 #, c-format
 msgid "%s: %s must be positive integer or `auto'"
 msgstr "%s: %s debe ser un entero positivo o `auto'"
 
-#: src/output/ascii.c:311
+#: src/output/ascii.c:314
 #, c-format
 msgid "ascii: page excluding margins and headers must be at least %d characters wide by %d lines long, but as configured is only %d characters by %d lines"
 msgstr "ascii: excluyendo los margenes y encabezamientos la página debe tener como mínimo %d caracteres de ancho por %d líneas de largo, pero tal como está configurada, sólo hay %d caracteres y %d líneas"
 
-#: src/output/ascii.c:360
+#: src/output/ascii.c:363
 #, c-format
-msgid "ascii: closing output file \"%s\""
-msgstr "ascii: cerrando el archivo de salida \"%s\""
+msgid "ascii: closing output file `%s'"
+msgstr "ascii: cerrando el archivo de resultados `%s'"
 
-#: src/output/ascii.c:503
+#: src/output/ascii.c:506
 #, c-format
 msgid "See %s for a chart."
 msgstr "Ver %s para gráfico."
 
-#: src/output/ascii.c:806
+#: src/output/ascii.c:833
 #, c-format
-msgid "ascii: opening output file \"%s\""
-msgstr "ascii: abriendo el archivo de resultados \"%s\""
+msgid "ascii: opening output file `%s'"
+msgstr "ascii: abriendo el archivo de resultados `%s'"
 
-#: src/output/ascii.c:913 src/output/cairo.c:784
+#: src/output/ascii.c:940
 #, c-format
 msgid "%s - Page %d"
 msgstr "%s - Página %d"
 
-#: src/output/csv.c:87 src/output/html.c:106 src/output/journal.c:93
+#: src/output/csv.c:97 src/output/html.c:106 src/output/journal.c:93
 #: src/output/msglog.c:66
 #, c-format
-msgid "error opening output file \"%s\""
-msgstr "error abriendo el fichero de resultados \"%s\""
+msgid "error opening output file `%s'"
+msgstr "error abriendo el fichero de resultados `%s'"
 
-#: src/output/driver.c:330
+#. TRANSLATORS: Don't translate the words `terminal' or `listing'.
+#: src/output/driver.c:283
 #, c-format
-msgid "%s is not a valid device type (the choices are \"terminal\" and \"listing\")"
-msgstr "%s no es un tipo de dispositivo válido (las opciones son \"terminal\" y \"listing\")"
+msgid "%s is not a valid device type (the choices are `terminal' and `listing')"
+msgstr "%s no es un tipo de dispositivo válido (las opciones son `terminal' y `listing')"
 
-#: src/output/driver.c:343
+#: src/output/driver.c:296
 #, c-format
-msgid "%s: unknown option \"%s\""
-msgstr "%s: opción desconocida \"%s\""
+msgid "%s: unknown option `%s'"
+msgstr "%s: opción desconocida `%s'"
 
 #: src/output/html.c:114
 msgid "PSPP Output"
 msgstr "Resultado de PSPP"
 
+#: src/output/html.c:258
+msgid "No description"
+msgstr "Sin descripción"
+
 #: src/output/journal.c:67
 #, c-format
-msgid "error writing output file \"%s\""
-msgstr "error al escribir el fichero de resultados \"%s\""
+msgid "error writing output file `%s'"
+msgstr "error al escribir el fichero de resultados `%s'"
 
 #: src/output/measure.c:65
 #, c-format
@@ -3488,110 +3835,110 @@ msgstr "tipo de papel desconocido `%.*s'"
 
 #: src/output/measure.c:248
 #, c-format
-msgid "error opening input file \"%s\""
-msgstr "error al abrir el fichero de datos \"%s\""
+msgid "error opening input file `%s'"
+msgstr "error al abrir el fichero de datos `%s'"
 
 #: src/output/measure.c:259
 #, c-format
-msgid "error reading file \"%s\""
-msgstr "error leyendo el archivo \"%s\""
+msgid "error reading file `%s'"
+msgstr "error leyendo el archivo `%s'"
 
 #: src/output/measure.c:276
 #, c-format
-msgid "paper size file \"%s\" does not state a paper size"
-msgstr "el archivo de medida de papel \"%s\" no indica una medida de papel"
+msgid "paper size file `%s' does not state a paper size"
+msgstr "el archivo de medida de papel `%s' no indica una medida de papel"
 
 #: src/output/options.c:113
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a Boolean value is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un valor Booleano"
+msgid "%s: `%s' is `%s' but a Boolean value is required"
+msgstr "%s: `%s' es `%s', pero se requiere un valor Booleano"
 
 #: src/output/options.c:188
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but one of the following is required: %s"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere uno de los siguientes: %s "
+msgid "%s: `%s' is `%s' but one of the following is required: %s"
+msgstr "%s: `%s' es `%s', pero se requiere uno de los siguientes: %s "
 
 #: src/output/options.c:232
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a nonnegative integer is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un entero no negativo"
+msgid "%s: `%s' is `%s' but a nonnegative integer is required"
+msgstr "%s: `%s' es `%s', pero se requiere un entero no negativo"
 
 #: src/output/options.c:236
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a positive integer is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un entero positivo"
+msgid "%s: `%s' is `%s' but a positive integer is required"
+msgstr "%s: `%s' es `%s', pero se requiere un entero positivo"
 
 #: src/output/options.c:239
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but an integer is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un entero"
+msgid "%s: `%s' is `%s' but an integer is required"
+msgstr "%s: `%s' es `%s', pero se requiere un entero"
 
 #: src/output/options.c:242
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but an integer greater than %d is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un entero mayor que %d"
+msgid "%s: `%s' is `%s' but an integer greater than %d is required"
+msgstr "%s: `%s' es `%s', pero se requiere un entero mayor que %d"
 
 #: src/output/options.c:247
 #, c-format
-msgid "%s: \"%s\" is \"%s\"  but an integer between %d and %d is required"
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un entero entre %d y %d"
+msgid "%s: `%s' is `%s'  but an integer between %d and %d is required"
+msgstr "%s: `%s' es `%s', pero se requiere un entero entre %d y %d"
 
 #: src/output/options.c:326
 #, c-format
-msgid "%s: \"%s\" is \"%s\" but a file name that contains \"#\" is required."
-msgstr "%s: \"%s\" es \"%s\", pero se requiere un nombre de fichero que contenga \"#\"."
+msgid "%s: `%s' is `%s' but a file name that contains `#' is required."
+msgstr "%s: `%s' es `%s', pero se requiere un nombre de fichero que contenga `#'."
 
-#: src/output/tab.c:206
+#: src/output/tab.c:207
 #, c-format
 msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr "incorrecta vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) en tabla de medida (%d,%d)\n"
 
-#: src/output/tab.c:244
+#: src/output/tab.c:245
 #, c-format
 msgid "bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in table size (%d,%d)\n"
 msgstr "incorrecta hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d en tabla de medida (%d,%d)\n"
 
-#: src/output/tab.c:288
+#: src/output/tab.c:289
 #, c-format
 msgid "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) en taula amb mida (%d,%d)\n"
 
-#: src/output/cairo.c:295
+#: src/output/cairo.c:193
+#, c-format
+msgid "`%s': bad font specification"
+msgstr "`%s': especificación de carácter no válida"
+
+#: src/output/cairo.c:357
 #, c-format
-msgid "error opening output file \"%s\": %s"
-msgstr "error abriendo el fichero de resultados \"%s\": %s"
+msgid "error opening output file `%s': %s"
+msgstr "error abriendo el fichero de resultados `%s': %s"
 
-#: src/output/cairo.c:312
+#: src/output/cairo.c:374
 #, c-format
 msgid "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."
 msgstr "La página definida no es suficientemente ancha como para contener al menos %d caracteres de la fuente por defecto.  De hecho, sólo hay espacio para %d caracteres."
 
-#: src/output/cairo.c:322
+#: src/output/cairo.c:384
 #, c-format
-msgid "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."
-msgstr "La página definida no es suficientemente larga como para contener margenes y cabezeras, además de al menos %d líneas de las fuentes por defecto.  De hecho, sólo hay espacio para %d líneas."
+msgid "The defined page is not long enough to hold at least %d lines in the default font.  In fact, there's only room for %d lines."
+msgstr "La página definida no es suficientemente larga como para contener al menos %d líneas en la fuente por defecto.  De hecho, sólo hay espacio para %d líneas."
 
-#: src/output/cairo.c:376
+#: src/output/cairo.c:435
 #, c-format
 msgid "error drawing output for %s driver: %s"
 msgstr "error dibujando resultados para el controlador %s: %s"
 
-#: src/output/cairo.c:864
-#, c-format
-msgid "\"%s\": bad font specification"
-msgstr "\"%s\": especificación de carácter no válida"
-
-#: src/output/cairo.c:1084
+#: src/output/cairo.c:1073
 #, c-format
-msgid "error writing output file \"%s\": %s"
-msgstr "Error escribiendo el fichero de resultados \"%s\": %s."
+msgid "error writing output file `%s': %s"
+msgstr "Error escribiendo el fichero de resultados `%s': %s."
 
 #: src/output/charts/np-plot-cairo.c:37
 #, c-format
 msgid "Normal Q-Q Plot of %s"
 msgstr "Gráfica Normal Q-Q de %s"
 
-#: src/output/charts/np-plot-cairo.c:38 src/output/charts/np-plot-cairo.c:66
+#: src/output/charts/np-plot-cairo.c:38 src/output/charts/np-plot-cairo.c:65
 msgid "Observed Value"
 msgstr "Valor Observado"
 
@@ -3604,7 +3951,7 @@ msgstr "Normal Esperada"
 msgid "Detrended Normal Q-Q Plot of %s"
 msgstr "Gráfica Normal Adireccional Q-Q de %s"
 
-#: src/output/charts/np-plot-cairo.c:67
+#: src/output/charts/np-plot-cairo.c:66
 msgid "Dev from Normal"
 msgstr "Desv. de la Normal"
 
@@ -3613,7 +3960,7 @@ msgid "HISTOGRAM"
 msgstr "HISTOGRAM"
 
 #: src/output/charts/plot-hist-cairo.c:112
-#: src/language/stats/frequencies.q:814
+#: src/language/stats/frequencies.q:824
 msgid "Frequency"
 msgstr "Frecuencia"
 
@@ -3629,151 +3976,224 @@ msgstr "Gráfico de Sedimentación"
 msgid "Eigenvalue"
 msgstr "Valor-propio"
 
-#: src/output/odt.c:93
+#: src/output/odt.c:94
 msgid "error creating temporary file"
 msgstr "error creando fichero temporal"
 
-#: src/ui/source-init-opts.c:78
-msgid "Algorithm must be either \"compatible\" or \"enhanced\"."
-msgstr "Algoritmo tiene que ser o \"compatible\" o \"ampliado\"."
+#: src/ui/source-init-opts.c:77
+msgid "Algorithm must be either `compatible' or `enhanced'."
+msgstr "Algoritmo tiene que ser o `compatible' o `enhaced'."
+
+#: src/ui/source-init-opts.c:104
+msgid "Syntax must be either `compatible' or `enhanced'."
+msgstr "La sintaxis tiene que ser `compatible' o `enhaced'."
 
-#: src/ui/source-init-opts.c:103
-msgid "Syntax must be either \"compatible\" or \"enhanced\"."
-msgstr "La sintaxis tiene que ser o \"compatible\" o \"ampliada\"."
+#: src/ui/terminal/main.c:145
+msgid "Error encountered while ERROR=STOP is effective."
+msgstr "Error detectado mientras está activo ERROR=STOP."
 
-#: src/ui/terminal/main.c:128
+#: src/ui/terminal/main.c:151
 msgid "Stopping syntax file processing here to avoid a cascade of dependent command failures."
 msgstr "Deteniendo el procesamiento del archivo de sintaxis aquí para evitar una cascada de errores derivados."
 
-#: src/ui/terminal/msg-ui.c:127
+#: src/ui/terminal/terminal-opts.c:122
 #, c-format
-msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
-msgstr "Las anotaciones (%d) han superado el límite (%d). Se suprimen las posteriores."
+msgid "%s: output option missing `='"
+msgstr "%s: falta una opción de resultado `='"
 
-#: src/ui/terminal/msg-ui.c:135
+#: src/ui/terminal/terminal-opts.c:129
 #, c-format
-msgid "Warnings (%d) exceed limit (%d)."
-msgstr "Avisos (%d) exceden el límite (%d)."
+msgid "%s: output option specified more than once"
+msgstr "%s: opción de resultado especificada más de una vez"
 
-#: src/ui/terminal/msg-ui.c:138
+#: src/ui/terminal/terminal-opts.c:171
 #, c-format
-msgid "Errors (%d) exceed limit (%d)."
-msgstr "Los errores (%d) exceden el límite (%d)."
+msgid ""
+"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"
+"  --no-output               disable default output driver\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"
+"  -b, --batch               interpret syntax in batch mode\n"
+"  -i, --interactive         interpret syntax in interactive mode\n"
+"  --syntax-encoding=ENCODING  specify encoding for syntax files\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"
+msgstr ""
+"PSPP, un programa de análisis estadístic para datos de muestreo.\n"
+"Uso: %s [OPTION]... FILE...\n"
+"\n"
+"Los arguments para options largas también se aplican a opciones cortas equivalentes.\n"
+"\n"
+"Opciones de salida:\n"
+"  -o, --output=FILE         salida a FILE, format por defecto según el nombre de FILE\n"
+"  -O format=FORMAT          sobreescribir el formato por el previo -o\n"
+"  -O OPTION=VALUE           establecer opciones de salida a las previas personalizadas -o\n"
+"  -O device={terminal|listing}  sustituir el tipo de dispositivo por el previo -o\n"
+"  -e, --error-file=FILE     añade errores, advertencias, y notas a FILE\n"
+"  --no-output               desactivar el dispositivo de salida por defecto\n"
+"Formatos de salida soportados: %s\n"
+"\n"
+"Opciones de lenguaje:\n"
+"  -I, --include=DIR         añadir DIR a la ruta de búsqueda\n"
+"  -I-, --no-include         limpiar la ruta de búsqueda\n"
+"  -r, --no-statrc           desactivar el archivo que ejectuta rc al inicio\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            establecer a `compatible' si se quiere una salida\n"
+"                            calculada a partir de algoritmos rotos\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            establecer a `compatible' para desactivar las extensiones PSPP\n"
+"  -b, --batch               interpretar la sintaxis en modo paquete\n"
+"  -i, --interactive         interpretar la sintaxis en modo interactivo\n"
+"  --syntax-encoding=ENCODING  especificar codificación para los archivos de sintaxis\n"
+"  -s, --safer               no permitir algunas operaciones poco seguras\n"
+"Ruta de búsqueda por defecto: %s\n"
+"\n"
+"Salida informativa:\n"
+"  -h, --help                muestra esta ayuda y acaba\n"
+"  -V, --version             información sobre versión de salida y acaba\n"
+"\n"
+"Los argumentos sin opción son interpretados como archivos de sintaxis para ser ejecutados.\n"
 
-#: src/ui/terminal/terminal.c:72
+#: src/ui/terminal/terminal.c:62
 #, c-format
 msgid "could not access definition for terminal `%s'"
 msgstr "no se puede acceder a la definición para terminal `%s'"
 
-#: src/ui/terminal/terminal-opts.c:119
-#, c-format
-msgid "%s: output option missing `='"
-msgstr "%s: falta una opción de resultado `='"
+#: src/ui/gui/aggregate-dialog.c:161
+msgid "Aggregate destination file"
+msgstr "Archivo de destino para agregación"
 
-#: src/ui/terminal/terminal-opts.c:126
-#, c-format
-msgid "%s: output option specified more than once"
-msgstr "%s: opción de resultado especificada más de una vez"
+#: src/ui/gui/aggregate-dialog.c:172 src/ui/gui/psppire-data-window.c:400
+#: src/ui/gui/psppire-data-window.c:601
+msgid "System Files (*.sav)"
+msgstr "Archivos de Sistema (*.sav)"
+
+#: src/ui/gui/aggregate-dialog.c:178 src/ui/gui/psppire-data-window.c:406
+#: src/ui/gui/psppire-data-window.c:607
+#, fuzzy
+msgid "Portable Files (*.por) "
+msgstr "Archivos Portátiles (*.por)"
 
-#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1213
-#: src/language/stats/crosstabs.q:1240 src/language/stats/crosstabs.q:1263
-#: src/language/stats/crosstabs.q:1287 src/language/stats/examine.q:1638
+#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1233
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1307 src/language/stats/examine.q:1637
 msgid "Statistic"
 msgstr "Estadístico"
 
-#: src/ui/gui/comments-dialog.c:58
+#: src/ui/gui/comments-dialog.c:57
 #, c-format
 msgid "Column Number: %d"
 msgstr "Número de columna: %d"
 
-#: src/ui/gui/crosstabs-dialog.c:41
+#: src/ui/gui/crosstabs-dialog.c:40
 msgid "Chisq"
 msgstr "Chi-C."
 
-#: src/ui/gui/crosstabs-dialog.c:42 src/language/stats/crosstabs.q:1774
+#: src/ui/gui/crosstabs-dialog.c:41 src/language/stats/crosstabs.q:1806
 msgid "Phi"
 msgstr "Phi"
 
-#: src/ui/gui/crosstabs-dialog.c:43
+#: src/ui/gui/crosstabs-dialog.c:42
 msgid "CC"
 msgstr "CC"
 
-#: src/ui/gui/crosstabs-dialog.c:44 src/language/stats/crosstabs.q:1912
+#: src/ui/gui/crosstabs-dialog.c:43 src/language/stats/crosstabs.q:1944
 msgid "Lambda"
 msgstr "Lambda"
 
-#: src/ui/gui/crosstabs-dialog.c:45
+#: src/ui/gui/crosstabs-dialog.c:44
 msgid "UC"
 msgstr "UC"
 
-#: src/ui/gui/crosstabs-dialog.c:46
+#: src/ui/gui/crosstabs-dialog.c:45
 msgid "BTau"
 msgstr "BTau"
 
-#: src/ui/gui/crosstabs-dialog.c:47
+#: src/ui/gui/crosstabs-dialog.c:46
 msgid "CTau"
 msgstr "CTau"
 
-#: src/ui/gui/crosstabs-dialog.c:48
+#: src/ui/gui/crosstabs-dialog.c:47
 msgid "Risk"
 msgstr "Riesgo"
 
-#: src/ui/gui/crosstabs-dialog.c:49 src/language/stats/crosstabs.q:1779
+#: src/ui/gui/crosstabs-dialog.c:48 src/language/stats/crosstabs.q:1811
 msgid "Gamma"
 msgstr "Gamma"
 
-#: src/ui/gui/crosstabs-dialog.c:50
+#: src/ui/gui/crosstabs-dialog.c:49
 msgid "D"
 msgstr "D"
 
-#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1782
+#: src/ui/gui/crosstabs-dialog.c:50 src/language/stats/crosstabs.q:1814
 msgid "Kappa"
 msgstr "Kappa"
 
-#: src/ui/gui/crosstabs-dialog.c:52 src/language/stats/crosstabs.q:1916
+#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1948
 msgid "Eta"
 msgstr "Eta"
 
-#: src/ui/gui/crosstabs-dialog.c:53
+#: src/ui/gui/crosstabs-dialog.c:52
 msgid "Corr"
 msgstr "Corr"
 
-#: src/ui/gui/crosstabs-dialog.c:54 src/ui/gui/crosstabs-dialog.c:65
-#: src/ui/gui/crosstabs-dialog.c:100 src/ui/gui/crosstabs-dialog.c:108
-#: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
+#: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
+#: src/ui/gui/psppire-var-store.c:613 src/ui/gui/var-display.c:16
 #: src/ui/gui/variable-info-dialog.c:41
 msgid "None"
 msgstr "Ninguno"
 
-#: src/ui/gui/crosstabs-dialog.c:57
+#: src/ui/gui/crosstabs-dialog.c:56
 msgid "Count"
 msgstr "Recuento"
 
-#: src/ui/gui/crosstabs-dialog.c:58
+#: src/ui/gui/crosstabs-dialog.c:57
 msgid "Row"
 msgstr "Fila"
 
-#: src/ui/gui/crosstabs-dialog.c:59
+#: src/ui/gui/crosstabs-dialog.c:58
 msgid "Column"
 msgstr "Columna"
 
-#: src/ui/gui/crosstabs-dialog.c:61
+#: src/ui/gui/crosstabs-dialog.c:60
 msgid "Expected"
 msgstr "Esperado"
 
-#: src/ui/gui/crosstabs-dialog.c:63
+#: src/ui/gui/crosstabs-dialog.c:62
 msgid "Std. Residual"
 msgstr "Residual Tipificado"
 
-#: src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:63
 msgid "Adjusted Std. Residual"
 msgstr "Residual Tipificado Ajustado"
 
-#: src/ui/gui/descriptives-dialog.c:41 src/ui/gui/frequencies-dialog.c:42
-msgid "Standard deviation"
-msgstr "Desviación Estándar"
-
-#: src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/descriptives-dialog.c:45
 msgid "Standard error"
 msgstr "Error Estándar"
 
@@ -3782,36 +4202,32 @@ msgstr "Error Estándar"
 msgid "Bad regular expression: %s"
 msgstr "Expresión regular incorrecta: %s"
 
-#: src/ui/gui/factor-dialog.c:344
+#: src/ui/gui/factor-dialog.c:343
 #, c-format
 msgid "Eigenvalues over %4.2f times the mean eigenvalue"
 msgstr "Algunos valores propios superan %4.2f veces el valor-propio medio"
 
-#: src/ui/gui/frequencies-dialog.c:45
+#: src/ui/gui/frequencies-dialog.c:44
 msgid "Standard error of the mean"
 msgstr "Error estándar en la media"
 
-#: src/ui/gui/frequencies-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:47
 msgid "Standard error of the skewness"
 msgstr "Error estándar de la asimetría"
 
-#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/frequencies.q:108
+#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/frequencies.q:108
 msgid "Mode"
 msgstr "Modo"
 
-#: src/ui/gui/frequencies-dialog.c:52
+#: src/ui/gui/frequencies-dialog.c:51
 msgid "Standard error of the kurtosis"
 msgstr "Error estándar en la curtosis"
 
-#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/examine.q:1469
+#: src/ui/gui/frequencies-dialog.c:52 src/language/stats/examine.q:1468
 #: src/language/stats/frequencies.q:107
 msgid "Median"
 msgstr "Mediana"
 
-#: src/ui/gui/helper.c:197
-msgid "Sorry. The help system hasn't yet been implemented."
-msgstr "Disculpen. El sistema de ayuda todavía no ha sido implementado."
-
 #: src/ui/gui/help-menu.c:67
 msgid "A program for the analysis of sampled data"
 msgstr "Un programa para el análisis de datos de muestreo"
@@ -3824,8 +4240,8 @@ msgstr "F.J. Miguel, J. Gómez, P. Payà"
 
 #: src/ui/gui/help-menu.c:98
 #, c-format
-msgid "Cannot open reference manual: %s.  The PSPP user manual is also available at http://www.gnu.org/software/pspp/documentation.html"
-msgstr "No puede abrirse el manual de referencia: %s. El manual del usuario de PSPP también está disponible en http://www.gnu.org/software/pspp/documentation.html"
+msgid "Cannot open reference manual: %s.  The PSPP user manual is also available at %s"
+msgstr "No puede abrirse el manual de referencia: %s. El manual de usuario de PSPP también está disponible en %s"
 
 #: src/ui/gui/help-menu.c:117
 msgid "_Help"
@@ -3835,6 +4251,61 @@ msgstr "Ayuda"
 msgid "_Reference Manual"
 msgstr "Manual de _Referencia"
 
+#: src/ui/gui/main.c:82
+#, c-format
+msgid ""
+"PSPPIRE, a GUI for 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"
+"GUI options:\n"
+"  -q, --no-splash           don't show splash screen during startup\n"
+"\n"
+"%sLanguage options:\n"
+"  -I, --include=DIR         append DIR to search path\n"
+"  -I-, --no-include         clear search path\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"
+"A non-option argument is interpreted as a .sav or .por file to load.\n"
+msgstr ""
+"PSPPIRE, un entorno gráfico (GUI) para PSPP, un programa de análisis estadístico para datos de muestreo.\n"
+"Uso: %s [OPTION]... FILE\n"
+"\n"
+"Argumentos para opciones largas también se aplican a opciones cortas equivalentes.\n"
+"\n"
+"Opciones gráficas:\n"
+"  -q, --no-splash           no mostrar la pantalla inicial druante el arranque\n"
+"\n"
+"%sOpciones de lenguaje:\n"
+"  -I, --include=DIR         añadir DIR a la ruta de búsqueda\n"
+"  -I-, --no-include         limpiar la ruta de búsqueda\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            establecer a `compatible' si se desean resultados\n"
+"                            calculados mediante algoritmos rotos\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            establecer a `compatible' para desactivar extensiones PSPP\n"
+"  -i, --interactive         interpretar la sintaxis en modo interactivo\n"
+"  -s, --safer               no permitir algunas operaciones poco seguras\n"
+"Ruta de búsqueda por defecto: %s\n"
+"\n"
+"Salidas informativas:\n"
+"  -h, --help                muestra esta ayuda y acaba\n"
+"  -V, --version             información de versión de salida y acaba\n"
+"\n"
+"Un argumento sin opciones es interpretado como un archivo .sav or .por para ser cargado.\n"
+
 #: src/ui/gui/missing-val-dialog.c:113 src/ui/gui/missing-val-dialog.c:167
 msgid "Incorrect value for variable type"
 msgstr "Valor incorrecto para el tipo de variable"
@@ -3843,24 +4314,24 @@ msgstr "Valor incorrecto para el tipo de variable"
 msgid "Incorrect range specification"
 msgstr "Especificación de intervalo incorrecta"
 
-#: src/ui/gui/oneway-anova-dialog.c:313
+#: src/ui/gui/oneway-anova-dialog.c:300
 #, c-format
 msgid "Contrast %d of %d"
 msgstr "Contraste %d de %d"
 
-#: src/ui/gui/psppire.c:224
+#: src/ui/gui/psppire.c:218
 msgid "_Reset"
 msgstr "_Reiniciar"
 
-#: src/ui/gui/psppire.c:225
+#: src/ui/gui/psppire.c:219
 msgid "_Select"
 msgstr "_Selecionar"
 
-#: src/ui/gui/psppire-data-editor.c:951
+#: src/ui/gui/psppire-data-editor.c:950
 msgid "Data View"
 msgstr "Vista de Datos"
 
-#: src/ui/gui/psppire-data-editor.c:954
+#: src/ui/gui/psppire-data-editor.c:953
 msgid "Variable View"
 msgstr "Vista de Variables"
 
@@ -3898,256 +4369,303 @@ msgstr "SIN Ponderar"
 msgid "Weight by %s"
 msgstr "Ponderado por %s"
 
-#: src/ui/gui/psppire-data-window.c:382
+#: src/ui/gui/psppire-data-window.c:380
 msgid "Open"
 msgstr "Abrir"
 
-#: src/ui/gui/psppire-data-window.c:392
+#: src/ui/gui/psppire-data-window.c:390
 msgid "Data and Syntax Files"
 msgstr "Ficheros de Datos y Sintaxsi"
 
-#: src/ui/gui/psppire-data-window.c:402 src/ui/gui/psppire-data-window.c:614
-msgid "System Files (*.sav)"
-msgstr "Archivos de Sistema (*.sav)"
-
-#: src/ui/gui/psppire-data-window.c:408 src/ui/gui/psppire-data-window.c:620
-msgid "Portable Files (*.por) "
-msgstr "Archivos Portátiles (*.por)"
-
-#: src/ui/gui/psppire-data-window.c:414 src/ui/gui/psppire-syntax-window.c:292
+#: src/ui/gui/psppire-data-window.c:412 src/ui/gui/psppire-syntax-window.c:505
 msgid "Syntax Files (*.sps) "
 msgstr "Archivos de Sintàxis (*.sps) "
 
-#: src/ui/gui/psppire-data-window.c:420 src/ui/gui/psppire-data-window.c:626
-#: src/ui/gui/psppire-syntax-window.c:298
+#: src/ui/gui/psppire-data-window.c:418 src/ui/gui/psppire-data-window.c:613
+#: src/ui/gui/psppire-syntax-window.c:511
 msgid "All Files"
 msgstr "Todos los archivos"
 
-#: src/ui/gui/psppire-data-window.c:606
+#: src/ui/gui/psppire-data-window.c:593 src/ui/gui/aggregate.ui:448
 msgid "Save"
 msgstr "Guardar"
 
-#: src/ui/gui/psppire-data-window.c:639
+#: src/ui/gui/psppire-data-window.c:626
 msgid "Portable File"
 msgstr "Archivo Portátil"
 
-#: src/ui/gui/psppire-data-window.c:776
+#: src/ui/gui/psppire-data-window.c:759
 msgid "Font Selection"
 msgstr "Selección de fuente"
 
-#: src/ui/gui/psppire-data-window.c:1264
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-data-window.c:1256
+msgid "PSPP-data"
+msgstr "datos-PSPP"
+
+#: src/ui/gui/psppire-data-window.c:1257
 msgid "Data Editor"
 msgstr "Editor de Datos"
 
-#: src/ui/gui/psppire-output-window.c:458
-msgid "Export Output"
-msgstr "Exporta Resultados"
-
-#: src/ui/gui/psppire-output-window.c:466
-msgid "PDF Files (*.pdf)"
-msgstr "Ficheros PDF (*.pdf)"
+#. TRANSLATORS: This string must be a valid variable name.  That means:
+#. - The string must be at most 64 bytes (not characters) long.
+#. - The string may not contain whitespace.
+#. - The first character may not be '$'
+#. - The first character may not be a digit
+#. - The final charactor may not be '.' or '_'
+#.
+#: src/ui/gui/psppire-dict.c:367
+#, c-format
+msgid "VAR%05d"
+msgstr "VAR%05d"
 
 #: src/ui/gui/psppire-output-window.c:467
-msgid "HTML Files (*.html)"
-msgstr "Ficheros HTML (*.html)"
+msgid "Infer file type from extension"
+msgstr "Inferir tipo de archivo por la extensión"
 
 #: src/ui/gui/psppire-output-window.c:468
-msgid "OpenDocument Files (*.odt)"
-msgstr "Ficheros OpenDocument (*.odt)"
+msgid "PDF (*.pdf)"
+msgstr "PDF (*.pdf)"
 
 #: src/ui/gui/psppire-output-window.c:469
-msgid "Text Files (*.txt)"
-msgstr "Ficheros de Text (*.txt)"
+msgid "HTML (*.html)"
+msgstr "HTML (*.html)"
 
 #: src/ui/gui/psppire-output-window.c:470
-msgid "PostScript Files (*.ps)"
-msgstr "Ficheros PostScript (*.ps)"
+msgid "OpenDocument (*.odt)"
+msgstr "OpenDocument (*.odt)"
 
 #: src/ui/gui/psppire-output-window.c:471
-msgid "Comma-Separated Value Files (*.csv)"
-msgstr "Ficheros de Valores Separados por Comas (*.csv)"
+msgid "Text (*.txt)"
+msgstr "Texto (*.txt)"
+
+#: src/ui/gui/psppire-output-window.c:472
+msgid "PostScript (*.ps)"
+msgstr "PostScript (*.ps)"
+
+#: src/ui/gui/psppire-output-window.c:473
+msgid "Comma-Separated Values (*.csv)"
+msgstr "Valores Separados por Comas (*.csv)"
 
-#: src/ui/gui/psppire-output-window.c:605
+#: src/ui/gui/psppire-output-window.c:574
+msgid "Export Output"
+msgstr "Exporta Resultados"
+
+#: src/ui/gui/psppire-output-window.c:828
+msgid "failed to create temporary directory"
+msgstr "error al crear el directorio temporal"
+
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-output-window.c:1059
+msgid "Output"
+msgstr "Resultado"
+
+#: src/ui/gui/psppire-output-window.c:1060
 msgid "Output Viewer"
 msgstr "Visor de resultados"
 
-#: src/ui/gui/psppire-syntax-window.c:265
+#: src/ui/gui/psppire-syntax-window.c:478
 #, c-format
-msgid "Saved file \"%s\""
-msgstr "Guardado archivo \"%s\""
+msgid "Saved file `%s'"
+msgstr "Guardado archivo `%s'"
 
-#: src/ui/gui/psppire-syntax-window.c:284
+#: src/ui/gui/psppire-syntax-window.c:497
 msgid "Save Syntax"
 msgstr "Guardar sintaxis"
 
-#: src/ui/gui/psppire-syntax-window.c:496
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-syntax-window.c:746
+msgid "Syntax"
+msgstr "Sintaxis"
+
+#: src/ui/gui/psppire-syntax-window.c:747
 msgid "Syntax Editor"
 msgstr "Editor de sintaxis"
 
-#: src/ui/gui/psppire-syntax-window.c:510
+#: src/ui/gui/psppire-syntax-window.c:761
 #, c-format
-msgid "Cannot load syntax file '%s'"
-msgstr "No se puede abrir el archivo de sintaxis \"%s\""
+msgid "Cannot load syntax file `%s'"
+msgstr "No se puede abrir el archivo de sintaxis `%s'"
 
-#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:833
-#: src/language/stats/crosstabs.q:1288 src/ui/gui/psppire.ui:2055
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:834
+#: src/language/stats/crosstabs.q:1308 src/ui/gui/compute.ui:599
 msgid "Type"
 msgstr "Tipo"
 
-#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:834
-#: src/ui/gui/psppire.ui:1974
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/compute.ui:517
 msgid "Width"
 msgstr "Ancho"
 
-#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:836
 msgid "Decimals"
 msgstr "Decimales"
 
-#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:838
 msgid "Values"
 msgstr "Valores"
 
-#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:838
-#: src/language/stats/crosstabs.q:822 src/language/stats/examine.q:1104
-#: src/language/stats/frequencies.q:864 src/language/stats/frequencies.q:1036
+#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:839
+#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1103
+#: src/language/stats/frequencies.q:874 src/language/stats/frequencies.q:1045
 msgid "Missing"
 msgstr "Perdidos"
 
-#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:840
+#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:841
 msgid "Align"
 msgstr "Alineación"
 
-#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:841
+#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:842
 msgid "Measure"
 msgstr "Medida"
 
-#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/var-sheet-dialogs.ui:43
+#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.ui:43
 msgid "Comma"
 msgstr "Coma"
 
-#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.ui:59
+#: src/ui/gui/psppire-var-store.c:624 src/ui/gui/var-sheet-dialogs.ui:59
 msgid "Dot"
 msgstr "Punto"
 
-#: src/ui/gui/psppire-var-store.c:624
+#: src/ui/gui/psppire-var-store.c:625
 msgid "Scientific"
 msgstr "Científico"
 
-#: src/ui/gui/psppire-var-store.c:625 src/ui/gui/var-sheet-dialogs.ui:91
+#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.ui:91
 msgid "Date"
 msgstr "Fecha"
 
-#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.ui:107
+#: src/ui/gui/psppire-var-store.c:627 src/ui/gui/var-sheet-dialogs.ui:107
 msgid "Dollar"
 msgstr "Dolar"
 
-#: src/ui/gui/psppire-var-store.c:627
+#: src/ui/gui/psppire-var-store.c:628
 msgid "Custom"
 msgstr "De usuario"
 
+#: src/ui/gui/psppire-var-store.c:756
+#, c-format
+msgid "{%s,`%s'}_"
+msgstr "{%s,`%s'}_"
+
 #: src/ui/gui/psppire-window.c:97
 #, c-format
 msgid "%s %s PSPPIRE %s"
 msgstr "%s %s PSPPIRE %s"
 
-#: src/ui/gui/psppire-window.c:468
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-window.c:247
+msgid "Untitled"
+msgstr "Sin título"
+
+#: src/ui/gui/psppire-window.c:469
 #, c-format
-msgid "Save the changes to \"%s\" before closing?"
-msgstr "Guarda los cambios en \"%s\" antes de salir?"
+msgid "Save the changes to `%s' before closing?"
+msgstr "¿Guardar los cambios en `%s' antes de salir?"
 
-#: src/ui/gui/psppire-window.c:475
+#: src/ui/gui/psppire-window.c:476
 #, c-format
 msgid "If you don't save, changes from the last %ld seconds will be permanently lost."
 msgstr "Si no se guarda ahora, los cambios de los últims %ld segundos se perderan permanentemente."
 
-#: src/ui/gui/psppire-window.c:479
+#: src/ui/gui/psppire-window.c:480
 msgid "Close _without saving"
 msgstr "Cerrar sin guardar"
 
-#: src/ui/gui/recode-dialog.c:911
+#: src/ui/gui/recode-dialog.c:886
 msgid "Recode into Different Variables"
 msgstr "Recodificar en variables Diferentes"
 
-#: src/ui/gui/recode-dialog.c:914 src/ui/gui/recode.ui:692
+#: src/ui/gui/recode-dialog.c:889 src/ui/gui/recode.ui:692
 msgid "Recode into Same Variables"
 msgstr "Recodificar en las Mismas variables"
 
-#: src/ui/gui/recode-dialog.c:929 src/ui/gui/recode-dialog.c:1025
+#: src/ui/gui/recode-dialog.c:903 src/ui/gui/recode-dialog.c:999
 msgid "New"
 msgstr "Nuevo"
 
-#: src/ui/gui/recode-dialog.c:944 src/ui/gui/recode-dialog.c:1017
+#: src/ui/gui/recode-dialog.c:918 src/ui/gui/recode-dialog.c:991
 msgid "Old"
 msgstr "Anterior"
 
-#: src/ui/gui/recode-dialog.c:1274
+#: src/ui/gui/recode-dialog.c:1236
 msgid "Recode into Different Variables: Old and New Values "
 msgstr "Recodifica en variables Diferentes: Anteriores y Nuevos valores "
 
-#: src/ui/gui/recode-dialog.c:1275
+#: src/ui/gui/recode-dialog.c:1237
 msgid "Recode into Same Variables: Old and New Values"
 msgstr "Recodifica en las mismas variables: Anteriores y Nuevos valores"
 
-#: src/ui/gui/regression-dialog.c:42
+#: src/ui/gui/regression-dialog.c:41
 msgid "Coeff"
 msgstr "Coef"
 
-#: src/ui/gui/regression-dialog.c:43 src/language/stats/regression.q:155
+#: src/ui/gui/regression-dialog.c:42 src/language/stats/regression.q:157
 msgid "R"
 msgstr "R"
 
-#: src/ui/gui/regression-dialog.c:44
+#: src/ui/gui/regression-dialog.c:43
 msgid "Anova"
 msgstr "Anova"
 
-#: src/ui/gui/regression-dialog.c:45
+#: src/ui/gui/regression-dialog.c:44
 msgid "Bcov"
 msgstr "Bcov"
 
-#: src/ui/gui/select-cases-dialog.c:82
+#: src/ui/gui/select-cases-dialog.c:81
 #, c-format
 msgid "Approximately %3d%% of all cases."
 msgstr "Aproximadamente %3d%% de todos los casos."
 
-#: src/ui/gui/select-cases-dialog.c:83
+#: src/ui/gui/select-cases-dialog.c:82
 #, c-format
 msgid "Exactly %3d cases from the first %3d cases."
 msgstr "Exactamente %3d casos de los primeros %3d casos."
 
-#: src/ui/gui/select-cases-dialog.c:223
+#: src/ui/gui/select-cases-dialog.c:221
 #, c-format
 msgid "%d thru %d"
 msgstr "%d hasta %d"
 
-#: src/ui/gui/text-data-import-dialog.c:461
+#: src/ui/gui/text-data-import-dialog.c:452
 #, c-format
-msgid "Could not open \"%s\": %s"
-msgstr "No se puede abrir \"%s\": %s"
+msgid "Could not open `%s': %s"
+msgstr "No se puede abrir `%s': %s"
 
-#: src/ui/gui/text-data-import-dialog.c:477
+#: src/ui/gui/text-data-import-dialog.c:468
 #, c-format
-msgid "Error reading \"%s\": %s"
-msgstr "Error leyendo \"%s\": %s"
+msgid "Error reading `%s': %s"
+msgstr "Error leyendo `%s': %s"
 
-#: src/ui/gui/text-data-import-dialog.c:480
+#: src/ui/gui/text-data-import-dialog.c:471
 #, c-format
-msgid "Failed to read \"%s\", because it contains a line over %d bytes long and therefore appears not to be a text file."
-msgstr "Error leyendo \"%s\", porque contiene una linea más allá de %d bytes y por tanto parece que no es un archivo de texto."
+msgid "Failed to read `%s', because it contains a line over %d bytes long and therefore appears not to be a text file."
+msgstr "Error leyendo `%s', porque contiene una linea más allá de %d bytes y por tanto parece que no es un archivo de texto."
 
-#: src/ui/gui/text-data-import-dialog.c:494
+#: src/ui/gui/text-data-import-dialog.c:485
 #, c-format
-msgid "\"%s\" is empty."
-msgstr "\"%s\" esta vacío."
+msgid "`%s' is empty."
+msgstr "`%s' esta vacío."
 
-#: src/ui/gui/text-data-import-dialog.c:539
+#: src/ui/gui/text-data-import-dialog.c:530
 msgid "Import Delimited Text Data"
 msgstr "Importar datos de texto delimitado"
 
-#: src/ui/gui/text-data-import-dialog.c:590
+#: src/ui/gui/text-data-import-dialog.c:581
 msgid "Importing Delimited Text Data"
 msgstr "Importando datos de texto delimitado"
 
-#: src/ui/gui/text-data-import-dialog.c:749
+#: src/ui/gui/text-data-import-dialog.c:730
+#, c-format
+msgid "Only the first %4d cases"
+msgstr "Sólo los primeros %4d casos"
+
+#: src/ui/gui/text-data-import-dialog.c:740
+#, c-format
+msgid "Only the first %3d %% of file (approximately)"
+msgstr "Sólo los primeros %3d %% del archivo (aproximadamente)"
+
+#: src/ui/gui/text-data-import-dialog.c:765
 msgid ""
 "This assistant will guide you through the process of importing data into PSPP from a text file with one line per case,  in which fields are separated by tabs, commas, or other delimiters.\n"
 "\n"
@@ -4155,46 +4673,59 @@ msgstr ""
 "Este asistente te quiará a lo largo del proceso de importar datos en PSPP desde un archivo de texto con una línea por caso,  en el que los campos estan separados por tabuladores, comas, u otros delimitadores.\n"
 "\n"
 
-#: src/ui/gui/text-data-import-dialog.c:755
+#: src/ui/gui/text-data-import-dialog.c:771
 #, c-format
 msgid "The selected file contains %zu line of text.  "
 msgid_plural "The selected file contains %zu lines of text.  "
 msgstr[0] "L'arxiu seleccionat conté %zu linies de text.  "
 msgstr[1] "El archivo seleccionado contiene %zu línias de texto.  "
 
-#: src/ui/gui/text-data-import-dialog.c:763
+#: src/ui/gui/text-data-import-dialog.c:779
 #, c-format
 msgid "The selected file contains approximately %lu line of text.  "
 msgid_plural "The selected file contains approximately %lu lines of text.  "
 msgstr[0] "El archivo seleccionado contiene aproximadamente %lu línea de texto.  "
 msgstr[1] "El archivo seleccionado contiene aproximadamente %lu líneas de texto.  "
 
-#: src/ui/gui/text-data-import-dialog.c:769
+#: src/ui/gui/text-data-import-dialog.c:785
 #, c-format
 msgid "Only the first %zu line of the file will be shown for preview purposes in the following screens.  "
 msgid_plural "Only the first %zu lines of the file will be shown for preview purposes in the following screens.  "
 msgstr[0] "Únicamente la primera %zu líneas del archivo se previsualizaran en las siguientes pantallas.  "
 msgstr[1] "Únicamente las primeras %zu líneas del archivo se previsualizaran en las siguientes pantallas.  "
 
-#: src/ui/gui/text-data-import-dialog.c:776
+#: src/ui/gui/text-data-import-dialog.c:792
 msgid "You may choose below how much of the file should actually be imported."
 msgstr "Puedes escoger a continuación que parte del archivo va a ser importado."
 
-#: src/ui/gui/text-data-import-dialog.c:1523
-#: src/ui/gui/text-data-import-dialog.c:1768
+#: src/ui/gui/text-data-import-dialog.c:875
+msgid "Text"
+msgstr "Texto"
+
+#: src/ui/gui/text-data-import-dialog.c:1539
+#: src/ui/gui/text-data-import-dialog.c:1785
 msgid "This input line has too few separators to fill in this field."
 msgstr "Esta línea de entrada no tiene suficientes separadores para llenar el campo."
 
-#: src/ui/gui/text-data-import-dialog.c:1759
+#: src/ui/gui/text-data-import-dialog.c:1776
 #, c-format
-msgid "Field content \"%.*s\" cannot be parsed in format %s."
-msgstr "El contenido del campo \"%.*s\" no puede ser analizado en formato %s."
+msgid "Cannot parse field content `%.*s' as format %s: %s"
+msgstr "No se puede analizar el contenido de campo `%.*s' como formato %s: %s"
+
+#: src/ui/gui/text-data-import-dialog.c:1929
+msgid "Line"
+msgstr "Línea"
 
 #: src/ui/gui/t-test-options.c:60
 #, c-format
 msgid "Confidence Interval: %2d %%"
 msgstr "Intervalo de Confianza: %2d %%"
 
+#: src/ui/gui/val-labs-dialog.c:515
+#, c-format
+msgid "%s = `%s'"
+msgstr "%s = `%s'"
+
 #: src/ui/gui/variable-info-dialog.c:77
 #, c-format
 msgid "Label: %s\n"
@@ -4224,429 +4755,435 @@ msgstr "Etiquetas de valor:\n"
 msgid "%s %s\n"
 msgstr "%s %s\n"
 
-#: src/ui/gui/weight-cases-dialog.c:81 src/ui/gui/psppire.ui:52
+#: src/ui/gui/weight-cases-dialog.c:80 src/ui/gui/psppire.ui:52
 #: src/ui/gui/psppire.ui:155
 msgid "Do not weight cases"
 msgstr "No ponderar los casos"
 
-#: src/ui/gui/weight-cases-dialog.c:87
+#: src/ui/gui/weight-cases-dialog.c:86
 #, c-format
 msgid "Weight cases by %s"
 msgstr "Ponderar los casos por %s"
 
-#: tests/dissect-sysfile.c:571
+#: tests/dissect-sysfile.c:572
 #, c-format
 msgid "Unrecognized record type 7, subtype %d."
 msgstr "Tipo de registro 7 no reconocido, subtipo %d."
 
-#: tests/dissect-sysfile.c:850
+#: tests/dissect-sysfile.c:595
+#, c-format
+msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
+msgstr "Campo de longitud (%zu) o cantidad (%zu) inválidos en el registro tipo 7, subtipo 3."
+
+#: tests/dissect-sysfile.c:626
+#, c-format
+msgid "Bad size (%zu) or count (%zu) on extension 4."
+msgstr "Longitud (%zu) o cantidad (%zu) de la extensión 4 no válida."
+
+#: tests/dissect-sysfile.c:692
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record"
+msgstr "Espacio perdido tras `%c' en la posición %zu del registro MRSETS"
+
+#: tests/dissect-sysfile.c:701
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record"
+msgstr "Valor de fuente de etiqueta inesperado `%s' tras `E' en la posición %zu del registro MRSETS"
+
+#: tests/dissect-sysfile.c:759
+#, c-format
+msgid "Bad size %zu on extension 11."
+msgstr "Longitud no válida %zu en la extensión 11."
+
+#: tests/dissect-sysfile.c:851
 #, c-format
 msgid "%s: Error parsing attribute value %s[%d]"
 msgstr "%s: Error al analizar el valor del atributo %s[%d]"
 
-#: tests/dissect-sysfile.c:856
+#: tests/dissect-sysfile.c:857
 #, c-format
 msgid "%s: Attribute value %s[%d] is not quoted: %s"
 msgstr "%s: El valor del atributo %s[%d] no está entre comillas: %s"
 
-#: tests/dissect-sysfile.c:880
+#: tests/dissect-sysfile.c:881
 #, c-format
 msgid "Bad size %zu for extended number of cases."
 msgstr "Longitud no válida %zu para un número extenso de casos."
 
-#: tests/dissect-sysfile.c:886
+#: tests/dissect-sysfile.c:887
 #, c-format
 msgid "Bad count %zu for extended number of cases."
 msgstr "Recuento incorrecto %zu para un número extenso de casos."
 
-#: src/language/utilities/set.q:188
+#: tests/dissect-sysfile.c:937
+#, c-format
+msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
+msgstr "La longitud del nombre de la variable en el registro de la etiqueta del valor de cadena larga (%d) supera el límite %d-byte."
+
+#: src/language/utilities/set.q:171
 msgid "WORKSPACE must be at least 1MB"
 msgstr "WORKSPACE debe ser como mínimo 1 Mb"
 
-#: src/language/utilities/set.q:194 src/language/utilities/set.q:196
-#: src/language/utilities/set.q:198 src/language/utilities/set.q:200
-#: src/language/utilities/set.q:202 src/language/utilities/set.q:204
-#: src/language/utilities/set.q:206 src/language/utilities/set.q:208
-#: src/language/utilities/set.q:210
+#: src/language/utilities/set.q:177 src/language/utilities/set.q:179
+#: src/language/utilities/set.q:181 src/language/utilities/set.q:183
+#: src/language/utilities/set.q:185 src/language/utilities/set.q:187
+#: src/language/utilities/set.q:189 src/language/utilities/set.q:191
+#: src/language/utilities/set.q:193
 #, c-format
 msgid "%s is obsolete."
 msgstr "%s está obsoleto."
 
-#: src/language/utilities/set.q:216
+#: src/language/utilities/set.q:199
 msgid "Active file compression is not implemented."
 msgstr "La compresión de archivos no está implementada."
 
-#: src/language/utilities/set.q:334
+#: src/language/utilities/set.q:317
 msgid "EPOCH must be 1500 or later."
 msgstr "EPOCH debe ser 1500 o posterior."
 
-#: src/language/utilities/set.q:341
+#: src/language/utilities/set.q:324
 msgid "expecting AUTOMATIC or year"
 msgstr "esperando AUTOMATICA o año"
 
-#: src/language/utilities/set.q:369
+#: src/language/utilities/set.q:352
 msgid "LENGTH must be at least 1."
 msgstr "LENGTH debe ser como mínimo 1."
 
-#: src/language/utilities/set.q:405
+#: src/language/utilities/set.q:388
 #, c-format
-msgid "%s is not a recognised encoding or locale name"
+msgid "%s is not a recognized encoding or locale name"
 msgstr "%s no es una codificación o un nombre local reconocido"
 
-#: src/language/utilities/set.q:467
+#: src/language/utilities/set.q:449
 msgid "WIDTH must be at least 40."
 msgstr "WIDTH debe ser como mínimo 40."
 
-#: src/language/utilities/set.q:490
+#: src/language/utilities/set.q:476
 #, c-format
 msgid "FORMAT requires numeric output format as an argument.  Specified format %s is of type string."
 msgstr "FORMAT requiere formato de resultado numérico como argumento.  El formato %s especificado es de tipo cadena."
 
-#: src/language/utilities/set.q:707
+#: src/language/utilities/set.q:690
 msgid "ISL (32-bit IEEE 754 single, little-endian)"
 msgstr "ISL (32-bit IEEE 754 single, little-endian)"
 
-#: src/language/utilities/set.q:710
+#: src/language/utilities/set.q:693
 msgid "ISB (32-bit IEEE 754 single, big-endian)"
 msgstr "ISB (32-bit IEEE 754 single, big-endian)"
 
-#: src/language/utilities/set.q:713
+#: src/language/utilities/set.q:696
 msgid "IDL (64-bit IEEE 754 double, little-endian)"
 msgstr "IDL (64-bit IEEE 754 double, little-endian)"
 
-#: src/language/utilities/set.q:716
+#: src/language/utilities/set.q:699
 msgid "IDB (64-bit IEEE 754 double, big-endian)"
 msgstr "IDB (64-bit IEEE 754 double, big-endian)"
 
-#: src/language/utilities/set.q:720
+#: src/language/utilities/set.q:703
 msgid "VF (32-bit VAX F, VAX-endian)"
 msgstr "VF (32-bit VAX F, VAX-endian)"
 
-#: src/language/utilities/set.q:723
+#: src/language/utilities/set.q:706
 msgid "VD (64-bit VAX D, VAX-endian)"
 msgstr "VD (64-bit VAX D, VAX-endian)"
 
-#: src/language/utilities/set.q:726
+#: src/language/utilities/set.q:709
 msgid "VG (64-bit VAX G, VAX-endian)"
 msgstr "VG (64-bit VAX G, VAX-endian)"
 
-#: src/language/utilities/set.q:730
+#: src/language/utilities/set.q:713
 msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 msgstr "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 
-#: src/language/utilities/set.q:733
+#: src/language/utilities/set.q:716
 msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 msgstr "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 
-#: src/language/utilities/set.q:835
+#: src/language/utilities/set.q:817
 #, c-format
 msgid "%s is %s."
 msgstr "%s es %s."
 
-#: src/language/stats/crosstabs.q:289
+#: src/language/utilities/set.q:920
+#, c-format
+msgid "Too many PRESERVE commands without a RESTORE: at most %d levels of saved settings are allowed."
+msgstr "Demasiados comandos PRESERVE sin un RESTORE: se permiten al menos %d niveles de configuraciones salvadas."
+
+#: src/language/utilities/set.q:939
+msgid "RESTORE without matching PRESERVE."
+msgstr "RESTORE sin el correspondiente PRESERVE."
+
+#: src/language/stats/crosstabs.q:295
 msgid "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
 msgstr "El INFORME de perdidos no está disponible en el modo general.  Se asume MISSING=TABLE."
 
-#: src/language/stats/crosstabs.q:399
+#: src/language/stats/crosstabs.q:405
 msgid "Too many cross-tabulation variables or dimensions."
 msgstr "Demasiadas variables o dimensiones para una Tabla Cruzada."
 
-#: src/language/stats/crosstabs.q:409
-msgid "expecting BY"
-msgstr "esperando BY"
-
-#: src/language/stats/crosstabs.q:466
+#: src/language/stats/crosstabs.q:472
 msgid "VARIABLES must be specified before TABLES."
 msgstr "Las VARIABLES tienen que ser especificadas antes de TABLES."
 
-#: src/language/stats/crosstabs.q:504
+#: src/language/stats/crosstabs.q:506
 #, c-format
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr "El valor máximo (%ld) en menor que el valor mínimo (%ld)."
 
-#: src/language/stats/crosstabs.q:818
+#: src/language/stats/crosstabs.q:827
 msgid "Summary."
 msgstr "Resumen."
 
-#: src/language/stats/crosstabs.q:820 src/language/stats/examine.q:1164
-#: src/language/stats/reliability.q:693
-msgid "Cases"
-msgstr "Casos"
-
-#: src/language/stats/crosstabs.q:821 src/language/stats/examine.q:1103
-#: src/language/stats/frequencies.q:1035 src/language/stats/reliability.q:696
-msgid "Valid"
-msgstr "Válido"
-
-#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1179
-#: src/language/stats/frequencies.q:815
+#: src/language/stats/crosstabs.q:840 src/language/stats/examine.q:1178
+#: src/language/stats/frequencies.q:825
 msgid "Percent"
 msgstr "Porcentaje"
 
-#: src/language/stats/crosstabs.q:1109
+#. TRANSLATORS: The %s here describes a crosstabulation.  It takes the
+#. form "var1 * var2 * var3 * ...".
+#: src/language/stats/crosstabs.q:936
+#, c-format
+msgid "Crosstabulation %s contained no non-missing cases."
+msgstr "La tabla de contingencia %s no contiene ningún caso no-perdido."
+
+#: src/language/stats/crosstabs.q:1134
 msgid "count"
 msgstr "recuento"
 
-#: src/language/stats/crosstabs.q:1110
+#: src/language/stats/crosstabs.q:1135
 msgid "row %"
 msgstr "fila %"
 
-#: src/language/stats/crosstabs.q:1111
+#: src/language/stats/crosstabs.q:1136
 msgid "column %"
 msgstr "columna %"
 
-#: src/language/stats/crosstabs.q:1112
+#: src/language/stats/crosstabs.q:1137
 msgid "total %"
 msgstr "total %"
 
-#: src/language/stats/crosstabs.q:1113
+#: src/language/stats/crosstabs.q:1138
 msgid "expected"
 msgstr "esperado"
 
-#: src/language/stats/crosstabs.q:1114
+#: src/language/stats/crosstabs.q:1139
 msgid "residual"
 msgstr "residual"
 
-#: src/language/stats/crosstabs.q:1115
+#: src/language/stats/crosstabs.q:1140
 msgid "std. resid."
 msgstr "residuo std."
 
-#: src/language/stats/crosstabs.q:1116
+#: src/language/stats/crosstabs.q:1141
 msgid "adj. resid."
 msgstr "resid.ajust."
 
-#: src/language/stats/crosstabs.q:1210
+#: src/language/stats/crosstabs.q:1230
 msgid "Chi-square tests."
 msgstr "Pruebas Chi-cuadrado."
 
-#: src/language/stats/crosstabs.q:1217
-msgid "Asymp. Sig. (2-sided)"
-msgstr "Sign. Asint. (2-colas)"
-
-#: src/language/stats/crosstabs.q:1219
-msgid "Exact Sig. (2-sided)"
-msgstr "Sign. Exacta (2-colas)"
-
-#: src/language/stats/crosstabs.q:1221
-msgid "Exact Sig. (1-sided)"
-msgstr "Sign. Exacta (1-cola)"
-
-#: src/language/stats/crosstabs.q:1236
+#: src/language/stats/crosstabs.q:1256
 msgid "Symmetric measures."
 msgstr "Medidas simétricas."
 
-#: src/language/stats/crosstabs.q:1242 src/language/stats/crosstabs.q:1290
+#: src/language/stats/crosstabs.q:1262 src/language/stats/crosstabs.q:1310
 msgid "Asymp. Std. Error"
 msgstr "Err. Est. Asint."
 
-#: src/language/stats/crosstabs.q:1243 src/language/stats/crosstabs.q:1291
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1311
 msgid "Approx. T"
 msgstr "T Aproxim."
 
-#: src/language/stats/crosstabs.q:1244 src/language/stats/crosstabs.q:1292
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1312
 msgid "Approx. Sig."
 msgstr "Sign. Aproxim."
 
-#: src/language/stats/crosstabs.q:1258
+#: src/language/stats/crosstabs.q:1278
 msgid "Risk estimate."
 msgstr "Estimador de Riesgo."
 
-#: src/language/stats/crosstabs.q:1262
+#: src/language/stats/crosstabs.q:1282
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr "Intervalo de Confianza del 95%%"
 
-#: src/language/stats/crosstabs.q:1265 src/language/stats/t-test.q:756
-#: src/language/stats/t-test.q:920 src/language/stats/t-test.q:1013
+#: src/language/stats/crosstabs.q:1285 src/language/stats/t-test.q:760
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1017
 msgid "Lower"
 msgstr "Inferior"
 
-#: src/language/stats/crosstabs.q:1266 src/language/stats/t-test.q:757
-#: src/language/stats/t-test.q:921 src/language/stats/t-test.q:1014
+#: src/language/stats/crosstabs.q:1286 src/language/stats/t-test.q:761
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1018
 msgid "Upper"
 msgstr "Superior"
 
-#: src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1303
 msgid "Directional measures."
 msgstr "Medidas direccionales."
 
-#: src/language/stats/crosstabs.q:1708
+#: src/language/stats/crosstabs.q:1740
 msgid "Pearson Chi-Square"
 msgstr "Chi-cuadrado de Pearson"
 
 #
-#: src/language/stats/crosstabs.q:1709
+#: src/language/stats/crosstabs.q:1741
 msgid "Likelihood Ratio"
 msgstr "Razón de Semejanza"
 
-#: src/language/stats/crosstabs.q:1710
+#: src/language/stats/crosstabs.q:1742
 msgid "Fisher's Exact Test"
 msgstr "Prueba exacta de Fisher"
 
-#: src/language/stats/crosstabs.q:1711
+#: src/language/stats/crosstabs.q:1743
 msgid "Continuity Correction"
 msgstr "Corrección de continuidad"
 
-#: src/language/stats/crosstabs.q:1712
+#: src/language/stats/crosstabs.q:1744
 msgid "Linear-by-Linear Association"
 msgstr "Asociación Lineal-by-Lineal"
 
-#: src/language/stats/crosstabs.q:1747 src/language/stats/crosstabs.q:1822
-#: src/language/stats/crosstabs.q:1887
+#: src/language/stats/crosstabs.q:1779 src/language/stats/crosstabs.q:1854
+#: src/language/stats/crosstabs.q:1919
 msgid "N of Valid Cases"
 msgstr "N de casos válidos"
 
-#: src/language/stats/crosstabs.q:1766 src/language/stats/crosstabs.q:1905
+#: src/language/stats/crosstabs.q:1798 src/language/stats/crosstabs.q:1937
 msgid "Nominal by Nominal"
 msgstr "Nominal según Nominal"
 
-#: src/language/stats/crosstabs.q:1767 src/language/stats/crosstabs.q:1906
+#: src/language/stats/crosstabs.q:1799 src/language/stats/crosstabs.q:1938
 msgid "Ordinal by Ordinal"
 msgstr "Ordinal según Ordinal"
 
-#: src/language/stats/crosstabs.q:1768
+#: src/language/stats/crosstabs.q:1800
 msgid "Interval by Interval"
 msgstr "Intervalo según Intervalo"
 
-#: src/language/stats/crosstabs.q:1769
+#: src/language/stats/crosstabs.q:1801
 msgid "Measure of Agreement"
 msgstr "Medida de Acuerdo"
 
-#: src/language/stats/crosstabs.q:1775
+#: src/language/stats/crosstabs.q:1807
 msgid "Cramer's V"
 msgstr "V de Cramer"
 
-#: src/language/stats/crosstabs.q:1776
+#: src/language/stats/crosstabs.q:1808
 msgid "Contingency Coefficient"
 msgstr "Coeficiente de Contingencia"
 
-#: src/language/stats/crosstabs.q:1777
+#: src/language/stats/crosstabs.q:1809
 msgid "Kendall's tau-b"
 msgstr "Tau-B de Kendall"
 
-#: src/language/stats/crosstabs.q:1778
+#: src/language/stats/crosstabs.q:1810
 msgid "Kendall's tau-c"
 msgstr "Tau-C de Kendall"
 
-#: src/language/stats/crosstabs.q:1780
+#: src/language/stats/crosstabs.q:1812
 msgid "Spearman Correlation"
 msgstr "Correlación de Spearman"
 
-#: src/language/stats/crosstabs.q:1781
+#: src/language/stats/crosstabs.q:1813
 msgid "Pearson's R"
 msgstr "R de Pearson"
 
-#: src/language/stats/crosstabs.q:1860
+#: src/language/stats/crosstabs.q:1892
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
 msgstr "Razón de diferencias para %s (%g / %g)"
 
-#: src/language/stats/crosstabs.q:1863
+#: src/language/stats/crosstabs.q:1895
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
 msgstr "Razón de diferencias para  %s (%.*s / %.*s)"
 
-#: src/language/stats/crosstabs.q:1871
+#: src/language/stats/crosstabs.q:1903
 #, c-format
 msgid "For cohort %s = %g"
 msgstr "Para la cohorte %s = %g"
 
-#: src/language/stats/crosstabs.q:1874
+#: src/language/stats/crosstabs.q:1906
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr "Para la cohorte %s = %.*s"
 
-#: src/language/stats/crosstabs.q:1907
+#: src/language/stats/crosstabs.q:1939
 msgid "Nominal by Interval"
 msgstr "Nominal según Intervalo"
 
-#: src/language/stats/crosstabs.q:1913
+#: src/language/stats/crosstabs.q:1945
 msgid "Goodman and Kruskal tau"
 msgstr "Tau de Kruskal y Goodman"
 
-#: src/language/stats/crosstabs.q:1914
+#: src/language/stats/crosstabs.q:1946
 msgid "Uncertainty Coefficient"
 msgstr "Coeficiente de Incertidumbre"
 
-#: src/language/stats/crosstabs.q:1915
+#: src/language/stats/crosstabs.q:1947
 msgid "Somers' d"
 msgstr "D de Somers"
 
-#: src/language/stats/crosstabs.q:1921
+#: src/language/stats/crosstabs.q:1953
 msgid "Symmetric"
 msgstr "Simétrico"
 
-#: src/language/stats/crosstabs.q:1922 src/language/stats/crosstabs.q:1923
+#: src/language/stats/crosstabs.q:1954 src/language/stats/crosstabs.q:1955
 #, c-format
 msgid "%s Dependent"
 msgstr "%s Dependiente"
 
-#: src/language/stats/examine.q:357
+#: src/language/stats/examine.q:355
 msgid "Not creating NP plot because data set is empty."
 msgstr "No se creará el gráfico NP porque el conjunto de datos está vacío."
 
-#: src/language/stats/examine.q:442 src/language/stats/examine.q:949
+#: src/language/stats/examine.q:441 src/language/stats/examine.q:948
 msgid "Not creating plot because data set is empty."
 msgstr "No se crea el gráfico porque el conjunto de datos está vacío."
 
-#: src/language/stats/examine.q:454
+#: src/language/stats/examine.q:453
 #, c-format
 msgid "Boxplot of %s vs. %s"
 msgstr "Diagrama de caja de %s vs. %s"
 
-#: src/language/stats/examine.q:458
+#: src/language/stats/examine.q:457
 #, c-format
 msgid "Boxplot of %s"
 msgstr "Diagrama de caja de %s"
 
-#: src/language/stats/examine.q:647 src/language/stats/examine.q:660
+#: src/language/stats/examine.q:646 src/language/stats/examine.q:659
 #, c-format
 msgid "%s and %s are mutually exclusive"
 msgstr "%s i %s son mútuamente excluyentes"
 
-#: src/language/stats/examine.q:1159 src/language/stats/reliability.q:670
-msgid "Case Processing Summary"
-msgstr "Resumen del proceso de casos"
-
-#: src/language/stats/examine.q:1449 src/language/stats/oneway.q:394
-#, c-format
-msgid "%g%% Confidence Interval for Mean"
-msgstr "Intervalo de Confianza %g%% para la Media"
-
-#: src/language/stats/examine.q:1464
+#: src/language/stats/examine.q:1463
 msgid "5% Trimmed Mean"
 msgstr "Media recortada al 5%"
 
-#: src/language/stats/examine.q:1499
+#: src/language/stats/examine.q:1498
 msgid "Interquartile Range"
 msgstr "Intervalo intercuartílico"
 
-#: src/language/stats/examine.q:1635 src/language/stats/oneway.q:404
-#: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
-msgid "Descriptives"
-msgstr "Descriptivos"
-
-#: src/language/stats/examine.q:1821
+#: src/language/stats/examine.q:1820
 msgid "Highest"
 msgstr "Máximo"
 
-#: src/language/stats/examine.q:1826
+#: src/language/stats/examine.q:1825
 msgid "Lowest"
 msgstr "Mínimo"
 
-#: src/language/stats/examine.q:1833
+#: src/language/stats/examine.q:1832
 msgid "Extreme Values"
 msgstr "Valores extremos"
 
-#: src/language/stats/examine.q:1837 src/language/data-io/list.q:158
+#: src/language/stats/examine.q:1836 src/language/data-io/list.q:157
 msgid "Case Number"
 msgstr "Número de Caso"
 
-#: src/language/stats/examine.q:1957
+#: src/language/stats/examine.q:1956
 msgid "Tukey's Hinges"
 msgstr "Bisagras de Tukey"
 
-#: src/language/stats/examine.q:2003
+#: src/language/stats/examine.q:2002
 #, c-format
 msgid "%g"
 msgstr "%g"
@@ -4665,171 +5202,50 @@ msgstr "Para el histograma, MAX debe ser mayor o igual a MIN, pero MIN se ha esp
 msgid "MAX for pie chart must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
 msgstr "Para el gráfico de sectores, MAX debe ser mayor o igual a MIN, pero MIN se ha especificado como %15g y MAX como %15g.  MIN y MAX serán ignorados."
 
-#: src/language/stats/frequencies.q:703
+#: src/language/stats/frequencies.q:704
 msgid "`)' expected after GROUPED interval list."
 msgstr "`)' esperada después de la lista de variables GRUPED."
 
-#: src/language/stats/frequencies.q:723
-#, c-format
-msgid "Variables %s specified multiple times on GROUPED subcommand."
-msgstr "La variable %s se ha especificado más de una vez en el subcomando GROUPED."
-
-#: src/language/stats/frequencies.q:733
-#, c-format
-msgid "Variables %s specified on GROUPED but not on VARIABLES."
-msgstr "Variables %s especificadas en GROUPED pero no en VARIABLES."
-
-#: src/language/stats/frequencies.q:812
-msgid "Value Label"
-msgstr "Etiqueta de Valor"
-
-#: src/language/stats/frequencies.q:816
-msgid "Valid Percent"
-msgstr "Porcentaje Válido"
-
-#: src/language/stats/frequencies.q:817
-msgid "Cum Percent"
-msgstr "Porcentaje Acumulado"
-
-#: src/language/stats/frequencies.q:1008
-#, c-format
-msgid "No valid data for variable %s; statistics not displayed."
-msgstr "No hay datos válidos para la variable %s; no se muestran estadísticas."
-
-#: src/language/stats/frequencies.q:1054
-msgid "50 (Median)"
-msgstr "50 (Mediana)"
-
-#: src/language/stats/frequencies.q:1209
-#, c-format
-msgid "Omitting pie chart for %s, which has only %d unique values."
-msgstr "Se omite el gráfico de sectores para %s, que sólo tiene %d valores únicos."
-
-#: src/language/stats/frequencies.q:1212
-#, c-format
-msgid "Omitting pie chart for %s, which has over 50 unique values."
-msgstr "Se omite el gráfico de sectores para %s, que tiene más de 50 valores únicos."
-
-#: src/language/stats/glm.q:247
-msgid "Multivariate GLM not yet supported"
-msgstr "GLM multivariable todavía no disponible"
-
-#: src/language/stats/means.q:100
-msgid "Missing required subcommand TABLES."
-msgstr "Falta el subcomando requerido TABLES."
-
-#: src/language/stats/means.q:134
-msgid "TABLES subcommand may not appear more than once."
-msgstr "El subcomando TABLES no puede aparecer más de una vez."
-
-#: src/language/stats/npar.q:111
-msgid "NPAR subcommand not currently implemented."
-msgstr "Actualmente no está implementado el subcomando NPAR."
-
-#: src/language/stats/npar.q:256
-#, c-format
-msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
-msgstr "El valor especificado para HI (%d) es menor que el especificado para LO (%d)"
-
-#: src/language/stats/npar.q:311
-#, c-format
-msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
-msgstr "Se han proporcionado %d valores esperados, pero el intervalo especificado (%d-%d) requiere exactamente %d valores."
-
-#: src/language/stats/npar.q:453 src/language/stats/t-test.q:380
-#, c-format
-msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
-msgstr "Se ha especificado PAIRED pero el número de variables antes de WITH (%zu) no coincide con el número de variables posterior (%zu)."
-
-#: src/language/stats/oneway.q:170
-msgid "Number of contrast coefficients must equal the number of groups"
-msgstr "El número de coeficientes de contraste debe ser igual al número de grupos"
-
-#: src/language/stats/oneway.q:179
-#, c-format
-msgid "Coefficients for contrast %zu do not total zero"
-msgstr "Los coeficientes para contrastar %zu no suman cero"
-
-#: src/language/stats/oneway.q:242
-#, c-format
-msgid "`%s' is not a variable name"
-msgstr "`%s' no es un nombre de variable"
-
-#: src/language/stats/oneway.q:274 src/language/stats/regression.q:283
-msgid "Sum of Squares"
-msgstr "Suma de Cuadrados"
-
-#: src/language/stats/oneway.q:276 src/language/stats/regression.q:285
-msgid "Mean Square"
-msgstr "Cuadrado medio"
-
-#: src/language/stats/oneway.q:277 src/language/stats/regression.q:286
-#: src/language/stats/t-test.q:749
-msgid "F"
-msgstr "F"
-
-#: src/language/stats/oneway.q:278 src/language/stats/oneway.q:535
-#: src/language/stats/regression.q:201 src/language/stats/regression.q:287
-msgid "Significance"
-msgstr "Significatividad"
-
-#: src/language/stats/oneway.q:300
-msgid "Between Groups"
-msgstr "Entre Grupos"
-
-#: src/language/stats/oneway.q:301
-msgid "Within Groups"
-msgstr "Intra Grupos"
-
-#: src/language/stats/oneway.q:345 src/language/stats/regression.q:312
-msgid "ANOVA"
-msgstr "ANOVA"
-
-#: src/language/stats/oneway.q:532
-msgid "Levene Statistic"
-msgstr "Estadístico de Levene"
-
-#: src/language/stats/oneway.q:533
-msgid "df1"
-msgstr "df1"
-
-#: src/language/stats/oneway.q:534
-msgid "df2"
-msgstr "df2"
+#: src/language/stats/frequencies.q:724
+#, c-format
+msgid "Variables %s specified multiple times on GROUPED subcommand."
+msgstr "La variable %s se ha especificado más de una vez en el subcomando GROUPED."
 
-#: src/language/stats/oneway.q:537
-msgid "Test of Homogeneity of Variances"
-msgstr "Prueba de Homogeneidad de Varianzas"
+#: src/language/stats/frequencies.q:734
+#, c-format
+msgid "Variables %s specified on GROUPED but not on VARIABLES."
+msgstr "Variables %s especificadas en GROUPED pero no en VARIABLES."
 
-#: src/language/stats/oneway.q:603
-msgid "Contrast Coefficients"
-msgstr "Coeficientes de Contraste"
+#: src/language/stats/frequencies.q:822
+msgid "Value Label"
+msgstr "Etiqueta de Valor"
 
-#: src/language/stats/oneway.q:605 src/language/stats/oneway.q:681
-msgid "Contrast"
-msgstr "Contraste"
+#: src/language/stats/frequencies.q:826
+msgid "Valid Percent"
+msgstr "Porcentaje Válido"
 
-#: src/language/stats/oneway.q:679
-msgid "Contrast Tests"
-msgstr "Pruebas de contrate"
+#: src/language/stats/frequencies.q:827
+msgid "Cum Percent"
+msgstr "Porcentaje Acumulado"
 
-#: src/language/stats/oneway.q:682
-msgid "Value of Contrast"
-msgstr "Valor de constraste"
+#: src/language/stats/frequencies.q:1017
+#, c-format
+msgid "No valid data for variable %s; statistics not displayed."
+msgstr "No hay datos válidos para la variable %s; no se muestran estadísticas."
 
-#: src/language/stats/oneway.q:684 src/language/stats/regression.q:200
-#: src/language/stats/t-test.q:751 src/language/stats/t-test.q:922
-#: src/language/stats/t-test.q:1009
-msgid "t"
-msgstr "t"
+#: src/language/stats/frequencies.q:1063
+msgid "50 (Median)"
+msgstr "50 (Mediana)"
 
-#: src/language/stats/oneway.q:730
-msgid "Assume equal variances"
-msgstr "Se asume igualdad de varianzas"
+#: src/language/stats/frequencies.q:1218
+#, c-format
+msgid "Omitting pie chart for %s, which has only %d unique values."
+msgstr "Se omite el gráfico de sectores para %s, que sólo tiene %d valores únicos."
 
-#: src/language/stats/oneway.q:734
-msgid "Does not assume equal"
-msgstr "No se asume igualdad"
+#: src/language/stats/frequencies.q:1221
+#, c-format
+msgid "Omitting pie chart for %s, which has over 50 unique values."
+msgstr "Se omite el gráfico de sectores para %s, que tiene más de 50 valores únicos."
 
 #: src/language/stats/rank.q:220
 #, c-format
@@ -4845,343 +5261,329 @@ msgstr "%s de %s"
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr "No se puede crear la nueva variable de rangos.  Todos los candidatos están en uso."
 
-#: src/language/stats/rank.q:693
+#: src/language/stats/rank.q:696
 msgid "Variables Created By RANK"
 msgstr "Variables creadas para RANK"
 
-#: src/language/stats/rank.q:717
+#: src/language/stats/rank.q:720
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr "%s en %s(%s de %s utilizando %s BY %s)"
 
-#: src/language/stats/rank.q:727
+#: src/language/stats/rank.q:730
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr "%s en %s(%s de %s BY %s)"
 
-#: src/language/stats/rank.q:740
+#: src/language/stats/rank.q:743
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr "%s en %s(%s de %s utilizando %s)"
 
-#: src/language/stats/rank.q:749
+#: src/language/stats/rank.q:752
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr "%s en %s(%s de %s)"
 
-#: src/language/stats/rank.q:761
+#: src/language/stats/rank.q:764
 msgid "FRACTION has been specified, but NORMAL and PROPORTION rank functions have not been requested.  The FRACTION subcommand will be ignored."
 msgstr "Se ha especificado FRACTION, pero no se han pedido funciones de rango NORMAL o PROPORTION.  La suborden FRACTION será ignorada."
 
-#: src/language/stats/rank.q:852
+#: src/language/stats/rank.q:855
 #, c-format
 msgid "Variable %s already exists."
 msgstr "La variable %s ya existe."
 
-#: src/language/stats/rank.q:857
+#: src/language/stats/rank.q:860
 msgid "Too many variables in INTO clause."
 msgstr "Demasiadas variables a la cláusula INTO."
 
-#: src/language/stats/regression.q:156
+#: src/language/stats/regression.q:158
 msgid "R Square"
 msgstr "R Cuadrada"
 
-#: src/language/stats/regression.q:157
+#: src/language/stats/regression.q:159
 msgid "Adjusted R Square"
 msgstr "R Cuadrada Ajustada"
 
-#: src/language/stats/regression.q:158
+#: src/language/stats/regression.q:160
 msgid "Std. Error of the Estimate"
 msgstr "Error estándard del Estimador"
 
-#: src/language/stats/regression.q:163
+#: src/language/stats/regression.q:165
 msgid "Model Summary"
 msgstr "Resumen del modelo"
 
-#: src/language/stats/regression.q:197
+#: src/language/stats/regression.q:199
 msgid "B"
 msgstr "B"
 
-#: src/language/stats/regression.q:199
+#: src/language/stats/regression.q:201
 msgid "Beta"
 msgstr "Beta"
 
-#: src/language/stats/regression.q:202
+#: src/language/stats/regression.q:204
 msgid "(Constant)"
 msgstr "(Constant)"
 
-#: src/language/stats/regression.q:254
+#: src/language/stats/regression.q:256
 msgid "Coefficients"
 msgstr "Coeficientes"
 
-#: src/language/stats/regression.q:289 src/ui/gui/regression.ui:7
+#: src/language/stats/regression.q:291 src/ui/gui/regression.ui:7
 msgid "Regression"
 msgstr "Regresión"
 
-#: src/language/stats/regression.q:370
+#: src/language/stats/regression.q:372
 msgid "Model"
 msgstr "Modelo"
 
-#: src/language/stats/regression.q:371
+#: src/language/stats/regression.q:373
 msgid "Covariances"
 msgstr "Covarianza"
 
-#: src/language/stats/regression.q:386
+#: src/language/stats/regression.q:388
 msgid "Coefficient Correlations"
 msgstr "Correlaciones de Coeficientes"
 
-#: src/language/stats/regression.q:793
+#: src/language/stats/regression.q:787
 msgid "The dependent variable is equal to the independent variable.The least squares line is therefore Y=X.Standard errors and related statistics may be meaningless."
 msgstr "La variable dependiente es igual a la variable independiente. La línea de minimos cuadrados es por tanto Y=X. Los errores estándard y los estadísticos relacionados podrian ser irrelevantes."
 
-#: src/language/stats/regression.q:891
+#: src/language/stats/regression.q:934
 msgid "REGRESSION requires numeric variables."
 msgstr "REGRESSION requiere variables numéricas."
 
-#: src/language/stats/regression.q:962
+#: src/language/stats/regression.q:1009
 msgid "No valid data found. This command was skipped."
 msgstr "No se han encontrado datos válidos. Se ignora esta orden."
 
-#: src/language/stats/reliability.q:421
-msgid "Reliability Statistics"
-msgstr "Estadísticas de fiabilidad"
-
-#: src/language/stats/reliability.q:462
-msgid "Item-Total Statistics"
-msgstr "Estadísticas de total de Ítems"
-
-#: src/language/stats/reliability.q:484
-msgid "Scale Mean if Item Deleted"
-msgstr "Escalar la mediana si se borra el elemento"
-
-#: src/language/stats/reliability.q:487
-msgid "Scale Variance if Item Deleted"
-msgstr "Escalar la varianza si se borra el elemento"
-
-#: src/language/stats/reliability.q:490
-msgid "Corrected Item-Total Correlation"
-msgstr "Correlación total-ítem corregida"
-
-#: src/language/stats/reliability.q:493
-msgid "Cronbach's Alpha if Item Deleted"
-msgstr "Alfa de Cronbach si se borra el elemento"
-
-#: src/language/stats/reliability.q:543 src/language/stats/reliability.q:562
-msgid "Cronbach's Alpha"
-msgstr "Alfa de Cronbach"
-
-#: src/language/stats/reliability.q:546 src/language/stats/reliability.q:571
-#: src/language/stats/reliability.q:582
-msgid "N of Items"
-msgstr "N de elementos"
-
-#: src/language/stats/reliability.q:565
-msgid "Part 1"
-msgstr "Parte 1"
-
-#: src/language/stats/reliability.q:576
-msgid "Part 2"
-msgstr "Parte 2"
-
-#: src/language/stats/reliability.q:587
-msgid "Total N of Items"
-msgstr "N total de elementos"
-
-#
-#: src/language/stats/reliability.q:590
-msgid "Correlation Between Forms"
-msgstr "Correlación entre formas"
-
-#: src/language/stats/reliability.q:594
-msgid "Spearman-Brown Coefficient"
-msgstr "Coeficiente de Spearman-Brown"
-
-#: src/language/stats/reliability.q:597
-msgid "Equal Length"
-msgstr "Ancho igual"
-
-#: src/language/stats/reliability.q:600
-msgid "Unequal Length"
-msgstr "Ancho desigual"
-
-#: src/language/stats/reliability.q:604
-msgid "Guttman Split-Half Coefficient"
-msgstr "Coeficiente Guttman de División en Mitades"
-
-#: src/language/stats/reliability.q:699
-msgid "Excluded"
-msgstr "Excluido"
-
-#: src/language/stats/reliability.q:707
-msgid "%"
-msgstr "%"
-
-#: src/language/stats/t-test.q:190
+#: src/language/stats/t-test.q:192
 msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
 msgstr "Debe especificarse sólo uno de los subcomandos TESTVAL, GROUPS y PAIRS."
 
-#: src/language/stats/t-test.q:211
+#: src/language/stats/t-test.q:213
 msgid "VARIABLES subcommand may not be used with PAIRS."
 msgstr "La suborden VARIABLES no puede ser utilizada con PAIRS."
 
-#: src/language/stats/t-test.q:230
+#: src/language/stats/t-test.q:232
 msgid "One or more VARIABLES must be specified."
 msgstr "Una o más VARIABLES deben ser especificadas."
 
-#: src/language/stats/t-test.q:324
+#: src/language/stats/t-test.q:328
 msgid "When applying GROUPS to a string variable, two values must be specified."
 msgstr "Cuando se aplica GROUPS a una variable alfabética, se deben especificar dos valores."
 
-#: src/language/stats/t-test.q:395
+#: src/language/stats/t-test.q:399
 msgid "At least two variables must be specified on PAIRS."
 msgstr "Al menos dos variables se deben especificar en PAIRS."
 
-#: src/language/stats/t-test.q:503
+#: src/language/stats/t-test.q:507
 msgid "One-Sample Statistics"
 msgstr "Estadísticas de una muestra"
 
-#: src/language/stats/t-test.q:522
+#: src/language/stats/t-test.q:526
 msgid "Group Statistics"
 msgstr "Estadísticas de grupo"
 
-#: src/language/stats/t-test.q:621
+#: src/language/stats/t-test.q:625
 msgid "Paired Sample Statistics"
 msgstr "Estadísticas de muestras emparejadas"
 
-#: src/language/stats/t-test.q:641 src/language/stats/t-test.q:944
-#: src/language/stats/t-test.q:1111
+#: src/language/stats/t-test.q:645 src/language/stats/t-test.q:948
+#: src/language/stats/t-test.q:1115
 #, c-format
 msgid "Pair %d"
 msgstr "Pareja %d"
 
-#: src/language/stats/t-test.q:737
+#: src/language/stats/t-test.q:741
 msgid "Independent Samples Test"
 msgstr "Prueba para muestras independientes"
 
-#: src/language/stats/t-test.q:745
+#: src/language/stats/t-test.q:749
 msgid "Levene's Test for Equality of Variances"
 msgstr "Prueba de Levene para la igualdad de varianzas"
 
-#: src/language/stats/t-test.q:747
+#: src/language/stats/t-test.q:751
 msgid "t-test for Equality of Means"
 msgstr "Prueba T para la Igualdad de Medias"
 
-#: src/language/stats/t-test.q:750 src/language/stats/t-test.q:1103
+#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1107
 msgid "Sig."
 msgstr "Sign."
 
-#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1012
+#: src/language/stats/t-test.q:758 src/language/stats/t-test.q:1016
 msgid "Mean Difference"
 msgstr "Diferencia Media"
 
-#: src/language/stats/t-test.q:755
+#: src/language/stats/t-test.q:759
 msgid "Std. Error Difference"
 msgstr "Err.Est. de la Diferencia"
 
-#: src/language/stats/t-test.q:760 src/language/stats/t-test.q:914
-#: src/language/stats/t-test.q:1004
+#: src/language/stats/t-test.q:764 src/language/stats/t-test.q:918
+#: src/language/stats/t-test.q:1008
 #, c-format
 msgid "%g%% Confidence Interval of the Difference"
 msgstr "Intervalo de confianza %g%% de la Diferencia"
 
-#: src/language/stats/t-test.q:814
+#: src/language/stats/t-test.q:818
 msgid "Equal variances assumed"
 msgstr "Se asume igualdad de varianzas"
 
-#: src/language/stats/t-test.q:860
+#: src/language/stats/t-test.q:864
 msgid "Equal variances not assumed"
 msgstr "Igualdad de varianzas no asumida"
 
-#: src/language/stats/t-test.q:904
+#: src/language/stats/t-test.q:908
 msgid "Paired Samples Test"
 msgstr "Prueba de muestras emparejadas"
 
-#: src/language/stats/t-test.q:907
+#: src/language/stats/t-test.q:911
 msgid "Paired Differences"
 msgstr "Diferencias emparejadas"
 
-#: src/language/stats/t-test.q:919
+#: src/language/stats/t-test.q:923
 msgid "Std. Error Mean"
 msgstr "Error Est. Media"
 
-#: src/language/stats/t-test.q:993
+#: src/language/stats/t-test.q:997
 msgid "One-Sample Test"
 msgstr "Prueba de una muestra"
 
-#: src/language/stats/t-test.q:998
+#: src/language/stats/t-test.q:1002
 #, c-format
 msgid "Test Value = %f"
 msgstr "Valor de prueba = %f"
 
-#: src/language/stats/t-test.q:1098
+#: src/language/stats/t-test.q:1102
 msgid "Paired Samples Correlations"
 msgstr "Correlaciones de muestras emparejadas"
 
-#: src/language/stats/t-test.q:1102
+#: src/language/stats/t-test.q:1106
 msgid "Correlation"
 msgstr "Correlación"
 
-#: src/language/stats/t-test.q:1113
+#: src/language/stats/t-test.q:1117
 #, c-format
 msgid "%s & %s"
 msgstr "%s & %s"
 
-#: src/language/data-io/file-handle.q:65
+#: src/language/data-io/file-handle.q:68
 #, c-format
 msgid "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining a file handle."
 msgstr "El manipulador de archivo %s ya está definido.  Usar CLOSE FILE HANDLE antes de redefinir un manipulador de archivos."
 
-#: src/language/data-io/file-handle.q:120
+#: src/language/data-io/file-handle.q:123
 msgid "RECFORM must be specified with MODE=360."
 msgstr "RECFORM debe ser especificado con MODE=360."
 
-#: src/language/data-io/file-handle.q:131
+#: src/language/data-io/file-handle.q:134
 #, c-format
 msgid "The specified file mode requires LRECL.  Assuming %zu-character records."
 msgstr "El modo de fichero especificado requiere LRECL. Se asumen registros de %zu caracteres."
 
-#: src/language/data-io/file-handle.q:135
+#: src/language/data-io/file-handle.q:138
 #, c-format
 msgid "Record length (%ld) must be between 1 and %lu bytes.  Assuming %d-character records."
 msgstr "El tamaño de registro (%ld) debe estar entre  1 y %lu bytes.  Se asume %d-registros de carácter."
 
-#: src/language/data-io/file-handle.q:177
+#: src/language/data-io/file-handle.q:182
 msgid "file"
 msgstr "archivo"
 
-#: src/language/data-io/file-handle.q:179
+#: src/language/data-io/file-handle.q:184
 msgid "inline file"
 msgstr "archivo en línea"
 
-#: src/language/data-io/file-handle.q:205
+#: src/language/data-io/file-handle.q:210
 msgid "expecting a file name or handle name"
 msgstr "esperando un nombre de archivo o un manipulador"
 
-#: src/language/data-io/file-handle.q:225
+#: src/language/data-io/file-handle.q:231
 #, c-format
 msgid "Handle for %s not allowed here."
 msgstr "Aquí no está permitido un manipulador para %s."
 
-#: src/language/data-io/list.q:99
+#: src/language/data-io/list.q:98
 #, c-format
 msgid "The first case (%ld) specified precedes the last case (%ld) specified.  The values will be swapped."
 msgstr "El primer caso (%ld) especificado precede al último caso (%ld) especificado.  Los valores se intercanviarán."
 
-#: src/language/data-io/list.q:107
+#: src/language/data-io/list.q:106
 #, c-format
 msgid "The first case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "EL primer caso (%ld) a listar es menor que 1.  El valor se ajusta a 1."
 
-#: src/language/data-io/list.q:113
+#: src/language/data-io/list.q:112
 #, c-format
 msgid "The last case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "El último caso (%ld) a listar es menor que 1.  El valor se ajusta a 1."
 
-#: src/language/data-io/list.q:119
+#: src/language/data-io/list.q:118
 #, c-format
 msgid "The step value %ld is less than 1.  The value is being reset to 1."
 msgstr "El valor de paso %ld es menor que 1.  El valor se ajusta a 1."
 
+#: src/ui/gui/aggregate.ui:7
+msgid "Aggregate Data"
+msgstr "Datos Agregados"
+
+#: src/ui/gui/aggregate.ui:100
+msgid "_Break variable(s)"
+msgstr "Variable(s) de corte"
+
+#: src/ui/gui/aggregate.ui:136
+msgid "Variable Name: "
+msgstr "Nombre de Variable: "
+
+#: src/ui/gui/aggregate.ui:161
+msgid "Variable Label: "
+msgstr "Etiqueta de variable: "
+
+#: src/ui/gui/aggregate.ui:190
+msgid "Function: "
+msgstr "Función: "
+
+#: src/ui/gui/aggregate.ui:253
+msgid "Argument 1: "
+msgstr "Argumento 1: "
+
+#: src/ui/gui/aggregate.ui:282
+msgid "Argument 2: "
+msgstr "Argumento 2: "
+
+#: src/ui/gui/aggregate.ui:328
+msgid "Aggregated variables"
+msgstr "Variables agregadas"
+
+#: src/ui/gui/aggregate.ui:362
+msgid "_Add aggregated variables to the active dataset"
+msgstr "_Añadir variables agregadas al conjunto de datos activo"
+
+#: src/ui/gui/aggregate.ui:376
+msgid "_Replace the current dataset with the aggregated variables"
+msgstr "_Reemplazar el conjunto de datos actual con variables agregadas"
+
+#: src/ui/gui/aggregate.ui:391
+msgid "_Write a new data file containing only the aggregated variables"
+msgstr "Escribir un nuevo archivo de datos que contenga sólo las variables agregadas"
+
+#: src/ui/gui/aggregate.ui:428
+msgid "label"
+msgstr "etiqueta"
+
+#: src/ui/gui/aggregate.ui:472
+msgid "File is _already sorted on break variable(s)"
+msgstr "EL archivo y_a está ordenado según variable(s) de corte."
+
+#: src/ui/gui/aggregate.ui:487
+msgid "Sort file before a_ggregating"
+msgstr "Ordenar el archivo antes de a_gregar"
+
+#: src/ui/gui/aggregate.ui:508
+msgid "Options for very large datasets"
+msgstr "Opciones para conjuntos de datos muy extensos"
+
 #: src/ui/gui/binomial.ui:57 src/ui/gui/chi-square.ui:57
 msgid "_Test Variable List:"
 msgstr "Lista de Variable _Test:"
@@ -5202,6 +5604,43 @@ msgstr "Definir Dicotomía"
 msgid "Test _Proportion:"
 msgstr "Test _Proporción:"
 
+#: src/ui/gui/compute.ui:8
+msgid "Compute Variable"
+msgstr "Calcular Variable"
+
+#: src/ui/gui/compute.ui:41
+msgid "Target Variable:"
+msgstr "Variable objetivo:"
+
+#: src/ui/gui/compute.ui:70
+msgid "Type & Label"
+msgstr "Tipos y Etiquetas"
+
+#: src/ui/gui/compute.ui:117
+msgid "="
+msgstr "="
+
+#: src/ui/gui/compute.ui:171
+msgid "Numeric Expressions:"
+msgstr "Expresiones Numéricas:"
+
+#: src/ui/gui/compute.ui:233
+msgid "Functions:"
+msgstr "Funciones:"
+
+#: src/ui/gui/compute.ui:298 src/ui/gui/recode.ui:741
+#: src/ui/gui/select-cases.ui:378
+msgid "If..."
+msgstr "Si..."
+
+#: src/ui/gui/compute.ui:351
+msgid "Compute Variable: Type and Label"
+msgstr "Calcular Variable: Tipo y Etiqueta"
+
+#: src/ui/gui/compute.ui:386
+msgid "Use expression as label"
+msgstr "Utilizar la expresión como etiqueta"
+
 #: src/ui/gui/correlation.ui:7
 msgid "Bivariate Correlations"
 msgstr "Correlaciones Bivariadas"
@@ -5406,91 +5845,107 @@ msgstr "Repetir valores"
 msgid "Missing Values"
 msgstr "Valores perdidos"
 
-#: src/ui/gui/factor.ui:21
+#: src/ui/gui/goto-case.ui:8
+msgid "Goto Case"
+msgstr "Ir al Cas"
+
+#: src/ui/gui/goto-case.ui:26
+msgid "Goto Case Number:"
+msgstr "Ir al caso número:"
+
+#: src/ui/gui/factor.ui:22
+msgid "Principal Components Analysis"
+msgstr "Análisis de Componentes Principales"
+
+#: src/ui/gui/factor.ui:26
+msgid "Principal Axis Factoring"
+msgstr "Factorización de Ejes Principales"
+
+#: src/ui/gui/factor.ui:29
 msgid "Factor Analysis"
 msgstr "Análisis Factorial"
 
-#: src/ui/gui/factor.ui:47
+#: src/ui/gui/factor.ui:55
 msgid "_Descriptives..."
 msgstr "_Descriptivos..."
 
-#: src/ui/gui/factor.ui:60
+#: src/ui/gui/factor.ui:68
 msgid "_Extraction..."
 msgstr "_Extracción..."
 
-#: src/ui/gui/factor.ui:74
+#: src/ui/gui/factor.ui:82
 msgid "_Rotations..."
 msgstr "_Rotaciones..."
 
-#: src/ui/gui/factor.ui:192
+#: src/ui/gui/factor.ui:200
 msgid "Factor Analysis: Extraction"
 msgstr "Análisis Factorial: Extracción"
 
-#: src/ui/gui/factor.ui:216
+#: src/ui/gui/factor.ui:224
 msgid "Method: "
 msgstr "Método: "
 
-#: src/ui/gui/factor.ui:266
+#: src/ui/gui/factor.ui:274
 msgid "Correlation matrix"
 msgstr "Matriz de Correlaciones"
 
-#: src/ui/gui/factor.ui:280
+#: src/ui/gui/factor.ui:288
 msgid "Covariance matrix"
 msgstr "Matriz de Covariancias"
 
-#: src/ui/gui/factor.ui:300
-msgid "Analyse"
-msgstr "Analizar"
+#: src/ui/gui/factor.ui:308
+msgid "Analyze"
+msgstr "_Analizar"
 
-#: src/ui/gui/factor.ui:324
-msgid "Unrotatated factor solution"
+#: src/ui/gui/factor.ui:332
+msgid "Unrotated factor solution"
 msgstr "Solución factorial sin rotar"
 
-#: src/ui/gui/factor.ui:338
+#: src/ui/gui/factor.ui:346
 msgid "Scree plot"
 msgstr "Gráfico de sedimentación"
 
-#: src/ui/gui/factor.ui:357 src/ui/gui/roc.ui:286
+#: src/ui/gui/factor.ui:365 src/ui/gui/roc.ui:286
 msgid "Display"
 msgstr "Contenido"
 
-#: src/ui/gui/factor.ui:430
+#: src/ui/gui/factor.ui:438
 msgid "Number of factors:"
 msgstr "Número de factores:"
 
-#: src/ui/gui/factor.ui:460
+#: src/ui/gui/factor.ui:468
 msgid "Extract"
 msgstr "Extracción"
 
-#: src/ui/gui/factor.ui:475 src/ui/gui/factor.ui:665
+#: src/ui/gui/factor.ui:483 src/ui/gui/factor.ui:673
 msgid "Maximum iterations for convergence:"
 msgstr "Iteraciones máximas para la convergencia:"
 
-#: src/ui/gui/factor.ui:538
+#: src/ui/gui/factor.ui:546
 msgid "Factor Analysis: Rotation"
 msgstr "Análisis Factorial: Rotación"
 
-#: src/ui/gui/factor.ui:571
+#: src/ui/gui/factor.ui:579
 msgid "_None"
 msgstr "_Ninguno"
 
-#: src/ui/gui/factor.ui:582
+#: src/ui/gui/factor.ui:590
 msgid "_Varimax"
 msgstr "_Varimax"
 
-#: src/ui/gui/factor.ui:598
+#: src/ui/gui/factor.ui:606
 msgid "_Quartimax"
 msgstr "_Quartimax"
 
-#: src/ui/gui/factor.ui:614
+#: src/ui/gui/factor.ui:622
 msgid "_Equimax"
 msgstr "_Equimax"
 
-#: src/ui/gui/factor.ui:637
+#: src/ui/gui/factor.ui:645
 msgid "Method"
 msgstr "Método"
 
-#: src/ui/gui/factor.ui:648
+#: src/ui/gui/factor.ui:656
 msgid "_Display rotated solution"
 msgstr "Muestra la solución rotada"
 
@@ -5636,6 +6091,30 @@ msgstr "Incluir sectores para los valores perdidos"
 msgid "<b>Pie Charts</b>"
 msgstr "<b>Diagramas de Sectores</b>"
 
+#: src/ui/gui/k-related.ui:7
+msgid "Tests for Several Related Samples"
+msgstr "Tests para diversas muestras relacionadas"
+
+#: src/ui/gui/k-related.ui:94
+msgid "_Test Variables:"
+msgstr "Variables de _Test:"
+
+#: src/ui/gui/k-related.ui:122
+msgid "_Friedman"
+msgstr "_Friedman"
+
+#: src/ui/gui/k-related.ui:136
+msgid "_Kendall's W"
+msgstr "W de _Kendall"
+
+#: src/ui/gui/k-related.ui:150
+msgid "_Cochran's Q"
+msgstr "Q de _Cochran"
+
+#: src/ui/gui/k-related.ui:169
+msgid "Test Type"
+msgstr "Tipo de Test"
+
 #: src/ui/gui/oneway.ui:8
 msgid "One-Way ANOVA"
 msgstr "ANOVA de un factor"
@@ -5648,227 +6127,74 @@ msgstr "_Factor:"
 msgid "Dependent _Variable(s):"
 msgstr "_Variable(s) Dependientes:"
 
-#: src/ui/gui/oneway.ui:184 src/ui/gui/data-editor.ui:328
+#: src/ui/gui/oneway.ui:184 src/ui/gui/data-editor.ui:332
 msgid "_Descriptives"
-msgstr "_Descriptivos"
-
-#: src/ui/gui/oneway.ui:200
-msgid "_Homogeneity"
-msgstr "_Homogeneidad"
-
-#: src/ui/gui/oneway.ui:238
-msgid "_Contrasts..."
-msgstr "_Contrastes..."
-
-#: src/ui/gui/oneway.ui:292
-msgid "One-Way ANOVA: Contrasts"
-msgstr "ANOVA de un factor: Contrastes"
-
-#: src/ui/gui/oneway.ui:369
-msgid "_Coefficients:"
-msgstr "_Coeficientes:"
-
-#: src/ui/gui/oneway.ui:416
-msgid "Coefficient Total: "
-msgstr "Coeficiente Total: "
-
-#: src/ui/gui/oneway.ui:452
-msgid "Contrast 1 of 1"
-msgstr "Contraste 1 de 1"
-
-#: src/ui/gui/psppire.ui:7
-msgid "Weight Cases"
-msgstr "Ponderar Casos"
-
-#: src/ui/gui/psppire.ui:66
-msgid "Weight cases by"
-msgstr "Ponderar casos por"
-
-#: src/ui/gui/psppire.ui:102
-msgid "Frequency Variable"
-msgstr "Variable de Frecuencia"
-
-#: src/ui/gui/psppire.ui:145
-msgid "Current Status: "
-msgstr "Estatus actual: "
-
-#: src/ui/gui/psppire.ui:195
-msgid "Transpose"
-msgstr "Transponer"
-
-#: src/ui/gui/psppire.ui:247
-msgid "Name Variable:"
-msgstr "Nombre de Variable:"
-
-#: src/ui/gui/psppire.ui:383
-msgid "Split File"
-msgstr "Dividir Archivo"
-
-#: src/ui/gui/psppire.ui:443
-msgid "Analyze all cases.  Do not create groups."
-msgstr "Analizar todos los casos.  No crear grupos."
-
-#: src/ui/gui/psppire.ui:459
-msgid "Compare groups."
-msgstr "Comparar grupos."
-
-#: src/ui/gui/psppire.ui:475
-msgid "Organize output by groups."
-msgstr "Organizar los resultados por grupos."
-
-#: src/ui/gui/psppire.ui:533
-msgid "Groups based on:"
-msgstr "Grupos basados en:"
-
-#: src/ui/gui/psppire.ui:592
-msgid "Sort the file by grouping variables."
-msgstr "Ordenar el archivo por variables de agrupación."
-
-#: src/ui/gui/psppire.ui:609
-msgid "File is already sorted."
-msgstr "EL archivo ya está ordenado."
-
-#: src/ui/gui/psppire.ui:662
-msgid "Current Status : "
-msgstr "Estatus actual : "
-
-#: src/ui/gui/psppire.ui:673
-msgid "Analysis by groups is off"
-msgstr "El análisis por grupos está activado"
-
-#: src/ui/gui/psppire.ui:709
-msgid "Compute Variable"
-msgstr "Calcular Variable"
-
-#: src/ui/gui/psppire.ui:742
-msgid "Target Variable:"
-msgstr "Variable objetivo:"
-
-#: src/ui/gui/psppire.ui:771
-msgid "Type & Label"
-msgstr "Tipos y Etiquetas"
-
-#: src/ui/gui/psppire.ui:818
-msgid "="
-msgstr "="
-
-#: src/ui/gui/psppire.ui:872
-msgid "Numeric Expressions:"
-msgstr "Expresiones Numéricas:"
-
-#: src/ui/gui/psppire.ui:934
-msgid "Functions:"
-msgstr "Funciones:"
-
-#: src/ui/gui/psppire.ui:999 src/ui/gui/psppire.ui:1422
-#: src/ui/gui/recode.ui:741
-msgid "If..."
-msgstr "Si..."
+msgstr "_Descriptivos"
 
-#: src/ui/gui/psppire.ui:1052
-msgid "Select Cases"
-msgstr "Seleccionar casos"
+#: src/ui/gui/oneway.ui:200
+msgid "_Homogeneity"
+msgstr "_Homogeneidad"
 
-#: src/ui/gui/psppire.ui:1240
-msgid "Use filter variable"
-msgstr "Utilizar variable de filtro"
+#: src/ui/gui/oneway.ui:238
+msgid "_Contrasts..."
+msgstr "_Contrastes..."
 
-#: src/ui/gui/psppire.ui:1299
-msgid "Based on time or case range"
-msgstr "Basado en intervalo de tiempos o casos"
+#: src/ui/gui/oneway.ui:292
+msgid "One-Way ANOVA: Contrasts"
+msgstr "ANOVA de un factor: Contrastes"
 
-#: src/ui/gui/psppire.ui:1311
-msgid "Range..."
-msgstr "Intervalo..."
+#: src/ui/gui/oneway.ui:369
+msgid "_Coefficients:"
+msgstr "_Coeficientes:"
 
-#: src/ui/gui/psppire.ui:1355
-msgid "Random sample of cases"
-msgstr "Muestra aleatoria de casos"
+#: src/ui/gui/oneway.ui:416
+msgid "Coefficient Total: "
+msgstr "Coeficiente Total: "
 
-#: src/ui/gui/psppire.ui:1368
-msgid "Sample..."
-msgstr "Muestra..."
+#: src/ui/gui/oneway.ui:452
+msgid "Contrast 1 of 1"
+msgstr "Contraste 1 de 1"
 
-#: src/ui/gui/psppire.ui:1410
-msgid "If condition is satisfied"
-msgstr "Si la condición se satisface"
+#: src/ui/gui/psppire.ui:7
+msgid "Weight Cases"
+msgstr "Ponderar Casos"
 
-#: src/ui/gui/psppire.ui:1462
-msgid "All Cases"
-msgstr "Todos los Casos"
+#: src/ui/gui/psppire.ui:66
+msgid "Weight cases by"
+msgstr "Ponderar casos por"
 
-#: src/ui/gui/psppire.ui:1477
-msgid "Select"
-msgstr "Seleccionar"
+#: src/ui/gui/psppire.ui:102
+msgid "Frequency Variable"
+msgstr "Variable de Frecuencia"
 
-#: src/ui/gui/psppire.ui:1504
-msgid "Filtered"
-msgstr "Filtrado"
+#: src/ui/gui/psppire.ui:145
+msgid "Current Status: "
+msgstr "Estatus actual: "
 
-#: src/ui/gui/psppire.ui:1520
-msgid "Deleted"
-msgstr "Eliminado"
+#: src/ui/gui/psppire.ui:195
+msgid "Transpose"
+msgstr "Transponer"
 
-#: src/ui/gui/psppire.ui:1543
-msgid "Unselected Cases Are"
-msgstr "Los casos no seleccionados són"
+#: src/ui/gui/psppire.ui:247
+msgid "Name Variable:"
+msgstr "Nombre de Variable:"
 
-#: src/ui/gui/psppire.ui:1585
+#: src/ui/gui/psppire.ui:383
 msgid "Data File Comments"
 msgstr "Comentarios del fichero de datos"
 
-#: src/ui/gui/psppire.ui:1609
+#: src/ui/gui/psppire.ui:407
 msgid "Comments:"
 msgstr "Comentarios:"
 
-#: src/ui/gui/psppire.ui:1650
+#: src/ui/gui/psppire.ui:448
 msgid "Display comments in output"
 msgstr "Mostrar comentarios en el resultado"
 
-#: src/ui/gui/psppire.ui:1669
+#: src/ui/gui/psppire.ui:467
 msgid "Column Number: 0"
 msgstr "Columna Número: 0"
 
-#: src/ui/gui/psppire.ui:1703
-msgid "Select Cases: Range"
-msgstr "Seleccionar casos: Rango"
-
-#: src/ui/gui/psppire.ui:1750
-msgid "First case"
-msgstr "Primer caso"
-
-#: src/ui/gui/psppire.ui:1763
-msgid "Last case"
-msgstr "Último caso"
-
-#: src/ui/gui/psppire.ui:1776
-msgid "Observation"
-msgstr "Observación"
-
-#: src/ui/gui/psppire.ui:1808
-msgid "Compute Variable: Type and Label"
-msgstr "Calcular Variable: Tipo y Etiqueta"
-
-#: src/ui/gui/psppire.ui:1843
-msgid "Use expression as label"
-msgstr "Utilizar la expresión como etiqueta"
-
-#: src/ui/gui/psppire.ui:2088
-msgid "Goto Case"
-msgstr "Ir al Cas"
-
-#: src/ui/gui/psppire.ui:2106
-msgid "Goto Case Number:"
-msgstr "Ir al caso número:"
-
-#: src/ui/gui/psppire.ui:2149
-msgid "Select Cases: Random Sample"
-msgstr "Seleccionar casos: Muestra aleatoria"
-
-#: src/ui/gui/psppire.ui:2247
-msgid "Sample Size"
-msgstr "Tamaño de muestra"
-
 #: src/ui/gui/rank.ui:8
 msgid "Rank Cases"
 msgstr "Rango de Casos"
@@ -5997,6 +6323,42 @@ msgstr "Descendente"
 msgid "Sort Order"
 msgstr "Ordenación"
 
+#: src/ui/gui/split-file.ui:8
+msgid "Split File"
+msgstr "Dividir Archivo"
+
+#: src/ui/gui/split-file.ui:68
+msgid "Analyze all cases.  Do not create groups."
+msgstr "Analizar todos los casos.  No crear grupos."
+
+#: src/ui/gui/split-file.ui:84
+msgid "Compare groups."
+msgstr "Comparar grupos."
+
+#: src/ui/gui/split-file.ui:100
+msgid "Organize output by groups."
+msgstr "Organizar los resultados por grupos."
+
+#: src/ui/gui/split-file.ui:158
+msgid "Groups based on:"
+msgstr "Grupos basados en:"
+
+#: src/ui/gui/split-file.ui:217
+msgid "Sort the file by grouping variables."
+msgstr "Ordenar el archivo por variables de agrupación."
+
+#: src/ui/gui/split-file.ui:234
+msgid "File is already sorted."
+msgstr "EL archivo ya está ordenado."
+
+#: src/ui/gui/split-file.ui:287
+msgid "Current Status : "
+msgstr "Estatus actual : "
+
+#: src/ui/gui/split-file.ui:298
+msgid "Analysis by groups is off"
+msgstr "El análisis por grupos está activado"
+
 #: src/ui/gui/recode.ui:185 src/ui/gui/recode.ui:467
 msgid "System Missing"
 msgstr "Perdido del Sistema"
@@ -6042,8 +6404,8 @@ msgid "New Value"
 msgstr "Nuevo Valor"
 
 #: src/ui/gui/recode.ui:596
-msgid "Convert numeric strings to numbers ('5' -> 5)"
-msgstr "Convertir cadenas numéricas a números ('5' -> 5)"
+msgid "Convert numeric strings to numbers (`5' -> 5)"
+msgstr "Convertir cadenas numéricas a números (`5' -> 5)"
 
 #: src/ui/gui/recode.ui:614
 msgid "Output variables are strings"
@@ -6101,22 +6463,26 @@ msgstr "Residuales"
 msgid "Regression: Statistics"
 msgstr "Regresión: Estadísticos"
 
-#: src/ui/gui/reliability.ui:27
+#: src/ui/gui/reliability.ui:26
 msgid "Reliability Analysis"
 msgstr "Análisis de Fiabilidad"
 
-#: src/ui/gui/reliability.ui:114
+#: src/ui/gui/reliability.ui:124
 msgid "_Items:"
 msgstr "_Items:"
 
-#: src/ui/gui/reliability.ui:136
+#: src/ui/gui/reliability.ui:141
 msgid "Model:\t"
 msgstr "Modelo:\t"
 
-#: src/ui/gui/reliability.ui:175
+#: src/ui/gui/reliability.ui:180
 msgid "Variables in first split:"
 msgstr "Variables a primera división:"
 
+#: src/ui/gui/reliability.ui:217
+msgid "Show descriptives for scale if _item is deleted"
+msgstr "Muestra descriptivos para escalas si el _item es eliminado"
+
 #: src/ui/gui/roc.ui:115
 msgid "_Test Variable:"
 msgstr "Variable de prueba:"
@@ -6145,6 +6511,78 @@ msgstr "_Error típico y Intervalo de Confianza"
 msgid "_Coordinate points of the ROC Curve"
 msgstr "_Coordenadas de la Curva ROC"
 
+#: src/ui/gui/select-cases.ui:8
+msgid "Select Cases"
+msgstr "Seleccionar casos"
+
+#: src/ui/gui/select-cases.ui:196
+msgid "Use filter variable"
+msgstr "Utilizar variable de filtro"
+
+#: src/ui/gui/select-cases.ui:255
+msgid "Based on time or case range"
+msgstr "Basado en intervalo de tiempos o casos"
+
+#: src/ui/gui/select-cases.ui:267
+msgid "Range..."
+msgstr "Intervalo..."
+
+#: src/ui/gui/select-cases.ui:311
+msgid "Random sample of cases"
+msgstr "Muestra aleatoria de casos"
+
+#: src/ui/gui/select-cases.ui:324
+msgid "Sample..."
+msgstr "Muestra..."
+
+#: src/ui/gui/select-cases.ui:366
+msgid "If condition is satisfied"
+msgstr "Si la condición se satisface"
+
+#: src/ui/gui/select-cases.ui:418
+msgid "All Cases"
+msgstr "Todos los Casos"
+
+#: src/ui/gui/select-cases.ui:433
+msgid "Select"
+msgstr "Seleccionar"
+
+#: src/ui/gui/select-cases.ui:460
+msgid "Filtered"
+msgstr "Filtrado"
+
+#: src/ui/gui/select-cases.ui:476
+msgid "Deleted"
+msgstr "Eliminado"
+
+#: src/ui/gui/select-cases.ui:499
+msgid "Unselected Cases Are"
+msgstr "Los casos no seleccionados són"
+
+#: src/ui/gui/select-cases.ui:541
+msgid "Select Cases: Range"
+msgstr "Seleccionar casos: Rango"
+
+#: src/ui/gui/select-cases.ui:590
+msgid "First case"
+msgstr "Primer caso"
+
+#: src/ui/gui/select-cases.ui:603
+msgid "Last case"
+msgstr "Último caso"
+
+#: src/ui/gui/select-cases.ui:616
+msgid "Observation"
+msgstr "Observación"
+
+#: src/ui/gui/select-cases.ui:648
+msgid "Select Cases: Random Sample"
+msgstr "Seleccionar casos: Muestra aleatoria"
+
+#: src/ui/gui/select-cases.ui:746
+msgid "Sample Size"
+msgstr "Tamaño de muestra"
+
 #: src/ui/gui/t-test.ui:8
 msgid "Independent-Samples T Test"
 msgstr "Prueba T para muestras Independientes"
@@ -6207,115 +6645,103 @@ msgstr ""
 "\n"
 "El archivo seleccionado contiene N líneas de texto.  Solo las primeras M se mostrarán como previsualización en las pantallas siguientes.  Puedes escoger a continuación qué parte del archivo ha de ser importado."
 
-#: src/ui/gui/text-data-import.ui:52
+#: src/ui/gui/text-data-import.ui:95
 msgid "All cases"
 msgstr "Todos los casos"
 
-#: src/ui/gui/text-data-import.ui:71 src/ui/gui/text-data-import.ui:128
-msgid "Only first "
-msgstr "Solo el primero"
-
-#: src/ui/gui/text-data-import.ui:106
-msgid " cases"
-msgstr " casos"
-
-#: src/ui/gui/text-data-import.ui:162
-msgid "% of file (approximately)"
-msgstr "% del archivo (aproximadamente)"
-
-#: src/ui/gui/text-data-import.ui:183
+#: src/ui/gui/text-data-import.ui:116
 msgid "<b>Amount to Import</b>"
 msgstr "<b>Cantidad a importar</b>"
 
-#: src/ui/gui/text-data-import.ui:202
+#: src/ui/gui/text-data-import.ui:135
 msgid "Select Data to Import"
 msgstr "Seleccionar datos para importar"
 
-#: src/ui/gui/text-data-import.ui:213
+#: src/ui/gui/text-data-import.ui:146
 msgid "Select the first line of the data file that contains data."
 msgstr "Seleccionar la primera línea del archivo que contiene datos."
 
-#: src/ui/gui/text-data-import.ui:241
+#: src/ui/gui/text-data-import.ui:174
 msgid "Line above selected line contains variable names"
 msgstr "La línea por encima de la seleccionada contiene los nombres de las variables"
 
-#: src/ui/gui/text-data-import.ui:259
+#: src/ui/gui/text-data-import.ui:192
 msgid "Choose Separators"
 msgstr "Escoger los separadores"
 
-#: src/ui/gui/text-data-import.ui:305
+#: src/ui/gui/text-data-import.ui:238
 msgid "C_ustom"
 msgstr "_Usuario"
 
-#: src/ui/gui/text-data-import.ui:320
+#: src/ui/gui/text-data-import.ui:253
 msgid "Slas_h (/)"
 msgstr "Barra (/)"
 
-#: src/ui/gui/text-data-import.ui:337
+#: src/ui/gui/text-data-import.ui:270
 msgid "Semicolo_n (;)"
 msgstr "Punto y coma (;)"
 
-#: src/ui/gui/text-data-import.ui:354
+#: src/ui/gui/text-data-import.ui:287
 msgid "P_ipe (|)"
 msgstr "Tub (|)"
 
-#: src/ui/gui/text-data-import.ui:369
+#: src/ui/gui/text-data-import.ui:302
 msgid "H_yphen (-)"
 msgstr "Guión (-)"
 
-#: src/ui/gui/text-data-import.ui:386
+#: src/ui/gui/text-data-import.ui:319
 msgid "Co_mma (,)"
 msgstr "Coma (,)"
 
-#: src/ui/gui/text-data-import.ui:403
+#: src/ui/gui/text-data-import.ui:336
 msgid "_Colon (:)"
 msgstr "Dos puntos (:)"
 
-#: src/ui/gui/text-data-import.ui:418
+#: src/ui/gui/text-data-import.ui:351
 msgid "Ban_g (!)"
 msgstr "Exclamación (!)"
 
-#: src/ui/gui/text-data-import.ui:433
+#: src/ui/gui/text-data-import.ui:366
 msgid "Ta_b"
 msgstr "Tabulador"
 
-#: src/ui/gui/text-data-import.ui:448
+#: src/ui/gui/text-data-import.ui:381
 msgid "_Space"
 msgstr "E_spacio"
 
-#: src/ui/gui/text-data-import.ui:465
+#: src/ui/gui/text-data-import.ui:398
 msgid "<b>Separators</b>"
 msgstr "<b>Separadores</b>"
 
-#: src/ui/gui/text-data-import.ui:495
+#: src/ui/gui/text-data-import.ui:428
 msgid "Doubled quote mark treated as escape"
 msgstr "Las dobles-comillas se tratan como ESCAPE"
 
-#: src/ui/gui/text-data-import.ui:524
+#: src/ui/gui/text-data-import.ui:457
 msgid "Quote separator characters with"
 msgstr "Anchura de caracteres separadores con comillas"
 
-#: src/ui/gui/text-data-import.ui:544
+#: src/ui/gui/text-data-import.ui:477
 msgid "<b>Quoting</b>"
 msgstr "<b>Comillas</b>"
 
-#: src/ui/gui/text-data-import.ui:592
+#: src/ui/gui/text-data-import.ui:525
 msgid "<b>Fields Preview</b>"
 msgstr "<b>Previsualizar Campos</b>"
 
-#: src/ui/gui/text-data-import.ui:607
+#: src/ui/gui/text-data-import.ui:540
 msgid "Adjust Variable Formats"
 msgstr "Ajustar formato de variables"
 
-#: src/ui/gui/text-data-import.ui:618
+#: src/ui/gui/text-data-import.ui:551
 msgid "Check the data formats displayed below and fix any that are incorrect.  You may set other variable properties now or later."
 msgstr "Comprueba los formatos de los datos mostrados a continuación y corrige los problemas.  Se pueden asignar propiedades de las variables ahora o más adelante."
 
-#: src/ui/gui/text-data-import.ui:662
+#: src/ui/gui/text-data-import.ui:595
 msgid "<b>Variables</b>"
 msgstr "<b>Variables</b>"
 
-#: src/ui/gui/text-data-import.ui:705
+#: src/ui/gui/text-data-import.ui:638
 msgid "<b>Data Preview</b>"
 msgstr "<b>Previsualización de datos</b>"
 
@@ -6387,306 +6813,302 @@ msgstr "Intervalo más un valor perdido discreto ocpional"
 msgid "Variable Information:"
 msgstr "Información de la Variable:"
 
-#: src/ui/gui/data-editor.ui:9
-msgid "Sort Ascending"
-msgstr "Ordenación Ascendente"
-
-#: src/ui/gui/data-editor.ui:15
-msgid "Sort Descending"
-msgstr "Ordenación Descendente"
-
-#: src/ui/gui/data-editor.ui:26 src/ui/gui/output-viewer.ui:9
+#: src/ui/gui/data-editor.ui:23 src/ui/gui/output-viewer.ui:9
 #: src/ui/gui/syntax-editor.ui:10
 msgid "_File"
 msgstr "_Archivo"
 
-#: src/ui/gui/data-editor.ui:38 src/ui/gui/syntax-editor.ui:22
+#: src/ui/gui/data-editor.ui:35 src/ui/gui/syntax-editor.ui:22
 #: src/ui/gui/syntax-editor.ui:40
 msgid "_Syntax"
 msgstr "_Sintaxis"
 
-#: src/ui/gui/data-editor.ui:44 src/ui/gui/data-editor.ui:217
-#: src/ui/gui/data-editor.ui:229 src/ui/gui/syntax-editor.ui:28
+#: src/ui/gui/data-editor.ui:41 src/ui/gui/data-editor.ui:214
+#: src/ui/gui/data-editor.ui:226 src/ui/gui/syntax-editor.ui:28
 #: src/ui/gui/syntax-editor.ui:46
 msgid "_Data"
 msgstr "_Datos"
 
-#: src/ui/gui/data-editor.ui:56
+#: src/ui/gui/data-editor.ui:53
 msgid "_Import Delimited Text Data"
 msgstr "_Importar datos de texto delimitados"
 
-#: src/ui/gui/data-editor.ui:75
+#: src/ui/gui/data-editor.ui:72
 msgid "D_isplay Data File Information"
 msgstr "Muestra _información del archivo de datos"
 
-#: src/ui/gui/data-editor.ui:81
+#: src/ui/gui/data-editor.ui:79
 msgid "Working File"
 msgstr "Archivos de trabajo"
 
-#: src/ui/gui/data-editor.ui:87
+#: src/ui/gui/data-editor.ui:85
 msgid "External File"
 msgstr "Archivo externo"
 
-#: src/ui/gui/data-editor.ui:93
+#: src/ui/gui/data-editor.ui:91
 msgid "Recently Used Da_ta"
 msgstr "Datos utilizados recientemente"
 
-#: src/ui/gui/data-editor.ui:99
+#: src/ui/gui/data-editor.ui:97
 msgid "Recently Used _Files"
 msgstr "Archivos utilizados recientemente"
 
-#: src/ui/gui/data-editor.ui:111 src/ui/gui/output-viewer.ui:28
+#: src/ui/gui/data-editor.ui:109 src/ui/gui/output-viewer.ui:28
 #: src/ui/gui/syntax-editor.ui:70
 msgid "_Edit"
 msgstr "_Editar"
 
-#: src/ui/gui/data-editor.ui:117
+#: src/ui/gui/data-editor.ui:115
 msgid "Insert Variable"
 msgstr "Insertar Variable"
 
-#: src/ui/gui/data-editor.ui:118
+#: src/ui/gui/data-editor.ui:116
 msgid "Create a new variable at the current position"
 msgstr "Crear una nueva variable en la posición seleccionada"
 
-#: src/ui/gui/data-editor.ui:125
+#: src/ui/gui/data-editor.ui:123
 msgid "Insert Cases"
 msgstr "Insertar Casos"
 
-#: src/ui/gui/data-editor.ui:126
+#: src/ui/gui/data-editor.ui:124
 msgid "Create a new case at the current position"
 msgstr "Crear un nuevo caso en la posición actual"
 
-#: src/ui/gui/data-editor.ui:132
+#: src/ui/gui/data-editor.ui:130
 msgid "Go To Case"
 msgstr "Ir al Caso"
 
-#: src/ui/gui/data-editor.ui:134
+#: src/ui/gui/data-editor.ui:132
 msgid "Jump to a case in the data sheet"
 msgstr "Ir a un caso en la matriz de datos"
 
-#: src/ui/gui/data-editor.ui:160
+#: src/ui/gui/data-editor.ui:158
 msgid "Cl_ear Variables"
 msgstr "_Eliminar Variables"
 
-#: src/ui/gui/data-editor.ui:161
+#: src/ui/gui/data-editor.ui:159
 msgid "Delete the variables at the selected position(s)"
 msgstr "Borra las variables en la posición(es) seleccionada(s)"
 
-#: src/ui/gui/data-editor.ui:169
+#: src/ui/gui/data-editor.ui:167
 msgid "_Clear Cases"
 msgstr "Eliminar _Casos"
 
-#: src/ui/gui/data-editor.ui:170
+#: src/ui/gui/data-editor.ui:168
 msgid "Delete the cases at the selected position(s)"
 msgstr "Borra los casos en la(s) posición(es) seleccionada(s)"
 
-#: src/ui/gui/data-editor.ui:182
+#: src/ui/gui/data-editor.ui:180
 msgid "_View"
 msgstr "_Vista"
 
-#: src/ui/gui/data-editor.ui:189
+#: src/ui/gui/data-editor.ui:187
 msgid "_Status Bar"
 msgstr "Barra de E_stado"
 
-#: src/ui/gui/data-editor.ui:195
-msgid "_Fonts"
-msgstr "_Fuentes"
-
-#: src/ui/gui/data-editor.ui:203
+#: src/ui/gui/data-editor.ui:200
 msgid "_Grid Lines"
 msgstr "Línias divisorias"
 
-#: src/ui/gui/data-editor.ui:209
+#: src/ui/gui/data-editor.ui:206
 msgid "Value _Labels"
 msgstr "Etiquetas de Valor"
 
-#: src/ui/gui/data-editor.ui:210
+#: src/ui/gui/data-editor.ui:207
 msgid "Show/hide value labels"
 msgstr "Muestra/Oculta etiquetas de valor"
 
-#: src/ui/gui/data-editor.ui:223 src/ui/gui/data-editor.ui:430
+#: src/ui/gui/data-editor.ui:220 src/ui/gui/data-editor.ui:440
 msgid "_Variables"
 msgstr "_Variables"
 
-#: src/ui/gui/data-editor.ui:234
+#: src/ui/gui/data-editor.ui:231
 msgid "_Sort Cases"
 msgstr "Ordenar Caso_s"
 
-#: src/ui/gui/data-editor.ui:237
-msgid "Sort cases in the active file"
-msgstr "Ordenar casos en el archivo activo"
+#: src/ui/gui/data-editor.ui:234
+msgid "Sort cases in the active dataset"
+msgstr "Ordenar casos en el archivo de datos activo"
 
-#: src/ui/gui/data-editor.ui:244
+#: src/ui/gui/data-editor.ui:241
 msgid "_Transpose"
 msgstr "_Trasponer"
 
-#: src/ui/gui/data-editor.ui:245
+#: src/ui/gui/data-editor.ui:242
 msgid "Transpose the cases with the variables"
 msgstr "Transponer casos y variables"
 
-#: src/ui/gui/data-editor.ui:251
+#: src/ui/gui/data-editor.ui:249
+msgid "_Aggregate"
+msgstr "_Agregar"
+
+#: src/ui/gui/data-editor.ui:255
 msgid "S_plit File"
 msgstr "Dividir Archivo"
 
-#: src/ui/gui/data-editor.ui:252
-msgid "Split the active file"
-msgstr "Dividir archivo activo"
+#: src/ui/gui/data-editor.ui:256
+msgid "Split the active dataset"
+msgstr "Dividir el archivo de datos activo"
 
-#: src/ui/gui/data-editor.ui:259
+#: src/ui/gui/data-editor.ui:263
 msgid "Select _Cases"
 msgstr "Seleccionar _Casos"
 
-#: src/ui/gui/data-editor.ui:265
+#: src/ui/gui/data-editor.ui:269
 msgid "_Weight Cases"
 msgstr "Ponderar Casos"
 
-#: src/ui/gui/data-editor.ui:266
+#: src/ui/gui/data-editor.ui:270
 msgid "Weight cases by variable"
 msgstr "Pondera casos por la variable"
 
-#: src/ui/gui/data-editor.ui:273
+#: src/ui/gui/data-editor.ui:277
 msgid "_Transform"
 msgstr "_Transformar"
 
-#: src/ui/gui/data-editor.ui:279
+#: src/ui/gui/data-editor.ui:283
 msgid "_Compute"
 msgstr "_Calcular"
 
-#: src/ui/gui/data-editor.ui:285
+#: src/ui/gui/data-editor.ui:289
 msgid "Ran_k Cases"
 msgstr "Rango de casos"
 
-#: src/ui/gui/data-editor.ui:291
+#: src/ui/gui/data-editor.ui:295
 msgid "Recode into _Same Variables"
 msgstr "Recodificar en las Misma_s Variables"
 
-#: src/ui/gui/data-editor.ui:297
+#: src/ui/gui/data-editor.ui:301
 msgid "Recode into _Different Variables"
 msgstr "Recodificar en variables _Diferentes"
 
-#: src/ui/gui/data-editor.ui:303
+#: src/ui/gui/data-editor.ui:307
 msgid "_Run Pending Transforms"
 msgstr "Ejecuta_r Transformaciones pendientes"
 
-#: src/ui/gui/data-editor.ui:310
+#: src/ui/gui/data-editor.ui:314
 msgid "_Analyze"
 msgstr "_Analizar"
 
-#: src/ui/gui/data-editor.ui:316
+#: src/ui/gui/data-editor.ui:320
 msgid "_Descriptive Statistics"
 msgstr "Estadística _Descriptiva"
 
-#: src/ui/gui/data-editor.ui:322
+#: src/ui/gui/data-editor.ui:326
 msgid "_Frequencies"
 msgstr "_Frecuencias"
 
-#: src/ui/gui/data-editor.ui:334
+#: src/ui/gui/data-editor.ui:338
 msgid "_Explore"
 msgstr "_Explorar"
 
-#: src/ui/gui/data-editor.ui:340
+#: src/ui/gui/data-editor.ui:344
 msgid "_Crosstabs"
 msgstr "Tablas _Cruzadas"
 
-#: src/ui/gui/data-editor.ui:346
+#: src/ui/gui/data-editor.ui:350
 msgid "Compare _Means"
 msgstr "Comparar _Medias"
 
-#: src/ui/gui/data-editor.ui:352
+#: src/ui/gui/data-editor.ui:356
 msgid "_One Sample T Test"
 msgstr "Prueba T para una muestra"
 
-#: src/ui/gui/data-editor.ui:358
+#: src/ui/gui/data-editor.ui:362
 msgid "_Independent Samples T Test"
 msgstr "Prueba T para muestras _Independientes"
 
-#: src/ui/gui/data-editor.ui:364
+#: src/ui/gui/data-editor.ui:368
 msgid "_Paired Samples T Test"
 msgstr "Prueba T para muestras Em_parejadas"
 
-#: src/ui/gui/data-editor.ui:370
+#: src/ui/gui/data-editor.ui:374
 msgid "One Way _ANOVA"
 msgstr "_ANOVA de un factor"
 
-#: src/ui/gui/data-editor.ui:376
+#: src/ui/gui/data-editor.ui:380
 msgid "Bivariate _Correlation..."
 msgstr "_Correlación Bivariada..."
 
-#: src/ui/gui/data-editor.ui:382
+#: src/ui/gui/data-editor.ui:386
 msgid "Factor _Analysis"
 msgstr "_Análisis Factorial"
 
-#: src/ui/gui/data-editor.ui:388
+#: src/ui/gui/data-editor.ui:392
 msgid "Re_liability"
 msgstr "Fiabi_lidad"
 
-#: src/ui/gui/data-editor.ui:394
+#: src/ui/gui/data-editor.ui:398
 msgid "Linear _Regression"
 msgstr "_Regresión Lineal"
 
-#: src/ui/gui/data-editor.ui:400
+#: src/ui/gui/data-editor.ui:404
 msgid "_Non-Parametric Statistics"
 msgstr "Pruebas _No-Paramétricas"
 
-#: src/ui/gui/data-editor.ui:406
+#: src/ui/gui/data-editor.ui:410
 msgid "_Chi-Square"
 msgstr "_Chi-cuadrado"
 
-#: src/ui/gui/data-editor.ui:412
+#: src/ui/gui/data-editor.ui:416
 msgid "_Binomial"
 msgstr "_Binomial"
 
-#: src/ui/gui/data-editor.ui:418
+#: src/ui/gui/data-editor.ui:422
+msgid "K Related _Samples"
+msgstr "K Muestra_s Relacionadas"
+
+#: src/ui/gui/data-editor.ui:428
 msgid "ROC Cur_ve..."
 msgstr "Curva ROC"
 
-#: src/ui/gui/data-editor.ui:424
+#: src/ui/gui/data-editor.ui:434
 msgid "_Utilities"
 msgstr "_Utilidades"
 
-#: src/ui/gui/data-editor.ui:431
+#: src/ui/gui/data-editor.ui:441
 msgid "Jump to variable"
 msgstr "Ir a la variable"
 
-#: src/ui/gui/data-editor.ui:438
+#: src/ui/gui/data-editor.ui:448
 msgid "Data File _Comments"
 msgstr "_Comentarios al archivo de datos"
 
-#: src/ui/gui/data-editor.ui:444 src/ui/gui/output-viewer.ui:40
-#: src/ui/gui/syntax-editor.ui:131
+#: src/ui/gui/data-editor.ui:454 src/ui/gui/output-viewer.ui:46
+#: src/ui/gui/syntax-editor.ui:135
 msgid "_Windows"
 msgstr "_Ventanas"
 
-#: src/ui/gui/data-editor.ui:450 src/ui/gui/output-viewer.ui:46
-#: src/ui/gui/syntax-editor.ui:137
+#: src/ui/gui/data-editor.ui:460 src/ui/gui/output-viewer.ui:52
+#: src/ui/gui/syntax-editor.ui:141
 msgid "_Minimize All Windows"
 msgstr "_Minimizar todas las ventanas"
 
-#: src/ui/gui/data-editor.ui:456
+#: src/ui/gui/data-editor.ui:466
 msgid "_Split"
 msgstr "Dividir"
 
-#: src/ui/gui/data-editor.ui:630
+#: src/ui/gui/data-editor.ui:642
 msgid "Information Area"
 msgstr "Área de Información"
 
-#: src/ui/gui/data-editor.ui:652
+#: src/ui/gui/data-editor.ui:664
 msgid "Processor Area"
 msgstr "Área del procesador"
 
-#: src/ui/gui/data-editor.ui:677
+#: src/ui/gui/data-editor.ui:689
 msgid "Case Counter Area"
 msgstr "Área de Recuento"
 
-#: src/ui/gui/data-editor.ui:702
+#: src/ui/gui/data-editor.ui:714
 msgid "Filter Use Status Area"
 msgstr "Área de uso de Filtro"
 
-#: src/ui/gui/data-editor.ui:728
+#: src/ui/gui/data-editor.ui:740
 msgid "Weight Status Area"
 msgstr "Área de Ponderación"
 
-#: src/ui/gui/data-editor.ui:754
+#: src/ui/gui/data-editor.ui:766
 msgid "Split File Status Area"
 msgstr "Área de División de Archivo"
 
@@ -6694,26 +7116,222 @@ msgstr "Área de División de Archivo"
 msgid "_Export"
 msgstr "_Exportar"
 
-#: src/ui/gui/syntax-editor.ui:100
+#: src/ui/gui/syntax-editor.ui:104
 msgid "_Run"
 msgstr "Ejecuta_r"
 
-#: src/ui/gui/syntax-editor.ui:106
+#: src/ui/gui/syntax-editor.ui:110
 msgid "All"
 msgstr "Todos"
 
-#: src/ui/gui/syntax-editor.ui:112
+#: src/ui/gui/syntax-editor.ui:116
 msgid "Selection"
 msgstr "Selección"
 
-#: src/ui/gui/syntax-editor.ui:118
+#: src/ui/gui/syntax-editor.ui:122
 msgid "Current Line"
 msgstr "Línea actual"
 
-#: src/ui/gui/syntax-editor.ui:125
+#: src/ui/gui/syntax-editor.ui:129
 msgid "To End"
 msgstr "Hasta el final"
 
+#~ msgid "column %d"
+#~ msgstr "columna %d"
+
+#~ msgid "columns %d-%d"
+#~ msgstr "columnas %d-%d"
+
+#~ msgid "%s field) "
+#~ msgstr "%s campo)"
+
+#~ msgid "Cannot create variable name from %s"
+#~ msgstr "No se puede crear el nombre de la variable desde %s"
+
+#~ msgid "%s: Creating temporary file: %s."
+#~ msgstr "%s: Creando archivo temporal: %s."
+
+#~ msgid "%s: Creating file: %s."
+#~ msgstr "%s: Creando archivo: %s."
+
+#~ msgid "Duplicate variable name %s in position %d."
+#~ msgstr "Nombre de la variable %s duplicado en la posición %d."
+
+#~ msgid "Recoded variable name duplicates an existing `%s' within system file."
+#~ msgstr "El nombre de la variable recodificada duplica `%s' existente dentro del archivo del sistema."
+
+#~ msgid "Duplicate variable name `%s' within system file."
+#~ msgstr "Nombre de variable '%s' duplicado dentro del archivo de sistema."
+
+#~ msgid "Document line contains null byte."
+#~ msgstr "Una línea del documento contiene un byte nulo."
+
+#~ msgid "Missing space following 'E' at offset %zu in MRSETS record"
+#~ msgstr "Espacio perdido tras 'E' en la posición %zu del registro MRSETS"
+
+#~ msgid "Duplicate long variable name `%s' within system file."
+#~ msgstr "Nombre de la variable larga '%s' duplicada dentro del archivo de sistema."
+
+#~ msgid "Invalid number of labels: %d.  Ignoring labels."
+#~ msgstr "Número de etiquetas inválido: %d. Ignorando etiquetas."
+
+#~ msgid "Reading `%s': %s."
+#~ msgstr "Leyendo `%s': %s."
+
+#~ msgid "Closing `%s': %s."
+#~ msgstr "Cerrando `%s': %s."
+
+#~ msgid "%s does not form a valid number."
+#~ msgstr "%s no constituye un número vàlido."
+
+#~ msgid "Syntax error %s at %s."
+#~ msgstr "Error de sintaxis %s en %s."
+
+#~ msgid "binary"
+#~ msgstr "binario"
+
+#~ msgid "octal"
+#~ msgstr "octal"
+
+#~ msgid "hex"
+#~ msgstr "hexadecimal"
+
+#~ msgid "Unexpected end of file in string concatenation."
+#~ msgstr "Final de archivo inesperado en la concatenación de cadenas."
+
+#~ msgid "String exceeds 255 characters in length (%zu characters)."
+#~ msgstr "La cadena supera los 255 carácteres de longitud (%zu carácteres)."
+
+#~ msgid "incorrect use of TO convention"
+#~ msgstr "uso incorrecto de la convención TO"
+
+# recursivamente? recurridamente? repetidamente?
+#~ msgid "DO REPEAT may not nest in compatibility mode."
+#~ msgstr "DO REPEAT no puede usarse recursivamente en modo compatibilidad."
+
+#~ msgid "expecting ATTRIBUTE= or DELETE="
+#~ msgstr "esperando ATTRIBUTE= o DELETE="
+
+#~ msgid "expecting `('"
+#~ msgstr "esperando `('"
+
+#~ msgid "String expected for variable label."
+#~ msgstr "Se espera una cadena como etiqueta de variable."
+
+#~ msgid "%s is too long for a variable name."
+#~ msgstr "%s es demasiado largo para un nombre de variable."
+
+#~ msgid "%zu-byte string needed but %zu-byte string supplied."
+#~ msgstr "Se necesita cadena de %zu-byte pero se han suministrado de %zu-byte."
+
+#~ msgid "Hexadecimal floating constant too long."
+#~ msgstr "Constante hexadecimal flotante demasiado larga."
+
+#~ msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
+#~ msgstr "conversión %s de %s desde %s en %s debería haber producido %s pero actualmente ha producido %s."
+
+#~ msgid "Too many values in single command."
+#~ msgstr "Demasiados valores en un sólo comando."
+
+#~ msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
+#~ msgstr "Esperando BATCH o INTERACTIVE después de SYNTAX."
+
+#~ msgid "Expecting YES or NO after CD."
+#~ msgstr "Esperando YES o NO después del CD."
+
+#~ msgid "Expecting CONTINUE or STOP after ERROR."
+#~ msgstr "Esperando CONTINUE o bien STOP después del ERROR."
+
+#~ msgid "Unexpected token: `%s'."
+#~ msgstr "Testimonio inesperado: `%s'."
+
+#~ msgid "Unable to open `%s': %s."
+#~ msgstr "No se puede abrir `%s': %s."
+
+#~ msgid "while expecting COLUMNWISE"
+#~ msgstr "mientras tanto esperando COLUMNWISE"
+
+#~ msgid "expecting BREAK"
+#~ msgstr "esperando BREAK"
+
+#~ msgid "expecting `)'"
+#~ msgstr "esperando ')'"
+
+#~ msgid "Sig. 1-tailed"
+#~ msgstr "Sig. (1-cola)"
+
+#~ msgid "Error closing FLIP source file: %s."
+#~ msgstr "Error de cierre del archivo de fuente FLIP: %s."
+
+#~ msgid "expecting FIXED or DELIMITED"
+#~ msgstr "esperando FIXED o DELIMITED"
+
+#~ msgid "expecting LINE or VARIABLES"
+#~ msgstr "esperando LINE o VARIABLES"
+
+#~ msgid "expecting VARIABLES"
+#~ msgstr "esperando VARIABLES"
+
+#~ msgid "expecting COMM or TAPE"
+#~ msgstr "esperando COMM o TAPE"
+
+#~ msgid "COLUMN subcommand multiply specified."
+#~ msgstr "subcomando COLUMN especificado múltiples veces."
+
+#~ msgid "in expression"
+#~ msgstr "en la expresión"
+
+#~ msgid "hash table:"
+#~ msgstr "tabla hash:"
+
+#~ msgid "Warnings (%d) exceed limit (%d)."
+#~ msgstr "Avisos (%d) exceden el límite (%d)."
+
+#~ msgid "Errors (%d) exceed limit (%d)."
+#~ msgstr "Los errores (%d) exceden el límite (%d)."
+
+#~ msgid "Field content \"%.*s\" cannot be parsed in format %s."
+#~ msgstr "El contenido del campo \"%.*s\" no puede ser analizado en formato %s."
+
+#~ msgid "expecting BY"
+#~ msgstr "esperando BY"
+
+#~ msgid "Asymp. Sig. (2-sided)"
+#~ msgstr "Sign. Asint. (2-colas)"
+
+#~ msgid "Exact Sig. (2-sided)"
+#~ msgstr "Sign. Exacta (2-colas)"
+
+#~ msgid "Exact Sig. (1-sided)"
+#~ msgstr "Sign. Exacta (1-cola)"
+
+#~ msgid "Multivariate GLM not yet supported"
+#~ msgstr "GLM multivariable todavía no disponible"
+
+#~ msgid "Missing required subcommand TABLES."
+#~ msgstr "Falta el subcomando requerido TABLES."
+
+#~ msgid "TABLES subcommand may not appear more than once."
+#~ msgstr "El subcomando TABLES no puede aparecer más de una vez."
+
+#~ msgid "`%s' is not a variable name"
+#~ msgstr "`%s' no es un nombre de variable"
+
+#~ msgid "Analyse"
+#~ msgstr "Analizar"
+
+#~ msgid " cases"
+#~ msgstr " casos"
+
+#~ msgid "Sort Ascending"
+#~ msgstr "Ordenación Ascendente"
+
+#~ msgid "Sort Descending"
+#~ msgstr "Ordenación Descendente"
+
+#~ msgid "_Fonts"
+#~ msgstr "_Fuentes"
+
 #~ msgid "Buttons"
 #~ msgstr "Botones"
 
@@ -6804,9 +7422,6 @@ msgstr "Hasta el final"
 #~ msgid "expected end of file"
 #~ msgstr "final de archivo esperado"
 
-#~ msgid "syntax error expecting end of line"
-#~ msgstr "error de sintaxis en esperar el final de línea"
-
 #~ msgid "number out of valid range"
 #~ msgstr "número fuera del intervalo válido"
 
@@ -6885,9 +7500,6 @@ msgstr "Hasta el final"
 #~ msgid "reading \"%s\""
 #~ msgstr "leyendo \"%s\""
 
-#~ msgid "syntax error"
-#~ msgstr "error de sintaxis"
-
 #~ msgid "error closing \"%s\""
 #~ msgstr "error en cerrar \"%s\""
 
@@ -7100,9 +7712,6 @@ msgstr "Hasta el final"
 #~ msgid "Import text data file"
 #~ msgstr "Importar archivo de texto"
 
-#~ msgid "Save data to file"
-#~ msgstr "Guardar datos en archivo"
-
 #~ msgid "Select cases from the active file"
 #~ msgstr "Seleccionar casos del archivo activo"
 
@@ -7253,6 +7862,3 @@ msgstr "Hasta el final"
 
 #~ msgid "`/FORMAT WEIGHT' specified, but weighting is not on."
 #~ msgstr "`/FORMAT WEIGHT' especificado, pero la ponderación no está activada."
-
-#~ msgid "Line"
-#~ msgstr "Línea"
diff --git a/po/lt.po b/po/lt.po
new file mode 100644 (file)
index 0000000..76742ca
--- /dev/null
+++ b/po/lt.po
@@ -0,0 +1,7616 @@
+# translation of pspp to Lithuanian
+# Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+# This file is distributed under the same licence as the PSPP package.#
+#
+# Mindaugas Baranauskas <embar@users.berlios.de>, 2010, 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: pspp-0.7.8\n"
+"Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
+"POT-Creation-Date: 2011-05-04 06:57-0700\n"
+"PO-Revision-Date: 2011-05-05 11:11+0300\n"
+"Last-Translator: Mindaugas Baranauskas <embar@users.berlios.de>\n"
+"Language-Team: Lithuanian <komp_lt@konferencijos.lt>\n"
+"Language: lt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.2\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 ? 0 : n%10==1 && n%100!=11 ? 1 : n%10>=2 && (n%100<10 || n%100>=20) ? 2 : 3);\n"
+
+#: src/ui/gui/helper.c:194
+msgid "Sorry. The help system hasn't yet been implemented."
+msgstr "Atleiskite, žinynas dar nerealizuotas."
+
+#: src/ui/gui/psppire-buttonbox.c:313 src/ui/gui/psppire-buttonbox.c:469
+msgid "Continue"
+msgstr "Tęsti"
+
+#: src/ui/gui/psppire-buttonbox.c:467
+msgid "OK"
+msgstr "Gerai"
+
+#: src/ui/gui/psppire-buttonbox.c:468
+msgid "Go To"
+msgstr "Šokti į"
+
+#: src/ui/gui/psppire-buttonbox.c:470
+msgid "Cancel"
+msgstr "Atsisakyti"
+
+#: src/ui/gui/psppire-buttonbox.c:471
+msgid "Help"
+msgstr "Pagalba"
+
+#: src/ui/gui/psppire-buttonbox.c:472
+msgid "Reset"
+msgstr "Atstatyti"
+
+#: src/ui/gui/psppire-buttonbox.c:473
+msgid "Paste"
+msgstr "Įdėti"
+
+#: src/ui/gui/psppire-dictview.c:466 src/language/dictionary/split-file.c:82
+#: src/language/dictionary/sys-file-info.c:149
+#: src/language/dictionary/sys-file-info.c:332
+#: src/language/dictionary/sys-file-info.c:646
+#: src/language/stats/descriptives.c:895
+#: src/language/data-io/data-parser.c:683
+#: src/language/data-io/data-parser.c:722 src/language/data-io/print.c:403
+msgid "Variable"
+msgstr "Kintamasis"
+
+#: src/ui/gui/psppire-dictview.c:503
+msgid "Prefer variable labels"
+msgstr "Jei įmanoma, naudoti kintamųjų etiketes"
+
+#: src/ui/gui/psppire-var-view.c:192
+#, c-format
+msgid "Var%d"
+msgstr "Kint%d"
+
+#: src/data/any-reader.c:60
+#, c-format
+msgid "An error occurred while opening `%s': %s."
+msgstr "Klaida bandant atverti „%s“: %s."
+
+#: src/data/any-reader.c:105
+#, c-format
+msgid "`%s' is not a system or portable file."
+msgstr "„%s“ nėra nei sisteminė, nei perkeliama rinkmena"
+
+#: src/data/any-reader.c:111 src/data/any-writer.c:67
+msgid "The inline file is not allowed here."
+msgstr "Į vidų įterpti rinkmeną neleidžiama."
+
+#: src/data/calendar.c:100
+#, c-format
+msgid "Month %d is not in acceptable range of 0 to 13."
+msgstr "Mėnuo %d nėra priimtiname intervale nuo 0 iki 13."
+
+#: src/data/calendar.c:110
+#, c-format
+msgid "Day %d is not in acceptable range of 0 to 31."
+msgstr "Diena %d nėra priimtiname intervale nuo 0 iki 31."
+
+#: src/data/calendar.c:119
+#, c-format
+msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
+msgstr " Data %04d-%d-%d yra anksčiau nei anksčiausia priimtina 1582-10-15."
+
+#: src/data/casereader-filter.c:221
+msgid "At least one case in the data read had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
+msgstr "Nuskaitytuose duomenyse bent vienas atvejis turi svorio reikšmę, kuri yra naudotojo apibrėžta kaip praleista, sisteminė praleista, nulis arba neigiamas skaičius. Šie atvejai ignoruojami."
+
+#. TRANSLATORS: this fragment will be interpolated into messages in fh_lock()
+#. that identify types of files.
+#: src/data/csv-file-writer.c:154
+msgid "CSV file"
+msgstr "CSV rinkmena"
+
+#: src/data/csv-file-writer.c:163 src/data/sys-file-writer.c:225
+#, c-format
+msgid "Error opening `%s' for writing as a system file: %s."
+msgstr "Klaida atveriant „%s“ rašymui į sisteminę rinkmeną: %s."
+
+#: src/data/csv-file-writer.c:464
+#, c-format
+msgid "An I/O error occurred writing CSV file `%s'."
+msgstr "Įvedimo/išvedimo klaida įrašant CSV rinkmeną „%s“."
+
+#: src/data/data-in.c:171
+#, c-format
+msgid "Data is not valid as format %s: %s"
+msgstr "duomenys neatitinka %s formato: %s"
+
+#: src/data/data-in.c:376 src/data/data-in.c:552
+msgid "Field contents are not numeric."
+msgstr "lauko turinys nėra skaitmeninis."
+
+#: src/data/data-in.c:378 src/data/data-in.c:554
+msgid "Number followed by garbage."
+msgstr "Už skaičiaus yra šiukšlių."
+
+#: src/data/data-in.c:391
+msgid "Invalid numeric syntax."
+msgstr "Neteisinga skaitmeninė sintaksė."
+
+#: src/data/data-in.c:399 src/data/data-in.c:570
+msgid "Too-large number set to system-missing."
+msgstr "Per didelis skaičius nustatytas kaip „sisteminė praleista“ reikšmė."
+
+#: src/data/data-in.c:405 src/data/data-in.c:576
+msgid "Too-small number set to zero."
+msgstr "Per mažas skaičius nustatytas kaip nulis."
+
+#: src/data/data-in.c:425
+msgid "All characters in field must be digits."
+msgstr "Visi lauko rašmenys turi būti skaitmenys."
+
+#: src/data/data-in.c:444
+msgid "Unrecognized character in field."
+msgstr "Lauke yra neatpažintas rašmuo."
+
+#: src/data/data-in.c:465 src/data/data-in.c:728
+msgid "Field must have even length."
+msgstr "Laukas privalo būti pakankamo ilgio."
+
+#: src/data/data-in.c:467 src/data/data-in.c:731
+msgid "Field must contain only hex digits."
+msgstr "Lauke gali būti tik šešioliktainiai skaitmenys."
+
+#: src/data/data-in.c:543
+msgid "Invalid zoned decimal syntax."
+msgstr ""
+
+#: src/data/data-in.c:643 src/data/data-in.c:649
+msgid "Invalid syntax for P field."
+msgstr "Neteisinga P lauko sintaksė."
+
+#: src/data/data-in.c:767 src/data/data-in.c:813
+msgid "Syntax error in date field."
+msgstr "Sintaksės klaida datos lauke."
+
+#: src/data/data-in.c:782
+#, c-format
+msgid "Day (%ld) must be between 1 and 31."
+msgstr "Diena (%ld) turi būti skaičius nuo 1 iki 31."
+
+#: src/data/data-in.c:827
+msgid "Delimiter expected between fields in date."
+msgstr "Tarp datos laukų tikėtasi rasti skirtuką."
+
+#: src/data/data-in.c:901
+msgid "Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names."
+msgstr "Mėnesio formatas neatpažintas. Mėnesį galite nurodyti arabiškais arba romėniškais skaitmenimis arba angliškų mėnesių pavadinimų bent trimis pirmosiomis raidėmis."
+
+#: src/data/data-in.c:928
+#, c-format
+msgid "Year (%ld) must be between 1582 and 19999."
+msgstr "Metai (%ld) turi būti iš intervalo nuo 1582 iki 19999."
+
+#: src/data/data-in.c:939
+#, c-format
+msgid "Trailing garbage `%.*s' following date."
+msgstr "Už datos yra šiukšlė „%.*s“."
+
+#: src/data/data-in.c:953
+msgid "Julian day must have exactly three digits."
+msgstr "Julijaus dieną turi sudaryti būtent trys skaitmenys"
+
+#: src/data/data-in.c:955
+#, c-format
+msgid "Julian day (%ld) must be between 1 and 366."
+msgstr "Julijaus diena (%ld) turi būti skaičius nuo 1 iki 366."
+
+#: src/data/data-in.c:979
+#, c-format
+msgid "Quarter (%ld) must be between 1 and 4."
+msgstr "Kvartilis (%ld) turi būti skaičius nuo 1 iki 4."
+
+#: src/data/data-in.c:1000
+#, c-format
+msgid "Week (%ld) must be between 1 and 53."
+msgstr "Savaitė (%ld) turi būti iš intervalo tarp 1 ir 53."
+
+#: src/data/data-in.c:1012
+msgid "Delimiter expected between fields in time."
+msgstr "Tarp laiko laukų tikėtasi rasti skirtuką."
+
+#: src/data/data-in.c:1032
+#, c-format
+msgid "Minute (%ld) must be between 0 and 59."
+msgstr "Minutė (%ld) turi būti iš intervalo nuo 0 iki 59."
+
+#: src/data/data-in.c:1070
+msgid "Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified."
+msgstr "Savaitės diena neatpažinta. Turi būti nurodytos angliško pavadinimo bent dvi pirmosios raidės (mo, tu, we, th, fr, sa, su)."
+
+#: src/data/data-in.c:1196
+#, c-format
+msgid "`%c' expected in date field."
+msgstr "Datos laukelyje tikėtasi „%c“."
+
+#: src/data/data-out.c:546
+#, c-format
+msgid "Weekday number %f is not between 1 and 7."
+msgstr "Savaitės dienos numeris %f nėra tarp 1 ir 7."
+
+#: src/data/data-out.c:571
+#, c-format
+msgid "Month number %f is not between 1 and 12."
+msgstr "Mėnesio numeris %f nėra tarp 1 ir 12."
+
+#: src/data/dataset-reader.c:54
+#, c-format
+msgid "Cannot read from dataset %s because no dictionary or data has been written to it yet."
+msgstr "Negalima skaityti iš duomenų rinkinio %s, nes į jame dar nėra įrašyto žodyno arba duomenų."
+
+#. TRANSLATORS: this fragment will be interpolated into
+#. messages in fh_lock() that identify types of files.
+#: src/data/dataset-writer.c:66 src/language/data-io/file-handle.q:182
+msgid "dataset"
+msgstr "duomenų rinkinys"
+
+#: src/data/dict-class.c:52
+msgid "ordinary"
+msgstr "paprasta"
+
+#: src/data/dict-class.c:54
+msgid "system"
+msgstr "sisteminė"
+
+#: src/data/dict-class.c:56
+msgid "scratch"
+msgstr ""
+
+#: src/data/dictionary.c:1003
+msgid "At least one case in the data file had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
+msgstr "Nuskaitytoje rinkmenoje bent vienas atvejis turi svorio reikšmę, kuri yra naudotojo apibrėžta kaip praleista, sisteminė praleista, nulis arba neigiamas skaičius. Šie atvejai ignoruojami."
+
+#: src/data/dictionary.c:1329
+#, c-format
+msgid "Truncating document line to %d bytes."
+msgstr "Dokumento eilutė sutrumpinta iki %d bitų(-o)."
+
+#: src/data/file-handle-def.c:254
+msgid "active dataset"
+msgstr "veikiamasis duomenų rinkinys"
+
+#: src/data/file-handle-def.c:465
+#, c-format
+msgid "Can't read from %s as a %s because it is already being read as a %s."
+msgstr "Negalima skaityti iš %s kaip %s, nes jau skaitoma kaip %s."
+
+#: src/data/file-handle-def.c:469
+#, c-format
+msgid "Can't write to %s as a %s because it is already being written as a %s."
+msgstr "Negalima rašyti į %s kaip %s, nes jau rašoma kaip %s."
+
+#: src/data/file-handle-def.c:476
+#, c-format
+msgid "Can't re-open %s as a %s."
+msgstr "Negalima iš naujo atverti %s kaip %s."
+
+#: src/data/file-name.c:168
+#, c-format
+msgid "Not opening pipe file `%s' because SAFER option set."
+msgstr ""
+
+#: src/data/format.c:320
+msgid "Input format"
+msgstr "Įvedimo formatas"
+
+#: src/data/format.c:320
+msgid "Output format"
+msgstr "Išvedimo formatas"
+
+#: src/data/format.c:329
+#, c-format
+msgid "Format %s may not be used for input."
+msgstr "Formato %s negalima naudoti įvedimui."
+
+#: src/data/format.c:336
+#, c-format
+msgid "%s specifies width %d, but %s requires an even width."
+msgstr "%s nurodo %d ilgį, bet %s turėtų būti lyginio ilgio."
+
+#: src/data/format.c:345
+#, c-format
+msgid "%s %s specifies width %d, but %s requires a width between %d and %d."
+msgstr "%s %s nurodo %d ilgį, bet %s turėtų būti nuo %d iki %d ilgio."
+
+#: src/data/format.c:354
+#, c-format
+msgid "%s %s specifies %d decimal place, but %s does not allow any decimals."
+msgid_plural "%s %s specifies %d decimal places, but %s does not allow any decimals."
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+#: src/data/format.c:365
+#, c-format
+msgid "%s %s specifies %d decimal place, but the given width allows at most %d decimals."
+msgid_plural "%s %s specifies %d decimal places, but the given width allows at most %d decimals."
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+#: src/data/format.c:372
+#, c-format
+msgid "%s %s specifies %d decimal place, but the given width does not allow for any decimals."
+msgid_plural "%s %s specifies %d decimal places, but the given width does not allow for any decimals."
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+#: src/data/format.c:411
+#, c-format
+msgid "%s variables are not compatible with %s format %s."
+msgstr "%s kintamieji nesuderinami su %s formatu %s."
+
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:628 src/ui/gui/compute.ui:503
+#: src/ui/gui/var-sheet-dialogs.ui:139
+msgid "String"
+msgstr "Teksto eilutė"
+
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
+#: src/ui/gui/psppire-var-store.c:621 src/ui/gui/compute.ui:584
+#: src/ui/gui/var-sheet-dialogs.ui:27
+msgid "Numeric"
+msgstr "Skaitmeninis"
+
+#: src/data/format.c:413 src/data/sys-file-reader.c:1671
+#: src/data/sys-file-reader.c:1673 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
+#: src/language/dictionary/apply-dictionary.c:78
+msgid "numeric"
+msgstr "skaitmeninis"
+
+#: src/data/format.c:413 src/data/sys-file-reader.c:1671
+#: src/data/sys-file-reader.c:1673 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
+#: src/language/dictionary/apply-dictionary.c:77
+#: src/language/dictionary/apply-dictionary.c:78
+msgid "string"
+msgstr "teksto eilutė "
+
+#: src/data/format.c:431
+#, c-format
+msgid "String variable with width %d is not compatible with format %s."
+msgstr "Teksto eilutės kintamasis, kurio plotis %d, yra nesuderinamas su %s formatu."
+
+#: src/data/gnumeric-reader.c:36
+msgid "Support for Gnumeric files was not compiled into this installation of PSPP"
+msgstr "Gnumeric rinkmenų palaikymas nebuvo sukonfigūruotas šioje PSPP kompiliacijoje"
+
+#: src/data/gnumeric-reader.c:363
+#, c-format
+msgid "Error opening `%s' for reading as a Gnumeric file: %s."
+msgstr "Klaida skaitymui atveriant „%s“ kaip Gnumeric rinkmeną: %s."
+
+#: src/data/gnumeric-reader.c:383
+#, c-format
+msgid "Invalid cell range `%s'"
+msgstr "Netinkama langelių sritis „%s“"
+
+#: src/data/gnumeric-reader.c:521
+#, c-format
+msgid "Selected sheet or range of spreadsheet `%s' is empty."
+msgstr "Pasirinktas lakštas arba skaičialentės sritis „%s“ yra tuščia."
+
+#: src/data/identifier2.c:60
+#, c-format
+msgid "Identifier `%s' exceeds %d-byte limit."
+msgstr "Identifikatorius „%s“ viršija %d bitų ribą."
+
+#: src/data/identifier2.c:84
+msgid "Identifier cannot be empty string."
+msgstr "Identifikatorius negali būti tuščia eilutė."
+
+#: src/data/identifier2.c:92
+#, c-format
+msgid "`%s' may not be used as an identifier because it is a reserved word."
+msgstr "„%s“ negali būti naudojamas kaip identifikatorius, nes šis žodis rezervuotas."
+
+#: src/data/identifier2.c:103
+#, c-format
+msgid "`%s' may not be used as an identifier because it contains ill-formed UTF-8 at byte offset %tu."
+msgstr ""
+
+#: src/data/identifier2.c:114
+#, c-format
+msgid "Character %s (in `%s') may not appear as the first character in a identifier."
+msgstr "Pirmuoju identifikatoriaus simboliu negali būti %s simbolis (ties „%s“)."
+
+#: src/data/identifier2.c:126
+#, c-format
+msgid "Character %s (in `%s') may not appear in an identifier."
+msgstr "Identifikatoriuje negali būti %s simbolis (ties „%s“)."
+
+#: src/data/make-file.c:71
+#, c-format
+msgid "Opening %s for writing: %s."
+msgstr "Atveriama %s įrašymui: %s."
+
+#: src/data/make-file.c:80
+#, c-format
+msgid "Opening stream for %s: %s."
+msgstr "Atveriamas %s srautas: %s."
+
+#: src/data/make-file.c:109
+#, c-format
+msgid "Creating temporary file to replace %s: %s."
+msgstr "%s pakeitimui kuriama laikinoji rinkmena: %s."
+
+#: src/data/make-file.c:120
+#, c-format
+msgid "Creating temporary file %s: %s."
+msgstr "Kuriama laikinoji rinkmena %s: %s."
+
+#: src/data/make-file.c:132
+#, c-format
+msgid "Opening stream for temporary file %s: %s."
+msgstr "Laikinajai rinkmenai %s atveriamas srautas: %s."
+
+#: src/data/make-file.c:173
+#, c-format
+msgid "Replacing %s by %s: %s."
+msgstr "%s pakeičiamas į %s: %s."
+
+#: src/data/make-file.c:201
+#, c-format
+msgid "Removing %s: %s."
+msgstr "Pašalinama %s: %s."
+
+#: src/data/mrset.c:83
+#, c-format
+msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
+msgstr ""
+
+#: src/data/por-file-reader.c:101
+#, c-format
+msgid "portable file %s corrupt at offset 0x%llx: "
+msgstr "perkeliama rinkmena %s sugadinta ties 0x%llx poslinkiu: "
+
+#: src/data/por-file-reader.c:133
+#, c-format
+msgid "reading portable file %s at offset 0x%llx: "
+msgstr "skaitoma perkeliama rinkmena %s ties 0x%llx poslinkiu: "
+
+#: src/data/por-file-reader.c:164
+#, c-format
+msgid "Error closing portable file `%s': %s."
+msgstr "Perkeliamos rinkmenos „%s“ užvėrimo klaida: %s."
+
+#: src/data/por-file-reader.c:216
+msgid "unexpected end of file"
+msgstr "netikėta rinkmenos pabaiga"
+
+#. TRANSLATORS: this fragment will be interpolated into
+#. messages in fh_lock() that identify types of files.
+#: src/data/por-file-reader.c:275 src/data/por-file-writer.c:148
+msgid "portable file"
+msgstr "perkeliama rinkmena"
+
+#: src/data/por-file-reader.c:283
+#, c-format
+msgid "An error occurred while opening `%s' for reading as a portable file: %s."
+msgstr "Klaida atveriant „%s“ skaitymui kaip perkeliamą rinkmeną: %s"
+
+#: src/data/por-file-reader.c:304
+msgid "Data record expected."
+msgstr "Tikėtasi duomenų įrašo."
+
+#: src/data/por-file-reader.c:386
+msgid "Number expected."
+msgstr "Tikėtasi skaičiaus."
+
+#: src/data/por-file-reader.c:414
+msgid "Missing numeric terminator."
+msgstr ""
+
+#: src/data/por-file-reader.c:437
+msgid "Invalid integer."
+msgstr "Netinkamas sveikasis skaičius."
+
+#: src/data/por-file-reader.c:448 src/data/por-file-reader.c:468
+#, c-format
+msgid "Bad string length %d."
+msgstr "Teksto eilutės ilgis %d yra netinkamas."
+
+#: src/data/por-file-reader.c:531
+#, c-format
+msgid "%s: Not a portable file."
+msgstr "%s: Nėra perkeliama rinkmena."
+
+#: src/data/por-file-reader.c:548
+#, c-format
+msgid "Unrecognized version code `%c'."
+msgstr "neatpažintas versijos kodas „%c“."
+
+#: src/data/por-file-reader.c:557
+#, c-format
+msgid "Bad date string length %zu."
+msgstr "Netinkamas tekstinės eilutės ilgis %zu."
+
+#: src/data/por-file-reader.c:559
+#, c-format
+msgid "Bad time string length %zu."
+msgstr "Netinkamas laiko ilgis %zu."
+
+#: src/data/por-file-reader.c:601
+#, c-format
+msgid "%s: Bad format specifier byte (%d).  Variable will be assigned a default format."
+msgstr ""
+
+#: src/data/por-file-reader.c:622
+#, c-format
+msgid "Numeric variable %s has invalid format specifier %s."
+msgstr ""
+
+#: src/data/por-file-reader.c:626
+#, c-format
+msgid "String variable %s with width %d has invalid format specifier %s."
+msgstr ""
+
+#: src/data/por-file-reader.c:650
+msgid "Expected variable count record."
+msgstr "Tikėtasi kintamųjų skaičiaus įrašo."
+
+#: src/data/por-file-reader.c:654
+#, c-format
+msgid "Invalid number of variables %d."
+msgstr "Netinkamas kintamųjų skaičius %d."
+
+#: src/data/por-file-reader.c:663
+#, c-format
+msgid "Weight variable name (%s) truncated."
+msgstr ""
+
+#: src/data/por-file-reader.c:678
+msgid "Expected variable record."
+msgstr "Tikėtasi kintamojo įrašo."
+
+#: src/data/por-file-reader.c:682
+#, c-format
+msgid "Invalid variable width %d."
+msgstr "Netinkamas kintamojo ilgis %d."
+
+#: src/data/por-file-reader.c:690
+#, c-format
+msgid "Invalid variable name `%s' in position %d."
+msgstr "Netinkamas kintamojo vardas „%s“ ties %d padėtimi."
+
+#: src/data/por-file-reader.c:694 src/data/sys-file-reader.c:963
+#, c-format
+msgid "Bad width %d for variable %s."
+msgstr "Plotis %d yra netinkamas kintamajam %s."
+
+#: src/data/por-file-reader.c:708
+#, c-format
+msgid "Duplicate variable name %s in position %d renamed to %s."
+msgstr "Besikartojantis kintamojo vardas %s ties %d padėtimi pakeistas į %s."
+
+#: src/data/por-file-reader.c:757
+#, c-format
+msgid "Weighting variable %s not present in dictionary."
+msgstr ""
+
+#: src/data/por-file-reader.c:801
+#, c-format
+msgid "Unknown variable %s while parsing value labels."
+msgstr "Nežinomas kintamasis %s analizuojant reikšmių etiketes."
+
+#: src/data/por-file-reader.c:804
+#, c-format
+msgid "Cannot assign value labels to %s and %s, which have different variable types."
+msgstr "Negalima priskirti reikšmių etikečių prie %s ir %s, kurie turi skirtingus kintamųjų tipus."
+
+#: src/data/por-file-writer.c:140
+#, c-format
+msgid "Invalid decimal digits count %d.  Treating as %d."
+msgstr ""
+
+#: src/data/por-file-writer.c:160
+#, c-format
+msgid "Error opening `%s' for writing as a portable file: %s."
+msgstr "Klaida atveriant rašymui „%s“ kaip perkeliamą rinkmeną: %s."
+
+#: src/data/por-file-writer.c:502
+#, c-format
+msgid "An I/O error occurred writing portable file `%s'."
+msgstr "Įvedimo/išvedimo klaida rašant perkeliamą rinkmeną „%s“."
+
+#: src/data/psql-reader.c:47
+msgid "Support for reading postgres databases was not compiled into this installation of PSPP"
+msgstr "Postgres duomenų bazių skaitymo palaikymas nebuvo sukonfigūruotas šioje PSPP kompiliacijoje"
+
+#: src/data/psql-reader.c:241
+msgid "Memory error whilst opening psql source"
+msgstr "Atminties klaida atveriant psql šaltinį"
+
+#: src/data/psql-reader.c:247
+#, c-format
+msgid "Error opening psql source: %s."
+msgstr "Klaida bandant atverti psql šaltinį: %s."
+
+#: src/data/psql-reader.c:262
+#, c-format
+msgid "Postgres server is version %s. Reading from versions earlier than 8.0 is not supported."
+msgstr "Postgres serverio versija yra %s. Skaitymas iš senesnių nei 8.0 versijos nepalaikomas."
+
+#: src/data/psql-reader.c:282
+msgid "Connection is unencrypted, but unencrypted connections have not been permitted."
+msgstr "Ryšys nešifruotas, bet nešifruotasis ryšys neleidžiamas."
+
+#: src/data/psql-reader.c:318 src/data/psql-reader.c:343
+#: src/data/psql-reader.c:353
+#, c-format
+msgid "Error from psql source: %s."
+msgstr "psql šaltinio klaida: %s."
+
+#: src/data/psql-reader.c:448
+#, c-format
+msgid "Unsupported OID %d.  SYSMIS values will be inserted."
+msgstr "Nepalaikomas OID %d.  Bus įterptos SYSMIS reikšmės."
+
+#: src/data/settings.c:384
+msgid "MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."
+msgstr ""
+
+#: src/data/settings.c:391
+#, c-format
+msgid "Warnings re-enabled. %d warnings will be issued before aborting syntax processing."
+msgstr ""
+
+#: src/data/settings.c:599
+#, c-format
+msgid "%s: Custom currency string `%s' does not contain exactly three periods or commas (or it contains both)."
+msgstr ""
+
+#. TRANSLATORS: this fragment will be interpolated into
+#. messages in fh_lock() that identify types of files.
+#: src/data/sys-file-reader.c:324 src/data/sys-file-writer.c:213
+msgid "system file"
+msgstr "sisteminė rinkmena"
+
+#: src/data/sys-file-reader.c:331
+#, c-format
+msgid "Error opening `%s' for reading as a system file: %s."
+msgstr "Klaida atveriant „%s“ skaitymui kaip iš sisteminės rinkmenos: %s."
+
+#: src/data/sys-file-reader.c:388 tests/dissect-sysfile.c:155
+msgid "Misplaced type 4 record."
+msgstr "4-to tipo įrašas padėtas ne vietoje."
+
+#: src/data/sys-file-reader.c:392
+msgid "Duplicate type 6 (document) record."
+msgstr "6-to tipo (dokumento) besikartojantis įrašas."
+
+#: src/data/sys-file-reader.c:401 src/data/sys-file-reader.c:900
+#, c-format
+msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Įrašo 7-tas tipas, %d potipis neatpažintas. Šios rinkmenos kopiją bei sintaksę, kuri ją sukūrė, siųskite %s."
+
+#: src/data/sys-file-reader.c:410
+#, c-format
+msgid "Record type 7, subtype %d found here has the same type as the record found near offset 0x%llx.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Įrašo 7-tas tipas, %d potipis yra to paties tipo kaip kaip įrašas ties 0x%llx poslinkiu. Šios rinkmenos kopiją bei sintaksę, kuri ją sukūrė, siųskite %s."
+
+#: src/data/sys-file-reader.c:423 tests/dissect-sysfile.c:166
+#, c-format
+msgid "Unrecognized record type %d."
+msgstr "Neatpažintas įrašo %d tipas."
+
+#: src/data/sys-file-reader.c:467
+#, c-format
+msgid "Weighting variable must be numeric (not string variable `%s')."
+msgstr "Svėrimo kintamasis turi būti skaitmeninis (ne teksto eilutės kintamasis „%s“)."
+
+#: src/data/sys-file-reader.c:502
+#, c-format
+msgid "File header claims %d variable positions but %zu were read from file."
+msgstr ""
+
+#: src/data/sys-file-reader.c:542
+#, c-format
+msgid "Error closing system file `%s': %s."
+msgstr "Sisteminės rinkmenos „%s“ užvėrimo klaida: %s."
+
+#: src/data/sys-file-reader.c:604 src/data/sys-file-reader.c:614
+#: tests/dissect-sysfile.c:203 tests/dissect-sysfile.c:213
+msgid "This is not an SPSS system file."
+msgstr "Tai ne SPSS sisteminė rinkmena."
+
+#: src/data/sys-file-reader.c:636 tests/dissect-sysfile.c:228
+msgid "Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format."
+msgstr ""
+
+#: src/data/sys-file-reader.c:712 tests/dissect-sysfile.c:357
+msgid "Variable label indicator field is not 0 or 1."
+msgstr "Kintamojo etiketės indikatoriaus laukas nėra 0 arba 1."
+
+#: src/data/sys-file-reader.c:722 tests/dissect-sysfile.c:388
+msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
+msgstr "Skaitmeninis praleistos reikšmės indikatoriaus laukas nėra -3, -2, 0, 1, 2 arba 3."
+
+#: src/data/sys-file-reader.c:729 tests/dissect-sysfile.c:403
+msgid "String missing value indicator field is not 0, 1, 2, or 3."
+msgstr "Teksto eilutės praleistos reikšmės indikatoriaus laukas nėra 0, 1, 2 arba 3."
+
+#: src/data/sys-file-reader.c:749
+#, c-format
+msgid "Invalid number of labels %zu."
+msgstr "Netinkamas etikečių skaičius %zu."
+
+#: src/data/sys-file-reader.c:774 tests/dissect-sysfile.c:469
+msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
+msgstr ""
+
+#: src/data/sys-file-reader.c:782
+#, c-format
+msgid "Number of variables associated with a value label (%zu) is not between 1 and the number of variables (%zu)."
+msgstr ""
+
+#: src/data/sys-file-reader.c:803
+#, c-format
+msgid "Number of document lines (%d) must be greater than 0 and less than %d."
+msgstr ""
+
+#: src/data/sys-file-reader.c:876
+#, c-format
+msgid "Record type 7, subtype %d has bad size %zu (expected %d)."
+msgstr "7-to tipo įrašo, %d potipio dydis %zu yra blogas (tikėtasi %d)."
+
+#: src/data/sys-file-reader.c:880
+#, c-format
+msgid "Record type 7, subtype %d has bad count %zu (expected %d)."
+msgstr "7-to tipo įrašo, %d potipio skaičius %zu yra blogas (tikėtasi %d)."
+
+#: src/data/sys-file-reader.c:959
+#, c-format
+msgid "Invalid variable name `%s'."
+msgstr "Netinkamas kintamojo vardas „%s“."
+
+#: src/data/sys-file-reader.c:967
+#, c-format
+msgid "Duplicate variable name `%s'."
+msgstr "Kintamojo vardas „%s“ kartojasi."
+
+#: src/data/sys-file-reader.c:1038
+msgid "Missing string continuation record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1059
+#, c-format
+msgid "Unknown variable format %<PRIu8>."
+msgstr "Nežinomas kintamojo formatas %<PRIu8>."
+
+#: src/data/sys-file-reader.c:1077
+#, c-format
+msgid "%s variable %s has invalid %s format %s."
+msgstr "%s kintamasis %s yra netinkamo %s formato %s."
+
+#: src/data/sys-file-reader.c:1080
+msgid "print"
+msgstr "spausdinti"
+
+#: src/data/sys-file-reader.c:1080
+msgid "write"
+msgstr "įrašyti"
+
+#: src/data/sys-file-reader.c:1084
+msgid "Suppressing further invalid format warnings."
+msgstr "Tolesni įspėjimai apie netinkamą formatą nerodomi."
+
+#: src/data/sys-file-reader.c:1136
+#, c-format
+msgid "Floating-point representation indicated by system file (%d) differs from expected (%d)."
+msgstr "Slankiojo kablelio vaizdavimas, kuris nurodytas sisteminėje rinkmenoje (%d), skiriasi nuo to, kurio tikėtasi (%d)."
+
+#: src/data/sys-file-reader.c:1150
+#, c-format
+msgid "Integer format indicated by system file (%d) differs from expected (%d)."
+msgstr "Sveikojo skaičiaus formatas, kuris nurodytas sisteminę rinkmeną (%d), skiriasi nuo to, kurio tikėtasi (%d)."
+
+#: src/data/sys-file-reader.c:1211 src/data/sys-file-reader.c:1215
+#: src/data/sys-file-reader.c:1219 tests/dissect-sysfile.c:631
+#: tests/dissect-sysfile.c:636 tests/dissect-sysfile.c:641
+#, c-format
+msgid "File specifies unexpected value %g as %s."
+msgstr "Rinkmena netikėtą reikšmę %g apibrėžia kaip %s."
+
+#: src/data/sys-file-reader.c:1252
+#, c-format
+msgid "`%s' does not begin with `$' at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1263 src/data/sys-file-reader.c:1282
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1292
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1299
+#, c-format
+msgid "Missing `C', `D', or `E' at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1331
+#, c-format
+msgid "Missing new-line parsing variable names at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1347
+#, c-format
+msgid "Duplicate variable name %s at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1363
+#, c-format
+msgid "MRSET %s contains both string and numeric variables."
+msgstr "MRSET %s turi ir tekstinės eilutės, ir skaitmeninius kintamuosius."
+
+#: src/data/sys-file-reader.c:1379
+#, c-format
+msgid "MRSET %s has only %zu variables."
+msgstr "MRSET %s turi tik %zu kintamuosius."
+
+#: src/data/sys-file-reader.c:1425 tests/dissect-sysfile.c:771
+#, c-format
+msgid "Extension 11 has bad count %zu (for %zu variables)."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1459
+#, c-format
+msgid "Invalid variable display parameters for variable %zu (%s).  Default parameters substituted."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1556
+#, c-format
+msgid "Long variable mapping from %s to invalid variable name `%s'."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1567
+#, c-format
+msgid "Duplicate long variable name `%s'."
+msgstr "Ilgas kintamojo vardas „%s“ kartojasi."
+
+#: src/data/sys-file-reader.c:1600
+#, c-format
+msgid "%s listed as string of invalid length %s in very long string record."
+msgstr "%s pateiktas kaip netinkamo ilgio %s teksto eilutė labai ilgame teksto eilutės įraše."
+
+#: src/data/sys-file-reader.c:1611
+#, c-format
+msgid "%s listed in very long string record with width %s, which requires only one segment."
+msgstr "%s pateiktas labai ilgame teksto eilutės įraše, kurio plotis %s, ir kuris reikalauja tik vieno segmento."
+
+#: src/data/sys-file-reader.c:1618
+#, c-format
+msgid "Very long string %s overflows dictionary."
+msgstr "Labai ilga teksto eilutė %s netelpa žodyne."
+
+#: src/data/sys-file-reader.c:1633
+#, c-format
+msgid "Very long string with width %ld has segment %d of width %d (expected %d)."
+msgstr "Labai ilga tekstinė eilutė, kurios plotis %ld, turi segmentą %d, kurio plotis %d (tikėtasi %d)."
+
+#: src/data/sys-file-reader.c:1667
+#, c-format
+msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1684
+#, c-format
+msgid "Value labels may not be added to long string variables (e.g. %s) using records types 3 and 4."
+msgstr "Kintamųjų etiketės negali būti priskiriamos ilgų tekstinių eilučių kintamiesiems (pvz., %s), jei įrašo tipas yra 3 arba 4."
+
+#: src/data/sys-file-reader.c:1703
+#, c-format
+msgid "Duplicate value label for %g on %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1707 src/data/sys-file-reader.c:1949
+#, c-format
+msgid "Duplicate value label for `%.*s' on %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1732
+#, c-format
+msgid "Variable index %d not in valid range 1...%zu."
+msgstr "Kintamojo indeksas %d nepriklauso tinkamam intervalui nuo 1 iki %zu."
+
+#: src/data/sys-file-reader.c:1741
+#, c-format
+msgid "Variable index %d refers to long string continuation."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1777
+#, c-format
+msgid "Error parsing attribute value %s[%d]."
+msgstr "Klaida nagrinėjant atributo reikšmę %s[%d]."
+
+#: src/data/sys-file-reader.c:1791
+#, c-format
+msgid "Attribute value %s[%d] is not quoted: %s."
+msgstr "Atributo reikšmė %s[%d] be kabučių: %s."
+
+#: src/data/sys-file-reader.c:1844
+msgid "Long string value label record ends unexpectedly."
+msgstr "Netikėtai baigiasi Ilgos tekstinės eilutės reikšmės etiketės įrašas."
+
+#: src/data/sys-file-reader.c:1883
+#, c-format
+msgid "Ignoring long string value record for unknown variable %s."
+msgstr "Nepaisoma nežinomo kintamojo %s ilgos tekstinės eilutės reikšmės įrašo."
+
+#: src/data/sys-file-reader.c:1888
+#, c-format
+msgid "Ignoring long string value record for numeric variable %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1895
+#, c-format
+msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)."
+msgstr ""
+
+#: src/data/sys-file-reader.c:1924
+#, c-format
+msgid "Ignoring long string value %zu for variable %s, with width %d, that has bad value width %zu."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2028
+msgid "File ends in partial case."
+msgstr "Rinkmena baigiasi nepilname atvejyje."
+
+#: src/data/sys-file-reader.c:2036
+#, c-format
+msgid "Error reading case from file %s."
+msgstr "klaida bandant nuskaityti atvejį iš rinkmenos „%s“."
+
+#: src/data/sys-file-reader.c:2138
+msgid "Possible compressed data corruption: compressed spaces appear in numeric field."
+msgstr "Tikėtina, kad suglaudinti duomenys yra sugadinti: skaitmeniniuose laukuose yra suglaudintų tarpų."
+
+#: src/data/sys-file-reader.c:2192
+#, c-format
+msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2286
+#, c-format
+msgid "Suppressed %d additional related warnings."
+msgstr "Neparodyti %d papildomi susiję įspėjimai."
+
+#: src/data/sys-file-reader.c:2332 src/data/sys-file-reader.c:2349
+#, c-format
+msgid "Dictionary record refers to unknown variable %s."
+msgstr "Žodyno įrašas nurodo į nežinomą kintamąjį %s."
+
+#: src/data/sys-file-reader.c:2411
+#, c-format
+msgid "Expecting digit at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2419
+#, c-format
+msgid "Expecting space at offset %zu in MRSETS record."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2427
+#, c-format
+msgid "%zu-byte string starting at offset %zu exceeds record length %zu."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2437
+#, c-format
+msgid "Expecting space at offset %zu following %zu-byte string."
+msgstr ""
+
+#: src/data/sys-file-reader.c:2478
+#, c-format
+msgid "`%s' near offset 0x%llx: "
+msgstr "„%s“ šalia 0x%llx poslinkio: "
+
+#: src/data/sys-file-reader.c:2481
+#, c-format
+msgid "`%s': "
+msgstr "„%s“: "
+
+#: src/data/sys-file-reader.c:2538 tests/dissect-sysfile.c:1356
+#, c-format
+msgid "System error: %s."
+msgstr "Sistemos klaida: %s."
+
+#: src/data/sys-file-reader.c:2540 tests/dissect-sysfile.c:1358
+msgid "Unexpected end of file."
+msgstr "Netikėta rinkmenos pabaiga."
+
+#: src/data/sys-file-writer.c:186
+#, c-format
+msgid "Unknown system file version %d. Treating as version %d."
+msgstr "Nežinoma sisteminės rinkmenos versija %d. Laikysima, kad tai yra %d."
+
+#: src/data/sys-file-writer.c:1015
+#, c-format
+msgid "An I/O error occurred writing system file `%s'."
+msgstr "Įvedimo/išvedimo klaida įrašant sisteminę rinkmeną „%s“."
+
+#: src/data/variable.c:601
+#, c-format
+msgid "Truncating variable label for variable `%s' to %d bytes."
+msgstr "Kintamojo „%s“ etiketė sutrumpinama iki %d baitų."
+
+#: src/language/command.c:196 src/language/expressions/parse.c:1294
+#: src/language/utilities/set.q:196
+#, c-format
+msgid "%s is not yet implemented."
+msgstr "%s dar nėra realizuota."
+
+#: src/language/command.c:201
+#, c-format
+msgid "%s may be used only in testing mode."
+msgstr "%s gali būti naudojamas tik išbandymo veiksenoje."
+
+#: src/language/command.c:206
+#, c-format
+msgid "%s may be used only in enhanced syntax mode."
+msgstr "%s gali būti naudojamas tik išplėstoje sintaksės veiksenoje."
+
+#: src/language/command.c:334
+msgid "expecting command name"
+msgstr "tikėtasi komandos vardo"
+
+#: src/language/command.c:336
+#, c-format
+msgid "Unknown command `%s'."
+msgstr "Nežinoma komanda „%s“."
+
+#: src/language/command.c:369
+#, c-format
+msgid "%s is allowed only before the active dataset has been defined."
+msgstr "%s leidžiama tik prieš nurodant veikiamąjį duomenų rinkinį."
+
+#: src/language/command.c:373
+#, c-format
+msgid "%s is allowed only after the active dataset has been defined."
+msgstr "%s leidžiama tik nurodžius veikiamąjį duomenų rinkinį."
+
+#: src/language/command.c:377
+#, c-format
+msgid "%s is allowed only inside INPUT PROGRAM."
+msgstr "%s leidžiama tik INPUT PROGRAM viduje."
+
+#: src/language/command.c:381
+#, c-format
+msgid "%s is allowed only inside FILE TYPE."
+msgstr "%s leidžiama tik FILE TYPE viduje."
+
+#: src/language/command.c:388
+#, c-format
+msgid "%s is allowed only before the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s leidžiama tik prieš nurodant veikiamąjį duomenų rinkinį arba INPUT PROGRAM viduje."
+
+#: src/language/command.c:392
+#, c-format
+msgid "%s is allowed only before the active dataset has been defined or inside FILE TYPE."
+msgstr "%s leidžiama tik prieš nurodant veikiamąjį duomenų rinkinį arba FILE TYPE viduje."
+
+#: src/language/command.c:396
+#, c-format
+msgid "%s is allowed only after the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s leidžiama tik nurodžius veikiamąjį duomenų rinkinį arba INPUT PROGRAM viduje."
+
+#: src/language/command.c:400
+#, c-format
+msgid "%s is allowed only after the active dataset has been defined or inside FILE TYPE."
+msgstr "%s leidžiama tik nurodžius veikiamąjį duomenų rinkinį arba FILE TYPE viduje."
+
+#: src/language/command.c:404
+#, c-format
+msgid "%s is allowed only inside INPUT PROGRAM or inside FILE TYPE."
+msgstr "%s leidžiama tik INPUT PROGRAM arba FILE TYPE viduje."
+
+#: src/language/command.c:410
+#, c-format
+msgid "%s is allowed only after the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s leidžiama tik nurodžius veikiamąjį duomenų rinkinį, INPUT PROGRAM viduje arba FILE TYPE viduje."
+
+#: src/language/command.c:415
+#, c-format
+msgid "%s is allowed only before the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s leidžiama tik prieš nurodant veikiamąjį duomenų rinkinį, INPUT PROGRAM viduje arba FILE TYPE viduje."
+
+#: src/language/command.c:433 src/language/command.c:436
+#, c-format
+msgid "%s is not allowed inside %s."
+msgstr "%s neleidžiama %s viduje."
+
+#: src/language/command.c:518 src/language/utilities/host.c:130
+#: src/language/utilities/permissions.c:104
+msgid "This command not allowed when the SAFER option is set."
+msgstr "Ši komanda neleidžiama, jei naudojama parinktis SAFER."
+
+#: src/language/command.c:534
+#, c-format
+msgid "Error removing `%s': %s."
+msgstr "Nepavyko pašalinti „%s“: %s."
+
+#: src/language/lexer/lexer.c:276
+#, c-format
+msgid "Subcommand %s may only be specified once."
+msgstr "Pokomandis %s gali būti nurodomas tik vieną kartą."
+
+#: src/language/lexer/lexer.c:284
+#, c-format
+msgid "missing required subcommand %s"
+msgstr "trūksta reikalingo pokomandžio %s"
+
+#: src/language/lexer/lexer.c:302
+msgid "Syntax error at end of input"
+msgstr "Sintaksės klaida įvedimo pabaigoje"
+
+#: src/language/lexer/lexer.c:323 src/language/xforms/select-if.c:60
+#: src/language/stats/autorecode.c:162 src/language/stats/npar.c:414
+#: src/language/data-io/print-space.c:72
+msgid "expecting end of command"
+msgstr "tikėtasi komandos pabaigos"
+
+#: src/language/lexer/lexer.c:494 src/language/lexer/lexer.c:511
+#, c-format
+msgid "expecting `%s'"
+msgstr "tikėtasi „%s“"
+
+#: src/language/lexer/lexer.c:525
+msgid "expecting string"
+msgstr "tikėtasi teksto eilutės"
+
+#: src/language/lexer/lexer.c:539
+msgid "expecting integer"
+msgstr "tikėtasi sveikojo skaičiaus"
+
+#: src/language/lexer/lexer.c:552
+msgid "expecting number"
+msgstr "tikėtasi skaičiaus"
+
+#: src/language/lexer/lexer.c:564
+msgid "expecting identifier"
+msgstr "tikėtasi identifikatoriaus"
+
+#: src/language/lexer/lexer.c:1187
+msgid "Syntax error at end of command"
+msgstr "Sintaksės klaida komandos pabaigoje"
+
+#: src/language/lexer/lexer.c:1196
+#, c-format
+msgid "Syntax error at `%s'"
+msgstr "Sintaksės klaida ties %s."
+
+#: src/language/lexer/lexer.c:1199
+msgid "Syntax error"
+msgstr "Sintaksės klaida"
+
+#: src/language/lexer/lexer.c:1363
+#, c-format
+msgid "String of hex digits has %d characters, which is not a multiple of 2"
+msgstr ""
+
+#: src/language/lexer/lexer.c:1370
+#, c-format
+msgid "`%c' is not a valid hex digit"
+msgstr "„%c“ nėra tinkamas šešioliktainis skaitmuo"
+
+#: src/language/lexer/lexer.c:1375
+#, c-format
+msgid "Unicode string contains %d bytes, which is not in the valid range of 1 to 8 bytes"
+msgstr "Unikodo eilutė turi %d bitus, bet tai nepatenka į tinkamą intervalą nuo 1 iki 8 bitų"
+
+#: src/language/lexer/lexer.c:1381
+#, c-format
+msgid "U+%04X is not a valid Unicode code point"
+msgstr "U+%04X nėra tinkamas unikodo kodo taškas"
+
+#: src/language/lexer/lexer.c:1386
+msgid "Unterminated string constant"
+msgstr ""
+
+#: src/language/lexer/lexer.c:1390
+#, c-format
+msgid "Missing exponent following `%s'"
+msgstr "Trūksta eksponentės po „%s“"
+
+#: src/language/lexer/lexer.c:1395
+msgid "Unexpected `.' in middle of command"
+msgstr "Komandos viduryje netikėtai rastas „.“"
+
+#: src/language/lexer/lexer.c:1401
+#, c-format
+msgid "Bad character %s in input"
+msgstr "Įvestyje yra neleistinas rašmuo %s"
+
+#: src/language/lexer/lexer.c:1495
+#, c-format
+msgid "Opening `%s': %s."
+msgstr "Atveriama „%s“: %s."
+
+#: src/language/lexer/lexer.c:1525
+#, c-format
+msgid "Error reading `%s': %s."
+msgstr "Klaida skaitant „%s“: %s."
+
+#: src/language/lexer/lexer.c:1539
+#, c-format
+msgid "Error closing `%s': %s."
+msgstr "Klaida užveriant „%s“: %s."
+
+#: src/language/lexer/format-parser.c:79
+msgid "expecting valid format specifier"
+msgstr ""
+
+#: src/language/lexer/format-parser.c:118
+#: src/language/lexer/format-parser.c:138
+#: src/language/data-io/placement-parser.c:225
+#, c-format
+msgid "Unknown format type `%s'."
+msgstr "Nežinomas formato tipas „%s“."
+
+#: src/language/lexer/format-parser.c:133
+msgid "expecting format type"
+msgstr "tikėtasi formato tipo"
+
+#: src/language/lexer/value-parser.c:65
+#, c-format
+msgid "Low end of range (%g) is below high end (%g).  The range will be treated as reversed."
+msgstr ""
+
+#: src/language/lexer/value-parser.c:73
+#, c-format
+msgid "Ends of range are equal (%g)."
+msgstr "Srities galai yra vienodi (%g)."
+
+#: src/language/lexer/value-parser.c:81
+msgid "LO or LOWEST must be part of a range."
+msgstr "LO arba LOWEST turi būti srities dalis."
+
+#: src/language/lexer/value-parser.c:117
+msgid "System-missing value is not valid here."
+msgstr "Sisteminė praleista reikšmė čia negalioja."
+
+#: src/language/lexer/value-parser.c:125
+msgid "expecting number or data string"
+msgstr "tikėtasi skaičiaus arba duomenų eilutės"
+
+#: src/language/lexer/variable-parser.c:67
+msgid "expecting variable name"
+msgstr "tikimasi kintamojo vardo"
+
+#: src/language/lexer/variable-parser.c:77
+#, c-format
+msgid "%s is not a variable name."
+msgstr "%s nėra kintamojo vardas."
+
+#: src/language/lexer/variable-parser.c:180
+#, c-format
+msgid "%s is not a numeric variable.  It will not be included in the variable list."
+msgstr "%s nėra skaitmeninis kintamasis. Jis nebus įtrauktas į kintamųjų sąrašą."
+
+#: src/language/lexer/variable-parser.c:183
+#, c-format
+msgid "%s is not a string variable.  It will not be included in the variable list."
+msgstr "%s nėra teksto eilutės kintamasis. Jis nebus įtrauktas į kintamųjų sąrašą."
+
+#: src/language/lexer/variable-parser.c:187
+#, c-format
+msgid "Scratch variables (such as %s) are not allowed here."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:191
+#, c-format
+msgid "%s and %s are not the same type.  All variables in this variable list must be of the same type.  %s will be omitted from the list."
+msgstr "%s ir %s nėra tas pats tipas. Visi šio sąrašo kintamieji turi būti to paties tipo. %s bus neįtrauktas į sąrašą."
+
+#: src/language/lexer/variable-parser.c:197
+#, c-format
+msgid "%s and %s are string variables with different widths.  All variables in this variable list must have the same width.  %s will be omitted from the list."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:202
+#: src/language/lexer/variable-parser.c:404
+#, c-format
+msgid "Variable %s appears twice in variable list."
+msgstr "Kintamasis %s kintamųjų sąraše pasikartoja du kartus."
+
+#: src/language/lexer/variable-parser.c:315
+#, c-format
+msgid "%s TO %s is not valid syntax since %s precedes %s in the dictionary."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:323
+#, c-format
+msgid "When using the TO keyword to specify several variables, both variables must be from the same variable dictionaries, of either ordinary, scratch, or system variables.  %s is a %s variable, whereas %s is %s."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:381
+#, c-format
+msgid "`%s' cannot be used with TO because it does not end in a digit."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:389
+#, c-format
+msgid "Numeric suffix on `%s' is larger than supported with TO."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:465
+msgid "Scratch variables not allowed here."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:497
+msgid "Prefixes don't match in use of TO convention."
+msgstr ""
+
+#: src/language/lexer/variable-parser.c:502
+msgid "Bad bounds in use of TO convention."
+msgstr ""
+
+#: src/language/xforms/compute.c:149 src/language/xforms/compute.c:204
+#, c-format
+msgid "When executing COMPUTE: SYSMIS is not a valid value as an index into vector %s."
+msgstr ""
+
+#: src/language/xforms/compute.c:153 src/language/xforms/compute.c:211
+#, c-format
+msgid "When executing COMPUTE: %g is not a valid value as an index into vector %s."
+msgstr ""
+
+#: src/language/xforms/compute.c:355
+#, c-format
+msgid "There is no vector named %s."
+msgstr "Tokio vektoriaus vardu %s nėra"
+
+#: src/language/xforms/count.c:125
+msgid "Destination cannot be a string variable."
+msgstr "Paskirtis negali būti teksto eilutės kintamasis."
+
+#: src/language/xforms/sample.c:76
+msgid "The sampling factor must be between 0 and 1 exclusive."
+msgstr ""
+
+#: src/language/xforms/sample.c:96
+#, c-format
+msgid "Cannot sample %d observations from a population of %d."
+msgstr ""
+
+#: src/language/xforms/recode.c:255
+msgid "Inconsistent target variable types.  Target variables must be all numeric or all string."
+msgstr ""
+
+#: src/language/xforms/recode.c:276
+msgid "CONVERT requires string input values and numeric output values."
+msgstr ""
+
+#: src/language/xforms/recode.c:333
+msgid "THRU is not allowed with string variables."
+msgstr ""
+
+#: src/language/xforms/recode.c:416
+msgid "expecting output value"
+msgstr "tikėtasi išvedimo reikšmės"
+
+#: src/language/xforms/recode.c:473
+#, c-format
+msgid "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same number of variables as source and target variables."
+msgstr ""
+
+#: src/language/xforms/recode.c:488
+#, c-format
+msgid "There is no variable named %s.  (All string variables specified on INTO must already exist.  Use the STRING command to create a string variable.)"
+msgstr ""
+
+#: src/language/xforms/recode.c:504
+#, c-format
+msgid "INTO is required with %s input values and %s output values."
+msgstr ""
+
+#: src/language/xforms/recode.c:517
+#, c-format
+msgid "Type mismatch.  Cannot store %s data in %s variable %s."
+msgstr ""
+
+#: src/language/xforms/select-if.c:100
+msgid "Syntax error expecting OFF or BY.  Turning off case filtering."
+msgstr ""
+
+#: src/language/xforms/select-if.c:115
+msgid "The filter variable must be numeric."
+msgstr "Filtro kintamasis privalo būti skaitmeninis."
+
+#: src/language/xforms/select-if.c:121
+msgid "The filter variable may not be scratch."
+msgstr ""
+
+#: src/language/control/control-stack.c:31
+#, c-format
+msgid "%s without %s."
+msgstr "%s be %s."
+
+#: src/language/control/control-stack.c:59
+#, c-format
+msgid "This command must appear inside %s...%s, without intermediate %s...%s."
+msgstr ""
+
+#: src/language/control/control-stack.c:76
+#, c-format
+msgid "This command cannot appear outside %s...%s."
+msgstr "Ši komanda negali būti naudojama už %s... %s."
+
+#: src/language/control/do-if.c:177
+msgid "This command may not follow ELSE in DO IF...END IF."
+msgstr ""
+
+#: src/language/control/loop.c:214
+msgid "Only one index clause may be specified."
+msgstr ""
+
+#: src/language/control/repeat.c:115
+#, c-format
+msgid "Dummy variable name `%s' hides dictionary variable `%s'."
+msgstr ""
+
+#: src/language/control/repeat.c:119
+#, c-format
+msgid "Dummy variable name `%s' is given twice."
+msgstr ""
+
+#: src/language/control/repeat.c:162
+#, c-format
+msgid "Dummy variable `%s' had %zu substitutions, so `%s' must also, but %zu were specified."
+msgstr ""
+
+#: src/language/control/repeat.c:366
+msgid "Ranges may only have integer bounds."
+msgstr "Sričių ribos gali būti tik sveikieji skaičiai."
+
+#: src/language/control/repeat.c:380
+#, c-format
+msgid "%ld TO %ld is an invalid range."
+msgstr "Netinkama sritis %ld TO %ld."
+
+#: src/language/control/repeat.c:414
+msgid "String expected."
+msgstr "Tikėtasi teksto eilutės."
+
+#: src/language/control/repeat.c:431
+msgid "No matching DO REPEAT."
+msgstr ""
+
+#: src/language/control/temporary.c:45
+msgid "This command may only appear once between procedures and procedure-like commands."
+msgstr ""
+
+#: src/language/dictionary/attributes.c:104
+msgid "Attribute array index must be between 1 and 65535."
+msgstr ""
+
+#: src/language/dictionary/attributes.c:200
+#: src/language/data-io/get-data.c:324 src/language/data-io/get-data.c:362
+#: src/language/data-io/get.c:99 src/language/data-io/save-translate.c:118
+#: src/language/data-io/save-translate.c:135
+#: src/language/data-io/save-translate.c:148
+#: src/language/data-io/save-translate.c:196
+#: src/language/data-io/save-translate.c:210
+#: src/language/data-io/save-translate.c:228 src/language/data-io/save.c:216
+#: src/language/data-io/save.c:231 src/language/data-io/save.c:259
+#, c-format
+msgid "expecting %s or %s"
+msgstr "tikėtasi %s arba %s"
+
+#: src/language/dictionary/apply-dictionary.c:74
+#, c-format
+msgid "Variable %s is %s in target file, but %s in source file."
+msgstr ""
+
+#: src/language/dictionary/apply-dictionary.c:110
+msgid "No matching variables found between the source and target files."
+msgstr ""
+
+#: src/language/dictionary/delete-variables.c:40
+msgid "DELETE VARIABLES may not be used after TEMPORARY.  Temporary transformations will be made permanent."
+msgstr ""
+
+#: src/language/dictionary/delete-variables.c:47
+msgid "DELETE VARIABLES may not be used to delete all variables from the active dataset dictionary.  Use NEW FILE instead."
+msgstr ""
+
+#: src/language/dictionary/formats.c:87
+msgid "`(' expected after variable list."
+msgstr "už kintamųjų sąrašo tikėtasi „(“."
+
+#: src/language/dictionary/formats.c:97 src/language/dictionary/numeric.c:75
+msgid "`)' expected after output format."
+msgstr "prieš rezultatų formatą tikėtasi „)“."
+
+#: src/language/dictionary/missing-values.c:70
+#, c-format
+msgid "Cannot mix numeric variables (e.g. %s) and string variables (e.g. %s) within a single list."
+msgstr "Tame pačiame sąraše negali būti kartu skaitmeninių kintamųjų (pvz., %s) ir teksto eilučių (pvz., %s)."
+
+#: src/language/dictionary/missing-values.c:119
+#, c-format
+msgid "Truncating missing value to maximum acceptable length (%d bytes)."
+msgstr ""
+
+#: src/language/dictionary/missing-values.c:142
+#, c-format
+msgid "Missing values provided are too long to assign to variable of width %d."
+msgstr ""
+
+#: src/language/dictionary/modify-variables.c:91
+msgid "MODIFY VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
+msgstr ""
+
+#: src/language/dictionary/modify-variables.c:113
+#: src/language/dictionary/modify-variables.c:177
+#: src/language/data-io/inpt-pgm.c:280
+#, c-format
+msgid "%s subcommand may be given at most once."
+msgstr "Pokomandį %s galima pateikti ne daugiau kaip vieną kartą."
+
+#: src/language/dictionary/modify-variables.c:136
+msgid "Cannot specify ALL after specifying a set of variables."
+msgstr "Nurodžius kintamųjų rinkinį, negalima nurodyti ALL (visų)."
+
+#: src/language/dictionary/modify-variables.c:146
+#: src/language/dictionary/modify-variables.c:190
+#, c-format
+msgid "`(' expected on %s subcommand."
+msgstr "pokomandyje %s tikėtasi „(“."
+
+#: src/language/dictionary/modify-variables.c:158
+msgid "`)' expected following variable names on REORDER subcommand."
+msgstr ""
+
+#: src/language/dictionary/modify-variables.c:199
+msgid "`=' expected between lists of new and old variable names on RENAME subcommand."
+msgstr ""
+
+#: src/language/dictionary/modify-variables.c:208
+#: src/language/dictionary/rename-variables.c:77
+#, c-format
+msgid "Differing number of variables in old name list (%zu) and in new name list (%zu)."
+msgstr ""
+
+#: src/language/dictionary/modify-variables.c:219
+msgid "`)' expected after variable lists on RENAME subcommand."
+msgstr "RENAME pokomandyje po kintamųjų sąrašo tikėtasi „)“."
+
+#: src/language/dictionary/modify-variables.c:234
+msgid "KEEP subcommand may be given at most once.  It may not be given in conjunction with the DROP subcommand."
+msgstr "Pokomandis KEEP gali būti pateikiamas tik vieną kartą. Jis negali būti pateikiamas kartu su pokomandžiu DROP."
+
+#: src/language/dictionary/modify-variables.c:277
+msgid "DROP subcommand may be given at most once.  It may not be given in conjunction with the KEEP subcommand."
+msgstr "Pokomandis DROP gali būti pateikiamas tik vieną kartą. Jis negali būti pateikiamas kartu su pokomandžiu KEEP."
+
+#: src/language/dictionary/modify-variables.c:303
+#, c-format
+msgid "Unrecognized subcommand name `%s'."
+msgstr "Neatpažintas pokomandžio vardas „%s“."
+
+#: src/language/dictionary/modify-variables.c:305
+msgid "Subcommand name expected."
+msgstr "Tikėtasi pokomandžio vardo."
+
+#: src/language/dictionary/modify-variables.c:313
+msgid "`/' or `.' expected."
+msgstr "Tikėtasi „/“ arba „.“."
+
+#: src/language/dictionary/mrsets.c:116
+#, c-format
+msgid "VARIABLES specified only variable %s on %s, but at least two variables are required."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:149
+msgid "Numeric VALUE must be an integer."
+msgstr "Skaitmeninė reikšmė (VALUE) turi būti sveikasis skaičius."
+
+#: src/language/dictionary/mrsets.c:208 src/language/dictionary/mrsets.c:214
+#: src/language/dictionary/mrsets.c:224
+#, c-format
+msgid "Required %s specification missing from %s subcommand."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:232 src/language/dictionary/mrsets.c:270
+#, c-format
+msgid "MDGROUP subcommand for group %s specifies a string VALUE, but the variables specified for this group are numeric."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:256
+#, c-format
+msgid "VALUE string on MDGROUP subcommand for group %s is %d bytes long, but it must be no longer than the narrowest variable in the group, which is %s with a width of %d bytes."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:282
+#, c-format
+msgid "MDGROUP subcommand for group %s specifies LABELSOURCE=VARLABEL but not CATEGORYLABELS=COUNTEDVALUES.  Ignoring LABELSOURCE."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:288
+#, c-format
+msgid "MDGROUP subcommand for group %s specifies both LABEL and LABELSOURCE, but only one of these subcommands may be used at a time.  Ignoring LABELSOURCE."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:328
+#, c-format
+msgid "Variables %s and %s specified as part of multiple dichotomy group %s have the same variable label.  Categories represented by these variables will not be distinguishable in output."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:358
+#, c-format
+msgid "Variable %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) has no value label for its counted value.  This category will not be distinguishable in output."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:371
+#, c-format
+msgid "Variables %s and %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) have the same value label for the the group's counted value.  These categories will not be distinguishable in output."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:428
+#, c-format
+msgid "Variables specified on MCGROUP should have the same categories, but %s and %s (and possibly others) in multiple category group %s have different value labels for value %s."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:486
+#, c-format
+msgid "No multiple response set named %s."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:540
+msgid "The active dataset dictionary does not contain any multiple response sets."
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:550
+msgid "Multiple Response Sets"
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:551 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:833
+msgid "Name"
+msgstr "Vardas"
+
+#: src/language/dictionary/mrsets.c:552 src/ui/gui/variable-info.ui:8
+msgid "Variables"
+msgstr "Kintamieji"
+
+#: src/language/dictionary/mrsets.c:553
+msgid "Details"
+msgstr "išsamiau"
+
+#: src/language/dictionary/mrsets.c:567
+msgid "Multiple dichotomy set"
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:568
+msgid "Multiple category set"
+msgstr ""
+
+#: src/language/dictionary/mrsets.c:570
+#: src/language/dictionary/split-file.c:84
+#: src/language/dictionary/sys-file-info.c:336
+#: src/language/dictionary/sys-file-info.c:575
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/compute.ui:467 src/ui/gui/crosstabs.ui:292
+msgid "Label"
+msgstr "Etiketė"
+
+#: src/language/dictionary/mrsets.c:574
+msgid "Label source"
+msgstr "Etikečių šaltinis"
+
+#: src/language/dictionary/mrsets.c:576
+msgid "First variable label among variables"
+msgstr "Pirmoji kintamojo etiketė tarp kintamųjų"
+
+#: src/language/dictionary/mrsets.c:577
+msgid "Provided by user"
+msgstr "Naudotojo pateiktas"
+
+#: src/language/dictionary/mrsets.c:578
+msgid "Counted value"
+msgstr "Apskaičiuota reikšmė"
+
+#: src/language/dictionary/mrsets.c:590
+msgid "Category label source"
+msgstr "Kategorijos etiketės šaltinis"
+
+#: src/language/dictionary/mrsets.c:592
+msgid "Variable labels"
+msgstr "Kintamųjų etiketės"
+
+#: src/language/dictionary/mrsets.c:593
+msgid "Value labels of counted value"
+msgstr ""
+
+#: src/language/dictionary/numeric.c:68
+#, c-format
+msgid "Format type %s may not be used with a numeric variable."
+msgstr "Formato %s tipas negali būti naudojamas su skaitmeniniu kintamuoju."
+
+#: src/language/dictionary/numeric.c:87 src/language/dictionary/numeric.c:157
+#, c-format
+msgid "There is already a variable named %s."
+msgstr "Kintamasis tokiu vardu %s jau yra."
+
+#: src/language/dictionary/numeric.c:142
+#, c-format
+msgid "Format type %s may not be used with a string variable."
+msgstr "Formato %s tipas negali būti naudojamas su teksto eilutės kintamuoju."
+
+#: src/language/dictionary/rename-variables.c:48
+msgid "RENAME VARS may not be used after TEMPORARY.  Temporary transformations will be made permanent."
+msgstr ""
+
+#: src/language/dictionary/rename-variables.c:58
+msgid "`(' expected."
+msgstr "tikėtasi „(“."
+
+#: src/language/dictionary/rename-variables.c:66
+msgid "`=' expected between lists of new and old variable names."
+msgstr "Tarp senų ir naujų kintamųjų vardų sąrašų tikėtasi „=“."
+
+#: src/language/dictionary/rename-variables.c:88
+msgid "`)' expected after variable names."
+msgstr "Po kintamųjų vardų tikėtasi „)“."
+
+#: src/language/dictionary/rename-variables.c:98
+#, c-format
+msgid "Renaming would duplicate variable name %s."
+msgstr "Pervadinama nekartojant kintamojo vardo %s."
+
+#: src/language/dictionary/split-file.c:83
+#: src/language/dictionary/sys-file-info.c:421
+#: src/language/dictionary/sys-file-info.c:574
+#: src/language/stats/cochran.c:170 src/language/stats/reliability.c:753
+#: src/language/stats/reliability.c:764 src/language/stats/crosstabs.q:1234
+#: src/language/stats/crosstabs.q:1261 src/language/stats/crosstabs.q:1284
+#: src/language/stats/crosstabs.q:1309 src/language/stats/examine.q:1840
+#: src/language/stats/frequencies.q:821
+msgid "Value"
+msgstr "Reikšmė"
+
+#: src/language/dictionary/sys-file-info.c:94
+msgid "File:"
+msgstr "Rinkmena:"
+
+#: src/language/dictionary/sys-file-info.c:96 src/ui/gui/compute.ui:405
+#: src/ui/gui/recode.ui:859
+msgid "Label:"
+msgstr "Etiketė:"
+
+#: src/language/dictionary/sys-file-info.c:100
+msgid "No label."
+msgstr "Be etiketės."
+
+#: src/language/dictionary/sys-file-info.c:103
+msgid "Created:"
+msgstr "Sukurta:"
+
+#: src/language/dictionary/sys-file-info.c:106
+msgid "Integer Format:"
+msgstr "Sveikojo skaičiaus formatas:"
+
+#: src/language/dictionary/sys-file-info.c:108
+msgid "Big Endian"
+msgstr "Mažėjantys baitai"
+
+#: src/language/dictionary/sys-file-info.c:109
+msgid "Little Endian"
+msgstr "Didėjantys baitai"
+
+#: src/language/dictionary/sys-file-info.c:110
+#: src/language/dictionary/sys-file-info.c:118
+#: src/language/dictionary/sys-file-info.c:123
+#: src/language/dictionary/sys-file-info.c:142
+msgid "Unknown"
+msgstr "Nežinoma"
+
+#: src/language/dictionary/sys-file-info.c:111
+msgid "Real Format:"
+msgstr ""
+
+#: src/language/dictionary/sys-file-info.c:113
+msgid "IEEE 754 LE."
+msgstr "IEEE 754 didėjantys baitai."
+
+#: src/language/dictionary/sys-file-info.c:114
+msgid "IEEE 754 BE."
+msgstr "IEEE 754 mažėjantys baitai."
+
+#: src/language/dictionary/sys-file-info.c:115
+msgid "VAX D."
+msgstr "VAX D."
+
+#: src/language/dictionary/sys-file-info.c:116
+msgid "VAX G."
+msgstr "VAX G."
+
+#: src/language/dictionary/sys-file-info.c:117
+msgid "IBM 390 Hex Long."
+msgstr ""
+
+#: src/language/dictionary/sys-file-info.c:119 src/ui/gui/descriptives.ui:85
+#: src/ui/gui/factor.ui:181 src/ui/gui/recode.ui:960
+msgid "Variables:"
+msgstr "Kintamieji:"
+
+#: src/language/dictionary/sys-file-info.c:121
+msgid "Cases:"
+msgstr "Atvejai:"
+
+#: src/language/dictionary/sys-file-info.c:126
+msgid "Type:"
+msgstr "Tipas:"
+
+#: src/language/dictionary/sys-file-info.c:127
+#: src/ui/gui/psppire-data-window.c:509
+msgid "System File"
+msgstr "Sisteminė rinkmena"
+
+#: src/language/dictionary/sys-file-info.c:128
+msgid "Weight:"
+msgstr "Svoris:"
+
+#: src/language/dictionary/sys-file-info.c:133
+msgid "Not weighted."
+msgstr "Nesveriama."
+
+#: src/language/dictionary/sys-file-info.c:135
+msgid "Mode:"
+msgstr "Veiksena:"
+
+#: src/language/dictionary/sys-file-info.c:137
+#, c-format
+msgid "Compression %s."
+msgstr "Glaudinimas %s."
+
+#: src/language/dictionary/sys-file-info.c:137
+msgid "on"
+msgstr "įjungta"
+
+#: src/language/dictionary/sys-file-info.c:137
+msgid "off"
+msgstr "išjungta"
+
+#: src/language/dictionary/sys-file-info.c:140
+msgid "Charset:"
+msgstr "Ženklų rinkinys:"
+
+#: src/language/dictionary/sys-file-info.c:150
+#: src/language/dictionary/sys-file-info.c:336
+msgid "Description"
+msgstr "Aprašas"
+
+#: src/language/dictionary/sys-file-info.c:151
+#: src/language/dictionary/sys-file-info.c:338
+#: src/language/dictionary/sys-file-info.c:645
+msgid "Position"
+msgstr "Pozicija"
+
+#: src/language/dictionary/sys-file-info.c:198
+msgid "The active dataset does not have a file label."
+msgstr "Veikiamasis duomenų rinkinys neturi rinkmenos etiketės."
+
+#: src/language/dictionary/sys-file-info.c:200
+#, c-format
+msgid "File label: %s"
+msgstr "Rinkmenos etiketė: %s"
+
+#: src/language/dictionary/sys-file-info.c:274
+msgid "No variables to display."
+msgstr "Nėra rodytinų kintamųjų."
+
+#: src/language/dictionary/sys-file-info.c:288
+msgid "Macros not supported."
+msgstr ""
+
+#: src/language/dictionary/sys-file-info.c:297
+msgid "The active dataset dictionary does not contain any documents."
+msgstr "Veikiamojo duomenų rinkinio žodynas neturi jokių dokumentų."
+
+#: src/language/dictionary/sys-file-info.c:304
+msgid "Documents in the active dataset:"
+msgstr "Veikiamojo duomenų rinkinio dokumentai:"
+
+#: src/language/dictionary/sys-file-info.c:420
+msgid "Attribute"
+msgstr "Atributas"
+
+#: src/language/dictionary/sys-file-info.c:476
+#, c-format
+msgid "Format: %s"
+msgstr "Formatas: %s"
+
+#: src/language/dictionary/sys-file-info.c:483
+#, c-format
+msgid "Print Format: %s"
+msgstr "Spausdinimo formatas: %s"
+
+#: src/language/dictionary/sys-file-info.c:487
+#, c-format
+msgid "Write Format: %s"
+msgstr "Įrašymo formatas: %s"
+
+#: src/language/dictionary/sys-file-info.c:500
+#, c-format
+msgid "Measure: %s"
+msgstr "Matavimo skalė: %s"
+
+#: src/language/dictionary/sys-file-info.c:501
+#: src/ui/gui/psppire-var-sheet.c:111
+msgid "Nominal"
+msgstr "Pavadinimų"
+
+#: src/language/dictionary/sys-file-info.c:502
+#: src/ui/gui/psppire-var-sheet.c:112
+msgid "Ordinal"
+msgstr "Rangų"
+
+#: src/language/dictionary/sys-file-info.c:503
+#: src/ui/gui/psppire-var-sheet.c:113
+msgid "Scale"
+msgstr "Intervalų"
+
+#: src/language/dictionary/sys-file-info.c:506
+#, c-format
+msgid "Display Alignment: %s"
+msgstr "Rodoma lygiuotė: %s"
+
+#: src/language/dictionary/sys-file-info.c:507
+#: src/ui/gui/psppire-var-sheet.c:104
+msgid "Left"
+msgstr "Kairinė"
+
+#: src/language/dictionary/sys-file-info.c:508
+#: src/ui/gui/psppire-var-sheet.c:106
+msgid "Center"
+msgstr "Centrinė"
+
+#: src/language/dictionary/sys-file-info.c:509
+#: src/ui/gui/psppire-var-sheet.c:105
+msgid "Right"
+msgstr "Dešininė"
+
+#: src/language/dictionary/sys-file-info.c:512
+#, c-format
+msgid "Display Width: %d"
+msgstr "Rodomas plotis: %d"
+
+#: src/language/dictionary/sys-file-info.c:526
+msgid "Missing Values: "
+msgstr "Praleistos reikšmės: "
+
+#: src/language/dictionary/sys-file-info.c:625
+msgid "No vectors defined."
+msgstr "Neapibrėžtas joks vektorius"
+
+#: src/language/dictionary/sys-file-info.c:644
+msgid "Vector"
+msgstr "Vektorius"
+
+#: src/language/dictionary/sys-file-info.c:647
+msgid "Print Format"
+msgstr "Spausdinimo formatas"
+
+#: src/language/dictionary/value-labels.c:154
+#, c-format
+msgid "Truncating value label to %d bytes."
+msgstr "Reikmės etiketė sutrumpinama iki %d bitų."
+
+#: src/language/dictionary/vector.c:65
+#, c-format
+msgid "A vector named %s already exists."
+msgstr "Vektorius tokiu vardu %s jau yra."
+
+#: src/language/dictionary/vector.c:73
+#, c-format
+msgid "Vector name %s is given twice."
+msgstr "Vektoriaus vardas %s pateiktas du kartus."
+
+#: src/language/dictionary/vector.c:97
+msgid "A slash must separate each vector specification in VECTOR's long form."
+msgstr ""
+
+#: src/language/dictionary/vector.c:130
+msgid "Vectors must have at least one element."
+msgstr "Vektoriai privalo turėti bent vieną elementą."
+
+#: src/language/dictionary/vector.c:151
+msgid "expecting vector length"
+msgstr "tikimasi vektoriaus ilgio"
+
+#: src/language/dictionary/vector.c:171
+#, c-format
+msgid "%s is an existing variable name."
+msgstr "%s yra jau esamo kintamojo vardas."
+
+#: src/language/dictionary/variable-display.c:120
+msgid "Variable display width must be a positive integer."
+msgstr "Kintamojo rodomas plotis turi būti sveikasis teigiamas skaičius."
+
+#: src/language/dictionary/weight.c:49
+msgid "The weighting variable must be numeric."
+msgstr "Svėrimo kintamasis turi būti skaitmeninis."
+
+#: src/language/dictionary/weight.c:54
+msgid "The weighting variable may not be scratch."
+msgstr "Svėrimo kintamasis negali būti tuščias."
+
+#: src/language/tests/moments-test.c:50
+msgid "expecting weight value"
+msgstr "tikėtasi svorio reikšmės"
+
+#: src/language/utilities/cd.c:45
+#, c-format
+msgid "Cannot change directory to %s:  %s "
+msgstr "Nepavyksta pakeisti katalogo į %s: %s "
+
+#: src/language/utilities/date.c:33
+msgid "Only USE ALL is currently implemented."
+msgstr "Šiuo metu realizuota tik USE ALL."
+
+#: src/language/utilities/host.c:87
+#, c-format
+msgid "Couldn't fork: %s."
+msgstr ""
+
+#: src/language/utilities/host.c:102
+msgid "Interactive shell not supported on this platform."
+msgstr ""
+
+#: src/language/utilities/host.c:114
+msgid "Command shell not supported on this platform."
+msgstr "Komandų apvalkalas šioje platformoje nėra palaikomas."
+
+#: src/language/utilities/host.c:120
+#, c-format
+msgid "Error executing command: %s."
+msgstr "Komandos vykdymo klaida: %s."
+
+#: src/language/utilities/title.c:97
+#, c-format
+msgid "   (Entered %s)"
+msgstr "   (įvesta %s)"
+
+#: src/language/utilities/include.c:65
+msgid "expecting file name"
+msgstr "tikimasi rinkmenos vardo"
+
+#: src/language/utilities/include.c:75
+#, c-format
+msgid "Can't find `%s' in include file search path."
+msgstr ""
+
+#: src/language/utilities/include.c:109
+#, c-format
+msgid "expecting %s, %s, or %s after %s"
+msgstr "tikėtasi %s, %s arba %s po %s"
+
+#: src/language/utilities/include.c:127 src/language/utilities/include.c:145
+#, c-format
+msgid "expecting %s or %s after %s"
+msgstr "tikėtasi %s arba %s po %s"
+
+#: src/language/utilities/permissions.c:78
+#, c-format
+msgid "Expecting %s or %s."
+msgstr "Tikimasi %s arba %s."
+
+#: src/language/utilities/permissions.c:113
+#, c-format
+msgid "Cannot stat %s: %s"
+msgstr ""
+
+#: src/language/utilities/permissions.c:127
+#, c-format
+msgid "Cannot change mode of %s: %s"
+msgstr "Nepavyksta pakeisti %s veiksenos: %s"
+
+#: src/language/stats/aggregate.c:95
+msgid "Sum of values"
+msgstr "Reikšmių suma"
+
+#: src/language/stats/aggregate.c:96
+msgid "Mean average"
+msgstr "Bendras vidurkis"
+
+#: src/language/stats/aggregate.c:97
+msgid "Median average"
+msgstr "Medianos vidurkis"
+
+#: src/language/stats/aggregate.c:98 src/ui/gui/descriptives-dialog.c:40
+#: src/ui/gui/frequencies-dialog.c:41
+msgid "Standard deviation"
+msgstr "Standartinis nuokrypis"
+
+#: src/language/stats/aggregate.c:99
+msgid "Maximum value"
+msgstr "Didžiausia reikšmė"
+
+#: src/language/stats/aggregate.c:100
+msgid "Minimum value"
+msgstr "Mažiausia reikšmė"
+
+#: src/language/stats/aggregate.c:101
+msgid "Percentage greater than"
+msgstr "Procentinė dalis didesnė už"
+
+#: src/language/stats/aggregate.c:102
+msgid "Percentage less than"
+msgstr "Procentinė dalis mažesnė už"
+
+#: src/language/stats/aggregate.c:103
+msgid "Percentage included in range"
+msgstr "Procentinė dalis įtraukta į sritį"
+
+#: src/language/stats/aggregate.c:104
+msgid "Percentage excluded from range"
+msgstr "Procentinė dalis neįtraukta į sritį"
+
+#: src/language/stats/aggregate.c:105
+msgid "Fraction greater than"
+msgstr "Trupmeninė dalis didesnė už"
+
+#: src/language/stats/aggregate.c:106
+msgid "Fraction less than"
+msgstr "Trupmeninė dalis mažesnė už "
+
+#: src/language/stats/aggregate.c:107
+msgid "Fraction included in range"
+msgstr "Trupmeninė dalis įtraukta į sritį"
+
+#: src/language/stats/aggregate.c:108
+msgid "Fraction excluded from range"
+msgstr "Trupmeninė dalis neįtraukta į sritį"
+
+#: src/language/stats/aggregate.c:109
+msgid "Number of cases"
+msgstr "Atvejų skaičius"
+
+#: src/language/stats/aggregate.c:110
+msgid "Number of cases (unweighted)"
+msgstr "Atvejų skaičius (nesveriant)"
+
+#: src/language/stats/aggregate.c:111
+msgid "Number of missing values"
+msgstr "Praleistų reikšmių skaičius"
+
+#: src/language/stats/aggregate.c:112
+msgid "Number of missing values (unweighted)"
+msgstr "Praleistų reikšmių skaičius (nesveriant)"
+
+#: src/language/stats/aggregate.c:113
+msgid "First non-missing value"
+msgstr "Pirmoji nepraleista reikšmė"
+
+#: src/language/stats/aggregate.c:114
+msgid "Last non-missing value"
+msgstr "Paskutinė nepraleista reikšmė"
+
+#: src/language/stats/aggregate.c:226 src/language/data-io/get-data.c:473
+#, c-format
+msgid "expecting %s"
+msgstr "tikėtasi %s"
+
+#: src/language/stats/aggregate.c:257
+msgid "When PRESORTED is specified, specifying sorting directions with (A) or (D) has no effect.  Output data will be sorted the same way as the input data."
+msgstr ""
+
+#: src/language/stats/aggregate.c:447
+msgid "expecting aggregation function"
+msgstr "tikimasi duomenų agregavimo funkcijos"
+
+#: src/language/stats/aggregate.c:459
+#, c-format
+msgid "Unknown aggregation function %s."
+msgstr "Nežinoma agregavimo funkcija %s"
+
+#: src/language/stats/aggregate.c:513
+#, c-format
+msgid "Missing argument %zu to %s."
+msgstr "Argumento %zu reikalauja %s."
+
+#: src/language/stats/aggregate.c:522
+#, c-format
+msgid "Arguments to %s must be of same type as source variables."
+msgstr "%s argumentas turi būti to paties tipo kaip ir šaltinio kintamasis."
+
+#: src/language/stats/aggregate.c:541
+#, c-format
+msgid "Number of source variables (%zu) does not match number of target variables (%zu)."
+msgstr "Šaltinio kintamųjų skaičius (%zu) neatitinka paskirties kintamųjų skaičiaus (%zu)."
+
+#: src/language/stats/aggregate.c:557
+#, c-format
+msgid "The value arguments passed to the %s function are out-of-order.  They will be treated as if they had been specified in the correct order."
+msgstr ""
+
+#: src/language/stats/aggregate.c:631
+#, c-format
+msgid "Variable name %s is not unique within the aggregate file dictionary, which contains the aggregate variables and the break variables."
+msgstr ""
+
+#: src/language/stats/autorecode.c:128
+#, c-format
+msgid "Source variable count (%zu) does not match target variable count (%zu)."
+msgstr ""
+
+#: src/language/stats/autorecode.c:140
+#, c-format
+msgid "Target variable %s duplicates existing variable %s."
+msgstr ""
+
+#: src/language/stats/binomial.c:136
+#, c-format
+msgid "Variable %s is not dichotomous"
+msgstr "Kintamasis %s nėra dvireikšmis"
+
+#: src/language/stats/binomial.c:187 src/ui/gui/binomial.ui:13
+msgid "Binomial Test"
+msgstr "Binominis kriterijus"
+
+#: src/language/stats/binomial.c:217
+msgid "Group1"
+msgstr "Pirma grupė"
+
+#: src/language/stats/binomial.c:218
+msgid "Group2"
+msgstr "Antra grupė"
+
+#: src/language/stats/binomial.c:219 src/language/stats/chisquare.c:177
+#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1460
+#: src/language/stats/kruskal-wallis.c:292
+#: src/language/stats/mann-whitney.c:188 src/language/stats/oneway.c:616
+#: src/language/stats/oneway.c:786 src/language/stats/reliability.c:533
+#: src/language/stats/sign.c:95 src/language/stats/wilcoxon.c:255
+#: src/ui/gui/crosstabs-dialog.c:59 src/language/stats/crosstabs.q:832
+#: src/language/stats/crosstabs.q:1176 src/language/stats/crosstabs.q:1560
+#: src/language/stats/examine.q:1104 src/language/stats/frequencies.q:879
+#: src/language/stats/regression.q:293
+msgid "Total"
+msgstr "Iš viso"
+
+#: src/language/stats/binomial.c:252 src/language/stats/chisquare.c:199
+#: src/language/stats/crosstabs.q:1259 src/language/stats/crosstabs.q:1306
+msgid "Category"
+msgstr "Kategorija"
+
+#: src/language/stats/binomial.c:253 src/language/stats/cochran.c:211
+#: src/language/stats/correlations.c:120 src/language/stats/correlations.c:228
+#: src/language/stats/friedman.c:275 src/language/stats/kruskal-wallis.c:257
+#: src/language/stats/mann-whitney.c:190 src/language/stats/npar-summary.c:123
+#: src/language/stats/oneway.c:686 src/language/stats/reliability.c:536
+#: src/language/stats/sign.c:74 src/language/stats/wilcoxon.c:238
+#: src/language/stats/crosstabs.q:839 src/language/stats/examine.q:1175
+#: src/language/stats/frequencies.q:1041 src/language/stats/t-test.q:509
+#: src/language/stats/t-test.q:529 src/language/stats/t-test.q:629
+#: src/language/stats/t-test.q:1105
+msgid "N"
+msgstr "N"
+
+#: src/language/stats/binomial.c:254
+msgid "Observed Prop."
+msgstr "Stebėta prop."
+
+#: src/language/stats/binomial.c:255
+msgid "Test Prop."
+msgstr "Kriter. prop."
+
+#: src/language/stats/binomial.c:258 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1241
+#, c-format
+msgid "Exact Sig. (%d-tailed)"
+msgstr "Tiksli p-reikšmė (%d-pusė)"
+
+#: src/language/stats/chisquare.c:150
+#, c-format
+msgid "CHISQUARE test specified %d expected values, but %d distinct values were encountered in variable %s."
+msgstr ""
+
+#: src/language/stats/chisquare.c:161 src/language/stats/chisquare.c:200
+msgid "Observed N"
+msgstr "Stebėtų N"
+
+#: src/language/stats/chisquare.c:162 src/language/stats/chisquare.c:201
+msgid "Expected N"
+msgstr "Prognozuotų N"
+
+#: src/language/stats/chisquare.c:163 src/language/stats/chisquare.c:202
+#: src/ui/gui/crosstabs-dialog.c:61 src/language/stats/regression.q:292
+msgid "Residual"
+msgstr "Liekana"
+
+#: src/language/stats/chisquare.c:195 src/language/stats/cochran.c:159
+#: src/language/stats/sign.c:62 src/ui/gui/frequencies.ui:9
+#: src/ui/gui/frequencies.ui:669
+msgid "Frequencies"
+msgstr "Dažniai"
+
+#: src/language/stats/chisquare.c:249 src/language/stats/cochran.c:208
+#: src/language/stats/friedman.c:272 src/language/stats/kruskal-wallis.c:310
+#: src/language/stats/mann-whitney.c:251 src/language/stats/sign.c:114
+#: src/language/stats/wilcoxon.c:304
+msgid "Test Statistics"
+msgstr "Kriterijaus statistika"
+
+#: src/language/stats/chisquare.c:263 src/language/stats/friedman.c:282
+#: src/language/stats/kruskal-wallis.c:313
+msgid "Chi-Square"
+msgstr "Chi-kvadratas"
+
+#: src/language/stats/chisquare.c:264 src/language/stats/cochran.c:217
+#: src/language/stats/friedman.c:285 src/language/stats/kruskal-wallis.c:316
+#: src/language/stats/oneway.c:593 src/language/stats/oneway.c:1002
+#: src/language/stats/crosstabs.q:1235 src/language/stats/regression.q:286
+#: src/language/stats/t-test.q:756 src/language/stats/t-test.q:927
+#: src/language/stats/t-test.q:1014
+msgid "df"
+msgstr "skirt."
+
+#: src/language/stats/chisquare.c:265 src/language/stats/cochran.c:220
+#: src/language/stats/friedman.c:288 src/language/stats/kruskal-wallis.c:319
+msgid "Asymp. Sig."
+msgstr "Asimt. p-reikšmė"
+
+#: src/language/stats/cochran.c:109
+msgid "More than two values encountered.  Cochran Q test will not be run."
+msgstr "Turimi daugiau nei du kintamieji. Cochran Q nebus skaičiuojamas."
+
+#: src/language/stats/cochran.c:172
+#, c-format
+msgid "Success (%g)"
+msgstr "Sėkmė (%g)"
+
+#: src/language/stats/cochran.c:173
+#, c-format
+msgid "Failure (%g)"
+msgstr "Nesėkmė (%g)"
+
+#: src/language/stats/cochran.c:214
+msgid "Cochran's Q"
+msgstr "Cochran Q"
+
+#: src/language/stats/correlations.c:97 src/language/stats/factor.c:1724
+#: src/language/stats/npar-summary.c:109
+msgid "Descriptive Statistics"
+msgstr "Aprašomoji statistika"
+
+#: src/language/stats/correlations.c:118 src/language/stats/descriptives.c:102
+#: src/language/stats/factor.c:1745 src/language/stats/npar-summary.c:126
+#: src/language/stats/oneway.c:687 src/ui/gui/descriptives-dialog.c:39
+#: src/ui/gui/frequencies-dialog.c:40 src/language/stats/examine.q:1443
+#: src/language/stats/frequencies.q:105 src/language/stats/t-test.q:510
+#: src/language/stats/t-test.q:530 src/language/stats/t-test.q:628
+#: src/language/stats/t-test.q:921
+msgid "Mean"
+msgstr "Vidurkis"
+
+#: src/language/stats/correlations.c:119 src/language/stats/factor.c:1746
+#: src/language/stats/npar-summary.c:129 src/language/stats/oneway.c:688
+#: src/language/stats/examine.q:1478 src/language/stats/t-test.q:511
+#: src/language/stats/t-test.q:531 src/language/stats/t-test.q:630
+#: src/language/stats/t-test.q:922
+msgid "Std. Deviation"
+msgstr "Std. nuokrypis"
+
+#: src/language/stats/correlations.c:191 src/language/stats/factor.c:1618
+msgid "Correlations"
+msgstr "Koreliacijos"
+
+#: src/language/stats/correlations.c:217
+msgid "Pearson Correlation"
+msgstr "Pirsono koreliacija"
+
+#: src/language/stats/correlations.c:219 src/language/stats/oneway.c:1003
+#: src/language/stats/t-test.q:757 src/language/stats/t-test.q:928
+#: src/language/stats/t-test.q:1015
+msgid "Sig. (2-tailed)"
+msgstr "p-reikšmė (2-pusė)"
+
+#: src/language/stats/correlations.c:219 src/language/stats/factor.c:1630
+msgid "Sig. (1-tailed)"
+msgstr "p-reikšmė (1-pusė)"
+
+#: src/language/stats/correlations.c:223
+msgid "Cross-products"
+msgstr ""
+
+#: src/language/stats/correlations.c:224
+msgid "Covariance"
+msgstr "Kovariacija"
+
+#: src/language/stats/correlations.c:456 src/language/stats/descriptives.c:363
+#: src/language/data-io/list.q:90
+msgid "No variables specified."
+msgstr "Nenurodytas joks kintamasis."
+
+#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:106
+#: src/language/stats/t-test.q:512 src/language/stats/t-test.q:532
+#: src/language/stats/t-test.q:631
+msgid "S.E. Mean"
+msgstr "Vidur. s.pakl."
+
+#: src/language/stats/descriptives.c:104 src/language/stats/frequencies.q:109
+msgid "Std Dev"
+msgstr "Std. nuokrypis"
+
+#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/frequencies-dialog.c:45 src/language/stats/examine.q:1473
+#: src/language/stats/frequencies.q:110
+msgid "Variance"
+msgstr "Dispersija"
+
+#: src/language/stats/descriptives.c:106 src/ui/gui/descriptives-dialog.c:47
+#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/examine.q:1509
+#: src/language/stats/frequencies.q:111
+msgid "Kurtosis"
+msgstr "Ekscesas"
+
+#: src/language/stats/descriptives.c:107 src/language/stats/frequencies.q:112
+msgid "S.E. Kurt"
+msgstr "Eksc. s.pakl."
+
+#: src/language/stats/descriptives.c:108 src/ui/gui/descriptives-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1504
+#: src/language/stats/frequencies.q:113
+msgid "Skewness"
+msgstr "Asimetrija"
+
+#: src/language/stats/descriptives.c:109 src/language/stats/frequencies.q:114
+msgid "S.E. Skew"
+msgstr "Asim. s.pakl."
+
+#: src/language/stats/descriptives.c:110 src/ui/gui/descriptives-dialog.c:43
+#: src/ui/gui/frequencies-dialog.c:48 src/language/stats/examine.q:1493
+#: src/language/stats/frequencies.q:115
+msgid "Range"
+msgstr "Sritis"
+
+#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:132
+#: src/language/stats/oneway.c:701 src/ui/gui/descriptives-dialog.c:41
+#: src/ui/gui/frequencies-dialog.c:42 src/language/stats/examine.q:1483
+#: src/language/stats/frequencies.q:116
+msgid "Minimum"
+msgstr "Mažiausia"
+
+#: src/language/stats/descriptives.c:112 src/language/stats/npar-summary.c:135
+#: src/language/stats/oneway.c:702 src/ui/gui/descriptives-dialog.c:42
+#: src/ui/gui/frequencies-dialog.c:43 src/language/stats/examine.q:1488
+#: src/language/stats/frequencies.q:117
+msgid "Maximum"
+msgstr "Didžiausia"
+
+#: src/language/stats/descriptives.c:113 src/ui/gui/descriptives-dialog.c:44
+#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/frequencies.q:118
+msgid "Sum"
+msgstr "Suma"
+
+#: src/language/stats/descriptives.c:345
+#, c-format
+msgid "Z-score variable name %s would be a duplicate variable name."
+msgstr ""
+
+#: src/language/stats/descriptives.c:457
+msgid "expecting statistic name: reverting to default"
+msgstr ""
+
+#: src/language/stats/descriptives.c:539
+msgid "Ran out of generic names for Z-score variables.  There are only 126 generic names: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
+msgstr ""
+
+#: src/language/stats/descriptives.c:568
+msgid "Mapping of variables to corresponding Z-scores."
+msgstr ""
+
+#: src/language/stats/descriptives.c:572
+msgid "Source"
+msgstr "Šaltinis"
+
+#: src/language/stats/descriptives.c:573
+msgid "Target"
+msgstr "Paskirtis"
+
+#: src/language/stats/descriptives.c:684
+#, c-format
+msgid "Z-score of %s"
+msgstr "%s z-reikšmė"
+
+#: src/language/stats/descriptives.c:898
+msgid "Valid N"
+msgstr "Galiojančių N"
+
+#: src/language/stats/descriptives.c:899
+msgid "Missing N"
+msgstr "Praleistų N"
+
+#: src/language/stats/descriptives.c:927
+#, c-format
+msgid "Valid cases = %g; cases with missing value(s) = %g."
+msgstr "Galiojančių atvejai = %g; atvejų su praleistomis reikšmėmis = %g."
+
+#: src/language/stats/factor.c:801
+msgid "Factor analysis on a single variable is not useful."
+msgstr "Faktorinė analizė remiantis vienu kintamuoju nėra naudinga."
+
+#: src/language/stats/factor.c:1204
+msgid "Component Number"
+msgstr "Komponentės numeris"
+
+#: src/language/stats/factor.c:1204
+msgid "Factor Number"
+msgstr "Faktoriaus numeris"
+
+#: src/language/stats/factor.c:1235
+msgid "Communalities"
+msgstr "Bendrumai"
+
+#: src/language/stats/factor.c:1241
+msgid "Initial"
+msgstr "Pradinė"
+
+#: src/language/stats/factor.c:1244
+msgid "Extraction"
+msgstr "Išskirta"
+
+#: src/language/stats/factor.c:1308 src/language/stats/factor.c:1435
+msgid "Component"
+msgstr "Komponentė"
+
+#: src/language/stats/factor.c:1313 src/language/stats/factor.c:1437
+msgid "Factor"
+msgstr "Faktorius"
+
+#: src/language/stats/factor.c:1345 src/ui/gui/psppire-data-store.c:755
+#: src/ui/gui/psppire-var-store.c:699 src/ui/gui/psppire-var-store.c:709
+#: src/ui/gui/psppire-var-store.c:719 src/ui/gui/psppire-var-store.c:826
+#, c-format
+msgid "%d"
+msgstr "%d"
+
+#: src/language/stats/factor.c:1410
+msgid "Total Variance Explained"
+msgstr "Visa paaiškinama dispersija"
+
+#: src/language/stats/factor.c:1442
+msgid "Initial Eigenvalues"
+msgstr "Pradinės tikrinės reikšmės"
+
+#: src/language/stats/factor.c:1448
+msgid "Extraction Sums of Squared Loadings"
+msgstr "Pradinė svorių kvadratų suma"
+
+#: src/language/stats/factor.c:1454
+msgid "Rotation Sums of Squared Loadings"
+msgstr "Svorių kvadratų suma po sukimo"
+
+#: src/language/stats/factor.c:1462
+#, no-c-format
+msgid "% of Variance"
+msgstr "% dispersijos"
+
+#: src/language/stats/factor.c:1463
+msgid "Cumulative %"
+msgstr "Sukaupta %"
+
+#: src/language/stats/factor.c:1493
+#, c-format
+msgid "%zu"
+msgstr "%zu"
+
+#: src/language/stats/factor.c:1576
+msgid "Correlation Matrix"
+msgstr "Koreliacijų matrica"
+
+#: src/language/stats/factor.c:1664
+msgid "Determinant"
+msgstr ""
+
+#: src/language/stats/factor.c:1695
+msgid "The dataset contains no complete observations. No analysis will be performed."
+msgstr ""
+
+#: src/language/stats/factor.c:1747
+msgid "Analysis N"
+msgstr ""
+
+#: src/language/stats/factor.c:1780
+msgid "The FACTOR criteria result in zero factors extracted. Therefore no analysis will be performed."
+msgstr ""
+
+#: src/language/stats/factor.c:1786
+msgid "The FACTOR criteria result in more factors than variables, which is not meaningful. No analysis will be performed."
+msgstr ""
+
+#: src/language/stats/factor.c:1869
+msgid "Component Matrix"
+msgstr "Komponenčių (faktorių svorių) matrica"
+
+#: src/language/stats/factor.c:1869
+msgid "Factor Matrix"
+msgstr "Faktorių matrica"
+
+#: src/language/stats/factor.c:1875
+msgid "Rotated Component Matrix"
+msgstr "Pasukta komponenčių matrica"
+
+#: src/language/stats/factor.c:1875
+msgid "Rotated Factor Matrix"
+msgstr "Pasukta faktorių matrica"
+
+#: src/language/stats/flip.c:99
+msgid "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
+msgstr ""
+
+#: src/language/stats/flip.c:151
+msgid "Could not create temporary file for FLIP."
+msgstr ""
+
+#: src/language/stats/flip.c:326
+#, c-format
+msgid "Error rewinding FLIP file: %s."
+msgstr ""
+
+#: src/language/stats/flip.c:333
+msgid "Error creating FLIP source file."
+msgstr ""
+
+#: src/language/stats/flip.c:346
+#, c-format
+msgid "Error reading FLIP file: %s."
+msgstr "klaida skaitant FLIP rinkmeną: %s."
+
+#: src/language/stats/flip.c:348
+msgid "Unexpected end of file reading FLIP file."
+msgstr "Netikėta skaitomos FLIP rinkmenos pabaiga."
+
+#: src/language/stats/flip.c:364
+#, c-format
+msgid "Error seeking FLIP source file: %s."
+msgstr ""
+
+#: src/language/stats/flip.c:372
+#, c-format
+msgid "Error writing FLIP source file: %s."
+msgstr ""
+
+#: src/language/stats/flip.c:387
+#, c-format
+msgid "Error rewinding FLIP source file: %s."
+msgstr ""
+
+#: src/language/stats/flip.c:420
+#, c-format
+msgid "Error reading FLIP temporary file: %s."
+msgstr "Klaida skaitant FLIP laikinąją rinkmeną: %s."
+
+#: src/language/stats/flip.c:423
+msgid "Unexpected end of file reading FLIP temporary file."
+msgstr "netikėta skaitomos FLIP laikinosios rinkmenos pabaiga."
+
+#: src/language/stats/friedman.c:227 src/language/stats/kruskal-wallis.c:242
+#: src/language/stats/mann-whitney.c:171 src/language/stats/wilcoxon.c:225
+msgid "Ranks"
+msgstr "Rangai"
+
+#: src/language/stats/friedman.c:238 src/language/stats/kruskal-wallis.c:256
+#: src/language/stats/mann-whitney.c:196 src/language/stats/wilcoxon.c:239
+msgid "Mean Rank"
+msgstr "Vidutinis rangas"
+
+#: src/language/stats/friedman.c:279
+msgid "Kendall's W"
+msgstr "Kendall W"
+
+#: src/language/stats/mann-whitney.c:202 src/language/stats/wilcoxon.c:240
+msgid "Sum of Ranks"
+msgstr "Rangų suma"
+
+#: src/language/stats/mann-whitney.c:264
+msgid "Mann-Whitney U"
+msgstr "Mann-Whitney U"
+
+#: src/language/stats/mann-whitney.c:265
+msgid "Wilcoxon W"
+msgstr "Wilcoxon W"
+
+#: src/language/stats/mann-whitney.c:266 src/language/stats/runs.c:396
+#: src/language/stats/wilcoxon.c:317
+msgid "Z"
+msgstr "Z"
+
+#: src/language/stats/mann-whitney.c:267 src/language/stats/runs.c:399
+#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1237
+msgid "Asymp. Sig. (2-tailed)"
+msgstr "Asimp. p-reikšmė (2-pusė)"
+
+#: src/language/stats/mann-whitney.c:271 src/language/stats/sign.c:133
+#: src/language/stats/wilcoxon.c:322
+msgid "Exact Sig. (2-tailed)"
+msgstr "Tiksli p-reikšmė (2-pusė)"
+
+#: src/language/stats/mann-whitney.c:272 src/language/stats/sign.c:139
+#: src/language/stats/wilcoxon.c:326
+msgid "Point Probability"
+msgstr "Taško tikimybė"
+
+#: src/language/stats/npar.c:337 src/language/stats/npar.c:364
+#, c-format
+msgid "The %s subcommand may be given only once."
+msgstr "Pokomandis %s gali būti nurodomas tik vieną kartą."
+
+#: src/language/stats/npar.c:447
+msgid "NPAR subcommand not currently implemented."
+msgstr "NPAR pokomandis dar nerealizuotas."
+
+#: src/language/stats/npar.c:601
+msgid "Expecting MEAN, MEDIAN, MODE or number"
+msgstr "Tikimasi MEAN, MEDIAN, MODE arba skaičiaus"
+
+#: src/language/stats/npar.c:751
+#, c-format
+msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
+msgstr ""
+
+#: src/language/stats/npar.c:801
+#, c-format
+msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
+msgstr ""
+
+#: src/language/stats/npar.c:941 src/language/stats/t-test.q:384
+#, c-format
+msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
+msgstr ""
+
+#: src/language/stats/npar-summary.c:142 src/language/stats/examine.q:1995
+#: src/language/stats/examine.q:2012 src/language/stats/frequencies.q:1057
+#: src/ui/gui/examine.ui:345
+msgid "Percentiles"
+msgstr "Procentiliai"
+
+#: src/language/stats/npar-summary.c:146
+msgid "25th"
+msgstr "25-asis"
+
+#: src/language/stats/npar-summary.c:149
+msgid "50th (Median)"
+msgstr "50-asis (mediana)"
+
+#: src/language/stats/npar-summary.c:152
+msgid "75th"
+msgstr "75-asis"
+
+#: src/language/stats/oneway.c:542
+msgid "Number of contrast coefficients must equal the number of groups"
+msgstr "Kontrastų koeficientų skaičius turi būti lygus grupių skaičiui"
+
+#: src/language/stats/oneway.c:551
+#, c-format
+msgid "Coefficients for contrast %zu do not total zero"
+msgstr ""
+
+#: src/language/stats/oneway.c:592 src/language/stats/regression.q:285
+msgid "Sum of Squares"
+msgstr "Kvadratų suma"
+
+#: src/language/stats/oneway.c:594 src/language/stats/regression.q:287
+msgid "Mean Square"
+msgstr "Vidutinis kvadratas"
+
+#: src/language/stats/oneway.c:595 src/language/stats/regression.q:288
+#: src/language/stats/t-test.q:753
+msgid "F"
+msgstr "F"
+
+#: src/language/stats/oneway.c:596 src/language/stats/oneway.c:841
+#: src/language/stats/regression.q:203 src/language/stats/regression.q:289
+msgid "Significance"
+msgstr "Reikšmingumo lygmuo"
+
+#: src/language/stats/oneway.c:614
+msgid "Between Groups"
+msgstr "Tarp grupių"
+
+#: src/language/stats/oneway.c:615
+msgid "Within Groups"
+msgstr "Vidinė"
+
+#: src/language/stats/oneway.c:648 src/language/stats/regression.q:314
+msgid "ANOVA"
+msgstr "ANOVA"
+
+#: src/language/stats/oneway.c:689 src/language/stats/oneway.c:1000
+#: src/language/stats/roc.c:975 src/language/stats/examine.q:1640
+#: src/language/stats/regression.q:200
+msgid "Std. Error"
+msgstr "Std. paklaida"
+
+#: src/language/stats/oneway.c:695 src/language/stats/examine.q:1448
+#, c-format
+msgid "%g%% Confidence Interval for Mean"
+msgstr "%g%% pasikliautinasis intervalas vidurkiams"
+
+#: src/language/stats/oneway.c:698 src/language/stats/roc.c:978
+#: src/language/stats/examine.q:1454
+msgid "Lower Bound"
+msgstr "Apačia"
+
+#: src/language/stats/oneway.c:699 src/language/stats/roc.c:979
+#: src/language/stats/examine.q:1459
+msgid "Upper Bound"
+msgstr "Viršus"
+
+#: src/language/stats/oneway.c:704 src/language/stats/examine.q:1634
+#: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
+msgid "Descriptives"
+msgstr "Aprašomoji"
+
+#: src/language/stats/oneway.c:838
+msgid "Levene Statistic"
+msgstr "Statistika (Levene)"
+
+#: src/language/stats/oneway.c:839
+msgid "df1"
+msgstr "skirt1"
+
+#: src/language/stats/oneway.c:840
+msgid "df2"
+msgstr "skirt2"
+
+#: src/language/stats/oneway.c:843
+msgid "Test of Homogeneity of Variances"
+msgstr "Dispersijų homogeniškumo kriterijus"
+
+#: src/language/stats/oneway.c:916
+msgid "Contrast Coefficients"
+msgstr "Kontrastų koeficientai"
+
+#: src/language/stats/oneway.c:918 src/language/stats/oneway.c:998
+msgid "Contrast"
+msgstr "Kontrastas"
+
+#: src/language/stats/oneway.c:996
+msgid "Contrast Tests"
+msgstr "Kontrastų kriterijus"
+
+#: src/language/stats/oneway.c:999
+msgid "Value of Contrast"
+msgstr "Kontrasto reikšmė"
+
+#: src/language/stats/oneway.c:1001 src/language/stats/regression.q:202
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:926
+#: src/language/stats/t-test.q:1013
+msgid "t"
+msgstr "t"
+
+#: src/language/stats/oneway.c:1053
+msgid "Assume equal variances"
+msgstr "Manant, kas dispersijos yra lygios"
+
+#: src/language/stats/oneway.c:1057
+msgid "Does not assume equal"
+msgstr "Nemanant, kad lygios"
+
+#: src/language/stats/quick-cluster.c:369
+msgid "Number of clusters may not be larger than the number of cases."
+msgstr "Klasterių skaičius negali būti didesnis nei atvejų skaičius."
+
+#: src/language/stats/quick-cluster.c:411
+msgid "Final Cluster Centers"
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:415
+msgid "Initial Cluster Centers"
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:418
+#: src/language/stats/quick-cluster.c:472
+msgid "Cluster"
+msgstr "Klasteris"
+
+#: src/language/stats/quick-cluster.c:470
+msgid "Number of Cases in each Cluster"
+msgstr "Atvejų skaičius kiekviename klasteryje"
+
+#: src/language/stats/quick-cluster.c:484 src/language/stats/reliability.c:527
+#: src/language/stats/crosstabs.q:830 src/language/stats/examine.q:1102
+#: src/language/stats/frequencies.q:1042
+msgid "Valid"
+msgstr "Galiojančių"
+
+#: src/language/stats/quick-cluster.c:515
+msgid "Variables cannot be parsed"
+msgstr "Kintamųjų išnagrinėti negalima"
+
+#: src/language/stats/reliability.c:141
+msgid "Reliability on a single variable is not useful."
+msgstr "Klausimynų patikimumo skaičiavimas remiantis vienu kintamuoju nėra naudingas."
+
+#: src/language/stats/reliability.c:501 src/language/stats/examine.q:1158
+msgid "Case Processing Summary"
+msgstr "Atvejų apdorojimo santrauka"
+
+#: src/language/stats/reliability.c:524 src/language/stats/crosstabs.q:829
+#: src/language/stats/examine.q:1163
+msgid "Cases"
+msgstr "Atvejų"
+
+#: src/language/stats/reliability.c:530
+msgid "Excluded"
+msgstr "Atmestų"
+
+#: src/language/stats/reliability.c:538
+msgid "%"
+msgstr "%"
+
+#: src/language/stats/reliability.c:583
+msgid "Item-Total Statistics"
+msgstr "„Elementas-visuma“ statistika"
+
+#: src/language/stats/reliability.c:605
+msgid "Scale Mean if Item Deleted"
+msgstr "Klausimyno vidurkis, jei elementas pašalintas"
+
+#: src/language/stats/reliability.c:608
+msgid "Scale Variance if Item Deleted"
+msgstr "Klausimyno dispersija, jei elementas pašalintas"
+
+#: src/language/stats/reliability.c:611
+msgid "Corrected Item-Total Correlation"
+msgstr "Koreguota „elementas-visuma“ koreliacija"
+
+#: src/language/stats/reliability.c:614
+msgid "Cronbach's Alpha if Item Deleted"
+msgstr "Cronbacho alfa, jei elementas pašalintas"
+
+#: src/language/stats/reliability.c:688
+msgid "Reliability Statistics"
+msgstr "Klausimynų patikimumo statistika"
+
+#: src/language/stats/reliability.c:728 src/language/stats/reliability.c:747
+msgid "Cronbach's Alpha"
+msgstr "Cronbacho alfa"
+
+#: src/language/stats/reliability.c:731 src/language/stats/reliability.c:756
+#: src/language/stats/reliability.c:767
+msgid "N of Items"
+msgstr "N elementų"
+
+#: src/language/stats/reliability.c:750
+msgid "Part 1"
+msgstr "1 dalis"
+
+#: src/language/stats/reliability.c:761
+msgid "Part 2"
+msgstr "2 dalis"
+
+#: src/language/stats/reliability.c:772
+msgid "Total N of Items"
+msgstr "Iš viso N elementų"
+
+#: src/language/stats/reliability.c:775
+msgid "Correlation Between Forms"
+msgstr "Koreliacija tarp formų"
+
+#: src/language/stats/reliability.c:779
+msgid "Spearman-Brown Coefficient"
+msgstr "Spearman-Brown koeficientas"
+
+#: src/language/stats/reliability.c:782
+msgid "Equal Length"
+msgstr "Vienodas ilgis"
+
+#: src/language/stats/reliability.c:785
+msgid "Unequal Length"
+msgstr "Nevienodas ilgis"
+
+#: src/language/stats/reliability.c:789
+msgid "Guttman Split-Half Coefficient"
+msgstr "Guttman dalinimo pusiau koeficientas"
+
+#: src/language/stats/roc.c:955
+msgid "Area Under the Curve"
+msgstr "Plotas po kreive"
+
+#: src/language/stats/roc.c:957
+#, c-format
+msgid "Area Under the Curve (%s)"
+msgstr "Plotas po kreive (%s)"
+
+#: src/language/stats/roc.c:962
+msgid "Area"
+msgstr "Plotas"
+
+#: src/language/stats/roc.c:976
+msgid "Asymptotic Sig."
+msgstr "Asimptotinė p-reikšmė"
+
+#: src/language/stats/roc.c:983
+#, c-format
+msgid "Asymp. %g%% Confidence Interval"
+msgstr "Asimp. %g%% pasikliautinasis intervalas"
+
+#: src/language/stats/roc.c:989
+msgid "Variable under test"
+msgstr "Kriterijaus kintamasis"
+
+#: src/language/stats/roc.c:1048
+msgid "Case Summary"
+msgstr "Atvejų suvestinė"
+
+#: src/language/stats/roc.c:1068
+msgid "Unweighted"
+msgstr "Nesverta"
+
+#: src/language/stats/roc.c:1069
+msgid "Weighted"
+msgstr "Sverta"
+
+#: src/language/stats/roc.c:1073
+msgid "Valid N (listwise)"
+msgstr "Galiojančių N (visuose)"
+
+#: src/language/stats/roc.c:1076
+msgid "Positive"
+msgstr "Teigiamų"
+
+#: src/language/stats/roc.c:1077
+msgid "Negative"
+msgstr "Neigiamų"
+
+#: src/language/stats/roc.c:1105
+msgid "Coordinates of the Curve"
+msgstr "Kreivės koordinatės"
+
+#: src/language/stats/roc.c:1107
+#, c-format
+msgid "Coordinates of the Curve (%s)"
+msgstr "Kreivės (%s) koordinatės"
+
+#: src/language/stats/roc.c:1115
+msgid "Test variable"
+msgstr "Kriterijaus kintamasis"
+
+#: src/language/stats/roc.c:1117
+msgid "Positive if greater than or equal to"
+msgstr "Teigiamas, jei didesnis arba lygus"
+
+#: src/language/stats/roc.c:1118 src/output/charts/roc-chart-cairo.c:38
+msgid "Sensitivity"
+msgstr "Jautrumas"
+
+#: src/language/stats/roc.c:1119 src/output/charts/roc-chart-cairo.c:37
+msgid "1 - Specificity"
+msgstr "1 - specifiškumas"
+
+#: src/language/stats/runs.c:167
+#, c-format
+msgid "Multiple modes exist for varible `%s'.  Using %g as the threshold value."
+msgstr ""
+
+#: src/language/stats/runs.c:322
+msgid "Runs Test"
+msgstr "Serijų kriterijus"
+
+#: src/language/stats/runs.c:367
+msgid "Test Value"
+msgstr "Kriterijaus reikšmė"
+
+#: src/language/stats/runs.c:371
+msgid "Test Value (mode)"
+msgstr "Kriterijaus reikšmė (moda)"
+
+#: src/language/stats/runs.c:375
+msgid "Test Value (mean)"
+msgstr "Kriterijaus reikšmė (vidurkis)"
+
+#: src/language/stats/runs.c:379
+msgid "Test Value (median)"
+msgstr "Kriterijaus reikšmė (mediana)"
+
+#: src/language/stats/runs.c:384
+msgid "Cases < Test Value"
+msgstr "Atvejai < kriterijaus reikšmė"
+
+#: src/language/stats/runs.c:387
+msgid "Cases >= Test Value"
+msgstr "Atvejai >= kriterijaus reikšmė"
+
+#: src/language/stats/runs.c:390
+msgid "Total Cases"
+msgstr "Iš viso atvejų"
+
+#: src/language/stats/runs.c:393
+msgid "Number of Runs"
+msgstr "Serijų skaičius"
+
+#: src/language/stats/sign.c:92
+msgid "Negative Differences"
+msgstr "Neigiami skirtumai"
+
+#: src/language/stats/sign.c:93
+msgid "Positive Differences"
+msgstr "Teigiami skirtumai"
+
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:254
+msgid "Ties"
+msgstr "Ryšiai"
+
+#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:323
+msgid "Exact Sig. (1-tailed)"
+msgstr "Tiksli p-reikšmė (1-pusė)"
+
+#: src/language/stats/sort-cases.c:64
+msgid "Buffer limit must be at least 2."
+msgstr "Buferio riba privalo būti bent 2."
+
+#: src/language/stats/sort-criteria.c:74
+msgid "`A' or `D' expected inside parentheses."
+msgstr "„A“ arba „D“ tikimasi rasti tarp skliaustų."
+
+#: src/language/stats/sort-criteria.c:79
+msgid "`)' expected."
+msgstr "tikėtasi „)“."
+
+#: src/language/stats/sort-criteria.c:92
+#, c-format
+msgid "Variable %s specified twice in sort criteria."
+msgstr "Rikiavimo kriterijui kintamasis %s nurodytas du kartus."
+
+#: src/language/stats/wilcoxon.c:252
+msgid "Negative Ranks"
+msgstr "Neigiami rangai"
+
+#: src/language/stats/wilcoxon.c:253
+msgid "Positive Ranks"
+msgstr "Teigiami rangai"
+
+#: src/language/data-io/combine-files.c:212
+msgid "Cannot specify the active dataset since none has been defined."
+msgstr "Nepavyksta nurodyti aktyvaus duomenų rinkinio, nes toks nebuvo apibrėžtas."
+
+#: src/language/data-io/combine-files.c:218
+msgid "This command may not be used after TEMPORARY when the active dataset is an input source.  Temporary transformations will be made permanent."
+msgstr "Ši komanda negali būti naudojama po TEMPORARY, jei veikiamasis duomenų rinkinys yra įvedimo šaltinis. Laikinos transformacijos bus nuolat."
+
+#: src/language/data-io/combine-files.c:252
+msgid "Multiple IN subcommands for a single FILE or TABLE."
+msgstr "Keletas IN pokomandžių vienai rinkmenai (FILE) ar lentelei (TABLE)."
+
+#: src/language/data-io/combine-files.c:304
+#, c-format
+msgid "File %s lacks BY variable %s."
+msgstr "Rinkmenai %s trūksta BY kintamojo %s."
+
+#: src/language/data-io/combine-files.c:307
+#, c-format
+msgid "Active dataset lacks BY variable %s."
+msgstr "Aktyviam duomenų rinkiniui trūksta BY kintamojo %s."
+
+#: src/language/data-io/combine-files.c:379
+msgid "The BY subcommand is required."
+msgstr "Reikalingas pokomandis BY."
+
+#: src/language/data-io/combine-files.c:384
+#: src/language/data-io/combine-files.c:389
+#, c-format
+msgid "BY is required when %s is specified."
+msgstr "Kai nurodomas %s, reikalinga BY komanda."
+
+#: src/language/data-io/combine-files.c:514
+msgid "Combining files with incompatible encodings. String data may not be represented correctly."
+msgstr "Derinamos rinkmenos su nesuderinamomis koduotėmis. Tekstinių eilučių duomenys gali būti pateikti netinkamai."
+
+#: src/language/data-io/combine-files.c:555
+#, c-format
+msgid "Variable %s in file %s has different type or width from the same variable in earlier file."
+msgstr "Kintamasis %s rinkmenoje %s yra kitokio tipo arba kitokio ilgio negu tas pats kintamasis ankstesnėje rinkmenoje."
+
+#: src/language/data-io/combine-files.c:561
+#, c-format
+msgid "In file %s, %s is numeric."
+msgstr "%s rinkmenoje: %s yra skaitmeninis."
+
+#: src/language/data-io/combine-files.c:564
+#, c-format
+msgid "In file %s, %s is a string variable with width %d."
+msgstr "%s rinkmenoje: %s yra teksto eilutės kintamasis, kurio plotis %d."
+
+#: src/language/data-io/combine-files.c:569
+#, c-format
+msgid "In an earlier file, %s was numeric."
+msgstr "Ankstesnėje rinkmenoje: %s buvo skaitmeninis."
+
+#: src/language/data-io/combine-files.c:572
+#, c-format
+msgid "In an earlier file, %s was a string variable with width %d."
+msgstr "Ankstesnėje rinkmenoje: %s buvo teksto eilutės kintamasis, kurio plotis %d."
+
+#: src/language/data-io/combine-files.c:612
+#, c-format
+msgid "Variable name %s specified on %s subcommand duplicates an existing variable name."
+msgstr "Kintamojo vardas %s, kuris nurodytas %s pokomandyje, dubliuoja esamą kintamojo vardą."
+
+#: src/language/data-io/combine-files.c:774
+#, c-format
+msgid "Encountered %zu sets of duplicate cases in the master file."
+msgstr ""
+
+#: src/language/data-io/data-list.c:140
+msgid "The END subcommand may only be used within INPUT PROGRAM."
+msgstr "Pokomandis END gali būti naudojamas tik INPUT PROGRAM viduje."
+
+#: src/language/data-io/data-list.c:146
+msgid "The END subcommand may only be specified once."
+msgstr "Pokomandis END gali būti nurodytas tik vieną kartą."
+
+#: src/language/data-io/data-list.c:184
+msgid "Only one of FIXED, FREE, or LIST may be specified."
+msgstr "Gali būti nurodytas tik kuris nors vienas: FIXED, FREE arba LIST."
+
+#: src/language/data-io/data-list.c:245
+msgid "Encoding should not be specified for inline data. It will be ignored."
+msgstr "Kodavimas neturėtų būti nurodomas duomenų viduje. Ignoruojama."
+
+#: src/language/data-io/data-list.c:254
+msgid "The END subcommand may be used only with DATA LIST FIXED."
+msgstr "Pokomandis END gali būti naudojamas tik su DATA LIST FIXED."
+
+#: src/language/data-io/data-list.c:269
+msgid "At least one variable must be specified."
+msgstr "Turi būti nurodytas bent vienas kintamasis.q"
+
+#: src/language/data-io/data-list.c:368 src/language/data-io/data-list.c:457
+#: src/language/data-io/get-data.c:540
+#, c-format
+msgid "%s is a duplicate variable name."
+msgstr "Kintamojo vardas „%s“ kartojasi."
+
+#: src/language/data-io/data-list.c:375
+#, c-format
+msgid "There is already a variable %s of a different type."
+msgstr "Toks kintamasis %s jau yra kitokio tipo."
+
+#: src/language/data-io/data-list.c:382
+#, c-format
+msgid "There is already a string variable %s of a different width."
+msgstr "Toks teksto eilutės kintamasis %s jau yra, bet kitokio pločio."
+
+#: src/language/data-io/data-list.c:390
+#, c-format
+msgid "Cannot place variable %s on record %d when RECORDS=%d is specified."
+msgstr ""
+
+#: src/language/data-io/data-parser.c:458
+#: src/language/data-io/data-parser.c:467
+msgid "Quoted string extends beyond end of line."
+msgstr "Tekste tarp kabučių yra nauja eilutė."
+
+#: src/language/data-io/data-parser.c:516
+#, c-format
+msgid "Data for variable %s is not valid as format %s: %s"
+msgstr "Kintamojo %s duomenys neatitinka %s formato: %s"
+
+#: src/language/data-io/data-parser.c:545
+#, c-format
+msgid "Partial case of %d of %d records discarded."
+msgstr ""
+
+#: src/language/data-io/data-parser.c:602
+#, c-format
+msgid "Partial case discarded.  The first variable missing was %s."
+msgstr ""
+
+#: src/language/data-io/data-parser.c:644
+#, c-format
+msgid "Missing value(s) for all variables from %s onward.  These will be filled with the system-missing value or blanks, as appropriate."
+msgstr ""
+
+#: src/language/data-io/data-parser.c:664
+msgid "Record ends in data not part of any field."
+msgstr ""
+
+#: src/language/data-io/data-parser.c:684 src/language/data-io/print.c:404
+msgid "Record"
+msgstr "Įrašas"
+
+#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:405
+#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:840
+#: src/ui/gui/crosstabs.ui:89
+msgid "Columns"
+msgstr "Stulpeliai"
+
+#: src/language/data-io/data-parser.c:686
+#: src/language/data-io/data-parser.c:723 src/language/data-io/print.c:406
+msgid "Format"
+msgstr "Formatas"
+
+#: src/language/data-io/data-parser.c:704
+#, c-format
+msgid "Reading %d record from %s."
+msgid_plural "Reading %d records from %s."
+msgstr[0] "Skaitomas %d įrašas iš %s."
+msgstr[1] "Skaitomas %d įrašas iš %s."
+msgstr[2] "Skaitomi %d įrašai iš %s."
+msgstr[3] "Skaitoma %d įrašų iš %s."
+
+#: src/language/data-io/data-parser.c:738
+#, c-format
+msgid "Reading free-form data from %s."
+msgstr "Skaitomi laisvo formato duomenys iš %s."
+
+#. TRANSLATORS: this fragment will be interpolated into
+#. messages in fh_lock() that identify types of files.
+#: src/language/data-io/data-reader.c:123
+#: src/language/data-io/data-writer.c:58
+msgid "data file"
+msgstr "duomenų rinkmena"
+
+#: src/language/data-io/data-reader.c:148
+#, c-format
+msgid "Could not open `%s' for reading as a data file: %s."
+msgstr "Nepavyksta atverti „%s“ nuskaitymui duomenų rinkmenos formatu: %s."
+
+#: src/language/data-io/data-reader.c:198
+msgid "Missing END DATA while reading inline data.  This probably indicates a missing or incorrectly formatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:219
+#, c-format
+msgid "Error reading file %s: %s."
+msgstr "Rinkmenos %s skaitymo klaida: %s."
+
+#: src/language/data-io/data-reader.c:222
+#, c-format
+msgid "Unexpected end of file reading %s."
+msgstr "Netikėta skaitomos rinkmenos %s pabaiga."
+
+#: src/language/data-io/data-reader.c:231
+#, c-format
+msgid "Unexpected end of file in partial record reading %s."
+msgstr "Netikėta rinkmenos pabaiga daliniame įraše skaitant %s."
+
+#: src/language/data-io/data-reader.c:291
+#, c-format
+msgid "Corrupt block descriptor word at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:292
+#, c-format
+msgid "Corrupt record descriptor word at offset 0x%lx in %s."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:305
+#, c-format
+msgid "Corrupt record size at offset 0x%lx in %s."
+msgstr "Sugadintas įrašo dydis ties 0x%lx poslinkiu (%s)."
+
+#: src/language/data-io/data-reader.c:445
+msgid "Record exceeds remaining block length."
+msgstr ""
+
+#: src/language/data-io/data-reader.c:519
+#, c-format
+msgid "Attempt to read beyond end-of-file on file %s."
+msgstr "Bandoma skaityti už rinkmenos %s pabaigos."
+
+#: src/language/data-io/data-reader.c:522
+msgid "Attempt to read beyond END DATA."
+msgstr "Bandoma skaityti už END DATA."
+
+#: src/language/data-io/data-reader.c:706
+msgid "This command is not valid here since the current input program does not access the inline file."
+msgstr ""
+
+#: src/language/data-io/data-writer.c:73
+#, c-format
+msgid "An error occurred while opening `%s' for writing as a data file: %s."
+msgstr "Klaida atveriant „%s“ įrašymui kaip duomenų rinkmeną: %s"
+
+#: src/language/data-io/data-writer.c:190
+#, c-format
+msgid "I/O error occurred writing data file `%s'."
+msgstr "Įvedimo/išvedimo klaida įrašant duomenų rinkmeną „%s“."
+
+#: src/language/data-io/dataset.c:63
+#, c-format
+msgid "There is no dataset named %s."
+msgstr "Tokio duomenų rinkinio vardu %s nėra"
+
+#: src/language/data-io/dataset.c:257
+msgid "Dataset"
+msgstr "Duomenų rinkinys"
+
+#: src/language/data-io/dataset.c:265
+msgid "unnamed dataset"
+msgstr "nepavadintas duomenų rinkinys"
+
+#: src/language/data-io/dataset.c:269
+msgid "(active dataset)"
+msgstr "(veikiamasis duomenų rinkinys)"
+
+#: src/language/data-io/get-data.c:64
+#, c-format
+msgid "Unsupported TYPE %s."
+msgstr "Nepalaikomas TYPE (tipas) %s."
+
+#: src/language/data-io/get-data.c:268
+#, c-format
+msgid "%s is allowed only with %s arrangement, but %s arrangement was stated or implied earlier in this command."
+msgstr ""
+
+#: src/language/data-io/get-data.c:337
+msgid "Value of FIRSTCASE must be 1 or greater."
+msgstr "FIRSTCASE turi būti 1 arba didesnė."
+
+#: src/language/data-io/get-data.c:375
+msgid "Value of FIXCASE must be at least 1."
+msgstr "FIXCASE reikšmė turi būti bent 1."
+
+#: src/language/data-io/get-data.c:395
+msgid "Value of FIRST must be at least 1."
+msgstr "FIRST reikšmė turi būti bent 1."
+
+#: src/language/data-io/get-data.c:407
+msgid "Value of PERCENT must be between 1 and 100."
+msgstr "PERCENT (procentų) reikšmė turi būti iš intervalo tarp 1 ir 100."
+
+#: src/language/data-io/get-data.c:458
+msgid "In compatible syntax mode, the QUALIFIER string must contain exactly one character."
+msgstr ""
+
+#: src/language/data-io/get-data.c:493
+#: src/language/data-io/placement-parser.c:377
+#, c-format
+msgid "The record number specified, %ld, is at or before the previous record, %d.  Data fields must be listed in order of increasing record number."
+msgstr ""
+
+#: src/language/data-io/get-data.c:502
+#, c-format
+msgid "The record number specified, %ld, exceeds the number of records per case specified on FIXCASE, %d."
+msgstr ""
+
+#: src/language/data-io/inpt-pgm.c:118
+msgid "Unexpected end-of-file within INPUT PROGRAM."
+msgstr ""
+
+#: src/language/data-io/inpt-pgm.c:131
+msgid "Input program did not create any variables."
+msgstr "Įvedimo programa nesukūrė jokių kintamųjų."
+
+#: src/language/data-io/inpt-pgm.c:330
+msgid "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
+msgstr "REREAD: stulpelių numeriai turi būti teigiami baigtiniai skaičiai. Stulpelis nustatomas į 1."
+
+#: src/language/data-io/placement-parser.c:86
+#, c-format
+msgid "Number of variables specified (%zu) differs from number of variable formats (%zu)."
+msgstr ""
+
+#: src/language/data-io/placement-parser.c:96
+msgid "SPSS-like or Fortran-like format specification expected after variable names."
+msgstr "Po kintamųjų vardų tikėtasi SPSS ar Fortran tipo formato specifikacijos."
+
+#: src/language/data-io/placement-parser.c:118
+#, c-format
+msgid "The %d columns %d-%d can't be evenly divided into %zu fields."
+msgstr ""
+
+#: src/language/data-io/placement-parser.c:302
+msgid "Column positions for fields must be positive."
+msgstr ""
+
+#: src/language/data-io/placement-parser.c:304
+msgid "Column positions for fields must not be negative."
+msgstr ""
+
+#: src/language/data-io/placement-parser.c:343
+msgid "The ending column for a field must be greater than the starting column."
+msgstr ""
+
+#: src/language/data-io/print-space.c:115
+msgid "The expression on PRINT SPACE evaluated to the system-missing value."
+msgstr ""
+
+#: src/language/data-io/print-space.c:118
+#, c-format
+msgid "The expression on PRINT SPACE evaluated to %g."
+msgstr ""
+
+#: src/language/data-io/print.c:179 src/language/data-io/trim.c:54
+msgid "expecting a valid subcommand"
+msgstr "tikimasi tinkamo pokomandžio"
+
+#: src/language/data-io/print.c:267
+#, c-format
+msgid "Output calls for %d records but %zu specified on RECORDS subcommand."
+msgstr ""
+
+#: src/language/data-io/print.c:436
+#, c-format
+msgid "Writing %zu record to %s."
+msgid_plural "Writing %zu records to %s."
+msgstr[0] "%zu įrašas įrašomas į %s."
+msgstr[1] "%zu įrašas įrašomas į %s."
+msgstr[2] "%zu įrašai įrašomi į %s."
+msgstr[3] "%zu įrašų įrašoma į %s."
+
+#: src/language/data-io/print.c:440
+#, c-format
+msgid "Writing %zu record."
+msgid_plural "Writing %zu records."
+msgstr[0] "Įrašomas %zu įrašas."
+msgstr[1] "Įrašomas %zu įrašas."
+msgstr[2] "Įrašomi %zu įrašai."
+msgstr[3] "Įrašoma %zu įrašų."
+
+#: src/language/data-io/save-translate.c:165
+#: src/language/data-io/save-translate.c:180
+#, c-format
+msgid "The %s string must contain exactly one character."
+msgstr "%s teksto eilutė privalo turėti būtent vieną simbolį."
+
+#: src/language/data-io/save-translate.c:250
+#, c-format
+msgid "Output file `%s' exists but REPLACE was not specified."
+msgstr "Išvedimo rinkmena „%s“ jau yra, bet nenurodyta ją pakeisti (REPLACE)."
+
+#: src/language/data-io/trim.c:89
+#, c-format
+msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, `/RENAME (A B C=B C A)'."
+msgstr ""
+
+#: src/language/data-io/trim.c:115
+msgid "`=' expected after variable list."
+msgstr "už kintamųjų sąrašo tikėtasi „=“."
+
+#: src/language/data-io/trim.c:123
+#, c-format
+msgid "Number of variables on left side of `=' (%zu) does not match number of variables on right side (%zu), in parenthesized group %d of RENAME subcommand."
+msgstr ""
+
+#: src/language/data-io/trim.c:136
+#, c-format
+msgid "Requested renaming duplicates variable name %s."
+msgstr ""
+
+#: src/language/data-io/trim.c:167
+msgid "Cannot DROP all variables from dictionary."
+msgstr "Negalima iš žodyno išmesti (DROP) visų kintamųjų."
+
+#: src/language/expressions/evaluate.c:152
+msgid "expecting number or string"
+msgstr "tikėtasi skaičiaus arba teksto eilutės"
+
+#: src/language/expressions/evaluate.c:166
+#, c-format
+msgid "Duplicate variable name %s."
+msgstr "Kintamojo vardas %s kartojasi."
+
+#: src/language/expressions/helpers.c:41
+msgid "One of the arguments to a DATE function is not an integer.  The result will be system-missing."
+msgstr ""
+
+#: src/language/expressions/helpers.c:69
+msgid "The week argument to DATE.WKYR is not an integer.  The result will be system-missing."
+msgstr ""
+
+#: src/language/expressions/helpers.c:75
+msgid "The week argument to DATE.WKYR is outside the acceptable range of 1 to 53.  The result will be system-missing."
+msgstr ""
+
+#: src/language/expressions/helpers.c:97
+msgid "The day argument to DATE.YRDAY is not an integer.  The result will be system-missing."
+msgstr ""
+
+#: src/language/expressions/helpers.c:103
+msgid "The day argument to DATE.YRDAY is outside the acceptable range of 1 to 366.  The result will be system-missing."
+msgstr ""
+
+#: src/language/expressions/helpers.c:125
+msgid "The year argument to YRMODA is greater than 47516.  The result will be system-missing."
+msgstr ""
+
+#. TRANSLATORS: Don't translate the the actual unit names `weeks', `days' etc
+#. They must remain in their original English.
+#: src/language/expressions/helpers.c:180
+#, c-format
+msgid "Unrecognized date unit `%.*s'.  Valid date units are `years', `quarters', `months', `weeks', `days', `hours', `minutes', and `seconds'."
+msgstr ""
+
+#: src/language/expressions/helpers.c:330
+msgid "Invalid DATESUM method.  Valid choices are `closest' and `rollover'."
+msgstr "Netinkamas DATESUM metodas. Tinkami metodai yra „closest“ ir „rollover“."
+
+#: src/language/expressions/parse.c:260
+#, c-format
+msgid "Type mismatch: expression has %s type, but a numeric value is required here."
+msgstr "Neatitinka tipai: išraiška yra %s tipo, bet reikia skaitmeninio kintamojo."
+
+#: src/language/expressions/parse.c:272
+#, c-format
+msgid "Type mismatch: expression has %s type, but a string value is required here."
+msgstr "Neatitinka tipai: išraiška yra %s tipo, bet reikia teksto eilutės kintamojo."
+
+#: src/language/expressions/parse.c:434
+#, c-format
+msgid "Type mismatch while applying %s operator: cannot convert %s to %s."
+msgstr "Neatitinka tipai pritaikant %s operatorių: negalima konvertuoti iš %s į %s."
+
+#: src/language/expressions/parse.c:648
+msgid "Chaining relational operators (e.g. `a < b < c') will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. `a < b AND b < c').  If chaining is really intended, parentheses will disable this warning (e.g. `(a < b) < c'.)"
+msgstr ""
+
+#: src/language/expressions/parse.c:750
+msgid "The exponentiation operator (`**') is left-associative, even though right-associative semantics are more useful.  That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'.  To disable this warning, insert parentheses."
+msgstr ""
+
+#: src/language/expressions/parse.c:830
+#, c-format
+msgid "Unknown system variable %s."
+msgstr "Nežinomas sisteminis kintamasis %s."
+
+#: src/language/expressions/parse.c:878
+#, c-format
+msgid "Unknown identifier %s."
+msgstr "Nežinomas identifikatorius %s."
+
+#: src/language/expressions/parse.c:1100
+#, c-format
+msgid "%s must have at least %d arguments in list."
+msgstr "%s privalo turėti bent %d argumentų."
+
+#: src/language/expressions/parse.c:1109
+#, c-format
+msgid "%s must have an even number of arguments in list."
+msgstr "%s privalo turėti lyginį argumentų skaičių."
+
+#: src/language/expressions/parse.c:1112
+#, c-format
+msgid "%s must have multiple of %d arguments in list."
+msgstr "%s privalo turėti keletą %d argumentų."
+
+#: src/language/expressions/parse.c:1122
+#, c-format
+msgid "%s function does not accept a minimum valid argument count."
+msgstr ""
+
+#: src/language/expressions/parse.c:1131
+#, c-format
+msgid "%s requires at least %d valid arguments in list."
+msgstr "%s reikalauja, kad sąraše būtų bent %d galiojančių argumentų."
+
+#: src/language/expressions/parse.c:1137
+#, c-format
+msgid "With %s, using minimum valid argument count of %d does not make sense when passing only %d arguments in list."
+msgstr ""
+
+#: src/language/expressions/parse.c:1191
+#, c-format
+msgid "Type mismatch invoking %s as "
+msgstr ""
+
+#: src/language/expressions/parse.c:1196
+msgid "Function invocation "
+msgstr "Kviečiama funkcija "
+
+#: src/language/expressions/parse.c:1198
+msgid " does not match any known function.  Candidates are:"
+msgstr " neatitinka jokios žinomos funkcijos. Pasiūlymai:"
+
+#: src/language/expressions/parse.c:1228
+#, c-format
+msgid "No function or vector named %s."
+msgstr "Tokios „%s“ funkcijos arba vektoriaus nėra."
+
+#: src/language/expressions/parse.c:1271
+#, c-format
+msgid "expecting `,' or `)' invoking %s function"
+msgstr ""
+
+#: src/language/expressions/parse.c:1291
+#, c-format
+msgid "%s is a PSPP extension."
+msgstr "%s yra PSPP plėtinys."
+
+#: src/language/expressions/parse.c:1300
+#, c-format
+msgid "%s may not appear after TEMPORARY."
+msgstr "%s gali nebūti po TEMPORARY."
+
+#: src/libpspp/ext-array.c:56
+msgid "failed to create temporary file"
+msgstr "nepavyko sukurti laikinos rinkmenos"
+
+#: src/libpspp/ext-array.c:96
+msgid "seeking in temporary file"
+msgstr "ieškoma laikinojoje rinkmenoje"
+
+#: src/libpspp/ext-array.c:115
+msgid "reading temporary file"
+msgstr "skaitoma laikinoji rinkmena"
+
+#: src/libpspp/ext-array.c:117
+msgid "unexpected end of file reading temporary file"
+msgstr "netikėta skaitomos laikinosios rinkmenos pabaiga"
+
+#: src/libpspp/ext-array.c:136
+msgid "writing to temporary file"
+msgstr "rašoma į laikinąją rinkmeną"
+
+#: src/libpspp/message.c:172
+msgid "error"
+msgstr "klaida"
+
+#: src/libpspp/message.c:175
+msgid "warning"
+msgstr "įspėjimas"
+
+#: src/libpspp/message.c:179
+msgid "note"
+msgstr "pastaba"
+
+#: src/libpspp/message.c:279
+#, c-format
+msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
+msgstr "Pastabų kiekis (%d) pasiekė ribą (%d). Daugiau pastabų nebus."
+
+#: src/libpspp/message.c:287
+#, c-format
+msgid "Warnings (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Įspėjimų kiekis (%d) pasiekė ribą (%d).  Sintaksės apdorojimas nutraukiamas."
+
+#: src/libpspp/message.c:290
+#, c-format
+msgid "Errors (%d) exceed limit (%d).  Syntax processing will be halted."
+msgstr "Klaidų kiekis (%d) pasiekė ribą (%d).  Sintaksės apdorojimas nutraukiamas."
+
+#: src/libpspp/zip-writer.c:91
+#, c-format
+msgid "%s: error opening output file"
+msgstr "%s: klaida bandant atverti išvesties rinkmeną"
+
+#: src/libpspp/zip-writer.c:224
+#, c-format
+msgid "%s: write failed"
+msgstr "%s: nepavyko rašyti"
+
+#: src/math/percentiles.c:36
+msgid "HAverage"
+msgstr ""
+
+#: src/math/percentiles.c:37
+msgid "Weighted Average"
+msgstr "Svertinis vidurkis"
+
+#: src/math/percentiles.c:38
+msgid "Rounded"
+msgstr "Suapvalintas"
+
+#: src/math/percentiles.c:39
+msgid "Empirical"
+msgstr "Empirinis"
+
+#: src/math/percentiles.c:40
+msgid "Empirical with averaging"
+msgstr ""
+
+#: src/output/ascii.c:298
+#, c-format
+msgid "%s: %s must be positive integer or `auto'"
+msgstr "%s: %s turi būti teigiamas sveikasis skaičius arba „auto“"
+
+#: src/output/ascii.c:331
+#, c-format
+msgid "ascii: page excluding margins and headers must be at least %d characters wide by %d lines long, but as configured is only %d characters by %d lines"
+msgstr ""
+
+#: src/output/ascii.c:377
+#, c-format
+msgid "ascii: closing output file `%s'"
+msgstr "ascii: užveriama rezultatų rinkmena „%s“"
+
+#: src/output/ascii.c:520
+#, c-format
+msgid "See %s for a chart."
+msgstr "Diagrama: %s."
+
+#: src/output/ascii.c:1102
+#, c-format
+msgid "ascii: opening output file `%s'"
+msgstr "ascii: atveriama rezultatų rinkmena „%s“"
+
+#: src/output/ascii.c:1173
+#, c-format
+msgid "%s - Page %d"
+msgstr "%s - %d puslapis"
+
+#: src/output/csv.c:97 src/output/html.c:104 src/output/journal.c:93
+#: src/output/msglog.c:66
+#, c-format
+msgid "error opening output file `%s'"
+msgstr "klaida bandant atverti išvesties rinkmeną „%s“"
+
+#. TRANSLATORS: Don't translate the words `terminal' or `listing'.
+#: src/output/driver.c:319
+#, c-format
+msgid "%s is not a valid device type (the choices are `terminal' and `listing')"
+msgstr "%s nėra tinkamas įrenginio tipas (tinka „terminal“ ir „listing“)"
+
+#: src/output/driver.c:332
+#, c-format
+msgid "%s: unknown option `%s'"
+msgstr "%s: nežinoma parinktis „%s“"
+
+#: src/output/html.c:112
+msgid "PSPP Output"
+msgstr "PSPP rezultatai"
+
+#: src/output/html.c:238
+msgid "No description"
+msgstr "Aprašo nėra"
+
+#: src/output/journal.c:67
+#, c-format
+msgid "error writing output file `%s'"
+msgstr "klaida bandant rašyti į rezultatų rinkmeną „%s“"
+
+#: src/output/measure.c:65
+#, c-format
+msgid "`%s' is not a valid length."
+msgstr "„%s“ nėra tinkamas ilgis."
+
+#: src/output/measure.c:93
+#, c-format
+msgid "syntax error in paper size `%s'"
+msgstr "sintaksės klaida ties popieriaus matmenimis „%s“"
+
+#: src/output/measure.c:230
+#, c-format
+msgid "unknown paper type `%.*s'"
+msgstr "nežinomas popieriaus tipas „%.*s“"
+
+#: src/output/measure.c:248
+#, c-format
+msgid "error opening input file `%s'"
+msgstr "klaida bandant atverti įvesties rinkmeną „%s“"
+
+#: src/output/measure.c:259
+#, c-format
+msgid "error reading file `%s'"
+msgstr "klaida bandant nuskaityti rinkmeną „%s“"
+
+#: src/output/measure.c:276
+#, c-format
+msgid "paper size file `%s' does not state a paper size"
+msgstr "popieriaus dydžio rinkmena „%s“ neatitinka popieriaus dydžio"
+
+#: src/output/options.c:113
+#, c-format
+msgid "%s: `%s' is `%s' but a Boolean value is required"
+msgstr "%s: „%s“ yra „%s“, reikia loginės reikšmės"
+
+#: src/output/options.c:188
+#, c-format
+msgid "%s: `%s' is `%s' but one of the following is required: %s"
+msgstr "%s: „%s“ yra „%s“, bet reikia vieno iš šių: %s"
+
+#: src/output/options.c:232
+#, c-format
+msgid "%s: `%s' is `%s' but a nonnegative integer is required"
+msgstr "%s: „%s“ yra „%s“, bet reikia neneigiamo sveikojo skaičiaus"
+
+#: src/output/options.c:236
+#, c-format
+msgid "%s: `%s' is `%s' but a positive integer is required"
+msgstr "%s: „%s“ yra „%s“, bet reikia teigiamo sveikojo skaičiaus"
+
+#: src/output/options.c:239
+#, c-format
+msgid "%s: `%s' is `%s' but an integer is required"
+msgstr "%s: „%s“ yra „%s“, bet reikia sveikojo skaičiaus"
+
+#: src/output/options.c:242
+#, c-format
+msgid "%s: `%s' is `%s' but an integer greater than %d is required"
+msgstr "%s: „%s“ yra „%s“, bet reikia sveikojo skaičiaus, didesnio už %d"
+
+#: src/output/options.c:247
+#, c-format
+msgid "%s: `%s' is `%s'  but an integer between %d and %d is required"
+msgstr "%s: „%s“ yra „%s“, bet reikia sveikojo skaičiaus iš intervalo nuo %d iki %d"
+
+#: src/output/options.c:326
+#, c-format
+msgid "%s: `%s' is `%s' but a file name that contains `#' is required."
+msgstr "%s: „%s“ yra „%s“, bet reikia rinkmenos pavadinimo, turinčio „#“."
+
+#: src/output/tab.c:207
+#, c-format
+msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
+msgstr ""
+
+#: src/output/tab.c:245
+#, c-format
+msgid "bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in table size (%d,%d)\n"
+msgstr ""
+
+#: src/output/tab.c:289
+#, c-format
+msgid "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
+msgstr ""
+
+#: src/output/cairo.c:193
+#, c-format
+msgid "`%s': bad font specification"
+msgstr "„%s“: netinkama šrifto specifikacija"
+
+#: src/output/cairo.c:357
+#, c-format
+msgid "error opening output file `%s': %s"
+msgstr "klaida bandant atverti rezultatų rinkmeną „%s“: %s"
+
+#: src/output/cairo.c:374
+#, c-format
+msgid "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."
+msgstr ""
+
+#: src/output/cairo.c:384
+#, c-format
+msgid "The defined page is not long enough to hold at least %d lines in the default font.  In fact, there's only room for %d lines."
+msgstr ""
+
+#: src/output/cairo.c:435
+#, c-format
+msgid "error drawing output for %s driver: %s"
+msgstr ""
+
+#: src/output/cairo.c:1073
+#, c-format
+msgid "error writing output file `%s': %s"
+msgstr "klaida bandant rašyti į rezultatų rinkmeną „%s“: %s"
+
+#: src/output/charts/np-plot-cairo.c:37
+#, c-format
+msgid "Normal Q-Q Plot of %s"
+msgstr ""
+
+#: src/output/charts/np-plot-cairo.c:38 src/output/charts/np-plot-cairo.c:65
+msgid "Observed Value"
+msgstr "Stebėta reikšmė"
+
+#: src/output/charts/np-plot-cairo.c:39
+msgid "Expected Normal"
+msgstr ""
+
+#: src/output/charts/np-plot-cairo.c:64
+#, c-format
+msgid "Detrended Normal Q-Q Plot of %s"
+msgstr ""
+
+#: src/output/charts/np-plot-cairo.c:66
+msgid "Dev from Normal"
+msgstr ""
+
+#: src/output/charts/plot-hist-cairo.c:110
+msgid "HISTOGRAM"
+msgstr "HISTOGRAMA"
+
+#: src/output/charts/plot-hist-cairo.c:112
+#: src/language/stats/frequencies.q:822
+msgid "Frequency"
+msgstr "Dažnis"
+
+#: src/output/charts/roc-chart-cairo.c:36 src/ui/gui/roc.ui:7
+msgid "ROC Curve"
+msgstr "Operatoriaus charakteringa kreivė"
+
+#: src/output/charts/scree-cairo.c:36
+msgid "Scree Plot"
+msgstr "Tikrinių reikšmių grafikas"
+
+#: src/output/charts/scree-cairo.c:38
+msgid "Eigenvalue"
+msgstr "Tikrinė reikšmė"
+
+#: src/output/odt.c:94
+msgid "error creating temporary file"
+msgstr "klaida bandant sukurti laikinąją rinkmeną"
+
+#: src/ui/source-init-opts.c:77
+msgid "Algorithm must be either `compatible' or `enhanced'."
+msgstr "Algoritmas turi būti „compatible“ arba „enhanced“."
+
+#: src/ui/source-init-opts.c:104
+msgid "Syntax must be either `compatible' or `enhanced'."
+msgstr "Sintaksė turi būti „compatible“ arba „enhanced“."
+
+#: src/ui/terminal/main.c:148
+msgid "Error encountered while ERROR=STOP is effective."
+msgstr "Klaida įvyko esant aktyviam ERROR=STOP."
+
+#: src/ui/terminal/main.c:154
+msgid "Stopping syntax file processing here to avoid a cascade of dependent command failures."
+msgstr "Sintaksės rinkmenos apdorojimas stabdomas tam, kad būtų išvengta klaidų susijusiose komandose."
+
+#: src/ui/terminal/terminal-opts.c:122
+#, c-format
+msgid "%s: output option missing `='"
+msgstr "%s: išvedimo parinkčiai trūksta „=“"
+
+#: src/ui/terminal/terminal-opts.c:129
+#, c-format
+msgid "%s: output option specified more than once"
+msgstr "%s: išvedimo parinktis nurodyta daugiau nei vieną kartą"
+
+#: src/ui/terminal/terminal-opts.c:171
+#, c-format
+msgid ""
+"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"
+"  --no-output               disable default output driver\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"
+"  -b, --batch               interpret syntax in batch mode\n"
+"  -i, --interactive         interpret syntax in interactive mode\n"
+"  --syntax-encoding=ENCODING  specify encoding for syntax files\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"
+msgstr ""
+"PSPP,  programa imties duomenų statistinei analizei.\n"
+"Naudojimas: %s [PARINKTIS]... RINKMENA...\n"
+"\n"
+"Argumentai, skirti ilgosioms parinktims, taip pat taikomi ir atitinkamoms trumposioms parinktims.\n"
+"\n"
+"Išvedimo parinktys:\n"
+"  -o, --output=RINKMENA     rezultatus rašyti į RINKMENĄ, formatas pagal jos pavadinimą\n"
+"  -O format=FORMATAS        naudoti formatą, nepaisant -o parinkties\n"
+"  -O PARINKTIS=REIKŠMĖ      nustatyti rezultatų išvedimo parinktį\n"
+"  -O device={terminal|listing}  naudoti įrenginio tipą aukščiau nurodytai -o\n"
+"  -e, --error-file=RINKMENA klaidas, įspėjimus, pastabas rašyti papildant RINKMENĄ\n"
+"  --no-output               uždrausti numatytąją rezultatų išvedimo tvarkyklę\n"
+"Palaikomi išvedimo formatai: %s\n"
+"\n"
+"Kalbos parinktys:\n"
+"  -I, --include=KATALOGAS   į paieškos kelią įtraukti KATALOGĄ\n"
+"  -I-, --no-include         išvalyti paieškos kelią\n"
+"  -r, --no-statrc           paleidžiant uždrausti veikiančią rc rinkmeną\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            nustatykite „compatible“, jei norite rezultatų,\n"
+"                            suskaičiuotų naudojant prastesnius algoritmus\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            rinkdamiesi „compatible“ uždrausite PSPP papildinius\n"
+"  -i, --interactive         sintaksę interpretuoti interaktyvioje veiksenoje\n"
+"  -s, --safer               neleisti nesaugių operacijų\n"
+"Numatytasis paieškos kelias:%s\n"
+"\n"
+"Informacijos išvedimas:\n"
+"  -h, --help                parodyti šį pagalbos pranešimą ir išeiti\n"
+"  -V, --version             parodyti versijos informaciją ir išeiti\n"
+"\n"
+"Argumentai, kurie nėra parinktys, interpretuojami kaip vykdytinos sintaksės rinkmenos.\n"
+
+#: src/ui/terminal/terminal.c:62
+#, c-format
+msgid "could not access definition for terminal `%s'"
+msgstr ""
+
+#: src/ui/gui/aggregate-dialog.c:161
+msgid "Aggregate destination file"
+msgstr "Agregavimo paskirties rinkmena"
+
+#: src/ui/gui/aggregate-dialog.c:172 src/ui/gui/psppire-data-window.c:489
+#: src/ui/gui/psppire-window.c:763
+msgid "System Files (*.sav)"
+msgstr "Sisteminės rinkmenos (*.sav)"
+
+#: src/ui/gui/aggregate-dialog.c:178 src/ui/gui/psppire-data-window.c:495
+#: src/ui/gui/psppire-window.c:769
+msgid "Portable Files (*.por) "
+msgstr "Perkeliamos (Portable) rinkmenos (*.por)"
+
+#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1233
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1307 src/language/stats/examine.q:1637
+msgid "Statistic"
+msgstr "Statistika"
+
+#: src/ui/gui/comments-dialog.c:57
+#, c-format
+msgid "Column Number: %d"
+msgstr "Stulpelio numeris: %d"
+
+#: src/ui/gui/crosstabs-dialog.c:40
+msgid "Chisq"
+msgstr "Chi-kvadr."
+
+#: src/ui/gui/crosstabs-dialog.c:41 src/language/stats/crosstabs.q:1806
+msgid "Phi"
+msgstr "Phi"
+
+#: src/ui/gui/crosstabs-dialog.c:42
+msgid "CC"
+msgstr "CC"
+
+#: src/ui/gui/crosstabs-dialog.c:43 src/language/stats/crosstabs.q:1944
+msgid "Lambda"
+msgstr "Liambda"
+
+#: src/ui/gui/crosstabs-dialog.c:44
+msgid "UC"
+msgstr "Neap.k."
+
+#: src/ui/gui/crosstabs-dialog.c:45
+msgid "BTau"
+msgstr "BTau"
+
+#: src/ui/gui/crosstabs-dialog.c:46
+msgid "CTau"
+msgstr "CTau"
+
+#: src/ui/gui/crosstabs-dialog.c:47
+msgid "Risk"
+msgstr "Rizikos laipsnis"
+
+#: src/ui/gui/crosstabs-dialog.c:48 src/language/stats/crosstabs.q:1811
+msgid "Gamma"
+msgstr "Gamma"
+
+#: src/ui/gui/crosstabs-dialog.c:49
+msgid "D"
+msgstr "D"
+
+#: src/ui/gui/crosstabs-dialog.c:50 src/language/stats/crosstabs.q:1814
+msgid "Kappa"
+msgstr "Kappa"
+
+#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1948
+msgid "Eta"
+msgstr "Eta"
+
+#: src/ui/gui/crosstabs-dialog.c:52
+msgid "Corr"
+msgstr "Korel."
+
+#: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
+#: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
+#: src/ui/gui/variable-info-dialog.c:41
+msgid "None"
+msgstr "Nieko"
+
+#: src/ui/gui/crosstabs-dialog.c:56
+msgid "Count"
+msgstr "Kiekis"
+
+#: src/ui/gui/crosstabs-dialog.c:57
+msgid "Row"
+msgstr "Eilutė"
+
+#: src/ui/gui/crosstabs-dialog.c:58
+msgid "Column"
+msgstr "Stulpelis"
+
+#: src/ui/gui/crosstabs-dialog.c:60
+msgid "Expected"
+msgstr "Spėjama"
+
+#: src/ui/gui/crosstabs-dialog.c:62
+msgid "Std. Residual"
+msgstr "Normuota liekana"
+
+#: src/ui/gui/crosstabs-dialog.c:63
+msgid "Adjusted Std. Residual"
+msgstr "Patikslinta normuota liekana"
+
+#: src/ui/gui/descriptives-dialog.c:45
+msgid "Standard error"
+msgstr "Standartinė paklaida"
+
+#: src/ui/gui/find-dialog.c:649
+#, c-format
+msgid "Bad regular expression: %s"
+msgstr "Netinkama reguliarioji išraiška: %s"
+
+#: src/ui/gui/factor-dialog.c:343
+#, c-format
+msgid "Eigenvalues over %4.2f times the mean eigenvalue"
+msgstr "Pagal tikrines reikšmes viršija %4.2f"
+
+#: src/ui/gui/frequencies-dialog.c:44
+msgid "Standard error of the mean"
+msgstr "Standartinė vidurkio paklaida"
+
+#: src/ui/gui/frequencies-dialog.c:47
+msgid "Standard error of the skewness"
+msgstr "Standartinė asimetrijos paklaida"
+
+#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/frequencies.q:108
+msgid "Mode"
+msgstr "Veiksena"
+
+#: src/ui/gui/frequencies-dialog.c:51
+msgid "Standard error of the kurtosis"
+msgstr "Standartinė eksceso paklaida"
+
+#: src/ui/gui/frequencies-dialog.c:52 src/language/stats/examine.q:1468
+#: src/language/stats/frequencies.q:107
+msgid "Median"
+msgstr "Mediana"
+
+#: src/ui/gui/help-menu.c:67
+msgid "A program for the analysis of sampled data"
+msgstr "Programa imties duomenų analizavimui"
+
+#. TRANSLATORS: Use this string to list the people who have helped with
+#. translation to your language.
+#: src/ui/gui/help-menu.c:77
+msgid "translator-credits"
+msgstr "Mindaugas Baranauskas"
+
+#: src/ui/gui/help-menu.c:98
+#, c-format
+msgid "Cannot open reference manual: %s.  The PSPP user manual is also available at %s"
+msgstr "Nepavyksta atverti žinyno: %s. PSPP naudotojo žinyną taip pat galite rasti %s"
+
+#: src/ui/gui/help-menu.c:117
+msgid "_Help"
+msgstr "_Pagalba"
+
+#: src/ui/gui/help-menu.c:124
+msgid "_Reference Manual"
+msgstr "Ž_inynas"
+
+#: src/ui/gui/main.c:82
+#, c-format
+msgid ""
+"PSPPIRE, a GUI for 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"
+"GUI options:\n"
+"  -q, --no-splash           don't show splash screen during startup\n"
+"\n"
+"%sLanguage options:\n"
+"  -I, --include=DIR         append DIR to search path\n"
+"  -I-, --no-include         clear search path\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"
+"A non-option argument is interpreted as a .sav or .por file to load.\n"
+msgstr ""
+"PSPPIRE, PSPP grafinė sąsaja, programa imties duomenų statistinei analizei.\n"
+"Naudojimas: %s [PARINKTIS]... RINKMENA...\n"
+"\n"
+"Argumentai, skirti ilgosioms parinktims, taip pat taikomi ir atitinkamoms trumposioms parinktims.\n"
+"\n"
+"Grafinės naudotojo sąsajos parinktys:\n"
+"  -q, --no-splash           paleidžiant nerodyti pristatymo lango\n"
+"\n"
+"%sKalbos parinktys:\n"
+"  -I, --include=KATALOGAS   į paieškos kelią įtraukti KATALOGĄ\n"
+"  -I-, --no-include         išvalyti paieškos kelią\n"
+"  -a, --algorithm={compatible|enhanced}\n"
+"                            nustatykite „compatible“, jei norite rezultatų,\n"
+"                            suskaičiuotų naudojant prastesnius algoritmus\n"
+"  -x, --syntax={compatible|enhanced}\n"
+"                            rinkdamiesi „compatible“ uždrausite PSPP papildinius\n"
+"  -i, --interactive         sintaksę interpretuoti interaktyvioje veiksenoje\n"
+"  -s, --safer               neleisti nesaugių operacijų\n"
+"Numatytasis paieškos kelias:%s\n"
+"\n"
+"Informacijos išvedimas:\n"
+"  -h, --help                parodyti šį pagalbos pranešimą ir išeiti\n"
+"  -V, --version             parodyti versijos informaciją ir išeiti\n"
+"\n"
+"Argumentai, kurie nėra parinktys, interpretuojami kaip vykdytinos .sav ar .por rinkmenos.\n"
+
+#: src/ui/gui/missing-val-dialog.c:113 src/ui/gui/missing-val-dialog.c:167
+msgid "Incorrect value for variable type"
+msgstr "Reikšmė netinka kintamojo tipui"
+
+#: src/ui/gui/missing-val-dialog.c:134 src/ui/gui/missing-val-dialog.c:143
+msgid "Incorrect range specification"
+msgstr "Klaidinga srities specifikacija"
+
+#: src/ui/gui/oneway-anova-dialog.c:300
+#, c-format
+msgid "Contrast %d of %d"
+msgstr "%d kontrastas iš %d"
+
+#: src/ui/gui/psppire.c:191
+msgid "_Reset"
+msgstr "At_statyti"
+
+#: src/ui/gui/psppire.c:192
+msgid "_Select"
+msgstr "_Pasirinkti"
+
+#: src/ui/gui/psppire-data-editor.c:970
+msgid "Data View"
+msgstr "Duomenų rodinys"
+
+#: src/ui/gui/psppire-data-editor.c:973
+msgid "Variable View"
+msgstr "Kintamųjų rodinys"
+
+#: src/ui/gui/psppire-data-store.c:744
+msgid "var"
+msgstr "kint"
+
+#: src/ui/gui/psppire-data-window.c:202
+msgid "Transformations Pending"
+msgstr "Laukiama transformacijos"
+
+#: src/ui/gui/psppire-data-window.c:218
+msgid "Filter off"
+msgstr "Nefiltr."
+
+#: src/ui/gui/psppire-data-window.c:232
+#, c-format
+msgid "Filter by %s"
+msgstr "Filtr. pg. %s"
+
+#: src/ui/gui/psppire-data-window.c:253
+msgid "No Split"
+msgstr "Neskaidoma"
+
+#: src/ui/gui/psppire-data-window.c:262
+msgid "Split by "
+msgstr "Skaid. pg. "
+
+#: src/ui/gui/psppire-data-window.c:290
+msgid "Weights off"
+msgstr "Nesveriama"
+
+#: src/ui/gui/psppire-data-window.c:304
+#, c-format
+msgid "Weight by %s"
+msgstr "Sverti pagal %s"
+
+#: src/ui/gui/psppire-data-window.c:481 src/ui/gui/aggregate.ui:448
+msgid "Save"
+msgstr "Įrašyti"
+
+#: src/ui/gui/psppire-data-window.c:501 src/ui/gui/psppire-syntax-window.c:508
+#: src/ui/gui/psppire-window.c:781
+msgid "All Files"
+msgstr "Visos rinkmenos"
+
+#: src/ui/gui/psppire-data-window.c:514
+msgid "Portable File"
+msgstr "Perkeliama rinkmena"
+
+#: src/ui/gui/psppire-data-window.c:571
+msgid "Delete Existing Dataset?"
+msgstr "Pašalinti esamą duomenų rinkinį?"
+
+#: src/ui/gui/psppire-data-window.c:575
+#, c-format
+msgid "Renaming \"%s\" to \"%s\" will delete destroy the existing dataset named \"%s\".  Are you sure that you want to do this?"
+msgstr "„%s“ pervadinant į „%s“, bus pašalintas esamas duomenų rinkinys vardu „%s“. Tikrai tęsti?"
+
+#: src/ui/gui/psppire-data-window.c:603
+#, c-format
+msgid "Please enter a new name for dataset \"%s\":"
+msgstr "Įveskite naują duomenų rinkinio „%s“ vardą:"
+
+#: src/ui/gui/psppire-data-window.c:605
+msgid "Rename Dataset"
+msgstr "Duomenų rinkinio pervadinimas"
+
+#: src/ui/gui/psppire-data-window.c:684
+msgid "Font Selection"
+msgstr "Šrifto pasirinkimas"
+
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-data-window.c:1287
+msgid "Data Editor"
+msgstr "Duomenų redaktorius"
+
+#. TRANSLATORS: This string must be a valid variable name.  That means:
+#. - The string must be at most 64 bytes (not characters) long.
+#. - The string may not contain whitespace.
+#. - The first character may not be '$'
+#. - The first character may not be a digit
+#. - The final charactor may not be '.' or '_'
+#.
+#: src/ui/gui/psppire-dict.c:367
+#, c-format
+msgid "VAR%05d"
+msgstr "Kint%05d"
+
+#: src/ui/gui/psppire-output-window.c:467
+msgid "Infer file type from extension"
+msgstr "Rinkmenos tipą nuspėti pagal prievardį"
+
+#: src/ui/gui/psppire-output-window.c:468
+msgid "PDF (*.pdf)"
+msgstr "PDF (*.pdf)"
+
+#: src/ui/gui/psppire-output-window.c:469
+msgid "HTML (*.html)"
+msgstr "HTML (*.html)"
+
+#: src/ui/gui/psppire-output-window.c:470
+msgid "OpenDocument (*.odt)"
+msgstr "OpenDocument (*.odt)"
+
+#: src/ui/gui/psppire-output-window.c:471
+msgid "Text (*.txt)"
+msgstr "Tekstinės rinkmenos (*.txt)"
+
+#: src/ui/gui/psppire-output-window.c:472
+msgid "PostScript (*.ps)"
+msgstr "Postskriptinės rinkmenos (*.ps)"
+
+#: src/ui/gui/psppire-output-window.c:473
+msgid "Comma-Separated Values (*.csv)"
+msgstr "Kableliais atskirtų reikšmių rinkmena (*.csv)"
+
+#: src/ui/gui/psppire-output-window.c:574
+msgid "Export Output"
+msgstr "Eksportuoti rezultatus"
+
+#: src/ui/gui/psppire-output-window.c:828
+msgid "failed to create temporary directory"
+msgstr "nepavyko sukurti laikinojo aplanko"
+
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-output-window.c:1059
+msgid "Output"
+msgstr "Rezultatai"
+
+#: src/ui/gui/psppire-output-window.c:1060
+msgid "Output Viewer"
+msgstr "Rezultatų peržiūra"
+
+#: src/ui/gui/psppire-syntax-window.c:475
+#, c-format
+msgid "Saved file `%s'"
+msgstr "Rinkmena „%s“ įrašyta"
+
+#: src/ui/gui/psppire-syntax-window.c:494
+msgid "Save Syntax"
+msgstr "Įrašyti sintaksę"
+
+#: src/ui/gui/psppire-syntax-window.c:502 src/ui/gui/psppire-window.c:775
+msgid "Syntax Files (*.sps) "
+msgstr "Sintaksės rinkmenos (*.sps)"
+
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-syntax-window.c:733
+msgid "Syntax Editor"
+msgstr "Sintaksės redaktorius"
+
+#: src/ui/gui/psppire-syntax-window.c:747
+#, c-format
+msgid "Cannot load syntax file `%s'"
+msgstr "Nepavyksta įkelti sintaksės rinkmenos „%s“"
+
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:834
+#: src/language/stats/crosstabs.q:1308 src/ui/gui/compute.ui:599
+msgid "Type"
+msgstr "Tipas"
+
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/compute.ui:517
+msgid "Width"
+msgstr "Ilgis"
+
+#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:836
+msgid "Decimals"
+msgstr "10-tainė skiltis"
+
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:838
+msgid "Values"
+msgstr "Reikšmės"
+
+#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:839
+#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1103
+#: src/language/stats/frequencies.q:872 src/language/stats/frequencies.q:1043
+msgid "Missing"
+msgstr "Praleista"
+
+#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:841
+msgid "Align"
+msgstr "Lygiuotė"
+
+#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:842
+msgid "Measure"
+msgstr "Matavimo skalė"
+
+#: src/ui/gui/psppire-var-store.c:622 src/ui/gui/var-sheet-dialogs.ui:43
+msgid "Comma"
+msgstr "Su kableliu"
+
+#: src/ui/gui/psppire-var-store.c:623 src/ui/gui/var-sheet-dialogs.ui:59
+msgid "Dot"
+msgstr "Su tašku"
+
+#: src/ui/gui/psppire-var-store.c:624
+msgid "Scientific"
+msgstr "Mokslinis"
+
+#: src/ui/gui/psppire-var-store.c:625 src/ui/gui/var-sheet-dialogs.ui:91
+msgid "Date"
+msgstr "Data"
+
+#: src/ui/gui/psppire-var-store.c:626 src/ui/gui/var-sheet-dialogs.ui:107
+msgid "Dollar"
+msgstr "Doleriai"
+
+#: src/ui/gui/psppire-var-store.c:627
+msgid "Custom"
+msgstr "Savitas"
+
+#: src/ui/gui/psppire-var-store.c:755
+#, c-format
+msgid "{%s,`%s'}_"
+msgstr "{%s,„%s“}_"
+
+#: src/ui/gui/psppire-window.c:549
+#, c-format
+msgid "Save the changes to `%s' before closing?"
+msgstr "Prieš užveriant įrašyti pakeitimus į „%s“?"
+
+#: src/ui/gui/psppire-window.c:556
+#, c-format
+msgid "If you don't save, changes from the last %ld seconds will be permanently lost."
+msgstr "Jei neįrašysite, visiškai prarasite pakeitimus, kuriuos atlikote per pastarąsias %ld sekundes."
+
+#: src/ui/gui/psppire-window.c:560
+msgid "Close _without saving"
+msgstr "Užverti _neįrašant"
+
+#: src/ui/gui/psppire-window.c:743
+msgid "Open"
+msgstr "Atverti"
+
+#: src/ui/gui/psppire-window.c:753
+msgid "Data and Syntax Files"
+msgstr "Duomenų ir sintaksės rinkmenos"
+
+#: src/ui/gui/recode-dialog.c:886
+msgid "Recode into Different Variables"
+msgstr "Perkoduoti į kitus kintamuosius"
+
+#: src/ui/gui/recode-dialog.c:889 src/ui/gui/recode.ui:692
+msgid "Recode into Same Variables"
+msgstr "Perkoduoti į tuos pačius kintamuosius"
+
+#: src/ui/gui/recode-dialog.c:903 src/ui/gui/recode-dialog.c:999
+msgid "New"
+msgstr "Naujas"
+
+#: src/ui/gui/recode-dialog.c:918 src/ui/gui/recode-dialog.c:991
+msgid "Old"
+msgstr "Sena"
+
+#: src/ui/gui/recode-dialog.c:1236
+msgid "Recode into Different Variables: Old and New Values "
+msgstr "Perkoduoti į kitus kintamuosius senos ir naujos reikšmės "
+
+#: src/ui/gui/recode-dialog.c:1237
+msgid "Recode into Same Variables: Old and New Values"
+msgstr "Perkoduoti į tuos pačius kintamuosius: senos ir naujos reikšmės"
+
+#: src/ui/gui/regression-dialog.c:41
+msgid "Coeff"
+msgstr "Koef."
+
+#: src/ui/gui/regression-dialog.c:42 src/language/stats/regression.q:157
+msgid "R"
+msgstr "R"
+
+#: src/ui/gui/regression-dialog.c:43
+msgid "Anova"
+msgstr "Anova"
+
+#: src/ui/gui/regression-dialog.c:44
+msgid "Bcov"
+msgstr "Bcov"
+
+#: src/ui/gui/select-cases-dialog.c:81
+#, c-format
+msgid "Approximately %3d%% of all cases."
+msgstr "Maždaug %3d%% visų atvejų."
+
+#: src/ui/gui/select-cases-dialog.c:82
+#, c-format
+msgid "Exactly %3d cases from the first %3d cases."
+msgstr "Tiksliai %3d atvejų iš %3d."
+
+#: src/ui/gui/select-cases-dialog.c:221
+#, c-format
+msgid "%d thru %d"
+msgstr "nuo %d iki %d"
+
+#: src/ui/gui/text-data-import-dialog.c:453
+#, c-format
+msgid "Could not open `%s': %s"
+msgstr "Nepavyksta atverti „%s“: %s"
+
+#: src/ui/gui/text-data-import-dialog.c:469
+#, c-format
+msgid "Error reading `%s': %s"
+msgstr "Klaida bandant nuskaityti „%s“: %s"
+
+#: src/ui/gui/text-data-import-dialog.c:472
+#, c-format
+msgid "Failed to read `%s', because it contains a line over %d bytes long and therefore appears not to be a text file."
+msgstr "Nepavyko nuskaityti „%s“, nes joje bent viena linija yra ilgesnė kaip %d bit. Galbūt tai nėra tekstinė rinkmena."
+
+#: src/ui/gui/text-data-import-dialog.c:486
+#, c-format
+msgid "`%s' is empty."
+msgstr "„%s“ yra tuščias."
+
+#: src/ui/gui/text-data-import-dialog.c:531
+msgid "Import Delimited Text Data"
+msgstr "Importuoti bet kokius tekstinius duomenis"
+
+#: src/ui/gui/text-data-import-dialog.c:582
+msgid "Importing Delimited Text Data"
+msgstr "Importuojami bet kokie tekstiniai duomenys"
+
+#: src/ui/gui/text-data-import-dialog.c:731
+#, c-format
+msgid "Only the first %4d cases"
+msgstr "Tik pirmuosius %4d"
+
+#: src/ui/gui/text-data-import-dialog.c:741
+#, c-format
+msgid "Only the first %3d %% of file (approximately)"
+msgstr "Tik %3d %% rinkmenos nuo pradžių (apytiksliai)"
+
+#: src/ui/gui/text-data-import-dialog.c:766
+msgid ""
+"This assistant will guide you through the process of importing data into PSPP from a text file with one line per case,  in which fields are separated by tabs, commas, or other delimiters.\n"
+"\n"
+msgstr ""
+"Šis vediklis padės į PSPP importuoti duomenis iš tekstinės rinkmenos, kur viena eilutė atitiks vieną atvejį, o laukai (būsimi kintamieji) atskiriami tabuliacija, kableliu ar kitu pasirinktu simboliu.\n"
+"\n"
+
+#: src/ui/gui/text-data-import-dialog.c:772
+#, c-format
+msgid "The selected file contains %zu line of text.  "
+msgid_plural "The selected file contains %zu lines of text.  "
+msgstr[0] "Pasirinkta rinkmena turi %zu eilutę teksto. "
+msgstr[1] "Pasirinkta rinkmena turi %zu eilutę teksto. "
+msgstr[2] "Pasirinkta rinkmena turi %zu eilutes teksto. "
+msgstr[3] "Pasirinkta rinkmena turi %zu eilučių teksto. "
+
+#: src/ui/gui/text-data-import-dialog.c:780
+#, c-format
+msgid "The selected file contains approximately %lu line of text.  "
+msgid_plural "The selected file contains approximately %lu lines of text.  "
+msgstr[0] "Pasirinkta rinkmena turi maždaug %lu eilutę teksto. "
+msgstr[1] "Pasirinkta rinkmena turi maždaug %lu eilutę teksto. "
+msgstr[2] "Pasirinkta rinkmena turi maždaug %lu eilutes teksto. "
+msgstr[3] "Pasirinkta rinkmena turi maždaug %lu eilučių teksto. "
+
+#: src/ui/gui/text-data-import-dialog.c:786
+#, c-format
+msgid "Only the first %zu line of the file will be shown for preview purposes in the following screens.  "
+msgid_plural "Only the first %zu lines of the file will be shown for preview purposes in the following screens.  "
+msgstr[0] "Sekančiame lange galėsite peržiūrėti tik pirmąją %zu eilutę."
+msgstr[1] "Sekančiame lange galėsite peržiūrėti tik pirmąsias %zu eilutes. "
+msgstr[2] "Sekančiame lange galėsite peržiūrėti tik pirmąsias %zu eilutes. "
+msgstr[3] "Sekančiame lange galėsite peržiūrėti tik pirmąsias %zu eilučių. "
+
+#: src/ui/gui/text-data-import-dialog.c:793
+msgid "You may choose below how much of the file should actually be imported."
+msgstr "Žemiau galite nurodyti, kiek importuoti rinkmenos duomenų."
+
+#: src/ui/gui/text-data-import-dialog.c:876
+msgid "Text"
+msgstr "Tekstas"
+
+#: src/ui/gui/text-data-import-dialog.c:1540
+#: src/ui/gui/text-data-import-dialog.c:1786
+msgid "This input line has too few separators to fill in this field."
+msgstr "Įvedimo eilutė turi per mažai skyriklių, tad šis laukas neužpildytas"
+
+#: src/ui/gui/text-data-import-dialog.c:1777
+#, c-format
+msgid "Cannot parse field content `%.*s' as format %s: %s"
+msgstr "Nepavyksta lauko turinio „%.*s“ išnagrinėti %s formatu: %s"
+
+#: src/ui/gui/text-data-import-dialog.c:1930
+msgid "Line"
+msgstr "Eilutė"
+
+#: src/ui/gui/t-test-options.c:60
+#, c-format
+msgid "Confidence Interval: %2d %%"
+msgstr "Pasikliautinasis intervalas: %2d %%"
+
+#: src/ui/gui/val-labs-dialog.c:519
+#, c-format
+msgid "%s = `%s'"
+msgstr "%s = „%s“"
+
+#: src/ui/gui/variable-info-dialog.c:77
+#, c-format
+msgid "Label: %s\n"
+msgstr "Etiketė: %s\n"
+
+#: src/ui/gui/variable-info-dialog.c:84
+#, c-format
+msgid "Type: %s\n"
+msgstr "Tipas: %s\n"
+
+#: src/ui/gui/variable-info-dialog.c:88
+#, c-format
+msgid "Missing Values: %s\n"
+msgstr "Praleistos reikšmės: %s\n"
+
+#: src/ui/gui/variable-info-dialog.c:92
+#, c-format
+msgid "Measurement Level: %s\n"
+msgstr "Matavimo skalė: %s\n"
+
+#: src/ui/gui/variable-info-dialog.c:105
+msgid "Value Labels:\n"
+msgstr "Reikšmių etiketės:\n"
+
+#: src/ui/gui/variable-info-dialog.c:115
+#, c-format
+msgid "%s %s\n"
+msgstr "%s %s\n"
+
+#: src/ui/gui/weight-cases-dialog.c:80 src/ui/gui/psppire.ui:52
+#: src/ui/gui/psppire.ui:155
+msgid "Do not weight cases"
+msgstr "Nesverti atvejų"
+
+#: src/ui/gui/weight-cases-dialog.c:86
+#, c-format
+msgid "Weight cases by %s"
+msgstr "Atvejus sverti pagal %s"
+
+#: tests/dissect-sysfile.c:572
+#, c-format
+msgid "Unrecognized record type 7, subtype %d."
+msgstr "Įrašo tipas 7, potipis %d neatpažintas."
+
+#: tests/dissect-sysfile.c:595
+#, c-format
+msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
+msgstr ""
+
+#: tests/dissect-sysfile.c:626
+#, c-format
+msgid "Bad size (%zu) or count (%zu) on extension 4."
+msgstr ""
+
+#: tests/dissect-sysfile.c:692
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record"
+msgstr ""
+
+#: tests/dissect-sysfile.c:701
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record"
+msgstr ""
+
+#: tests/dissect-sysfile.c:759
+#, c-format
+msgid "Bad size %zu on extension 11."
+msgstr "11-to plėtinio blogas dydis %zu."
+
+#: tests/dissect-sysfile.c:851
+#, c-format
+msgid "%s: Error parsing attribute value %s[%d]"
+msgstr "%s: klaida nagrinėjant atributo reikšmę %s[%d]"
+
+#: tests/dissect-sysfile.c:857
+#, c-format
+msgid "%s: Attribute value %s[%d] is not quoted: %s"
+msgstr "%s: Atributo reikšmė %s[%d] be kabučių: %s"
+
+#: tests/dissect-sysfile.c:881
+#, c-format
+msgid "Bad size %zu for extended number of cases."
+msgstr ""
+
+#: tests/dissect-sysfile.c:887
+#, c-format
+msgid "Bad count %zu for extended number of cases."
+msgstr ""
+
+#: tests/dissect-sysfile.c:937
+#, c-format
+msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
+msgstr ""
+
+#: src/language/utilities/set.q:171
+msgid "WORKSPACE must be at least 1MB"
+msgstr "WORKSPACE turi būti bent 1MB"
+
+#: src/language/utilities/set.q:177 src/language/utilities/set.q:179
+#: src/language/utilities/set.q:181 src/language/utilities/set.q:183
+#: src/language/utilities/set.q:185 src/language/utilities/set.q:187
+#: src/language/utilities/set.q:189 src/language/utilities/set.q:191
+#: src/language/utilities/set.q:193
+#, c-format
+msgid "%s is obsolete."
+msgstr "%s yra pasenęs."
+
+#: src/language/utilities/set.q:199
+msgid "Active file compression is not implemented."
+msgstr "Veikiamosios rinkmenos glaudinimas dar nerealizuotas."
+
+#: src/language/utilities/set.q:317
+msgid "EPOCH must be 1500 or later."
+msgstr "EPOCH turi būti 1500 arba daugiau."
+
+#: src/language/utilities/set.q:324
+msgid "expecting AUTOMATIC or year"
+msgstr "tikėtasi AUTOMATIC arba metų"
+
+#: src/language/utilities/set.q:352
+msgid "LENGTH must be at least 1."
+msgstr "LENGTH (ilgis) turi būti bent 1."
+
+#: src/language/utilities/set.q:388
+#, c-format
+msgid "%s is not a recognized encoding or locale name"
+msgstr "%s neatpažinta kaip koduotė ar lokalė"
+
+#: src/language/utilities/set.q:449
+msgid "WIDTH must be at least 40."
+msgstr "WIDTH (plotis) turi būti bent 40."
+
+#: src/language/utilities/set.q:476
+#, c-format
+msgid "FORMAT requires numeric output format as an argument.  Specified format %s is of type string."
+msgstr "FORMAT reikalauja skaitmeninio išvedimo formato kaip argumento.  Nurodytas formato %s tipas yra teksto eilutė."
+
+#: src/language/utilities/set.q:690
+msgid "ISL (32-bit IEEE 754 single, little-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:693
+msgid "ISB (32-bit IEEE 754 single, big-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:696
+msgid "IDL (64-bit IEEE 754 double, little-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:699
+msgid "IDB (64-bit IEEE 754 double, big-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:703
+msgid "VF (32-bit VAX F, VAX-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:706
+msgid "VD (64-bit VAX D, VAX-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:709
+msgid "VG (64-bit VAX G, VAX-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:713
+msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:716
+msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
+msgstr ""
+
+#: src/language/utilities/set.q:817
+#, c-format
+msgid "%s is %s."
+msgstr "%s yra %s."
+
+#: src/language/utilities/set.q:920
+#, c-format
+msgid "Too many PRESERVE commands without a RESTORE: at most %d levels of saved settings are allowed."
+msgstr ""
+
+#: src/language/utilities/set.q:939
+msgid "RESTORE without matching PRESERVE."
+msgstr "RESTORE be atitinkamo PRESERVE."
+
+#: src/language/stats/crosstabs.q:295
+msgid "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
+msgstr ""
+
+#: src/language/stats/crosstabs.q:405
+msgid "Too many cross-tabulation variables or dimensions."
+msgstr "Požymių dažnių lentelėms yra per daug kintamųjų arba dimensijų."
+
+#: src/language/stats/crosstabs.q:472
+msgid "VARIABLES must be specified before TABLES."
+msgstr "VARIABLES (kintamieji) turi nurodyti pirmiau nei TABLES (lentelės)."
+
+#: src/language/stats/crosstabs.q:506
+#, c-format
+msgid "Maximum value (%ld) less than minimum value (%ld)."
+msgstr "Didžiausia reikšmė (%ld) yra mažesnė mažiausiąją (%ld)."
+
+#: src/language/stats/crosstabs.q:827
+msgid "Summary."
+msgstr "Santrauka."
+
+#: src/language/stats/crosstabs.q:840 src/language/stats/examine.q:1178
+#: src/language/stats/frequencies.q:823
+msgid "Percent"
+msgstr "Procentai"
+
+#. TRANSLATORS: The %s here describes a crosstabulation.  It takes the
+#. form "var1 * var2 * var3 * ...".
+#: src/language/stats/crosstabs.q:936
+#, c-format
+msgid "Crosstabulation %s contained no non-missing cases."
+msgstr "Požymių dažnių lentelėje „%s“ visi atvejai turi praleistas reikšmes."
+
+#: src/language/stats/crosstabs.q:1134
+msgid "count"
+msgstr "kiekis"
+
+#: src/language/stats/crosstabs.q:1135
+msgid "row %"
+msgstr "% eilutė"
+
+#: src/language/stats/crosstabs.q:1136
+msgid "column %"
+msgstr "% stulpelis"
+
+#: src/language/stats/crosstabs.q:1137
+msgid "total %"
+msgstr "iš viso %"
+
+#: src/language/stats/crosstabs.q:1138
+msgid "expected"
+msgstr "tikėtasi"
+
+#: src/language/stats/crosstabs.q:1139
+msgid "residual"
+msgstr "liekana"
+
+#: src/language/stats/crosstabs.q:1140
+msgid "std. resid."
+msgstr "norm. liekana"
+
+#: src/language/stats/crosstabs.q:1141
+msgid "adj. resid."
+msgstr "patiksl. norm. liekana"
+
+#: src/language/stats/crosstabs.q:1230
+msgid "Chi-square tests."
+msgstr "Chi-kvadrato kriterij."
+
+#: src/language/stats/crosstabs.q:1256
+msgid "Symmetric measures."
+msgstr "Simetriniai matavimai."
+
+#: src/language/stats/crosstabs.q:1262 src/language/stats/crosstabs.q:1310
+msgid "Asymp. Std. Error"
+msgstr "Asimpt. std. paklaida"
+
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1311
+msgid "Approx. T"
+msgstr "Apytiksl. T"
+
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1312
+msgid "Approx. Sig."
+msgstr "Apytiksl. p-reikšmė"
+
+#: src/language/stats/crosstabs.q:1278
+msgid "Risk estimate."
+msgstr "Rizikos įvertis."
+
+#: src/language/stats/crosstabs.q:1282
+#, c-format
+msgid "95%% Confidence Interval"
+msgstr "95%% pasikliautinasis intervalas"
+
+#: src/language/stats/crosstabs.q:1285 src/language/stats/t-test.q:760
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1017
+msgid "Lower"
+msgstr "Apačia"
+
+#: src/language/stats/crosstabs.q:1286 src/language/stats/t-test.q:761
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1018
+msgid "Upper"
+msgstr "Viršus"
+
+#: src/language/stats/crosstabs.q:1303
+msgid "Directional measures."
+msgstr "Kryptingi matavimai."
+
+#: src/language/stats/crosstabs.q:1740
+msgid "Pearson Chi-Square"
+msgstr "Pirsono Chi-kvadratas"
+
+#: src/language/stats/crosstabs.q:1741
+msgid "Likelihood Ratio"
+msgstr "Tikėtinumo santykis"
+
+#: src/language/stats/crosstabs.q:1742
+msgid "Fisher's Exact Test"
+msgstr "Tikslus Fišerio kriterijus"
+
+#: src/language/stats/crosstabs.q:1743
+msgid "Continuity Correction"
+msgstr "Tolydumo pataisa"
+
+#: src/language/stats/crosstabs.q:1744
+msgid "Linear-by-Linear Association"
+msgstr "Dvitiesinė priklausomybė"
+
+#: src/language/stats/crosstabs.q:1779 src/language/stats/crosstabs.q:1854
+#: src/language/stats/crosstabs.q:1919
+msgid "N of Valid Cases"
+msgstr "N galiojančių atvejų"
+
+#: src/language/stats/crosstabs.q:1798 src/language/stats/crosstabs.q:1937
+msgid "Nominal by Nominal"
+msgstr "Pavadinimų x pavadinimų"
+
+#: src/language/stats/crosstabs.q:1799 src/language/stats/crosstabs.q:1938
+msgid "Ordinal by Ordinal"
+msgstr "Rangų x rangų"
+
+#: src/language/stats/crosstabs.q:1800
+msgid "Interval by Interval"
+msgstr "Intervalų x intervalų"
+
+#: src/language/stats/crosstabs.q:1801
+msgid "Measure of Agreement"
+msgstr "Sutarimas"
+
+#: src/language/stats/crosstabs.q:1807
+msgid "Cramer's V"
+msgstr "Kramerio V"
+
+#: src/language/stats/crosstabs.q:1808
+msgid "Contingency Coefficient"
+msgstr "Kontingencijos koeficientas"
+
+#: src/language/stats/crosstabs.q:1809
+msgid "Kendall's tau-b"
+msgstr "Kendall tau-b"
+
+#: src/language/stats/crosstabs.q:1810
+msgid "Kendall's tau-c"
+msgstr "Kendall tau-c"
+
+#: src/language/stats/crosstabs.q:1812
+msgid "Spearman Correlation"
+msgstr "Spirmano koreliacija"
+
+#: src/language/stats/crosstabs.q:1813
+msgid "Pearson's R"
+msgstr "Pirsono R"
+
+#: src/language/stats/crosstabs.q:1892
+#, c-format
+msgid "Odds Ratio for %s (%g / %g)"
+msgstr "Galimybių santykis: %s (%g / %g)"
+
+#: src/language/stats/crosstabs.q:1895
+#, c-format
+msgid "Odds Ratio for %s (%.*s / %.*s)"
+msgstr "Galimybių santykis: %s (%.*s / %.*s)"
+
+#: src/language/stats/crosstabs.q:1903
+#, c-format
+msgid "For cohort %s = %g"
+msgstr "Kohortai %s = %g"
+
+#: src/language/stats/crosstabs.q:1906
+#, c-format
+msgid "For cohort %s = %.*s"
+msgstr "Kohortai %s = %.*s"
+
+#: src/language/stats/crosstabs.q:1939
+msgid "Nominal by Interval"
+msgstr "Pavadinimų x intervalų"
+
+#: src/language/stats/crosstabs.q:1945
+msgid "Goodman and Kruskal tau"
+msgstr "Gudmano-Kruskalio tau"
+
+#: src/language/stats/crosstabs.q:1946
+msgid "Uncertainty Coefficient"
+msgstr "Neapibrėžtumo koeficientas"
+
+#: src/language/stats/crosstabs.q:1947
+msgid "Somers' d"
+msgstr "Somers d"
+
+#: src/language/stats/crosstabs.q:1953
+msgid "Symmetric"
+msgstr "Simetrinis"
+
+#: src/language/stats/crosstabs.q:1954 src/language/stats/crosstabs.q:1955
+#, c-format
+msgid "%s Dependent"
+msgstr "%s priklausomas"
+
+#: src/language/stats/examine.q:355
+msgid "Not creating NP plot because data set is empty."
+msgstr ""
+
+#: src/language/stats/examine.q:441 src/language/stats/examine.q:948
+msgid "Not creating plot because data set is empty."
+msgstr "Diagrama nebraižoma, nes pateiktas tuščias duomenų rinkinys."
+
+#: src/language/stats/examine.q:453
+#, c-format
+msgid "Boxplot of %s vs. %s"
+msgstr "%s ir %s stulpelinės sklaidos diagrama"
+
+#: src/language/stats/examine.q:457
+#, c-format
+msgid "Boxplot of %s"
+msgstr "%s stulpelinės sklaidos diagrama"
+
+#: src/language/stats/examine.q:646 src/language/stats/examine.q:659
+#, c-format
+msgid "%s and %s are mutually exclusive"
+msgstr ""
+
+#: src/language/stats/examine.q:1463
+msgid "5% Trimmed Mean"
+msgstr "5% nupjautasis vidurkis"
+
+#: src/language/stats/examine.q:1498
+msgid "Interquartile Range"
+msgstr "Intervalas tarp kvartilių"
+
+#: src/language/stats/examine.q:1820
+msgid "Highest"
+msgstr "Didžiausias"
+
+#: src/language/stats/examine.q:1825
+msgid "Lowest"
+msgstr "Mažiausias"
+
+#: src/language/stats/examine.q:1832
+msgid "Extreme Values"
+msgstr "Ekstremumų reikšmės"
+
+#: src/language/stats/examine.q:1836 src/language/data-io/list.q:157
+msgid "Case Number"
+msgstr "Atvejo numeris"
+
+#: src/language/stats/examine.q:1956
+msgid "Tukey's Hinges"
+msgstr ""
+
+#: src/language/stats/examine.q:2002
+#, c-format
+msgid "%g"
+msgstr "%g"
+
+#: src/language/stats/frequencies.q:381
+msgid "Bar charts are not implemented."
+msgstr "Stulpelinės diagramos dar nerealizuotos."
+
+#: src/language/stats/frequencies.q:398
+#, c-format
+msgid "MAX for histogram must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
+msgstr ""
+
+#: src/language/stats/frequencies.q:419
+#, c-format
+msgid "MAX for pie chart must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
+msgstr ""
+
+#: src/language/stats/frequencies.q:702
+msgid "`)' expected after GROUPED interval list."
+msgstr ""
+
+#: src/language/stats/frequencies.q:722
+#, c-format
+msgid "Variables %s specified multiple times on GROUPED subcommand."
+msgstr ""
+
+#: src/language/stats/frequencies.q:732
+#, c-format
+msgid "Variables %s specified on GROUPED but not on VARIABLES."
+msgstr "Kintamieji %s nurodyti ties GROUPED, bet ne ties VARIABLES."
+
+#: src/language/stats/frequencies.q:820
+msgid "Value Label"
+msgstr "Reikšmės etiketė"
+
+#: src/language/stats/frequencies.q:824
+msgid "Valid Percent"
+msgstr "Galiojanti procentinė dalis"
+
+#: src/language/stats/frequencies.q:825
+msgid "Cum Percent"
+msgstr "Sukauptoji procentinė dalis"
+
+#: src/language/stats/frequencies.q:1015
+#, c-format
+msgid "No valid data for variable %s; statistics not displayed."
+msgstr "Kintamasis %s neturi tinkamų duomenų; statistika nerodoma."
+
+#: src/language/stats/frequencies.q:1061
+msgid "50 (Median)"
+msgstr "50 (mediana)"
+
+#: src/language/stats/frequencies.q:1217
+#, c-format
+msgid "Omitting pie chart for %s, which has only %d unique values."
+msgstr "Skritulinė diagrama „%s“ praleidžiama, nes ji turi tik %d reikšmę(-ių)."
+
+#: src/language/stats/frequencies.q:1220
+#, c-format
+msgid "Omitting pie chart for %s, which has over 50 unique values."
+msgstr "Skritulinė diagrama „%s“ praleidžiama, nes ji turi daugiau kaip 50 unikalių reikšmių."
+
+#: src/language/stats/rank.q:219
+#, c-format
+msgid "%s of %s by %s"
+msgstr "%s iš %s pagal %s"
+
+#: src/language/stats/rank.q:224
+#, c-format
+msgid "%s of %s"
+msgstr "%s iš %s"
+
+#: src/language/stats/rank.q:599
+msgid "Cannot create new rank variable.  All candidates in use."
+msgstr "Nepavyksta sukurti naujo rangų kintamojo. Visi kandidatai panaudoti."
+
+#: src/language/stats/rank.q:694
+msgid "Variables Created By RANK"
+msgstr "Kintamieji, sukurti pagal RANK"
+
+#: src/language/stats/rank.q:718
+#, c-format
+msgid "%s into %s(%s of %s using %s BY %s)"
+msgstr "%s į %s (%s iš %s naudojant %s pagal %s)"
+
+#: src/language/stats/rank.q:728
+#, c-format
+msgid "%s into %s(%s of %s BY %s)"
+msgstr "%s į %s (%s iš %s pagal %s)"
+
+#: src/language/stats/rank.q:741
+#, c-format
+msgid "%s into %s(%s of %s using %s)"
+msgstr "%s į %s (%s iš %s naudojant %s)"
+
+#: src/language/stats/rank.q:750
+#, c-format
+msgid "%s into %s(%s of %s)"
+msgstr "%s į %s (%s iš %s)"
+
+#: src/language/stats/rank.q:762
+msgid "FRACTION has been specified, but NORMAL and PROPORTION rank functions have not been requested.  The FRACTION subcommand will be ignored."
+msgstr ""
+
+#: src/language/stats/rank.q:853
+#, c-format
+msgid "Variable %s already exists."
+msgstr "Toks kintamasis %s jau yra."
+
+#: src/language/stats/rank.q:858
+msgid "Too many variables in INTO clause."
+msgstr "INTO sąlygoje per daug kintamųjų."
+
+#: src/language/stats/regression.q:158
+msgid "R Square"
+msgstr "R kvadratas"
+
+#: src/language/stats/regression.q:159
+msgid "Adjusted R Square"
+msgstr "Koreguotas R kvadratas"
+
+#: src/language/stats/regression.q:160
+msgid "Std. Error of the Estimate"
+msgstr "Įverčio std. paklaida"
+
+#: src/language/stats/regression.q:165
+msgid "Model Summary"
+msgstr "Modelio santrauka"
+
+#: src/language/stats/regression.q:199
+msgid "B"
+msgstr "B"
+
+#: src/language/stats/regression.q:201
+msgid "Beta"
+msgstr "Beta"
+
+#: src/language/stats/regression.q:204
+msgid "(Constant)"
+msgstr "(Konstanta)"
+
+#: src/language/stats/regression.q:256
+msgid "Coefficients"
+msgstr "Koeficientai"
+
+#: src/language/stats/regression.q:291 src/ui/gui/regression.ui:7
+msgid "Regression"
+msgstr "Regresija"
+
+#: src/language/stats/regression.q:372
+msgid "Model"
+msgstr "Modelis"
+
+#: src/language/stats/regression.q:373
+msgid "Covariances"
+msgstr "Kovariacija"
+
+#: src/language/stats/regression.q:388
+msgid "Coefficient Correlations"
+msgstr "Koeficientų koreliacijos"
+
+#: src/language/stats/regression.q:787
+msgid "The dependent variable is equal to the independent variable.The least squares line is therefore Y=X.Standard errors and related statistics may be meaningless."
+msgstr "Priklausomas kintamasis lygus nepriklausomam kintamajam. Todėl mažiausiųjų kvadratų linija yra Y=X. Standartinė paklaida ir kita statistika gali būti beprasmiška."
+
+#: src/language/stats/regression.q:934
+msgid "REGRESSION requires numeric variables."
+msgstr "REGRESSION reikalauja skaitmeninių kintamųjų."
+
+#: src/language/stats/regression.q:1009
+msgid "No valid data found. This command was skipped."
+msgstr "Nerasta tinkamų duomenų. Ši komanda buvo praleista."
+
+#: src/language/stats/t-test.q:192
+msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
+msgstr "Būtina nurodyti kurią nors vienintelę iš šių pokomandžių: TESTVAL, GROUPS, PAIRS."
+
+#: src/language/stats/t-test.q:213
+msgid "VARIABLES subcommand may not be used with PAIRS."
+msgstr "Pokomandžio VARIABLES negalima naudoti su PAIRS."
+
+#: src/language/stats/t-test.q:232
+msgid "One or more VARIABLES must be specified."
+msgstr "Turi būti nurodytas bent vienas kintamasis ties VARIABLES."
+
+#: src/language/stats/t-test.q:328
+msgid "When applying GROUPS to a string variable, two values must be specified."
+msgstr ""
+
+#: src/language/stats/t-test.q:399
+msgid "At least two variables must be specified on PAIRS."
+msgstr "Naudojant PAIRS, reikia nurodyti bent du kintamuosius."
+
+#: src/language/stats/t-test.q:507
+msgid "One-Sample Statistics"
+msgstr "Vienos imties statistika"
+
+#: src/language/stats/t-test.q:526
+msgid "Group Statistics"
+msgstr "Grupių statistika"
+
+#: src/language/stats/t-test.q:625
+msgid "Paired Sample Statistics"
+msgstr "Porinių imčių statistika"
+
+#: src/language/stats/t-test.q:645 src/language/stats/t-test.q:948
+#: src/language/stats/t-test.q:1115
+#, c-format
+msgid "Pair %d"
+msgstr "%d pora "
+
+#: src/language/stats/t-test.q:741
+msgid "Independent Samples Test"
+msgstr "Kriterijus nepriklausomoms imtims"
+
+#: src/language/stats/t-test.q:749
+msgid "Levene's Test for Equality of Variances"
+msgstr "Levene kriterijus dispersijų lygybei"
+
+#: src/language/stats/t-test.q:751
+msgid "t-test for Equality of Means"
+msgstr "t kriterijus vidurkių lygybei"
+
+#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1107
+msgid "Sig."
+msgstr "p-reikšmė"
+
+#: src/language/stats/t-test.q:758 src/language/stats/t-test.q:1016
+msgid "Mean Difference"
+msgstr "Vidurkių skirtumas"
+
+#: src/language/stats/t-test.q:759
+msgid "Std. Error Difference"
+msgstr "Vidurkių skirtumo std. paklaida"
+
+#: src/language/stats/t-test.q:764 src/language/stats/t-test.q:918
+#: src/language/stats/t-test.q:1008
+#, c-format
+msgid "%g%% Confidence Interval of the Difference"
+msgstr "Skirtumo %g%% pasikliautinasis intervalas"
+
+#: src/language/stats/t-test.q:818
+msgid "Equal variances assumed"
+msgstr "Jei dispersijos būtų lygios"
+
+#: src/language/stats/t-test.q:864
+msgid "Equal variances not assumed"
+msgstr "Jei dispersijos būtų nelygios"
+
+#: src/language/stats/t-test.q:908
+msgid "Paired Samples Test"
+msgstr "Kriterijus porinėms imtims"
+
+#: src/language/stats/t-test.q:911
+msgid "Paired Differences"
+msgstr "Porinių imčių skirtumai"
+
+#: src/language/stats/t-test.q:923
+msgid "Std. Error Mean"
+msgstr "std. vidurkio paklaida"
+
+#: src/language/stats/t-test.q:997
+msgid "One-Sample Test"
+msgstr "Kriterijus vienai imčiai"
+
+#: src/language/stats/t-test.q:1002
+#, c-format
+msgid "Test Value = %f"
+msgstr "Kriterijaus reikšmė = %f"
+
+#: src/language/stats/t-test.q:1102
+msgid "Paired Samples Correlations"
+msgstr "Porinių imčių koreliacija"
+
+#: src/language/stats/t-test.q:1106
+msgid "Correlation"
+msgstr "Koreliacija"
+
+#: src/language/stats/t-test.q:1117
+#, c-format
+msgid "%s & %s"
+msgstr "%s ir %s"
+
+#: src/language/data-io/file-handle.q:70
+#, c-format
+msgid "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining a file handle."
+msgstr ""
+
+#: src/language/data-io/file-handle.q:122
+msgid "RECFORM must be specified with MODE=360."
+msgstr "RECFORM turi būti nurodytas su MODE=360."
+
+#: src/language/data-io/file-handle.q:133
+#, c-format
+msgid "The specified file mode requires LRECL.  Assuming %zu-character records."
+msgstr ""
+
+#: src/language/data-io/file-handle.q:137
+#, c-format
+msgid "Record length (%ld) must be between 1 and %lu bytes.  Assuming %zu-character records."
+msgstr ""
+
+#: src/language/data-io/file-handle.q:178
+msgid "file"
+msgstr "rinkmena"
+
+#: src/language/data-io/file-handle.q:180
+msgid "inline file"
+msgstr ""
+
+#: src/language/data-io/file-handle.q:228
+msgid "expecting a file name or handle name"
+msgstr ""
+
+#: src/language/data-io/file-handle.q:243
+#, c-format
+msgid "Handle for %s not allowed here."
+msgstr ""
+
+#: src/language/data-io/list.q:98
+#, c-format
+msgid "The first case (%ld) specified precedes the last case (%ld) specified.  The values will be swapped."
+msgstr ""
+
+#: src/language/data-io/list.q:106
+#, c-format
+msgid "The first case (%ld) to list is less than 1.  The value is being reset to 1."
+msgstr ""
+
+#: src/language/data-io/list.q:112
+#, c-format
+msgid "The last case (%ld) to list is less than 1.  The value is being reset to 1."
+msgstr ""
+
+#: src/language/data-io/list.q:118
+#, c-format
+msgid "The step value %ld is less than 1.  The value is being reset to 1."
+msgstr "Žingsnio reikšmė %ld mažesnė nei 1. Reikšmė atstatyta į 1."
+
+#: src/ui/gui/aggregate.ui:7
+msgid "Aggregate Data"
+msgstr "Duomenų agregavimas"
+
+#: src/ui/gui/aggregate.ui:100
+msgid "_Break variable(s)"
+msgstr "_Skaidantieji kintamieji"
+
+#: src/ui/gui/aggregate.ui:136
+msgid "Variable Name: "
+msgstr "Kint. vardas: "
+
+#: src/ui/gui/aggregate.ui:161
+msgid "Variable Label: "
+msgstr "Kint. etiketė: "
+
+#: src/ui/gui/aggregate.ui:190
+msgid "Function: "
+msgstr "Funkcija: "
+
+#: src/ui/gui/aggregate.ui:253
+msgid "Argument 1: "
+msgstr "1 argumentas: "
+
+#: src/ui/gui/aggregate.ui:282
+msgid "Argument 2: "
+msgstr "2 argumentas: "
+
+#: src/ui/gui/aggregate.ui:328
+msgid "Aggregated variables"
+msgstr "Agreguoti kintamieji"
+
+#: src/ui/gui/aggregate.ui:362
+msgid "_Add aggregated variables to the active dataset"
+msgstr "Agreguotus kintamuosius pridėti prie _veikiamojo duomenų rinkinio"
+
+#: src/ui/gui/aggregate.ui:376
+msgid "_Replace the current dataset with the aggregated variables"
+msgstr "Pa_keisti veikiamąjį duomenų rinkinį agreguotaisiais kintamaisiais"
+
+#: src/ui/gui/aggregate.ui:391
+msgid "_Write a new data file containing only the aggregated variables"
+msgstr "Sukurti _naują duomenų rinkmeną, turinčią tik agreguotuosius kintamuosius"
+
+#: src/ui/gui/aggregate.ui:428
+msgid "label"
+msgstr "etiketė"
+
+#: src/ui/gui/aggregate.ui:472
+msgid "File is _already sorted on break variable(s)"
+msgstr "R_inkmena jau surikiuota pagal skaidantįjį kintamąjį (skaidančiuosius kintamuosius)"
+
+#: src/ui/gui/aggregate.ui:487
+msgid "Sort file before a_ggregating"
+msgstr "Rikiuoti rinkmeną prieš agr_egavimą"
+
+#: src/ui/gui/aggregate.ui:508
+msgid "Options for very large datasets"
+msgstr "Parinktys labai dideliems duomenų rinkiniams"
+
+#: src/ui/gui/binomial.ui:57 src/ui/gui/chi-square.ui:57
+msgid "_Test Variable List:"
+msgstr "_Kriterijaus kintamųjų sąrašas:"
+
+#: src/ui/gui/binomial.ui:126 src/ui/gui/chi-square.ui:126
+msgid "_Get from data"
+msgstr "_Imti iš duomenų"
+
+#: src/ui/gui/binomial.ui:143 src/ui/gui/t-test.ui:333
+msgid "_Cut point:"
+msgstr "_Perskirti ties:"
+
+#: src/ui/gui/binomial.ui:178
+msgid "Define Dichotomy"
+msgstr "Perskyrimas"
+
+#: src/ui/gui/binomial.ui:197
+msgid "Test _Proportion:"
+msgstr "Kriterijaus proporcija"
+
+#: src/ui/gui/compute.ui:8
+msgid "Compute Variable"
+msgstr "Kintamojo apskaičiavimas"
+
+#: src/ui/gui/compute.ui:41
+msgid "Target Variable:"
+msgstr "Paskirties kintamasis:"
+
+#: src/ui/gui/compute.ui:70
+msgid "Type & Label"
+msgstr "Tipas ir etiketė"
+
+#: src/ui/gui/compute.ui:117
+msgid "="
+msgstr "="
+
+#: src/ui/gui/compute.ui:171
+msgid "Numeric Expressions:"
+msgstr "Skaičiuojamas reiškinys:"
+
+#: src/ui/gui/compute.ui:233
+msgid "Functions:"
+msgstr "Funkcijos:"
+
+#: src/ui/gui/compute.ui:298 src/ui/gui/recode.ui:741
+#: src/ui/gui/select-cases.ui:378
+msgid "If..."
+msgstr "Jeigu..."
+
+#: src/ui/gui/compute.ui:351
+msgid "Compute Variable: Type and Label"
+msgstr "Kintamojo apskaičiavimas: tipas ir etiketė"
+
+#: src/ui/gui/compute.ui:386
+msgid "Use expression as label"
+msgstr "Reiškinį naudoti kaip etiketę"
+
+#: src/ui/gui/correlation.ui:7
+msgid "Bivariate Correlations"
+msgstr "Dviejų kintamųjų koreliacijos"
+
+#: src/ui/gui/correlation.ui:108
+msgid "Pearso_n"
+msgstr "Pirso_no"
+
+#: src/ui/gui/correlation.ui:123
+msgid "_Kendall's tau-b"
+msgstr "_Kendall tau-b"
+
+#: src/ui/gui/correlation.ui:138
+msgid "_Spearman"
+msgstr "_Spirmano"
+
+#: src/ui/gui/correlation.ui:158
+msgid "Correlation Coefficients"
+msgstr "Koreliacijos koeficientai"
+
+#: src/ui/gui/correlation.ui:182
+msgid "_Two-tailed"
+msgstr "_Dvipusis"
+
+#: src/ui/gui/correlation.ui:198
+msgid "One-tai_led"
+msgstr "_Vienpusis"
+
+#: src/ui/gui/correlation.ui:220
+msgid "Test of Significance"
+msgstr "Reikšmingumo kriterijus"
+
+#: src/ui/gui/correlation.ui:232
+msgid "_Flag significant correlations"
+msgstr "_Pažymėti reikšmingas koreliacijas"
+
+#: src/ui/gui/crosstabs.ui:7
+msgid "Crosstabs"
+msgstr "Požymių dažnių lentelės"
+
+#: src/ui/gui/crosstabs.ui:50
+msgid "Rows"
+msgstr "Eilutės"
+
+#: src/ui/gui/crosstabs.ui:124
+msgid "Format..."
+msgstr "Formatas..."
+
+#: src/ui/gui/crosstabs.ui:137 src/ui/gui/examine.ui:245
+#: src/ui/gui/regression.ui:27
+msgid "Statistics..."
+msgstr "Statistika..."
+
+#: src/ui/gui/crosstabs.ui:150
+msgid "Cells..."
+msgstr "Langeliai..."
+
+#: src/ui/gui/crosstabs.ui:227
+msgid "Crosstabs: Format"
+msgstr "Požymių dažnių lentelės: formatas"
+
+#: src/ui/gui/crosstabs.ui:241
+msgid "Print tables"
+msgstr "Spausdinti lenteles"
+
+#: src/ui/gui/crosstabs.ui:254
+msgid "Pivot"
+msgstr "Dinaminės lentelės"
+
+#: src/ui/gui/crosstabs.ui:267 src/ui/gui/sort.ui:130
+msgid "Ascending"
+msgstr "Didėjančiai"
+
+#: src/ui/gui/crosstabs.ui:304
+msgid "No label"
+msgstr "Be etikečių"
+
+#: src/ui/gui/crosstabs.ui:317
+msgid "Suppress value labels"
+msgstr "Nerodyti reikšmių etikečių"
+
+#: src/ui/gui/crosstabs.ui:335
+msgid "Labeling"
+msgstr "Etikečių uždėjimas"
+
+#: src/ui/gui/crosstabs.ui:369
+msgid "Crosstabs: Cells"
+msgstr "Požymių dažnių lentelės: langeliai"
+
+#: src/ui/gui/crosstabs.ui:402
+msgid "Cell Display"
+msgstr "Rodytini langeliai"
+
+#: src/ui/gui/crosstabs.ui:430
+msgid "Crosstabs: Statistics"
+msgstr "Požymių dažnių lentelės: statistika"
+
+#: src/ui/gui/crosstabs.ui:463 src/ui/gui/oneway.ui:222
+#: src/ui/gui/regression.ui:340
+msgid "Statistics"
+msgstr "Statistika"
+
+#: src/ui/gui/chi-square.ui:13
+msgid "Chi-Square Test"
+msgstr "Chi-kvadrato kriterijus"
+
+#: src/ui/gui/chi-square.ui:140
+msgid "Use _specified range"
+msgstr "Naudoti nurodytą sritį"
+
+#: src/ui/gui/chi-square.ui:162
+msgid "_Lower:"
+msgstr "_Apačia:"
+
+#: src/ui/gui/chi-square.ui:170
+msgid "_Upper:"
+msgstr "_Viršus:"
+
+#: src/ui/gui/chi-square.ui:214
+msgid "Expected Range:"
+msgstr "Prognozuojama sritis:"
+
+#: src/ui/gui/chi-square.ui:240
+msgid "All categor_ies equal"
+msgstr "_Visose kategorijose po lygiai"
+
+#: src/ui/gui/chi-square.ui:257
+msgid "_Values"
+msgstr "_Reikšmės"
+
+#: src/ui/gui/chi-square.ui:301
+msgid "Expected Values:"
+msgstr "Prognozuojamos reikšmės:"
+
+#: src/ui/gui/descriptives.ui:130 src/ui/gui/frequencies.ui:140
+msgid "Statistics:"
+msgstr "Statistika:"
+
+#: src/ui/gui/descriptives.ui:192
+msgid "Exclude entire case if any selected variable is missing"
+msgstr "Atmesti visą atvejį, jei bent viename pasirinktame kintamajame jo reikšmė yra praleista"
+
+#: src/ui/gui/descriptives.ui:207
+msgid "Include user-missing data in analysis"
+msgstr "Į analizę įtraukti „naudotojo praleistus“ duomenis"
+
+#: src/ui/gui/descriptives.ui:222
+msgid "Save Z-scores of selected variables as new variables"
+msgstr "Įrašyti pasirinktų kintamųjų standartizuotas Z-reikšmes kaip naujus kintamuosius"
+
+#: src/ui/gui/descriptives.ui:243
+msgid "Options:"
+msgstr "Parinktys:"
+
+#: src/ui/gui/examine.ui:8
+msgid "Explore"
+msgstr "Tyrinėti"
+
+#: src/ui/gui/examine.ui:51
+msgid "Label Cases by:"
+msgstr "Atvejams suteikti etiketes pagal:"
+
+#: src/ui/gui/examine.ui:99
+msgid "Factor List:"
+msgstr "Faktorių sąrašas:"
+
+#: src/ui/gui/examine.ui:146
+msgid "Dependent List:"
+msgstr "Analizuotini kintamieji:"
+
+#: src/ui/gui/examine.ui:259 src/ui/gui/t-test.ui:68 src/ui/gui/t-test.ui:658
+#: src/ui/gui/t-test.ui:819
+msgid "Options..."
+msgstr "Parinktys..."
+
+#: src/ui/gui/examine.ui:302
+msgid "Explore: Statistics"
+msgstr "Tyrinėti: statistika"
+
+#: src/ui/gui/examine.ui:332
+msgid "Extremes"
+msgstr "Ekstremumai"
+
+#: src/ui/gui/examine.ui:381
+msgid "Explore: Options"
+msgstr "Tyrinėti: parinktys"
+
+#: src/ui/gui/examine.ui:405
+msgid "Exclude cases listwise"
+msgstr "Atvejai neįtraukiami visose analizėse"
+
+#: src/ui/gui/examine.ui:419
+msgid "Exclude cases pairwise"
+msgstr "Atvejai neįtraukiami porų analizėse"
+
+#: src/ui/gui/examine.ui:434
+msgid "Repeat values"
+msgstr "Kartoti reikšmes"
+
+#: src/ui/gui/examine.ui:455 src/ui/gui/t-test.ui:493
+#: src/ui/gui/var-sheet-dialogs.ui:684
+msgid "Missing Values"
+msgstr "Praleistos reikšmės"
+
+#: src/ui/gui/goto-case.ui:8
+msgid "Goto Case"
+msgstr "Šokti į atvejį"
+
+#: src/ui/gui/goto-case.ui:26
+msgid "Goto Case Number:"
+msgstr "Atvejo, į kurį šoksima, numeris:"
+
+#: src/ui/gui/factor.ui:22
+msgid "Principal Components Analysis"
+msgstr "Pagrindinių komponenčių analizė"
+
+#: src/ui/gui/factor.ui:26
+msgid "Principal Axis Factoring"
+msgstr "Pagrindinių ašių faktorizacija"
+
+#: src/ui/gui/factor.ui:29
+msgid "Factor Analysis"
+msgstr "Faktorinė analizė"
+
+#: src/ui/gui/factor.ui:55 src/ui/gui/data-editor.ui:343
+msgid "_Descriptives..."
+msgstr "_Aprašomoji..."
+
+#: src/ui/gui/factor.ui:68
+msgid "_Extraction..."
+msgstr "_Išskyrimas"
+
+#: src/ui/gui/factor.ui:82
+msgid "_Rotations..."
+msgstr "_Sukimas..."
+
+#: src/ui/gui/factor.ui:200
+msgid "Factor Analysis: Extraction"
+msgstr "Faktorinė analizė: išskyrimas"
+
+#: src/ui/gui/factor.ui:224
+msgid "Method: "
+msgstr "Metodas: "
+
+#: src/ui/gui/factor.ui:274
+msgid "Correlation matrix"
+msgstr "Koreliacijų matrica"
+
+#: src/ui/gui/factor.ui:288
+msgid "Covariance matrix"
+msgstr "Kovariacijų matrica"
+
+#: src/ui/gui/factor.ui:308
+msgid "Analyze"
+msgstr "Analizuoti"
+
+#: src/ui/gui/factor.ui:332
+msgid "Unrotated factor solution"
+msgstr "Faktorių išskyrimas be sukimo"
+
+#: src/ui/gui/factor.ui:346
+msgid "Scree plot"
+msgstr "Tikrinių reikšmių grafikas"
+
+#: src/ui/gui/factor.ui:365 src/ui/gui/roc.ui:286
+msgid "Display"
+msgstr "Rodyti"
+
+#: src/ui/gui/factor.ui:438
+msgid "Number of factors:"
+msgstr "Faktorių skaičius:"
+
+#: src/ui/gui/factor.ui:468
+msgid "Extract"
+msgstr "Išskirti"
+
+#: src/ui/gui/factor.ui:483 src/ui/gui/factor.ui:673
+msgid "Maximum iterations for convergence:"
+msgstr "Didžiausias iteracijų skaičius:"
+
+#: src/ui/gui/factor.ui:546
+msgid "Factor Analysis: Rotation"
+msgstr "Faktorinė analizė: sukimas"
+
+#: src/ui/gui/factor.ui:579
+msgid "_None"
+msgstr "_Nieko"
+
+#: src/ui/gui/factor.ui:590
+msgid "_Varimax"
+msgstr "_Varimax"
+
+#: src/ui/gui/factor.ui:606
+msgid "_Quartimax"
+msgstr "_Quartimax"
+
+#: src/ui/gui/factor.ui:622
+msgid "_Equimax"
+msgstr "_Equimax"
+
+#: src/ui/gui/factor.ui:645
+msgid "Method"
+msgstr "Metodas"
+
+#: src/ui/gui/factor.ui:656
+msgid "_Display rotated solution"
+msgstr "_Rodyti pasuktą sprendimą"
+
+#: src/ui/gui/find.ui:8
+msgid "Find Case"
+msgstr "Ieškoti atvejo"
+
+#: src/ui/gui/find.ui:88
+msgid "Variable:"
+msgstr "Kintamasis:"
+
+#: src/ui/gui/find.ui:124 src/ui/gui/recode.ui:173
+#: src/ui/gui/var-sheet-dialogs.ui:531
+msgid "Value:"
+msgstr "Reikšmė:"
+
+#: src/ui/gui/find.ui:147
+msgid "Search value labels"
+msgstr "Ieškoti reikšmių etikečių"
+
+#: src/ui/gui/find.ui:171
+msgid "Regular expression Match"
+msgstr "Naudoti reguliarųjį reiškinį"
+
+#: src/ui/gui/find.ui:187
+msgid "Search substrings"
+msgstr "Ieškoti teksto poeilučių (nepilnų žodžių)"
+
+#: src/ui/gui/find.ui:203
+msgid "Wrap around"
+msgstr "Visame lakšte"
+
+#: src/ui/gui/find.ui:218
+msgid "Search backward"
+msgstr "Ieškoti atgal"
+
+#: src/ui/gui/frequencies.ui:102 src/ui/gui/psppire.ui:282
+#: src/ui/gui/rank.ui:105
+msgid "Variable(s):"
+msgstr "Kintamasis(-ieji):"
+
+#: src/ui/gui/frequencies.ui:151
+msgid "Include missing values"
+msgstr "Įtraukti praleistas reikšmes"
+
+#: src/ui/gui/frequencies.ui:189
+msgid "Charts..."
+msgstr "Diagramos..."
+
+#: src/ui/gui/frequencies.ui:201
+msgid "Frequency Tables..."
+msgstr "Dažnių lentelės..."
+
+#: src/ui/gui/frequencies.ui:251
+msgid "Frequencies: Frequency Tables"
+msgstr "Dažniai: dažnių lentelės"
+
+#: src/ui/gui/frequencies.ui:281
+msgid "Always"
+msgstr "Visada"
+
+#: src/ui/gui/frequencies.ui:297
+msgid "Never"
+msgstr "Niekada"
+
+#: src/ui/gui/frequencies.ui:316
+msgid "If no more than "
+msgstr "Jei reikšmių ne daugiau kaip "
+
+#: src/ui/gui/frequencies.ui:347
+msgid "values"
+msgstr " "
+
+#: src/ui/gui/frequencies.ui:368
+msgid "Display frequency tables"
+msgstr "Rodyti dažnių lenteles"
+
+#: src/ui/gui/frequencies.ui:396
+msgid "Ascending value"
+msgstr "Didėjančia reikšme"
+
+#: src/ui/gui/frequencies.ui:412
+msgid "Descending value"
+msgstr "Mažėjančia reikšme"
+
+#: src/ui/gui/frequencies.ui:428
+msgid "Ascending frequency"
+msgstr "Didėjančiu dažnumu"
+
+#: src/ui/gui/frequencies.ui:444
+msgid "Descending frequency"
+msgstr "Mažėjančiu dažnumu"
+
+#: src/ui/gui/frequencies.ui:466
+msgid "Order by"
+msgstr "Rikiuojama"
+
+#: src/ui/gui/frequencies.ui:508
+msgid "Frequencies: Charts"
+msgstr "Dažniai: diagramos"
+
+#: src/ui/gui/frequencies.ui:536
+msgid "Exclude values below "
+msgstr "Atmesti reikšmes mažesnes už"
+
+#: src/ui/gui/frequencies.ui:571
+msgid "Exclude values above "
+msgstr "Atmesti reikšmes didesnes už"
+
+#: src/ui/gui/frequencies.ui:609
+msgid "<b>Chart Formatting</b>"
+msgstr "<b>Diagramų formatas</b>"
+
+#: src/ui/gui/frequencies.ui:633
+msgid "Draw histograms"
+msgstr "Braižyti histogramas"
+
+#: src/ui/gui/frequencies.ui:645
+msgid "Superimpose normal curve"
+msgstr "Uždėti normaliąją kreivę"
+
+#: src/ui/gui/frequencies.ui:661
+msgid "Scale:"
+msgstr "Skalė:"
+
+#: src/ui/gui/frequencies.ui:682
+msgid "Percentages"
+msgstr "Procentiniai santykiai"
+
+#: src/ui/gui/frequencies.ui:705
+msgid "<b>Histograms</b>"
+msgstr "<b>Histogramos</b>"
+
+#: src/ui/gui/frequencies.ui:729
+msgid "Draw pie charts"
+msgstr "Braižyti skritulines diagramas"
+
+#: src/ui/gui/frequencies.ui:741
+msgid "Include slices for missing values"
+msgstr "Įtraukti praleistų reikšmių skiltis"
+
+#: src/ui/gui/frequencies.ui:758
+msgid "<b>Pie Charts</b>"
+msgstr "<b>Skritulinė diagrama</b>"
+
+#: src/ui/gui/k-related.ui:7
+msgid "Tests for Several Related Samples"
+msgstr "Kriterijai kelioms priklausomoms (porinėms) imtims"
+
+#: src/ui/gui/k-related.ui:94
+msgid "_Test Variables:"
+msgstr "_Kriterijaus kintamieji:"
+
+#: src/ui/gui/k-related.ui:122
+msgid "_Friedman"
+msgstr "Friedman"
+
+#: src/ui/gui/k-related.ui:136
+msgid "_Kendall's W"
+msgstr "Kendall W"
+
+#: src/ui/gui/k-related.ui:150
+msgid "_Cochran's Q"
+msgstr "Cochran Q"
+
+#: src/ui/gui/k-related.ui:169
+msgid "Test Type"
+msgstr "Kriterijaus tipas"
+
+#: src/ui/gui/oneway.ui:8
+msgid "One-Way ANOVA"
+msgstr "Vienfaktorinė ANOVA"
+
+#: src/ui/gui/oneway.ui:31
+msgid "_Factor:"
+msgstr "_Faktorius:"
+
+#: src/ui/gui/oneway.ui:69
+msgid "Dependent _Variable(s):"
+msgstr "Priklausomas _kintamasis(-ieji):"
+
+#: src/ui/gui/oneway.ui:184
+msgid "_Descriptives"
+msgstr "_Aprašomoji"
+
+#: src/ui/gui/oneway.ui:200
+msgid "_Homogeneity"
+msgstr "_Homogeniškumas"
+
+#: src/ui/gui/oneway.ui:238
+msgid "_Contrasts..."
+msgstr "Kon_trastai..."
+
+#: src/ui/gui/oneway.ui:292
+msgid "One-Way ANOVA: Contrasts"
+msgstr "Vienfaktorinė ANOVA: kontrastai"
+
+#: src/ui/gui/oneway.ui:369
+msgid "_Coefficients:"
+msgstr "_Koeficientai:"
+
+#: src/ui/gui/oneway.ui:416
+msgid "Coefficient Total: "
+msgstr "Koeficientų suma: "
+
+#: src/ui/gui/oneway.ui:452
+msgid "Contrast 1 of 1"
+msgstr "1 kontrastas iš 1"
+
+#: src/ui/gui/psppire.ui:7
+msgid "Weight Cases"
+msgstr "Sverti atvejus"
+
+#: src/ui/gui/psppire.ui:66
+msgid "Weight cases by"
+msgstr "Atvejus sverti pagal"
+
+#: src/ui/gui/psppire.ui:102
+msgid "Frequency Variable"
+msgstr "Dažnių kintamasis"
+
+#: src/ui/gui/psppire.ui:145
+msgid "Current Status: "
+msgstr "Dabartinė būsena: "
+
+#: src/ui/gui/psppire.ui:195
+msgid "Transpose"
+msgstr "Perstatyti"
+
+#: src/ui/gui/psppire.ui:247
+msgid "Name Variable:"
+msgstr "Vardų kintamasis:"
+
+#: src/ui/gui/psppire.ui:383
+msgid "Data File Comments"
+msgstr "Duomenų rinkmenos komentarai"
+
+#: src/ui/gui/psppire.ui:407
+msgid "Comments:"
+msgstr "Komentarai:"
+
+#: src/ui/gui/psppire.ui:448
+msgid "Display comments in output"
+msgstr "Rezultatuose rodyti komentarus"
+
+#: src/ui/gui/psppire.ui:467
+msgid "Column Number: 0"
+msgstr "Stulpelio numeris: 0"
+
+#: src/ui/gui/rank.ui:8
+msgid "Rank Cases"
+msgstr "Ranguoti atvejus"
+
+#: src/ui/gui/rank.ui:58
+msgid "By:"
+msgstr "Pagal:"
+
+#: src/ui/gui/rank.ui:204
+msgid "_Smallest Value"
+msgstr "_Mažiausia reikšmė"
+
+#: src/ui/gui/rank.ui:221
+msgid "_Largest Value"
+msgstr "_Didžiausia reikšmė"
+
+#: src/ui/gui/rank.ui:245
+msgid "Assign rank 1 to:"
+msgstr "Pirmą rangą priskirti:"
+
+#: src/ui/gui/rank.ui:261
+msgid "_Display summary tables"
+msgstr "Rodyti _santraukos lenteles"
+
+#: src/ui/gui/rank.ui:279
+msgid "Rank T_ypes"
+msgstr "Rangų _tipai"
+
+#: src/ui/gui/rank.ui:294
+msgid "_Ties..."
+msgstr "_Ryšiai"
+
+#: src/ui/gui/rank.ui:346
+msgid "Rank Cases: Types"
+msgstr "Ranguoti atvejus: tipai"
+
+#: src/ui/gui/rank.ui:366
+msgid "Sum of case weights"
+msgstr "Kintamųjų svorių suma"
+
+#: src/ui/gui/rank.ui:382
+msgid "Fractional rank as %"
+msgstr "Santykinis rangas procentais"
+
+#: src/ui/gui/rank.ui:396
+msgid "Fractional rank"
+msgstr "Santykinis rangas"
+
+#: src/ui/gui/rank.ui:410
+msgid "Savage score"
+msgstr "Savage taškas"
+
+#: src/ui/gui/rank.ui:424
+msgid "Rank"
+msgstr "Rangas"
+
+#: src/ui/gui/rank.ui:438
+msgid "Ntiles"
+msgstr "N- procentilės"
+
+#: src/ui/gui/rank.ui:481
+msgid "Proportion Estimates"
+msgstr "Dalies įverčiai"
+
+#: src/ui/gui/rank.ui:494
+msgid "Normal Scores"
+msgstr "Normalieji taškai"
+
+#: src/ui/gui/rank.ui:529
+msgid "Blom"
+msgstr "Blom"
+
+#: src/ui/gui/rank.ui:543
+msgid "Tukey"
+msgstr "Tukey"
+
+#: src/ui/gui/rank.ui:557
+msgid "Rankit"
+msgstr "Rankit"
+
+#: src/ui/gui/rank.ui:571
+msgid "Van der Wärden"
+msgstr "Van der Wärden"
+
+#: src/ui/gui/rank.ui:591
+msgid "Proportion Estimation Formula"
+msgstr "Dalies įverčių formulė"
+
+#: src/ui/gui/rank.ui:625
+msgid "Rank Cases: Ties"
+msgstr "Ranguoti atvejus: ryšiai"
+
+#: src/ui/gui/rank.ui:651
+msgid "_Mean"
+msgstr "_Vidurkis"
+
+#: src/ui/gui/rank.ui:668
+msgid "_Low"
+msgstr "_Mažiausiasis"
+
+#: src/ui/gui/rank.ui:686
+msgid "_High"
+msgstr "_Didžiausiasis"
+
+#: src/ui/gui/rank.ui:709
+msgid "_Sequential ranks to unique values"
+msgstr "_Nuosekliai didėjantys rangai (didžiausias rangas lygus skirtingų reikšmių skaičiui)"
+
+#: src/ui/gui/rank.ui:732
+msgid "Rank Assigned to Ties"
+msgstr "Rangas, priskiriamas esant vienodoms reikšmėms, yra rangų:"
+
+#: src/ui/gui/sort.ui:8
+msgid "Sort Cases"
+msgstr "Rikiuoti atvejus"
+
+#: src/ui/gui/sort.ui:79
+msgid "Sort by:"
+msgstr "Rikiuoti pagal:"
+
+#: src/ui/gui/sort.ui:146
+msgid "Descending"
+msgstr "Mažėjančiai"
+
+#: src/ui/gui/sort.ui:168
+msgid "Sort Order"
+msgstr "Rikiavimo tvarka"
+
+#: src/ui/gui/split-file.ui:8
+msgid "Split File"
+msgstr "Skaidyti rinkmeną"
+
+#: src/ui/gui/split-file.ui:68
+msgid "Analyze all cases.  Do not create groups."
+msgstr "Analizuoti visus atvejus.  Nekuti grupių."
+
+#: src/ui/gui/split-file.ui:84
+msgid "Compare groups."
+msgstr "Palyginti grupes."
+
+#: src/ui/gui/split-file.ui:100
+msgid "Organize output by groups."
+msgstr "Rezultatus pateikti pagal grupes."
+
+#: src/ui/gui/split-file.ui:158
+msgid "Groups based on:"
+msgstr "Grupuoti pagal:"
+
+#: src/ui/gui/split-file.ui:217
+msgid "Sort the file by grouping variables."
+msgstr "Rinkmeną rikiuoti pagal grupavimo kintamąjį"
+
+#: src/ui/gui/split-file.ui:234
+msgid "File is already sorted."
+msgstr "Rinkmena jau surikiuota."
+
+#: src/ui/gui/split-file.ui:287
+msgid "Current Status : "
+msgstr "Dabartinė būsena: "
+
+#: src/ui/gui/split-file.ui:298
+msgid "Analysis by groups is off"
+msgstr "Analizė pagal grupes yra išjungta"
+
+#: src/ui/gui/recode.ui:185 src/ui/gui/recode.ui:467
+msgid "System Missing"
+msgstr "Sisteminė praleista"
+
+#: src/ui/gui/recode.ui:199
+msgid "System or User Missing"
+msgstr "Sisteminė arba naudotojo praleista"
+
+#: src/ui/gui/recode.ui:237
+msgid "through"
+msgstr "iki"
+
+#: src/ui/gui/recode.ui:275
+msgid "Range, LOWEST thru value"
+msgstr "Sritis, nuo MAŽIAUSIOS reikšmės iki ..."
+
+#: src/ui/gui/recode.ui:289
+msgid "Range, value thru HIGHEST"
+msgstr "Sritis, nuo reikšmės ... iki DIDŽIAUSIOS"
+
+#: src/ui/gui/recode.ui:319
+msgid "All other values"
+msgstr "Visos kitos reikšmės"
+
+#: src/ui/gui/recode.ui:355
+msgid "Range:"
+msgstr "Sritis: nuo"
+
+#: src/ui/gui/recode.ui:384
+msgid "Old Value"
+msgstr "Sena reikšmė"
+
+#: src/ui/gui/recode.ui:481
+msgid "Copy old values"
+msgstr "Kopijuoti senas reikšmes"
+
+#: src/ui/gui/recode.ui:505
+msgid "Value: "
+msgstr "Reikšmė: "
+
+#: src/ui/gui/recode.ui:538
+msgid "New Value"
+msgstr "Nauja reikšmė"
+
+#: src/ui/gui/recode.ui:596
+msgid "Convert numeric strings to numbers (`5' -> 5)"
+msgstr "Konvertuoti skaitmenines eilutes į skaičius (`5' -> 5)"
+
+#: src/ui/gui/recode.ui:614
+msgid "Output variables are strings"
+msgstr "Išvedami kintamieji yra teksto eilutės. "
+
+#: src/ui/gui/recode.ui:629
+msgid "Width: "
+msgstr "Ilgis: "
+
+#: src/ui/gui/recode.ui:757
+msgid "(optional case selection condition)"
+msgstr "(atvejų atrankos sąlyga, nebūtina)"
+
+#: src/ui/gui/recode.ui:838
+msgid "Name:"
+msgstr "Vardas:"
+
+#: src/ui/gui/recode.ui:881
+msgid "Change"
+msgstr "Pakeisti"
+
+#: src/ui/gui/recode.ui:907
+msgid "Output Variable"
+msgstr "Išvedamas kintamasis"
+
+#: src/ui/gui/recode.ui:981
+msgid "Old and New Values"
+msgstr "Senos ir naujos reikšmės"
+
+#: src/ui/gui/regression.ui:41
+msgid "Save..."
+msgstr "Įrašyti..."
+
+#: src/ui/gui/regression.ui:156
+msgid "Dependent"
+msgstr "Priklausomas"
+
+#: src/ui/gui/regression.ui:201
+msgid "Independent"
+msgstr "Nepriklausomas"
+
+#: src/ui/gui/regression.ui:236
+msgid "Regression: Save"
+msgstr "Regresija: įrašyti"
+
+#: src/ui/gui/regression.ui:250
+msgid "Predicted values"
+msgstr "Prognozuojamos reikšmės"
+
+#: src/ui/gui/regression.ui:263
+msgid "Residuals"
+msgstr "Liekanos"
+
+#: src/ui/gui/regression.ui:298
+msgid "Regression: Statistics"
+msgstr "Regresija: statistika"
+
+#: src/ui/gui/reliability.ui:26
+msgid "Reliability Analysis"
+msgstr "Klausimynų patikimumo analizė"
+
+#: src/ui/gui/reliability.ui:124
+msgid "_Items:"
+msgstr "_Elementai:"
+
+#: src/ui/gui/reliability.ui:141
+msgid "Model:\t"
+msgstr "Modelis:\t"
+
+#: src/ui/gui/reliability.ui:180
+msgid "Variables in first split:"
+msgstr "Kintamieji pirmoje dalyje:"
+
+#: src/ui/gui/reliability.ui:217
+msgid "Show descriptives for scale if _item is deleted"
+msgstr "Aprašomoji statistika, jei elementas būtų pašalintas"
+
+#: src/ui/gui/roc.ui:115
+msgid "_Test Variable:"
+msgstr "_Kriterijaus kintamasis:"
+
+#: src/ui/gui/roc.ui:147
+msgid "_State Variable:"
+msgstr "_Būsenos kintamasis"
+
+#: src/ui/gui/roc.ui:172
+msgid "_Value of state variable:"
+msgstr "Būsenos kintamojo _reikšmė:"
+
+#: src/ui/gui/roc.ui:209
+msgid "ROC C_urve"
+msgstr "Operatoria_us charakteringa kreivė"
+
+#: src/ui/gui/roc.ui:227
+msgid "_With diagonal reference line"
+msgstr "_Brėžti įstrižainę"
+
+#: src/ui/gui/roc.ui:251
+msgid "Standard _Error and Confidence Interval"
+msgstr "_Standartinė paklaida ir pasikliautinasis intervalas"
+
+#: src/ui/gui/roc.ui:266
+msgid "_Coordinate points of the ROC Curve"
+msgstr "O_ChK koordinačių taškų lentelė"
+
+#: src/ui/gui/select-cases.ui:8
+msgid "Select Cases"
+msgstr "Atvejų atranka"
+
+#: src/ui/gui/select-cases.ui:196
+msgid "Use filter variable"
+msgstr "Naudoti filtro kintamąjį"
+
+#: src/ui/gui/select-cases.ui:255
+msgid "Based on time or case range"
+msgstr "Pagal laiką arba atvejų sritį"
+
+#: src/ui/gui/select-cases.ui:267
+msgid "Range..."
+msgstr "Sritis..."
+
+#: src/ui/gui/select-cases.ui:311
+msgid "Random sample of cases"
+msgstr "Atsitiktinė atvejų imtis"
+
+#: src/ui/gui/select-cases.ui:324
+msgid "Sample..."
+msgstr "Imtis..."
+
+#: src/ui/gui/select-cases.ui:366
+msgid "If condition is satisfied"
+msgstr "Jeigu tenkinama sąlyga"
+
+#: src/ui/gui/select-cases.ui:418
+msgid "All Cases"
+msgstr "Visi atvejai"
+
+#: src/ui/gui/select-cases.ui:433
+msgid "Select"
+msgstr "Pasirinkti"
+
+#: src/ui/gui/select-cases.ui:460
+msgid "Filtered"
+msgstr "Filtruojami"
+
+#: src/ui/gui/select-cases.ui:476
+msgid "Deleted"
+msgstr "Pašalinami"
+
+#: src/ui/gui/select-cases.ui:499
+msgid "Unselected Cases Are"
+msgstr "Nepasirinkti atvejai yra"
+
+#: src/ui/gui/select-cases.ui:541
+msgid "Select Cases: Range"
+msgstr "Atvejų atranka: sritis"
+
+#: src/ui/gui/select-cases.ui:590
+msgid "First case"
+msgstr "Pirmas atvejis"
+
+#: src/ui/gui/select-cases.ui:603
+msgid "Last case"
+msgstr "Paskutinis atvejis"
+
+#: src/ui/gui/select-cases.ui:616
+msgid "Observation"
+msgstr "Stebėjimas"
+
+#: src/ui/gui/select-cases.ui:648
+msgid "Select Cases: Random Sample"
+msgstr "Atvejų atranka: atsitiktinė imtis"
+
+#: src/ui/gui/select-cases.ui:746
+msgid "Sample Size"
+msgstr "Imties dydis"
+
+#: src/ui/gui/t-test.ui:8
+msgid "Independent-Samples T Test"
+msgstr "T kriterijus nepriklausomoms imtims"
+
+#: src/ui/gui/t-test.ui:54 src/ui/gui/t-test.ui:175 src/ui/gui/t-test.ui:231
+msgid "Define Groups"
+msgstr "Apibrėžti grupes"
+
+#: src/ui/gui/t-test.ui:131 src/ui/gui/t-test.ui:584 src/ui/gui/t-test.ui:803
+msgid "Test Variable(s):"
+msgstr "Kriterijaus kintamasis(-ieji):"
+
+#: src/ui/gui/t-test.ui:271
+msgid "Group_2 value:"
+msgstr "_2 grupės reikšmė:"
+
+#: src/ui/gui/t-test.ui:284
+msgid "Group_1 value:"
+msgstr "_1 grupės reikšmė:"
+
+#: src/ui/gui/t-test.ui:365
+msgid "_Use specified values:"
+msgstr "_Naudoti nurodytas reikšmes:"
+
+#: src/ui/gui/t-test.ui:420
+msgid "Options"
+msgstr "Parinktys"
+
+#: src/ui/gui/t-test.ui:452
+msgid "Exclude cases _analysis by analysis"
+msgstr "Neįtraukiamos konkrečioje _analizėje"
+
+#: src/ui/gui/t-test.ui:469
+msgid "Exclude cases _listwise"
+msgstr "Atvejai neįtraukiami _visose analizėse"
+
+#: src/ui/gui/t-test.ui:529
+msgid "One - Sample T Test"
+msgstr "T kriterijus vienai imčiai"
+
+#: src/ui/gui/t-test.ui:626
+msgid "Test Value: "
+msgstr "Kriterijaus reikšmė: "
+
+#: src/ui/gui/t-test.ui:704
+msgid "Paired Samples T Test"
+msgstr "Kriterijus porinėms imtims"
+
+#: src/ui/gui/text-data-import.ui:8
+msgid "Importing Textual Data"
+msgstr "Importuojami tekstiniai duomenys"
+
+#: src/ui/gui/text-data-import.ui:19
+msgid ""
+"This assistant will guide you through the process of importing data into PSPP from a text file with one line per case,  in which fields are separated by tabs, commas, or other delimiters.\n"
+"\n"
+"The selected file contains N lines of text.  Only the first M of these will be shown for preview purposes in the following screens.  You may choose below how much of the file should actually be imported."
+msgstr ""
+"Šis vediklis padės į PSPP importuoti duomenis iš tekstinės rinkmenos, kur viena eilutė atitiks vieną atvejį, o laukai (būsimi kintamieji) atskiriami tabuliacija, kableliu ar kitu pasirinktu simboliu.\n"
+"\n"
+"Pasirinkta rinkmena turi N eilučių teksto. Sekančiame lange galėsite peržiūrėti tik pirmąsias M eilučių. Žemiau galite nurodyti, kiek importuoti rinkmenos duomenų."
+
+#: src/ui/gui/text-data-import.ui:95
+msgid "All cases"
+msgstr "Visi atvejai"
+
+#: src/ui/gui/text-data-import.ui:116
+msgid "<b>Amount to Import</b>"
+msgstr "<b>Importuojamas kiekis</b>"
+
+#: src/ui/gui/text-data-import.ui:135
+msgid "Select Data to Import"
+msgstr "Pasirinkite importuotinus duomenis"
+
+#: src/ui/gui/text-data-import.ui:146
+msgid "Select the first line of the data file that contains data."
+msgstr "Pasirinkite pirmąją importuotinų duomenų eilutę."
+
+#: src/ui/gui/text-data-import.ui:174
+msgid "Line above selected line contains variable names"
+msgstr "Virš pasirinktosios eilutės yra kintamųjų vardai"
+
+#: src/ui/gui/text-data-import.ui:192
+msgid "Choose Separators"
+msgstr "Pasirinkite skirtukus"
+
+#: src/ui/gui/text-data-import.ui:238
+msgid "C_ustom"
+msgstr "Sa_viti"
+
+#: src/ui/gui/text-data-import.ui:253
+msgid "Slas_h (/)"
+msgstr "D_ešininis brūkšnys (/)"
+
+#: src/ui/gui/text-data-import.ui:270
+msgid "Semicolo_n (;)"
+msgstr "Kab_liataškis (;)"
+
+#: src/ui/gui/text-data-import.ui:287
+msgid "P_ipe (|)"
+msgstr "Status brūkš_nys (|)"
+
+#: src/ui/gui/text-data-import.ui:302
+msgid "H_yphen (-)"
+msgstr "B_rūkšnelis (-)"
+
+#: src/ui/gui/text-data-import.ui:319
+msgid "Co_mma (,)"
+msgstr "_Kablelis (,)"
+
+#: src/ui/gui/text-data-import.ui:336
+msgid "_Colon (:)"
+msgstr "_Dvitaškis (:)"
+
+#: src/ui/gui/text-data-import.ui:351
+msgid "Ban_g (!)"
+msgstr "Ša_uktukas (!)"
+
+#: src/ui/gui/text-data-import.ui:366
+msgid "Ta_b"
+msgstr "Ta_buliacija"
+
+#: src/ui/gui/text-data-import.ui:381
+msgid "_Space"
+msgstr "_Tarpas"
+
+#: src/ui/gui/text-data-import.ui:398
+msgid "<b>Separators</b>"
+msgstr "<b>Skirtukai</b>"
+
+#: src/ui/gui/text-data-import.ui:428
+msgid "Doubled quote mark treated as escape"
+msgstr "Dvi kabutės iš eilės - grįžtis"
+
+#: src/ui/gui/text-data-import.ui:457
+msgid "Quote separator characters with"
+msgstr "Teksto skirtukai pažymėti kabutėmis"
+
+#: src/ui/gui/text-data-import.ui:477
+msgid "<b>Quoting</b>"
+msgstr "<b>Kabutės</b>"
+
+#: src/ui/gui/text-data-import.ui:525
+msgid "<b>Fields Preview</b>"
+msgstr "<b>Laukų peržiūra</b>"
+
+#: src/ui/gui/text-data-import.ui:540
+msgid "Adjust Variable Formats"
+msgstr "Priderinkite kintamųjų formatus"
+
+#: src/ui/gui/text-data-import.ui:551
+msgid "Check the data formats displayed below and fix any that are incorrect.  You may set other variable properties now or later."
+msgstr "Peržiūrėkite žemiau pateiktą duomenų formatą ir, jei reikia, jį pataisykite. Kitas kintamųjų savybes galite nustatyti tiek dabar, tiek vėliau."
+
+#: src/ui/gui/text-data-import.ui:595
+msgid "<b>Variables</b>"
+msgstr "<b>Kintamieji</b>"
+
+#: src/ui/gui/text-data-import.ui:638
+msgid "<b>Data Preview</b>"
+msgstr "<b>Duomenų peržiūra</b>"
+
+#: src/ui/gui/var-sheet-dialogs.ui:7
+msgid "Variable Type"
+msgstr "Kintamojo tipas"
+
+#: src/ui/gui/var-sheet-dialogs.ui:75
+msgid "Scientific notation"
+msgstr "Mokslinis užrašas"
+
+#: src/ui/gui/var-sheet-dialogs.ui:123
+msgid "Custom currency"
+msgstr "Savita valiuta"
+
+#: src/ui/gui/var-sheet-dialogs.ui:225
+msgid "positive"
+msgstr "teigiamas"
+
+#: src/ui/gui/var-sheet-dialogs.ui:234
+msgid "negative"
+msgstr "neigiamas"
+
+#: src/ui/gui/var-sheet-dialogs.ui:247
+msgid "Sample"
+msgstr "Imtis"
+
+#: src/ui/gui/var-sheet-dialogs.ui:294
+msgid "Width:"
+msgstr "Ilgis:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:339
+msgid "Decimal Places:"
+msgstr "Dešimtainė skiltis:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:419 src/ui/gui/var-sheet-dialogs.ui:610
+msgid "Value Labels"
+msgstr "Reikšmių etiketės"
+
+#: src/ui/gui/var-sheet-dialogs.ui:518
+msgid "Value Label:"
+msgstr "Reikšmės etiketė:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:711
+msgid "_No missing values"
+msgstr "_Nėra praleistų reikšmių"
+
+#: src/ui/gui/var-sheet-dialogs.ui:782
+msgid "_Discrete missing values"
+msgstr "_Diskrečios praleistos reikšmės"
+
+#: src/ui/gui/var-sheet-dialogs.ui:816
+msgid "_Low:"
+msgstr "_Apačia:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:835
+msgid "_High:"
+msgstr "_Viršus:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:860
+msgid "Di_screte value:"
+msgstr "Di_skreti reikšmė:"
+
+#: src/ui/gui/var-sheet-dialogs.ui:888
+msgid "_Range plus one optional discrete missing value"
+msgstr "_Sritis ir viena diskreti praleista reikšmė"
+
+#: src/ui/gui/variable-info.ui:50
+msgid "Variable Information:"
+msgstr "Informacija apie kintamąjį:"
+
+#: src/ui/gui/data-editor.ui:23 src/ui/gui/output-viewer.ui:9
+#: src/ui/gui/syntax-editor.ui:10
+msgid "_File"
+msgstr "_Rinkmena"
+
+#: src/ui/gui/data-editor.ui:35 src/ui/gui/syntax-editor.ui:22
+msgid "_Syntax"
+msgstr "_Sintaksė"
+
+#: src/ui/gui/data-editor.ui:41 src/ui/gui/data-editor.ui:224
+#: src/ui/gui/data-editor.ui:237 src/ui/gui/syntax-editor.ui:28
+msgid "_Data"
+msgstr "_Duomenys"
+
+#: src/ui/gui/data-editor.ui:48 src/ui/gui/syntax-editor.ui:35
+msgid "_Open..."
+msgstr "_Atverti..."
+
+#: src/ui/gui/data-editor.ui:54
+msgid "_Import Delimited Text Data..."
+msgstr "_Importuoti tekstinius duomenis..."
+
+#: src/ui/gui/data-editor.ui:61
+msgid "_Rename Dataset..."
+msgstr "_Pervadinti duomenų rinkinį..."
+
+#: src/ui/gui/data-editor.ui:74 src/ui/gui/syntax-editor.ui:48
+msgid "Save _As..."
+msgstr "Įrašyti _kaip..."
+
+#: src/ui/gui/data-editor.ui:80
+msgid "D_isplay Data File Information"
+msgstr "_Rodyti duomenų rinkmenos informaciją"
+
+#: src/ui/gui/data-editor.ui:87
+msgid "Working File"
+msgstr "Veikiamoji rinkmena"
+
+#: src/ui/gui/data-editor.ui:93
+msgid "External File..."
+msgstr "Išorinė rinkmena..."
+
+#: src/ui/gui/data-editor.ui:99
+msgid "Recently Used Da_ta"
+msgstr "Paskiausi _duomenys"
+
+#: src/ui/gui/data-editor.ui:105
+msgid "Recently Used _Files"
+msgstr "Paskiausios _rinkmenos"
+
+#: src/ui/gui/data-editor.ui:117 src/ui/gui/output-viewer.ui:29
+#: src/ui/gui/syntax-editor.ui:60
+msgid "_Edit"
+msgstr "_Taisa"
+
+#: src/ui/gui/data-editor.ui:123
+msgid "Insert Variable"
+msgstr "Įterpti kintamąjį"
+
+#: src/ui/gui/data-editor.ui:124
+msgid "Create a new variable at the current position"
+msgstr "Sukurti naują kintamąjį šioje vietoje"
+
+#: src/ui/gui/data-editor.ui:131
+msgid "Insert Cases"
+msgstr "Įterpti atvejus"
+
+#: src/ui/gui/data-editor.ui:132
+msgid "Create a new case at the current position"
+msgstr "Sukurti naują atvejį šioje vietoje"
+
+#: src/ui/gui/data-editor.ui:138
+msgid "Go To Case..."
+msgstr "Šokti į atvejį..."
+
+#: src/ui/gui/data-editor.ui:140
+msgid "Jump to a case in the data sheet"
+msgstr "Šokti į atvejį duomenų lakšte"
+
+#: src/ui/gui/data-editor.ui:166
+msgid "Cl_ear Variables"
+msgstr "Iš_valyti kintamuosius"
+
+#: src/ui/gui/data-editor.ui:167
+msgid "Delete the variables at the selected position(s)"
+msgstr "Pašalinti pasirinktų pozicijų kintamuosius"
+
+#: src/ui/gui/data-editor.ui:175
+msgid "_Clear Cases"
+msgstr "Iš_valyti atvejus"
+
+#: src/ui/gui/data-editor.ui:176
+msgid "Delete the cases at the selected position(s)"
+msgstr "Pašalinti pasirinktų pozicijų atvejus"
+
+#: src/ui/gui/data-editor.ui:183
+msgid "_Find..."
+msgstr "_Ieškoti..."
+
+#: src/ui/gui/data-editor.ui:189
+msgid "_View"
+msgstr "Ro_dinys"
+
+#: src/ui/gui/data-editor.ui:196
+msgid "_Status Bar"
+msgstr "_Būsenos juosta"
+
+#: src/ui/gui/data-editor.ui:203
+msgid "_Font..."
+msgstr "Šri_ftai..."
+
+#: src/ui/gui/data-editor.ui:210
+msgid "_Grid Lines"
+msgstr "_Tinklelis"
+
+#: src/ui/gui/data-editor.ui:216
+msgid "Value _Labels"
+msgstr "Reikšmių _etiketės"
+
+#: src/ui/gui/data-editor.ui:217
+msgid "Show/hide value labels"
+msgstr "Rodyti / slėpti reikšmių etiketes"
+
+#: src/ui/gui/data-editor.ui:230
+msgid "_Variables"
+msgstr "_Kintamieji"
+
+#: src/ui/gui/data-editor.ui:242
+msgid "_Sort Cases..."
+msgstr "_Rikiuoti atvejus..."
+
+#: src/ui/gui/data-editor.ui:245
+msgid "Sort cases in the active dataset"
+msgstr "Rikiuoti veikiamojo duomenų rinkinio atvejus"
+
+#: src/ui/gui/data-editor.ui:252
+msgid "_Transpose..."
+msgstr "_Perstatyti..."
+
+#: src/ui/gui/data-editor.ui:253
+msgid "Transpose the cases with the variables"
+msgstr "Perstatyti atvejus ir kintamuosius"
+
+#: src/ui/gui/data-editor.ui:260
+msgid "_Aggregate..."
+msgstr "Agreg_uoti..."
+
+#: src/ui/gui/data-editor.ui:266
+msgid "S_plit File..."
+msgstr "_Skaidyti rinkmeną..."
+
+#: src/ui/gui/data-editor.ui:267
+msgid "Split the active dataset"
+msgstr "Skaidyti veikiamąjį duomenų rinkinį"
+
+#: src/ui/gui/data-editor.ui:274
+msgid "Select _Cases..."
+msgstr "_Atvejų atranka..."
+
+#: src/ui/gui/data-editor.ui:280
+msgid "_Weight Cases..."
+msgstr "S_verti atvejus..."
+
+#: src/ui/gui/data-editor.ui:281
+msgid "Weight cases by variable"
+msgstr "Atvejus sverti pagal kintamąjį"
+
+#: src/ui/gui/data-editor.ui:288
+msgid "_Transform"
+msgstr "Trans_formuoti"
+
+#: src/ui/gui/data-editor.ui:294
+msgid "_Compute..."
+msgstr "_Skaičiuoti..."
+
+#: src/ui/gui/data-editor.ui:300
+msgid "Ran_k Cases..."
+msgstr "_Ranguoti atvejus..."
+
+#: src/ui/gui/data-editor.ui:306
+msgid "Recode into _Same Variables..."
+msgstr "Perkoduoti į _tuos pačius kintamuosius..."
+
+#: src/ui/gui/data-editor.ui:312
+msgid "Recode into _Different Variables..."
+msgstr "Perkoduoti į _kitus kintamuosius..."
+
+#: src/ui/gui/data-editor.ui:318
+msgid "_Run Pending Transforms"
+msgstr "_Vykdyti laukiančias transformacijas"
+
+#: src/ui/gui/data-editor.ui:325
+msgid "_Analyze"
+msgstr "_Analizuoti"
+
+#: src/ui/gui/data-editor.ui:331
+msgid "_Descriptive Statistics"
+msgstr "_Aprašomoji statistika"
+
+#: src/ui/gui/data-editor.ui:337
+msgid "_Frequencies..."
+msgstr "_Dažniai..."
+
+#: src/ui/gui/data-editor.ui:349
+msgid "_Explore..."
+msgstr "_Tyrinėti..."
+
+#: src/ui/gui/data-editor.ui:355
+msgid "_Crosstabs..."
+msgstr "_Požymių dažnių lentelės..."
+
+#: src/ui/gui/data-editor.ui:361
+msgid "Compare _Means"
+msgstr "Palyginti _vidurkius"
+
+#: src/ui/gui/data-editor.ui:367
+msgid "_One Sample T Test..."
+msgstr "T kriterijus _vienai imčiai..."
+
+#: src/ui/gui/data-editor.ui:373
+msgid "_Independent Samples T Test..."
+msgstr "T kriterijus _nepriklausomoms imtims..."
+
+#: src/ui/gui/data-editor.ui:379
+msgid "_Paired Samples T Test..."
+msgstr "_T kriterijus porinėms imtims..."
+
+#: src/ui/gui/data-editor.ui:385
+msgid "One Way _ANOVA..."
+msgstr "Vienfaktorinė _ANOVA..."
+
+#: src/ui/gui/data-editor.ui:391
+msgid "Bivariate _Correlation..."
+msgstr "_Dviejų kintamųjų koreliacija..."
+
+#: src/ui/gui/data-editor.ui:397
+msgid "Factor _Analysis..."
+msgstr "_Faktorinė analizė..."
+
+#: src/ui/gui/data-editor.ui:403
+msgid "Re_liability..."
+msgstr "_Klausimynų patikimumas..."
+
+#: src/ui/gui/data-editor.ui:409
+msgid "Linear _Regression..."
+msgstr "_Tiesinė regresija..."
+
+#: src/ui/gui/data-editor.ui:415
+msgid "_Non-Parametric Statistics"
+msgstr "_Neparametrinė statistika"
+
+#: src/ui/gui/data-editor.ui:421
+msgid "_Chi-Square..."
+msgstr "_Chi-kvadratas..."
+
+#: src/ui/gui/data-editor.ui:427
+msgid "_Binomial..."
+msgstr "_Binominis..."
+
+#: src/ui/gui/data-editor.ui:433
+msgid "K Related _Samples..."
+msgstr "_K priklausomų imčių..."
+
+#: src/ui/gui/data-editor.ui:439
+msgid "ROC Cur_ve..."
+msgstr "_Operatoriaus charakteringa kreivė..."
+
+#: src/ui/gui/data-editor.ui:445
+msgid "_Utilities"
+msgstr "Įra_nkiai"
+
+#: src/ui/gui/data-editor.ui:451
+msgid "_Variables..."
+msgstr "_Kintamieji..."
+
+#: src/ui/gui/data-editor.ui:452
+msgid "Jump to variable"
+msgstr "Šokti į kintamąjį"
+
+#: src/ui/gui/data-editor.ui:459
+msgid "Data File _Comments..."
+msgstr "Duomenų rinkmenos _komentarai..."
+
+#: src/ui/gui/data-editor.ui:465 src/ui/gui/output-viewer.ui:47
+#: src/ui/gui/syntax-editor.ui:125
+msgid "_Windows"
+msgstr "_Langas"
+
+#: src/ui/gui/data-editor.ui:471 src/ui/gui/output-viewer.ui:53
+#: src/ui/gui/syntax-editor.ui:131
+msgid "_Minimize All Windows"
+msgstr "_Suskleisti visus langus"
+
+#: src/ui/gui/data-editor.ui:477
+msgid "_Split"
+msgstr "_Skaidyti"
+
+#: src/ui/gui/data-editor.ui:654
+msgid "Information Area"
+msgstr "Informacijos sritis"
+
+#: src/ui/gui/data-editor.ui:676
+msgid "Processor Area"
+msgstr "Doroklės sritis"
+
+#: src/ui/gui/data-editor.ui:701
+msgid "Case Counter Area"
+msgstr "Atvejų skaičiavimo sritis"
+
+#: src/ui/gui/data-editor.ui:726
+msgid "Filter Use Status Area"
+msgstr "Filtro naudojimo būsenos sritis"
+
+#: src/ui/gui/data-editor.ui:752
+msgid "Weight Status Area"
+msgstr "Svėrimo būsenos sritis"
+
+#: src/ui/gui/data-editor.ui:778
+msgid "Split File Status Area"
+msgstr "Rinkmenos skaidymo sritis"
+
+#: src/ui/gui/output-viewer.ui:16
+msgid "_Print..."
+msgstr "Spausdinti..."
+
+#: src/ui/gui/output-viewer.ui:23
+msgid "_Export..."
+msgstr "_Eksportuoti..."
+
+#: src/ui/gui/syntax-editor.ui:94
+msgid "_Run"
+msgstr "_Vykdyti"
+
+#: src/ui/gui/syntax-editor.ui:100
+msgid "All"
+msgstr "Viskas"
+
+#: src/ui/gui/syntax-editor.ui:106
+msgid "Selection"
+msgstr "Išrinkimas"
+
+#: src/ui/gui/syntax-editor.ui:112
+msgid "Current Line"
+msgstr "Veikiamoji eilutė"
+
+#: src/ui/gui/syntax-editor.ui:119
+msgid "To End"
+msgstr "Iki galo"
+
+#~ msgid "Variable suffix too large."
+#~ msgstr "Kintamojo priesaga yra per ilga."
+
+#~ msgid "PSPP-data"
+#~ msgstr "PSPP-duomenys"
+
+#~ msgid "Syntax"
+#~ msgstr "Sintaksė"
+
+#~ msgid "%s %s PSPPIRE %s"
+#~ msgstr "%s %s PSPPIRE %s"
+
+#~ msgid "Untitled"
+#~ msgstr "Bevardė"
+
+#~ msgid "Cannot create variable name from %s"
+#~ msgstr "Nepavyksta sukurti kintamojo vardo iš %s"
+
+#~ msgid "Recoded variable name duplicates an existing `%s' within system file."
+#~ msgstr "Kintamojo, į kurį ketinama perkoduoti, vardas jau yra „%s“ sistemos rinkmenoje."
+
+#~ msgid "Variable name begins with invalid character `%c'."
+#~ msgstr "Kintamojo vardas prasideda netinkamu rašmeniu „%c“."
+
+#~ msgid "Reading `%s': %s."
+#~ msgstr "Skaitoma „%s“: %s."
+
+#~ msgid "Closing `%s': %s."
+#~ msgstr "Užveriama „%s“: %s."
+
+#~ msgid "binary"
+#~ msgstr "dvejetainis"
+
+#~ msgid "octal"
+#~ msgstr "aštuntainis"
+
+#~ msgid "hex"
+#~ msgstr "šešioliktainis"
+
+#~ msgid "DO REPEAT without END REPEAT."
+#~ msgstr "DO REPEAT be END REPEAT."
+
+#~ msgid "%s is too long for a variable name."
+#~ msgstr "%s yra per ilgas kad būtų kintamojo vardu."
+
+#~ msgid "Too many values in single command."
+#~ msgstr "Vienoje komandoje yra per daug reikšmių."
+
+#~ msgid "Unexpected token: `%s'."
+#~ msgstr "Netikėta leksema: „%s“."
+
+#~ msgid "Unable to open `%s': %s."
+#~ msgstr "Nepavyksta atverti „%s“: %s."
+
+#~ msgid "Corrected Model"
+#~ msgstr "Koreguotas modelis"
+
+#~ msgid "Error"
+#~ msgstr "Klaida"
+
+#~ msgid "Analyse"
+#~ msgstr "Analizuoti"
+
+#~ msgid "Sig. 1-tailed"
+#~ msgstr "p-reikšmė (1-pusė)"
+
+#~ msgid "column %d"
+#~ msgstr "%d stulpelis"
+
+#~ msgid "columns %d-%d"
+#~ msgstr "%d-%d stulpeliai"
+
+#~ msgid "Syntax error %s at %s."
+#~ msgstr "Sintaksės klaida %s ties %s."
+
+#~ msgid "expecting `('"
+#~ msgstr "tikėtasi „(“"
+
+#~ msgid "String expected for variable label."
+#~ msgstr "Kintamojo etiketėje tikėtasi teksto eilutės."
+
+#~ msgid "expecting `)'"
+#~ msgstr "tikimasi „)“"
+
+#~ msgid "in expression"
+#~ msgstr "reiškinyje"
+
+#~ msgid ""
+#~ "Alpha\n"
+#~ "Split"
+#~ msgstr ""
+#~ "Alpha\n"
+#~ "Dalinimas pusiau"
+
+#~ msgid "Asymp. Sig. (2-sided)"
+#~ msgstr "Asimp. p-reikšmė (2-pusė)"
+
+#~ msgid "Exact Sig. (2-sided)"
+#~ msgstr "Tiksli p-reikšmė (2-pusė)"
+
+#~ msgid "Exact Sig. (1-sided)"
+#~ msgstr "Tiksli p-reikšmė (1-pusė)"
+
+#~ msgid "`%s' is not a variable name"
+#~ msgstr "„%s“ nėra kintamojo vardas"
+
+#~ msgid " cases"
+#~ msgstr " atvejai"
+
+#~ msgid "%s: Creating temporary file: %s."
+#~ msgstr "%s: Kuriama laikinoji rinkmena: %s."
+
+#~ msgid "%s: Creating file: %s."
+#~ msgstr "%s: Kuriama rinkmena: %s."
+
+#~ msgid "Sort Ascending"
+#~ msgstr "Rikiuoti didėjančia tvarka"
+
+#~ msgid "Sort Descending"
+#~ msgstr "Rikiuoti mažėjančia tvarka"
+
+#~ msgid "little-endian"
+#~ msgstr "didėjantys baitai"
+
+#~ msgid "big-endian"
+#~ msgstr "mažėjantys baitai"
+
+#~ msgid "S E Mean"
+#~ msgstr "Vid st pakl"
+
+#~ msgid "S E Kurt"
+#~ msgstr "Eksc st pakl"
+
+#~ msgid "S E Skew"
+#~ msgstr "Asim st pakl"
+
+#~ msgid "PSPP --- A program for statistical analysis"
+#~ msgstr "PSPP --- statistinės analizės programa"
+
+#~ msgid "FILE1, FILE2 ... FILEn"
+#~ msgstr "RINKMENA1, RINKMENA2 ... RINKMENAn"
+
+#~ msgid "Don't show the splash screen"
+#~ msgstr "Nerodyti pristatymo lango"
+
+#~ msgid "PSPPIRE --- A user interface for PSPP"
+#~ msgstr "PSPPIRE --- grafinė PSPP naudotojo sąsaja"
+
+#~ msgid "Miscellaneous options:"
+#~ msgstr "Kitos parinktys:"
+
+#~ msgid "Recode values into the same variables"
+#~ msgstr "Perkoduoti reikšmes į tuos pačius kintamuosius"
+
+#~ msgid "Recode values into different variables"
+#~ msgstr "Perkoduoti reikšmes į kitus kintamuosius"
+
+#~ msgid "Split the window vertically and horizontally"
+#~ msgstr "Skaidyti langą vertikaliai ir horizontaliai"
+
+#~ msgid "Open Syntax"
+#~ msgstr "Atverti sintaksę"
+
+#~ msgid "Var 1"
+#~ msgstr "Pirmasis kintamasis"
+
+#~ msgid "Var 2"
+#~ msgstr "Antrasis kintamasis"
+
+#~ msgid "N of items"
+#~ msgstr "N elementų"
+
+#~ msgid "SE. Mean"
+#~ msgstr "Vid. st.pakl."
+
+#~ msgid "_About"
+#~ msgstr "_Apie"
+
+#~ msgid "Buttons"
+#~ msgstr "Mygtukai"
+
+#~ msgid "...found \"%s\""
+#~ msgstr "...rastas „%s“"
+
+#~ msgid "...not found"
+#~ msgstr "...nerasta"
+
+#~ msgid "Unknown."
+#~ msgstr "Nežinoma."
+
+#~ msgid "System File."
+#~ msgstr "Sisteminė rinkmena."
+
+#~ msgid "unexpected end of line"
+#~ msgstr "netikėta eilutės pabaiga"
+
+#~ msgid "reading \"%s\""
+#~ msgstr "skaitoma „%s“"
+
+#~ msgid "error closing \"%s\""
+#~ msgstr "užvėrimo klaida „%s“"
+
+#~ msgid "reading font file \"%s\""
+#~ msgstr "skaitoma šrifto rinkmena „%s“"
+
+#~ msgid "creating \"%s\""
+#~ msgstr "Kuriama „%s“"
+
+#~ msgid "data file error"
+#~ msgstr "duomenų rinkmenos klaida"
+
+#~ msgid "PSPP error"
+#~ msgstr "PSPP klaida"
+
+#~ msgid "syntax warning"
+#~ msgstr "sintaksės įspėjimas"
+
+#~ msgid "data file warning"
+#~ msgstr "duomenų rinkmenos įspėjimas"
+
+#~ msgid "PSPP warning"
+#~ msgstr "PSPP įspėjimas"
+
+#~ msgid "syntax information"
+#~ msgstr "sintaksės informacija"
+
+#~ msgid "data file information"
+#~ msgstr "duomenų rinkmenos informacija"
+
+#~ msgid "PSPP information"
+#~ msgstr "PSPP informacija"
+
+#~ msgid "The PSPP processing engine reported the following message:"
+#~ msgid_plural "The PSPP processing engine reported the following messages:"
+#~ msgstr[0] "PSPP apdorojimo variklis pateikė šį pranešimą:"
+#~ msgstr[1] "PSPP apdorojimo variklis pateikė šiuos pranešimus:"
+#~ msgstr[2] "PSPP apdorojimo variklis pateikė šiuos pranešimus:"
+#~ msgstr[3] "PSPP apdorojimo variklis pateikė šiuos pranešimus:"
+
+#~ msgid "The PSPP processing engine reported %d message."
+#~ msgid_plural "The PSPP processing engine reported %d messages."
+#~ msgstr[0] "PSPP apdorojimo variklis pateikė vieną pranešimą."
+#~ msgstr[1] "PSPP apdorojimo variklis pateikė %d pranešimą."
+#~ msgstr[2] "PSPP apdorojimo variklis pateikė %d pranešimus."
+#~ msgstr[3] "PSPP apdorojimo variklis pateikė %d pranešimų."
+
+#~ msgid "%d of these messages are displayed below."
+#~ msgid_plural "%d of these messages are displayed below."
+#~ msgstr[0] "Viena iš šių žinučių pateikta žemiau."
+#~ msgstr[1] "%d iš šių žinučių pateikta žemiau."
+#~ msgstr[2] "%d iš šių žinučių pateikta žemiau."
+#~ msgstr[3] "%d iš šių žinučių pateikta žemiau."
+
+#~ msgid "Clear"
+#~ msgstr "Išvalyti"
+
+#~ msgid "Insert Case"
+#~ msgstr "Įterpti atvejį"
+
+#~ msgid "Open a data file"
+#~ msgstr "Atverti duomenų rinkmeną"
+
+#~ msgid "New data file"
+#~ msgstr "Nauja duomenų rinkmena"
+
+#~ msgid "Import text data file"
+#~ msgstr "Importuoti tekstinių duomenų rinkmeną"
+
+#~ msgid "Select cases from the active file"
+#~ msgstr "Atrinkti atvejus iš veikiamosios rinkmenos"
+
+#~ msgid "Undo"
+#~ msgstr "Atšaukti"
+
+#~ msgid "Redo"
+#~ msgstr "Grąžinti"
+
+#~ msgid "Find"
+#~ msgstr "Ieškoti"
+
+#~ msgid "Use Sets"
+#~ msgstr "Naudoti rinkinius"
+
+#~ msgid "Messages Reported"
+#~ msgstr "Gauti pranešimai"
+
+#~ msgid "The PSPP processor reported # errors.  The first # and last # are shown below:"
+#~ msgstr "PSPP apdorojimo variklis pranešė apie # klaidas.  Pirmoji # ir paskutinioji # pateiktos žemiau:"
+
+#~ msgid "Freq"
+#~ msgstr "Dažnis"
+
+#~ msgid "%s --- PSPP Data Editor"
+#~ msgstr "%s --- PSPP duomenų redaktorius"
+
+#~ msgid "%s --- PSPP Output"
+#~ msgstr "%s --- PSPP rezultatai"
+
+#~ msgid "%s --- PSPP Syntax Editor"
+#~ msgstr "u%s --- PSPP sintaksės redaktorius"
+
+#~ msgid "%s is not currently supported."
+#~ msgstr "%s šiuo metu nepalaikoma."
+
+#~ msgid "%s is not implemented."
+#~ msgstr "%s nėra realizuota."
+
+#~ msgid "%s is unimplemented."
+#~ msgstr "%s nerealizuota."
+
+#~ msgid "Ascending Order"
+#~ msgstr "Didėjančia tvarka"
+
+#~ msgid "Bad variable width %d."
+#~ msgstr "Kintamojo ilgis %d yra netinkmas."
+
+#~ msgid "Descending Order"
+#~ msgstr "Mažėjančia tvarka"
+
+#~ msgid "Display Frequency Table"
+#~ msgstr "Rodyti dažnių lentelę"
+
+#~ msgid "Insert Ca_se"
+#~ msgstr "Įterpti _atvejį"
+
+#~ msgid "Insert _Variable"
+#~ msgstr "Įterpti _kintamąjį"
+
+#~ msgid "Jump to Variable"
+#~ msgstr "Šokti į kintamąjį"
+
+#~ msgid "Psppire Syntax Editor"
+#~ msgstr "Psppire sintaksės redaktorius"
+
+#~ msgid "Recode values into different Variables"
+#~ msgstr "Perkoduoti reikšmes į kitus kintamuosius"
+
+#~ msgid "Recode values into the same Variables"
+#~ msgstr "Perkoduoti reikšmes į tuos pačius kintamuosius"
+
+#~ msgid "S_plit"
+#~ msgstr "_Skaidyti"
+
+#~ msgid "This is beta status software.  Please report bugs to bug-gnu-pspp@gnu.org"
+#~ msgstr "Tai tik bandomoji programinė įranga. Apie rastas klaidas praneškite el. pašto adresu bug-gnu-pspp@gnu.org"
+
+#~ msgid "WEIGHT is off."
+#~ msgstr "SVĖRIMAS išjungtas."
+
+#~ msgid "_Goto Case"
+#~ msgstr "Š_okti į atvejį"
+
+#~ msgid "_Import Text Data"
+#~ msgstr "_Importuoti tekstinius duomenis"
+
+#~ msgid "_Labels"
+#~ msgstr "_Etiketės"
+
+#~ msgid "_New"
+#~ msgstr "_Nauja"
+
+#~ msgid "_Sort"
+#~ msgstr "_Rikiuoti"
+
+#~ msgid "_Weights"
+#~ msgstr "S_voriai"
+
+#~ msgid "cases"
+#~ msgstr "atvejai"
+
+#~ msgid "error opening \"%s\""
+#~ msgstr "atvėrimo klaida „%s“"
+
+#~ msgid "error opening \"%s\" for writing"
+#~ msgstr "„%s“ atvėrimo rašymui klaida"
+
+#~ msgid "error reading \"%s\""
+#~ msgstr "skaitymo klaida „%s“"
+
+#~ msgid "error writing \"%s\""
+#~ msgstr "įrašymo klaida „%s“"
+
+#~ msgid "Regresion: Statistics"
+#~ msgstr "Regresija: statistika"
+
+#~ msgid "Delete"
+#~ msgstr "Pašalinti"
+
+#~ msgid "One _Sample T Test"
+#~ msgstr "T kriterijus _vienai imčiai"
+
+#~ msgid "Oneway _ANOVA"
+#~ msgstr "Vienfaktorinė _ANOVA"
index 81a88adae2f3b3436a6949619b9f6813eba48509..11a703ea0c7673dbb5889c42800eab6c72f03391 100644 (file)
--- a/po/nl.po
+++ b/po/nl.po
@@ -1,5 +1,5 @@
-# translation of pspp-0.7.6.po to Dutch
-# Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+# translation of pspp-0.7.8.po to Dutch
+# Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 # This file is distributed under the same licence as the PSPP package.
 #
 # Vertaalde woorden:
@@ -10,6 +10,7 @@
 #  Command    = Opdracht
 #  Display    = Toon
 #  Dictionary = Woordenboek
+#  Identifier = Identificator
 #  Invalid    = Ongeldig
 #  Missing    = Ontbrekende
 #  Required   = vereist
 #  View       = Beeld/Weergave
 #  Window     = venster
 #  Weighting  = Weging
+# Harry Thijssen <pspp@sjpaes.nl>, 2009, 2010, 2011.
 #
-# Harry Thijssen <pspp@sjpaes.nl>, 2009, 2010.
 msgid ""
 msgstr ""
-"Project-Id-Version: pspp-0.7.6\n"
+"Project-Id-Version: pspp-0.7.8\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2010-10-16 13:02-0700\n"
-"PO-Revision-Date: 2010-10-06 22:27+0200\n"
+"POT-Creation-Date: 2011-05-04 06:57-0700\n"
+"PO-Revision-Date: 2011-05-10 23:41+0200\n"
 "Last-Translator: Harry Thijssen <pspp@sjpaes.nl>\n"
 "Language-Team: Dutch <vertaling@vrijschrift.org>\n"
+"Language: nl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"Plural-Forms: nplurals=2; plural=n != 1\n"
 "X-Generator: Lokalize 1.0\n"
 
 #: src/ui/gui/helper.c:194
 msgid "Sorry. The help system hasn't yet been implemented."
 msgstr "Sorry. Het hulp systeem is nog niet geïmplementeerd."
 
-#: src/ui/gui/psppire-buttonbox.c:275 src/ui/gui/psppire-buttonbox.c:437
+#: src/ui/gui/psppire-buttonbox.c:313 src/ui/gui/psppire-buttonbox.c:469
 msgid "Continue"
 msgstr "Verder"
 
-#: src/ui/gui/psppire-buttonbox.c:435
+#: src/ui/gui/psppire-buttonbox.c:467
 msgid "OK"
 msgstr "OK"
 
-#: src/ui/gui/psppire-buttonbox.c:436
+#: src/ui/gui/psppire-buttonbox.c:468
 msgid "Go To"
 msgstr "Ga naar"
 
-#: src/ui/gui/psppire-buttonbox.c:438
+#: src/ui/gui/psppire-buttonbox.c:470
 msgid "Cancel"
 msgstr "Afbreken"
 
-#: src/ui/gui/psppire-buttonbox.c:439
+#: src/ui/gui/psppire-buttonbox.c:471
 msgid "Help"
 msgstr "Help"
 
-#: src/ui/gui/psppire-buttonbox.c:440
+#: src/ui/gui/psppire-buttonbox.c:472
 msgid "Reset"
 msgstr "Herstel"
 
-#: src/ui/gui/psppire-buttonbox.c:441
+#: src/ui/gui/psppire-buttonbox.c:473
 msgid "Paste"
 msgstr "Plak"
 
 #: src/ui/gui/psppire-dictview.c:466 src/language/dictionary/split-file.c:82
 #: src/language/dictionary/sys-file-info.c:149
-#: src/language/dictionary/sys-file-info.c:339
-#: src/language/dictionary/sys-file-info.c:663
-#: src/language/stats/descriptives.c:881
-#: src/language/data-io/data-parser.c:682
-#: src/language/data-io/data-parser.c:721 src/language/data-io/print.c:403
+#: src/language/dictionary/sys-file-info.c:332
+#: src/language/dictionary/sys-file-info.c:646
+#: src/language/stats/descriptives.c:895
+#: src/language/data-io/data-parser.c:683
+#: src/language/data-io/data-parser.c:722 src/language/data-io/print.c:403
 msgid "Variable"
 msgstr "Variabele"
 
@@ -86,36 +88,36 @@ msgstr "Variabele"
 msgid "Prefer variable labels"
 msgstr "Prefereer variable labels"
 
-#: src/ui/gui/psppire-var-view.c:193
+#: src/ui/gui/psppire-var-view.c:192
 #, c-format
 msgid "Var%d"
 msgstr "Var%d"
 
-#: src/data/any-reader.c:56
+#: src/data/any-reader.c:60
 #, c-format
 msgid "An error occurred while opening `%s': %s."
 msgstr "Fout opgetreden bij openen van '%s': %s."
 
-#: src/data/any-reader.c:101
+#: src/data/any-reader.c:105
 #, c-format
 msgid "`%s' is not a system or portable file."
 msgstr "'%s' is geen systeem of overdraagbaar bestand."
 
-#: src/data/any-reader.c:107 src/data/any-writer.c:63
+#: src/data/any-reader.c:111 src/data/any-writer.c:67
 msgid "The inline file is not allowed here."
 msgstr "Het inline-bestand is hier niet toegestaan."
 
-#: src/data/calendar.c:81
+#: src/data/calendar.c:100
 #, c-format
 msgid "Month %d is not in acceptable range of 0 to 13."
 msgstr "Maand %d valt niet in het acceptabele bereik van 0 tot 13."
 
-#: src/data/calendar.c:91
+#: src/data/calendar.c:110
 #, c-format
 msgid "Day %d is not in acceptable range of 0 to 31."
 msgstr "Dag %d valt niet in het acceptabele bereik van 0 tot 31."
 
-#: src/data/calendar.c:100
+#: src/data/calendar.c:119
 #, c-format
 msgid "Date %04d-%d-%d is before the earliest acceptable date of 1582-10-15."
 msgstr "Datum %04d-%d-%d ligt voor de eerste acceptabele datum van 1582-10-15."
@@ -126,145 +128,154 @@ msgstr "Tenminste een case in de gelezen gegevens heeft een gewichtwaarde 'user-
 
 #. TRANSLATORS: this fragment will be interpolated into messages in fh_lock()
 #. that identify types of files.
-#: src/data/csv-file-writer.c:152
+#: src/data/csv-file-writer.c:154
 msgid "CSV file"
 msgstr "CSV bestand"
 
-#: src/data/csv-file-writer.c:161 src/data/sys-file-writer.c:218
+#: src/data/csv-file-writer.c:163 src/data/sys-file-writer.c:225
 #, c-format
 msgid "Error opening `%s' for writing as a system file: %s."
 msgstr "Fout bij het openen van '%s' voor het schrijven als een systeembestand: %s."
 
-#: src/data/csv-file-writer.c:462
+#: src/data/csv-file-writer.c:464
 #, c-format
 msgid "An I/O error occurred writing CSV file `%s'."
 msgstr "Een I/O fout is opgetreden tijdens het schrijven van systeembestand '%s'."
 
-#: src/data/data-in.c:172
-#, fuzzy, c-format
+#: src/data/data-in.c:171
+#, c-format
 msgid "Data is not valid as format %s: %s"
-msgstr "%s variabele %s heeft ongeldig %s opmaak %s."
+msgstr "Data is niet geldig als opmaak %s: %s"
 
-#: src/data/data-in.c:377 src/data/data-in.c:553
+#: src/data/data-in.c:376 src/data/data-in.c:552
 msgid "Field contents are not numeric."
 msgstr "Veldinhoud is niet numeriek."
 
-#: src/data/data-in.c:379 src/data/data-in.c:555
+#: src/data/data-in.c:378 src/data/data-in.c:554
 msgid "Number followed by garbage."
 msgstr "Nummer gevolgd door rommel."
 
-#: src/data/data-in.c:392
+#: src/data/data-in.c:391
 msgid "Invalid numeric syntax."
 msgstr "Ongeldige numerieke syntax."
 
-#: src/data/data-in.c:400 src/data/data-in.c:571
+#: src/data/data-in.c:399 src/data/data-in.c:570
 msgid "Too-large number set to system-missing."
 msgstr "Te groot getal, is op system-missing gezet."
 
-#: src/data/data-in.c:406 src/data/data-in.c:577
+#: src/data/data-in.c:405 src/data/data-in.c:576
 msgid "Too-small number set to zero."
 msgstr "Te klein getal, is op nul gezet."
 
-#: src/data/data-in.c:426
+#: src/data/data-in.c:425
 msgid "All characters in field must be digits."
 msgstr "Alle tekens in veld moeten cijfers zijn."
 
-#: src/data/data-in.c:445
+#: src/data/data-in.c:444
 msgid "Unrecognized character in field."
 msgstr "Niet herkenbaar teken in veld."
 
-#: src/data/data-in.c:466 src/data/data-in.c:729
+#: src/data/data-in.c:465 src/data/data-in.c:728
 msgid "Field must have even length."
 msgstr "Veld moet een even lengte hebben."
 
-#: src/data/data-in.c:468 src/data/data-in.c:732
+#: src/data/data-in.c:467 src/data/data-in.c:731
 msgid "Field must contain only hex digits."
 msgstr "Veld mag alleen hexadecimale cijfers bevatten."
 
-#: src/data/data-in.c:544
-#, fuzzy
+#: src/data/data-in.c:543
 msgid "Invalid zoned decimal syntax."
-msgstr "Ongeldige numerieke syntax."
+msgstr ""
 
-#: src/data/data-in.c:644 src/data/data-in.c:650
-#, fuzzy
+#: src/data/data-in.c:643 src/data/data-in.c:649
 msgid "Invalid syntax for P field."
-msgstr "Ongeldige numerieke syntax."
+msgstr "Ongeldige syntax voor P veld."
 
-#: src/data/data-in.c:768 src/data/data-in.c:814
+#: src/data/data-in.c:767 src/data/data-in.c:813
 msgid "Syntax error in date field."
 msgstr "Syntaxfout in datumveld."
 
-#: src/data/data-in.c:783
+#: src/data/data-in.c:782
 #, c-format
 msgid "Day (%ld) must be between 1 and 31."
 msgstr "Dag (%ld) moet tussen 1 en 31 liggen."
 
-#: src/data/data-in.c:828
+#: src/data/data-in.c:827
 msgid "Delimiter expected between fields in date."
 msgstr "Veldscheider verwacht tussen velden in datum."
 
-#: src/data/data-in.c:902
+#: src/data/data-in.c:901
 msgid "Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names."
 msgstr "Niet-herkende maand opmaak.  Maanden mogen gespecificeerd zijn als Arabisch of Romeins numeriek of als tenminste de eerste 3 letters van hun Engelse naam."
 
-#: src/data/data-in.c:929
+#: src/data/data-in.c:928
 #, c-format
 msgid "Year (%ld) must be between 1582 and 19999."
 msgstr "Jaar (%ld) moet tussen 1582 en 19999 liggen."
 
-#: src/data/data-in.c:940
+#: src/data/data-in.c:939
 #, c-format
 msgid "Trailing garbage `%.*s' following date."
 msgstr "Afsluitende rommel '%.*s' achter datum."
 
-#: src/data/data-in.c:954
+#: src/data/data-in.c:953
 msgid "Julian day must have exactly three digits."
 msgstr "Juliaanse datum moet bestaan uit precies 3 cijfers."
 
-#: src/data/data-in.c:956
+#: src/data/data-in.c:955
 #, c-format
 msgid "Julian day (%ld) must be between 1 and 366."
 msgstr "Juliaanse dag (%ld) moet tussen 1 en 366 zijn."
 
-#: src/data/data-in.c:980
+#: src/data/data-in.c:979
 #, c-format
 msgid "Quarter (%ld) must be between 1 and 4."
 msgstr "Kwartaal (%ld) moet tussen 1 en 4 zijn."
 
-#: src/data/data-in.c:1001
+#: src/data/data-in.c:1000
 #, c-format
 msgid "Week (%ld) must be between 1 and 53."
 msgstr "Week (%ld) moet tussen 1 en 53 zijn."
 
-#: src/data/data-in.c:1013
+#: src/data/data-in.c:1012
 msgid "Delimiter expected between fields in time."
 msgstr "Veldscheider verwacht tussen velden in tijd."
 
-#: src/data/data-in.c:1033
+#: src/data/data-in.c:1032
 #, c-format
 msgid "Minute (%ld) must be between 0 and 59."
 msgstr "Minuut (%ld) moet tussen 0 en 59 zijn."
 
-#: src/data/data-in.c:1071
+#: src/data/data-in.c:1070
 msgid "Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified."
 msgstr "Niet-herkende weekdagnaam.  Tenminste de eerste 2 letters van een Engelse weekdagnaam moeten opgegeven worden."
 
-#: src/data/data-in.c:1197
+#: src/data/data-in.c:1196
 #, c-format
 msgid "`%c' expected in date field."
 msgstr "'%c' verwacht in datumveld."
 
-#: src/data/data-out.c:481
+#: src/data/data-out.c:546
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr "Weekdagnummer %f ligt niet tussen 1 en 7."
 
-#: src/data/data-out.c:502
+#: src/data/data-out.c:571
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr "Maandnummer %f is niet tussen 1 en 12."
 
+#: src/data/dataset-reader.c:54
+#, c-format
+msgid "Cannot read from dataset %s because no dictionary or data has been written to it yet."
+msgstr "Kan niet lezen van dataset %s omdat er nog geen bibliotheek of data heen is geschreven."
+
+#. TRANSLATORS: this fragment will be interpolated into
+#. messages in fh_lock() that identify types of files.
+#: src/data/dataset-writer.c:66 src/language/data-io/file-handle.q:182
+msgid "dataset"
+msgstr "dataset"
+
 #: src/data/dict-class.c:52
 msgid "ordinary"
 msgstr "gewoon"
@@ -277,26 +288,30 @@ msgstr "systeem"
 msgid "scratch"
 msgstr "scratch"
 
-#: src/data/dictionary.c:981
+#: src/data/dictionary.c:1003
 msgid "At least one case in the data file had a weight value that was user-missing, system-missing, zero, or negative.  These case(s) were ignored."
 msgstr "Op zijn minst een case in het gegevensbestand heeft een gewichtwaarde user-missing, system-missing, nul, of negatief.  Deze case(s) zijn genegeerd."
 
-#: src/data/dictionary.c:1284
+#: src/data/dictionary.c:1329
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr "Documentregel afgekapt tot %d bytes."
 
-#: src/data/file-handle-def.c:471
+#: src/data/file-handle-def.c:254
+msgid "active dataset"
+msgstr "actieve dataset"
+
+#: src/data/file-handle-def.c:465
 #, c-format
 msgid "Can't read from %s as a %s because it is already being read as a %s."
 msgstr "Kan niet lezen van %s als een %s omdat het al gelezen wordt als een %s."
 
-#: src/data/file-handle-def.c:475
+#: src/data/file-handle-def.c:469
 #, c-format
 msgid "Can't write to %s as a %s because it is already being written as a %s."
 msgstr "Kan niet schrijven naar %s als een %s omdat het al geschreven wordt als een %s."
 
-#: src/data/file-handle-def.c:482
+#: src/data/file-handle-def.c:476
 #, c-format
 msgid "Can't re-open %s as a %s."
 msgstr "Kan %s niet heropenen als een %s."
@@ -306,86 +321,86 @@ msgstr "Kan %s niet heropenen als een %s."
 msgid "Not opening pipe file `%s' because SAFER option set."
 msgstr "Pijpbestand '%s' wordt niet geopend omdat de SAFER optie is gezet."
 
-#: src/data/format.c:314
+#: src/data/format.c:320
 msgid "Input format"
 msgstr "Invoerindeling"
 
-#: src/data/format.c:314
+#: src/data/format.c:320
 msgid "Output format"
 msgstr "Uitvoerindeling"
 
-#: src/data/format.c:323
+#: src/data/format.c:329
 #, c-format
 msgid "Format %s may not be used for input."
 msgstr "Indeling %s mag niet gebruikt worden voor invoer."
 
-#: src/data/format.c:330
+#: src/data/format.c:336
 #, c-format
 msgid "%s specifies width %d, but %s requires an even width."
 msgstr "%s specificeert breedte %d, maar %s vereist een even breedte."
 
-#: src/data/format.c:339
+#: src/data/format.c:345
 #, c-format
 msgid "%s %s specifies width %d, but %s requires a width between %d and %d."
 msgstr "%s %s specificeert breedte %d, maar %s vereist een breedte tussen %d en %d."
 
-#: src/data/format.c:348
+#: src/data/format.c:354
 #, c-format
 msgid "%s %s specifies %d decimal place, but %s does not allow any decimals."
 msgid_plural "%s %s specifies %d decimal places, but %s does not allow any decimals."
 msgstr[0] "%s %s specificeert %d decimaal, maar %s staat geen decimalen toe."
 msgstr[1] "%s %s specificeert %d decimalen, maar %s staat geen decimalen toe."
 
-#: src/data/format.c:359
+#: src/data/format.c:365
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width allows at most %d decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width allows at most %d decimals."
 msgstr[0] "%s %s specificeert %d decimaal, maar de opgegeven breedte staat maximaal %d decimalen toe."
 msgstr[1] "%s %s specificeert %d decimalen, maar de opgegeven breedte staat maximaal %d decimalen toe."
 
-#: src/data/format.c:366
+#: src/data/format.c:372
 #, c-format
 msgid "%s %s specifies %d decimal place, but the given width does not allow for any decimals."
 msgid_plural "%s %s specifies %d decimal places, but the given width does not allow for any decimals."
 msgstr[0] "%s %s specificeert %d decimaal, maar de opgegeven breedte staat geen decimalen toe."
 msgstr[1] "%s %s specificeert %d decimalen, maar de opgegeven breedte staat geen decimalen toe."
 
-#: src/data/format.c:405
+#: src/data/format.c:411
 #, c-format
 msgid "%s variables are not compatible with %s format %s."
 msgstr "%s variabelen zijn niet overeenkomstig met %s opmaak %s."
 
-#: src/data/format.c:406 src/data/sys-file-reader.c:751
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
 #: src/ui/gui/psppire-var-store.c:628 src/ui/gui/compute.ui:503
 #: src/ui/gui/var-sheet-dialogs.ui:139
 msgid "String"
 msgstr "Tekenreeks"
 
-#: src/data/format.c:406 src/data/sys-file-reader.c:751
+#: src/data/format.c:412 src/data/sys-file-reader.c:1078
 #: src/ui/gui/psppire-var-store.c:621 src/ui/gui/compute.ui:584
 #: src/ui/gui/var-sheet-dialogs.ui:27
 msgid "Numeric"
 msgstr "Numeriek"
 
-#: src/data/format.c:407 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:496
-#: src/language/xforms/recode.c:497 src/language/xforms/recode.c:509
-#: src/language/xforms/recode.c:510
+#: src/data/format.c:413 src/data/sys-file-reader.c:1671
+#: src/data/sys-file-reader.c:1673 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
 #: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
 msgid "numeric"
 msgstr "numeriek"
 
-#: src/data/format.c:407 src/data/sys-file-reader.c:1472
-#: src/data/sys-file-reader.c:1474 src/language/xforms/recode.c:496
-#: src/language/xforms/recode.c:497 src/language/xforms/recode.c:509
-#: src/language/xforms/recode.c:510
+#: src/data/format.c:413 src/data/sys-file-reader.c:1671
+#: src/data/sys-file-reader.c:1673 src/language/xforms/recode.c:506
+#: src/language/xforms/recode.c:507 src/language/xforms/recode.c:519
+#: src/language/xforms/recode.c:520
 #: src/language/dictionary/apply-dictionary.c:77
 #: src/language/dictionary/apply-dictionary.c:78
 msgid "string"
 msgstr "tekenreeks"
 
-#: src/data/format.c:425
+#: src/data/format.c:431
 #, c-format
 msgid "String variable with width %d is not compatible with format %s."
 msgstr "Tekenreeksvariabele met breedte %d is niet overeenkomstig met opmaaak %s."
@@ -394,26 +409,50 @@ msgstr "Tekenreeksvariabele met breedte %d is niet overeenkomstig met opmaaak %s
 msgid "Support for Gnumeric files was not compiled into this installation of PSPP"
 msgstr "Ondersteuning voor Gnumeric-bestanden is niet gecompileerd in deze installatie van PSPP"
 
-#: src/data/gnumeric-reader.c:364
+#: src/data/gnumeric-reader.c:363
 #, c-format
 msgid "Error opening `%s' for reading as a Gnumeric file: %s."
 msgstr "Fout bij het openen van '%s' voor het lezen als een Gnumeric-bestand: %s."
 
-#: src/data/gnumeric-reader.c:384
+#: src/data/gnumeric-reader.c:383
 #, c-format
 msgid "Invalid cell range `%s'"
 msgstr "Ongeldig celbereik '%s'"
 
-#: src/data/gnumeric-reader.c:516 src/data/psql-reader.c:187
-#, c-format
-msgid "Cannot create variable name from %s"
-msgstr "Kan geen variabelennaam creëren van %s"
-
-#: src/data/gnumeric-reader.c:528
+#: src/data/gnumeric-reader.c:521
 #, c-format
 msgid "Selected sheet or range of spreadsheet `%s' is empty."
 msgstr "Geselecteerd blad of bereik van werkblad '%s' is leeg."
 
+#: src/data/identifier2.c:60
+#, c-format
+msgid "Identifier `%s' exceeds %d-byte limit."
+msgstr "Identificator %s overschrijdt de limiet van %d-bytes."
+
+#: src/data/identifier2.c:84
+msgid "Identifier cannot be empty string."
+msgstr "Identificator kan geen lege tekenreeks zijn."
+
+#: src/data/identifier2.c:92
+#, c-format
+msgid "`%s' may not be used as an identifier because it is a reserved word."
+msgstr "'%s' mag niet gebruikt worden als identificator omdat het een gereserveerd woord is."
+
+#: src/data/identifier2.c:103
+#, c-format
+msgid "`%s' may not be used as an identifier because it contains ill-formed UTF-8 at byte offset %tu."
+msgstr "'%s' mag niet gebruikt worden als identificator omdat het een foutief opgemaakt UTF-8 bevat op byte offset %tu."
+
+#: src/data/identifier2.c:114
+#, c-format
+msgid "Character %s (in `%s') may not appear as the first character in a identifier."
+msgstr "Teken %s (in `%s') mag niet als eerste teken in een identificator voorkomen."
+
+#: src/data/identifier2.c:126
+#, c-format
+msgid "Character %s (in `%s') may not appear in an identifier."
+msgstr "Teken %s (in `%s') mag niet in een identificator voorkomen."
+
 #: src/data/make-file.c:71
 #, c-format
 msgid "Opening %s for writing: %s."
@@ -449,146 +488,146 @@ msgstr "Vervangen %s door %s: %s."
 msgid "Removing %s: %s."
 msgstr "Verwijderen %s: %s."
 
-#: src/data/por-file-reader.c:98
+#: src/data/mrset.c:83
+#, c-format
+msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
+msgstr "%s is geen geldige naam voor meervoudige response set.  Meervoudige response set namen moeten beginnen met `$'."
+
+#: src/data/por-file-reader.c:101
 #, c-format
 msgid "portable file %s corrupt at offset 0x%llx: "
 msgstr "overdraagbaar-bestand %s beschadigd op positie 0x%llx: "
 
-#: src/data/por-file-reader.c:129
+#: src/data/por-file-reader.c:133
 #, c-format
 msgid "reading portable file %s at offset 0x%llx: "
 msgstr "lezen overdraagbaar bestand %s op positie 0x%llx: "
 
-#: src/data/por-file-reader.c:159
+#: src/data/por-file-reader.c:164
 #, c-format
 msgid "Error closing portable file `%s': %s."
 msgstr "Fout bij het afsluiten van overdraagbaar bestand '%s': %s."
 
-#: src/data/por-file-reader.c:211
+#: src/data/por-file-reader.c:216
 msgid "unexpected end of file"
 msgstr "onverwacht einde-bestand"
 
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/por-file-reader.c:270 src/data/por-file-writer.c:148
+#: src/data/por-file-reader.c:275 src/data/por-file-writer.c:148
 msgid "portable file"
 msgstr "overdraagbaar bestand"
 
-#: src/data/por-file-reader.c:278
+#: src/data/por-file-reader.c:283
 #, c-format
 msgid "An error occurred while opening `%s' for reading as a portable file: %s."
 msgstr "Fout opgetreden tijdens het openen van '%s' voor het lezen als overdraagbaar bestand: %s."
 
-#: src/data/por-file-reader.c:299
+#: src/data/por-file-reader.c:304
 msgid "Data record expected."
 msgstr "Gegevensrecord verwacht."
 
-#: src/data/por-file-reader.c:381
+#: src/data/por-file-reader.c:386
 msgid "Number expected."
 msgstr "Nummer verwacht."
 
-#: src/data/por-file-reader.c:409
+#: src/data/por-file-reader.c:414
 msgid "Missing numeric terminator."
 msgstr "Ontbrekende numerieke afsluiter."
 
-#: src/data/por-file-reader.c:432
+#: src/data/por-file-reader.c:437
 msgid "Invalid integer."
 msgstr "Ongeldige integer."
 
-#: src/data/por-file-reader.c:443 src/data/por-file-reader.c:463
+#: src/data/por-file-reader.c:448 src/data/por-file-reader.c:468
 #, c-format
 msgid "Bad string length %d."
 msgstr "Onjuiste tekenreekslengte %d."
 
-#: src/data/por-file-reader.c:526
+#: src/data/por-file-reader.c:531
 #, c-format
 msgid "%s: Not a portable file."
 msgstr "%s: Geen overdraagbaar bestand."
 
-#: src/data/por-file-reader.c:543
+#: src/data/por-file-reader.c:548
 #, c-format
 msgid "Unrecognized version code `%c'."
 msgstr "Niet-herkende versiecode '%c'."
 
-#: src/data/por-file-reader.c:552
+#: src/data/por-file-reader.c:557
 #, c-format
 msgid "Bad date string length %zu."
 msgstr "Onjuiste datum-tekenreekslengte %zu."
 
-#: src/data/por-file-reader.c:554
+#: src/data/por-file-reader.c:559
 #, c-format
 msgid "Bad time string length %zu."
 msgstr "Onjuiste tijd-tekenreekslengte %zu."
 
-#: src/data/por-file-reader.c:596
+#: src/data/por-file-reader.c:601
 #, c-format
 msgid "%s: Bad format specifier byte (%d).  Variable will be assigned a default format."
 msgstr "%s: Onjuist opmaakspecificatie byte (%d). Variabele krijgt een standaardopmaak."
 
-#: src/data/por-file-reader.c:617
+#: src/data/por-file-reader.c:622
 #, c-format
 msgid "Numeric variable %s has invalid format specifier %s."
 msgstr "Numerieke variabele %s heeft een ongeldig opmaakspecificatie %s."
 
-#: src/data/por-file-reader.c:621
+#: src/data/por-file-reader.c:626
 #, c-format
 msgid "String variable %s with width %d has invalid format specifier %s."
 msgstr "Tekenreeksvariabele %s met breedte %d heeft ongeldig opmaakspecificatie %s."
 
-#: src/data/por-file-reader.c:645
+#: src/data/por-file-reader.c:650
 msgid "Expected variable count record."
 msgstr "Variabelenteller record verwacht."
 
-#: src/data/por-file-reader.c:649
+#: src/data/por-file-reader.c:654
 #, c-format
 msgid "Invalid number of variables %d."
 msgstr "Ongeldig aantal variabelen %d."
 
-#: src/data/por-file-reader.c:658
+#: src/data/por-file-reader.c:663
 #, c-format
 msgid "Weight variable name (%s) truncated."
 msgstr "Wegingsvariabelennaam (%s) is afgekapt."
 
-#: src/data/por-file-reader.c:673
+#: src/data/por-file-reader.c:678
 msgid "Expected variable record."
 msgstr "Variabelenrecord verwacht."
 
-#: src/data/por-file-reader.c:677
+#: src/data/por-file-reader.c:682
 #, c-format
 msgid "Invalid variable width %d."
 msgstr "Ongeldige variabelenbreedte %d."
 
-#: src/data/por-file-reader.c:684
+#: src/data/por-file-reader.c:690
 #, c-format
 msgid "Invalid variable name `%s' in position %d."
 msgstr "Ongeldige variabelennaam '%s' op positie %d."
 
-#: src/data/por-file-reader.c:688 src/data/sys-file-reader.c:605
+#: src/data/por-file-reader.c:694 src/data/sys-file-reader.c:963
 #, c-format
 msgid "Bad width %d for variable %s."
 msgstr "Onjuiste breedte %d voor variabele %s."
 
-#: src/data/por-file-reader.c:703
-#, c-format
-msgid "Duplicate variable name %s in position %d."
-msgstr "Dubbele variabelennaam %s op positie %d."
-
-#: src/data/por-file-reader.c:704
+#: src/data/por-file-reader.c:708
 #, c-format
 msgid "Duplicate variable name %s in position %d renamed to %s."
 msgstr "Dubbele variabelennaam %s op positie %d is hernoemd naar %s."
 
-#: src/data/por-file-reader.c:753
+#: src/data/por-file-reader.c:757
 #, c-format
 msgid "Weighting variable %s not present in dictionary."
 msgstr "Wegingvariabele %s niet aanwezig in woordenboek."
 
-#: src/data/por-file-reader.c:797
+#: src/data/por-file-reader.c:801
 #, c-format
 msgid "Unknown variable %s while parsing value labels."
 msgstr "Onbekende variabele %s tijdens het ontleden van waardelabels."
 
-#: src/data/por-file-reader.c:800
+#: src/data/por-file-reader.c:804
 #, c-format
 msgid "Cannot assign value labels to %s and %s, which have different variable types."
 msgstr "Kan geen waardelabels toekennen aan %s en %s, die verschillende variabelentypes hebben."
@@ -603,714 +642,666 @@ msgstr "Ongeldige decimaal cijfers teller %d. Behandeld als %d."
 msgid "Error opening `%s' for writing as a portable file: %s."
 msgstr "Fout tijdens openen '%s' voor het schrijven als een overdraagbaar bestand: %s."
 
-#: src/data/por-file-writer.c:505
+#: src/data/por-file-writer.c:502
 #, c-format
 msgid "An I/O error occurred writing portable file `%s'."
 msgstr "Een I/O fout opgetreden tijdens het schrijven van overdraagbaar bestand '%s'."
 
-#: src/data/psql-reader.c:46
+#: src/data/psql-reader.c:47
 msgid "Support for reading postgres databases was not compiled into this installation of PSPP"
 msgstr "Ondersteuning voor het lezen van postgres databases was niet gecompileerd in deze installatie van PSPP"
 
-#: src/data/psql-reader.c:242
+#: src/data/psql-reader.c:241
 msgid "Memory error whilst opening psql source"
 msgstr "Geheugenfout tijdens het openen van psql source"
 
-#: src/data/psql-reader.c:248
+#: src/data/psql-reader.c:247
 #, c-format
 msgid "Error opening psql source: %s."
 msgstr "Fout tijdens openen psql source: %s."
 
-#: src/data/psql-reader.c:263
+#: src/data/psql-reader.c:262
 #, c-format
 msgid "Postgres server is version %s. Reading from versions earlier than 8.0 is not supported."
 msgstr "Postgres server is versie %s. Lezen van versies ouder dan 8.0 wordt niet ondersteund."
 
-#: src/data/psql-reader.c:283
+#: src/data/psql-reader.c:282
 msgid "Connection is unencrypted, but unencrypted connections have not been permitted."
 msgstr "Connectie is niet geëncrypt, maar niet geëncrypte connecties zijn niet toegestaan."
 
-#: src/data/psql-reader.c:321 src/data/psql-reader.c:346
-#: src/data/psql-reader.c:356
+#: src/data/psql-reader.c:318 src/data/psql-reader.c:343
+#: src/data/psql-reader.c:353
 #, c-format
 msgid "Error from psql source: %s."
 msgstr "Fout van psql source: %s."
 
-#: src/data/psql-reader.c:451
+#: src/data/psql-reader.c:448
 #, c-format
 msgid "Unsupported OID %d.  SYSMIS values will be inserted."
 msgstr "Niet ondersteunde OID %d. SYSMIS waarde wordt ingevoegd."
 
-#: src/data/scratch-reader.c:54
-#, c-format
-msgid "Scratch file handle %s has not yet been written, using SAVE or another procedure, so it cannot yet be used for reading."
-msgstr ""
-
-#. TRANSLATORS: this fragment will be interpolated into
-#. messages in fh_lock() that identify types of files.
-#: src/data/scratch-writer.c:66 src/language/data-io/file-handle.q:181
-msgid "scratch file"
-msgstr "scratchbestand"
-
-#: src/data/settings.c:388
+#: src/data/settings.c:384
 msgid "MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."
-msgstr ""
+msgstr "MXWARNS is op nul gezet.  Er worden verder geen waarschuwingen gegeven, zelfs niet wanneer potentieel problematische situaties tegengekomen worden."
 
-#: src/data/settings.c:395
+#: src/data/settings.c:391
 #, c-format
 msgid "Warnings re-enabled. %d warnings will be issued before aborting syntax processing."
-msgstr ""
+msgstr "Waarschuwing gereactiveerd. %d waarschuwingen zullen worden gegeven voordat de syntax verwerking wordt afgebroken."
 
-#: src/data/settings.c:639
+#: src/data/settings.c:599
 #, c-format
 msgid "%s: Custom currency string `%s' does not contain exactly three periods or commas (or it contains both)."
 msgstr "%s: Aangepaste munt-tekenreeks '%s' bevat niet exact drie punten of komma's (of het bevat beiden)."
 
-#: src/data/short-names.c:52
-msgid "Variable suffix too large."
-msgstr "Variabelen-achtervoegsel te lang."
-
-#: src/data/sys-file-reader.c:225
-#, c-format
-msgid "Recoded variable name duplicates an existing `%s' within system file."
-msgstr "Gehercodeerde variabelennaam dupliceert een bestaande '%s' binnen systeembestand."
-
 #. TRANSLATORS: this fragment will be interpolated into
 #. messages in fh_lock() that identify types of files.
-#: src/data/sys-file-reader.c:289 src/data/sys-file-writer.c:206
+#: src/data/sys-file-reader.c:324 src/data/sys-file-writer.c:213
 msgid "system file"
 msgstr "systeembestand"
 
-#: src/data/sys-file-reader.c:296
+#: src/data/sys-file-reader.c:331
 #, c-format
 msgid "Error opening `%s' for reading as a system file: %s."
 msgstr "Fout bij het openen van '%s' voor het lezen als een systeembestand: %s."
 
-#: src/data/sys-file-reader.c:335 tests/dissect-sysfile.c:155
+#: src/data/sys-file-reader.c:388 tests/dissect-sysfile.c:155
 msgid "Misplaced type 4 record."
 msgstr "Verkeerd geplaatst type 4 record."
 
-#: src/data/sys-file-reader.c:346 tests/dissect-sysfile.c:166
+#: src/data/sys-file-reader.c:392
+msgid "Duplicate type 6 (document) record."
+msgstr "Meerdere type 6 (document) records."
+
+# c-format
+#: src/data/sys-file-reader.c:401 src/data/sys-file-reader.c:900
+#, c-format
+msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr "Niet-herkend type 7, subtype %d.  Stuur s.v.p. een kopie van dit bestand en de syntax waarmee het is aangemaakt naar %s "
+
+#: src/data/sys-file-reader.c:410
+#, c-format
+msgid "Record type 7, subtype %d found here has the same type as the record found near offset 0x%llx.  Please send a copy of this file, and the syntax which created it to %s."
+msgstr ""
+
+#: src/data/sys-file-reader.c:423 tests/dissect-sysfile.c:166
 #, c-format
 msgid "Unrecognized record type %d."
 msgstr "Niet-herkend recordtype %d."
 
-#: src/data/sys-file-reader.c:387
+#: src/data/sys-file-reader.c:467
 #, c-format
-msgid "File header claims %d variable positions but %d were read from file."
-msgstr "Bestandskop claimt %d variabelenposities maar er zijn er %d gelezen van het bestand."
+msgid "Weighting variable must be numeric (not string variable `%s')."
+msgstr "Wegingvariabele moet numeriek zijn  (niet tekenreeks variabele `%s')."
 
-#: src/data/sys-file-reader.c:427
+#: src/data/sys-file-reader.c:502
+#, c-format
+msgid "File header claims %d variable positions but %zu were read from file."
+msgstr "Bestandskop claimt %d variabelenposities maar %zu zijn er gelezen van het bestand."
+
+#: src/data/sys-file-reader.c:542
 #, c-format
 msgid "Error closing system file `%s': %s."
-msgstr "Fout bij het sluiten van systeembestand '%s': %s."
+msgstr "Fout bij het sluiten van systeembestand `%s': %s."
 
-#: src/data/sys-file-reader.c:492 src/data/sys-file-reader.c:502
+#: src/data/sys-file-reader.c:604 src/data/sys-file-reader.c:614
 #: tests/dissect-sysfile.c:203 tests/dissect-sysfile.c:213
 msgid "This is not an SPSS system file."
 msgstr "Dit is geen SPSS-systeembestand."
 
-#: src/data/sys-file-reader.c:524 tests/dissect-sysfile.c:228
+#: src/data/sys-file-reader.c:636 tests/dissect-sysfile.c:228
 msgid "Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format."
 msgstr ""
 
-#: src/data/sys-file-reader.c:598
-#, fuzzy, c-format
-msgid "Variable name begins with invalid character `%c'."
-msgstr "Variabele index %d niet in geldig bereik 1...%d."
-
-#: src/data/sys-file-reader.c:601
-#, c-format
-msgid "Invalid variable name `%s'."
-msgstr "Ongeldige variabelennaam '%s'."
-
-#: src/data/sys-file-reader.c:609
-#, c-format
-msgid "Duplicate variable name `%s' within system file."
-msgstr "Dubbele variabelennaam '%s' binnen systeembestand."
-
-#: src/data/sys-file-reader.c:617 tests/dissect-sysfile.c:357
+#: src/data/sys-file-reader.c:712 tests/dissect-sysfile.c:357
 msgid "Variable label indicator field is not 0 or 1."
 msgstr "Variabelen-labelindicatorveld is niet 0 of 1."
 
-#: src/data/sys-file-reader.c:648 tests/dissect-sysfile.c:388
+#: src/data/sys-file-reader.c:722 tests/dissect-sysfile.c:388
 msgid "Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
 msgstr "Numeriek ontbrekende-waarde indicatorveld is niet -3, -2, 0, 1, 2, of 3."
 
-#: src/data/sys-file-reader.c:666 tests/dissect-sysfile.c:403
+#: src/data/sys-file-reader.c:729 tests/dissect-sysfile.c:403
 msgid "String missing value indicator field is not 0, 1, 2, or 3."
 msgstr "Tekenreeks ontbrekende-waarde indicatorveld is niet 0, 1, 2, of 3."
 
-#: src/data/sys-file-reader.c:698
+#: src/data/sys-file-reader.c:749
+#, c-format
+msgid "Invalid number of labels %zu."
+msgstr "Ongeldig aantal labels %zu."
+
+#: src/data/sys-file-reader.c:774 tests/dissect-sysfile.c:469
+msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
+msgstr "Variabele index record (type 4) volgt niet onmiddellijk waardelabel record (type 3) zoals het moet."
+
+#: src/data/sys-file-reader.c:782
+#, c-format
+msgid "Number of variables associated with a value label (%zu) is not between 1 and the number of variables (%zu)."
+msgstr "Aantal variabelen geassocieerd aan waardelabel (%zu) is niet tussen 1 en het aantal variabelen (%zu)."
+
+#: src/data/sys-file-reader.c:803
+#, c-format
+msgid "Number of document lines (%d) must be greater than 0 and less than %d."
+msgstr "Aantal documentregels (%d) moet groter dan 0 en kleiner dan %d zijn."
+
+#: src/data/sys-file-reader.c:876
+#, c-format
+msgid "Record type 7, subtype %d has bad size %zu (expected %d)."
+msgstr "Record type 7, subtype %d heeft een foutieve lengte %zu (verwacht %d)."
+
+#: src/data/sys-file-reader.c:880
+#, c-format
+msgid "Record type 7, subtype %d has bad count %zu (expected %d)."
+msgstr "Record type 7, subtype %d heeft een foutieve teller %zu (verwacht %d)."
+
+#: src/data/sys-file-reader.c:959
+#, c-format
+msgid "Invalid variable name `%s'."
+msgstr "Ongeldige variabelennaam '%s'."
+
+# c-format
+#: src/data/sys-file-reader.c:967
+#, c-format
+msgid "Duplicate variable name `%s'."
+msgstr "Dubbele variabelennaam ´%s´."
+
+#: src/data/sys-file-reader.c:1038
 msgid "Missing string continuation record."
 msgstr "Mis tekenreeks continuering record."
 
-#: src/data/sys-file-reader.c:732
+#: src/data/sys-file-reader.c:1059
 #, c-format
 msgid "Unknown variable format %<PRIu8>."
 msgstr "Onbekend variabelenopmaak %<PRIu8>."
 
-#: src/data/sys-file-reader.c:750
+#: src/data/sys-file-reader.c:1077
 #, c-format
 msgid "%s variable %s has invalid %s format %s."
 msgstr "%s variabele %s heeft ongeldig %s opmaak %s."
 
-#: src/data/sys-file-reader.c:753
+#: src/data/sys-file-reader.c:1080
 msgid "print"
 msgstr "afdrukken"
 
-#: src/data/sys-file-reader.c:753
+#: src/data/sys-file-reader.c:1080
 msgid "write"
 msgstr "schrijf"
 
-#: src/data/sys-file-reader.c:757
+#: src/data/sys-file-reader.c:1084
 msgid "Suppressing further invalid format warnings."
 msgstr "Onderdrukt verdere ongeldig indelingswaarschuwingen."
 
-#: src/data/sys-file-reader.c:775
-msgid "Weighting variable must be numeric."
-msgstr "Wegingvariabele moet numeriek zijn."
-
-#: src/data/sys-file-reader.c:789
-msgid "Multiple type 6 (document) records."
-msgstr "Meerdere type 6 (document) records."
-
-#: src/data/sys-file-reader.c:793
-#, c-format
-msgid "Number of document lines (%d) must be greater than 0."
-msgstr "Aantal documentregels (%d) moet groter dan 0 zijn."
-
-#: src/data/sys-file-reader.c:801
-msgid "Document line contains null byte."
-msgstr "Documentregel bevat null byte."
-
-#: src/data/sys-file-reader.c:892
-#, c-format
-msgid "Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s"
-msgstr "Niet-herkend type 7, subtype %d.  Stuur s.v.p. een kopie van dit bestand en de syntax waarmee het is aangemaakt naar %s "
-
-#: src/data/sys-file-reader.c:919 tests/dissect-sysfile.c:595
-#, c-format
-msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
-msgstr "Onjuiste lengte (%zu) of aantal (%zu) veld in recordtype 7, subtype 3."
-
-#: src/data/sys-file-reader.c:939
+#: src/data/sys-file-reader.c:1136
 #, c-format
 msgid "Floating-point representation indicated by system file (%d) differs from expected (%d)."
 msgstr "Drijvende komma representatie aangegeven door systeembestand %d verschilt van verwachting (%d)."
 
-#: src/data/sys-file-reader.c:952 src/language/dictionary/sys-file-info.c:109
-msgid "Little Endian"
-msgstr "Little Endian"
-
-#: src/data/sys-file-reader.c:952 src/language/dictionary/sys-file-info.c:108
-msgid "Big Endian"
-msgstr "Big Endian"
-
-#: src/data/sys-file-reader.c:953
+#: src/data/sys-file-reader.c:1150
 #, c-format
-msgid "Integer format indicated by system file (%s) differs from expected (%s)."
-msgstr "Integer indeling aangegeven door systeembestand (%s) verschilt van verwacht (%s)."
-
-#: src/data/sys-file-reader.c:1010 tests/dissect-sysfile.c:626
-#, c-format
-msgid "Bad size (%zu) or count (%zu) on extension 4."
-msgstr "Onjuiste lengte (%zu) of aantal (%zu) bij extensie 4."
+msgid "Integer format indicated by system file (%d) differs from expected (%d)."
+msgstr "Integer indeling aangegeven door systeembestand (%d) verschilt van verwacht (%d)."
 
-#: src/data/sys-file-reader.c:1014 src/data/sys-file-reader.c:1018
-#: src/data/sys-file-reader.c:1022 tests/dissect-sysfile.c:631
+#: src/data/sys-file-reader.c:1211 src/data/sys-file-reader.c:1215
+#: src/data/sys-file-reader.c:1219 tests/dissect-sysfile.c:631
 #: tests/dissect-sysfile.c:636 tests/dissect-sysfile.c:641
 #, c-format
 msgid "File specifies unexpected value %g as %s."
 msgstr "Bestand specificeert onverwachte waarde %g als %s."
 
-#: src/data/sys-file-reader.c:1055 src/data/sys-file-reader.c:1073
-#: tests/dissect-sysfile.c:692
-#, fuzzy, c-format
-msgid "Missing space following `%c' at offset %zu in MRSETS record"
-msgstr "Dubbele variabelenaam %s op offset %zu in MRSETS record."
+#: src/data/sys-file-reader.c:1252
+#, c-format
+msgid "`%s' does not begin with `$' at offset %zu in MRSETS record."
+msgstr "`%s' begint niet met  `$' op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:1082 tests/dissect-sysfile.c:701
-#, fuzzy, c-format
-msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record"
-msgstr "Dubbele variabelenaam %s op offset %zu in MRSETS record."
+#: src/data/sys-file-reader.c:1263 src/data/sys-file-reader.c:1282
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record."
+msgstr "Ontbrekende spatie achter `%c' op offset %zu in MRSETS record."
+
+#: src/data/sys-file-reader.c:1292
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record."
+msgstr "Onverwachte labelbron waarde `%s' achter `E' op offset %zu in MRSETS "
 
-#: src/data/sys-file-reader.c:1088
+#: src/data/sys-file-reader.c:1299
 #, c-format
 msgid "Missing `C', `D', or `E' at offset %zu in MRSETS record."
 msgstr "Ontbrekende `C', `D', of `E' op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:1117
+#: src/data/sys-file-reader.c:1331
 #, c-format
 msgid "Missing new-line parsing variable names at offset %zu in MRSETS record."
-msgstr ""
+msgstr "Mis nieuwe-regel bij het ontleden van variabelennamen op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:1128
+#: src/data/sys-file-reader.c:1347
 #, c-format
 msgid "Duplicate variable name %s at offset %zu in MRSETS record."
-msgstr "Dubbele variabelenaam %s op offset %zu in MRSETS record."
+msgstr "Dubbele variabelennaam %s op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:1141
+#: src/data/sys-file-reader.c:1363
 #, c-format
 msgid "MRSET %s contains both string and numeric variables."
 msgstr "MRSET %s bevat zowel tekenreeks als numerieke variabelen."
 
-#: src/data/sys-file-reader.c:1156
+#: src/data/sys-file-reader.c:1379
 #, c-format
 msgid "MRSET %s has only %zu variables."
 msgstr "MRSET %s heeft slechts %zu variabelen."
 
-#: src/data/sys-file-reader.c:1194 tests/dissect-sysfile.c:759
-#, c-format
-msgid "Bad size %zu on extension 11."
-msgstr "Onjuiste lengte %zu voor extensie 11."
-
-#: src/data/sys-file-reader.c:1206 tests/dissect-sysfile.c:771
+#: src/data/sys-file-reader.c:1425 tests/dissect-sysfile.c:771
 #, c-format
 msgid "Extension 11 has bad count %zu (for %zu variables)."
 msgstr "Extensie 11 heeft een foutief aantal %zu (voor %zu variabelen)."
 
-#: src/data/sys-file-reader.c:1227
+#: src/data/sys-file-reader.c:1459
 #, c-format
 msgid "Invalid variable display parameters for variable %zu (%s).  Default parameters substituted."
 msgstr "Ongeldige variabelen-toon-parameters voor variabele %zu (%s).  Standaard parameters ingevuld."
 
-#: src/data/sys-file-reader.c:1271
+#: src/data/sys-file-reader.c:1556
 #, c-format
 msgid "Long variable mapping from %s to invalid variable name `%s'."
 msgstr "Lange variabele afbeelding van %s tot ongeldige naam '%s'."
 
-#: src/data/sys-file-reader.c:1281
+#: src/data/sys-file-reader.c:1567
 #, c-format
-msgid "Duplicate long variable name `%s' within system file."
-msgstr "Dubbele lange variabelennaam '%s' binnen systeembestand."
+msgid "Duplicate long variable name `%s'."
+msgstr "Dubbele lange variabelennaam `%s'."
 
-#: src/data/sys-file-reader.c:1334
+#: src/data/sys-file-reader.c:1600
 #, c-format
-msgid "%s listed as string of invalid length %s in very length string record."
-msgstr ""
+msgid "%s listed as string of invalid length %s in very long string record."
+msgstr "%s weergegeven als  tekenreeks van foutieve lengte %s in erg lange tekenreeks record."
 
-#: src/data/sys-file-reader.c:1344
+#: src/data/sys-file-reader.c:1611
 #, c-format
 msgid "%s listed in very long string record with width %s, which requires only one segment."
 msgstr "%s vermeld in erg lang tekenreeks-record met breedte %s, dat slechts een segment vereist."
 
-#: src/data/sys-file-reader.c:1350
+#: src/data/sys-file-reader.c:1618
 #, c-format
 msgid "Very long string %s overflows dictionary."
 msgstr "Erg lange-tekenreeks %s is te groot voor woordenboek."
 
-#: src/data/sys-file-reader.c:1364
+#: src/data/sys-file-reader.c:1633
 #, c-format
-msgid "Very long string with width %ld has segment %d of width %d (expected %d)"
-msgstr "Erg lange-tekenreeks met breedte %ld heeft segment %d van breedte %d (verwacht %d)"
+msgid "Very long string with width %ld has segment %d of width %d (expected %d)."
+msgstr "Erg lange-tekenreeks met breedte %ld heeft segment %d van breedte %d (verwacht %d)."
 
-#: src/data/sys-file-reader.c:1410
+#: src/data/sys-file-reader.c:1667
 #, c-format
-msgid "Invalid number of labels: %d.  Ignoring labels."
-msgstr "Ongeldig aantal labels: %d. Labels worden genegeerd."
-
-#: src/data/sys-file-reader.c:1441 tests/dissect-sysfile.c:469
-msgid "Variable index record (type 4) does not immediately follow value label record (type 3) as it should."
-msgstr "Variabele index record (type 4) volgt niet onmiddellijk waardelabel record (type 3) zoals het moet."
-
-#: src/data/sys-file-reader.c:1448
-#, c-format
-msgid "Number of variables associated with a value label (%d) is not between 1 and the number of variables (%zu)."
-msgstr "Aantal variabelen geassocieerd aan waardelabel (%d) is niet tussen 1 en het aantal variabelen (%zu)."
+msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
+msgstr "Variabelen geassocieerd met waardelabel zijn niet allemaal van het identieke type.  Variabele %s is %s, maar variabele %s is %s."
 
-#: src/data/sys-file-reader.c:1459
+#: src/data/sys-file-reader.c:1684
 #, c-format
 msgid "Value labels may not be added to long string variables (e.g. %s) using records types 3 and 4."
 msgstr "Waardelabels mogen niet toegevoegd aan lange tekenreeks-variabelen (bv %s) bij het gebruik van records types 3 en 4."
 
-#: src/data/sys-file-reader.c:1468
-#, c-format
-msgid "Variables associated with value label are not all of identical type.  Variable %s is %s, but variable %s is %s."
-msgstr "Variabelen geassocieerd met waardelabel zijn niet allemaal van het identieke type.  Variabele %s is %s, maar variabele %s is %s."
-
-#: src/data/sys-file-reader.c:1502
+#: src/data/sys-file-reader.c:1703
 #, c-format
 msgid "Duplicate value label for %g on %s."
 msgstr "Dubbel waardelabel voor %g in %s."
 
-#: src/data/sys-file-reader.c:1505 src/data/sys-file-reader.c:1686
+#: src/data/sys-file-reader.c:1707 src/data/sys-file-reader.c:1949
 #, c-format
 msgid "Duplicate value label for `%.*s' on %s."
 msgstr "Dubbel waardelabel voor '%.*s' in %s."
 
-#: src/data/sys-file-reader.c:1543
+#: src/data/sys-file-reader.c:1732
 #, c-format
-msgid "Error parsing attribute value %s[%d]"
-msgstr "Fout tijdens ontleden attribuut waarde %s[%d]"
+msgid "Variable index %d not in valid range 1...%zu."
+msgstr "Variabele index %d niet in geldig bereik 1...%zu."
 
-#: src/data/sys-file-reader.c:1557
+#: src/data/sys-file-reader.c:1741
 #, c-format
-msgid "Attribute value %s[%d] is not quoted: %s"
-msgstr "Attribuut waarde %s[%d] is niet geciteerd: %s"
+msgid "Variable index %d refers to long string continuation."
+msgstr "Variabele index %d verwijst naar lange-tekenreeks voortzetting."
 
-#: src/data/sys-file-reader.c:1620 tests/dissect-sysfile.c:937
+#: src/data/sys-file-reader.c:1777
 #, c-format
-msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
-msgstr ""
+msgid "Error parsing attribute value %s[%d]."
+msgstr "Fout tijdens ontleden attribuut waarde %s[%d]."
+
+#: src/data/sys-file-reader.c:1791
+#, c-format
+msgid "Attribute value %s[%d] is not quoted: %s."
+msgstr "Attribuut waarde %s[%d] is niet geciteerd: %s."
+
+#: src/data/sys-file-reader.c:1844
+msgid "Long string value label record ends unexpectedly."
+msgstr "Lange tekenreeks waarde label record eindigt onverwacht."
 
-#: src/data/sys-file-reader.c:1630
+#: src/data/sys-file-reader.c:1883
 #, c-format
 msgid "Ignoring long string value record for unknown variable %s."
 msgstr "Negeren lange tekenreeks waarde record voor onbekende variabele %s."
 
-#: src/data/sys-file-reader.c:1637
+#: src/data/sys-file-reader.c:1888
 #, c-format
 msgid "Ignoring long string value record for numeric variable %s."
 msgstr "Negeren lange tekenreeks waarde record voor numerieke variabele %s."
 
-#: src/data/sys-file-reader.c:1644
+#: src/data/sys-file-reader.c:1895
 #, c-format
-msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)"
-msgstr ""
+msgid "Ignoring long string value record for variable %s because the record's width (%d) does not match the variable's width (%d)."
+msgstr "Negeren lange tekenreeks waarde record voor variabele %s omdat de recordbreedte (%d) niet matched met de variabele breedte (%d)."
 
-#: src/data/sys-file-reader.c:1666
+#: src/data/sys-file-reader.c:1924
 #, c-format
 msgid "Ignoring long string value %zu for variable %s, with width %d, that has bad value width %zu."
-msgstr ""
+msgstr "Negeren lange tekenreeks waarde %zu voor variabele %s, met breedte %d, die een foutieve breedte waarde %zu heeft."
 
-#: src/data/sys-file-reader.c:1781
+#: src/data/sys-file-reader.c:2028
 msgid "File ends in partial case."
 msgstr "Bestand eindigt in gedeeltelijke case."
 
-#: src/data/sys-file-reader.c:1789
+#: src/data/sys-file-reader.c:2036
 #, c-format
 msgid "Error reading case from file %s."
 msgstr "Fout tijdens lezen case van bestand %s."
 
-#: src/data/sys-file-reader.c:1890
+#: src/data/sys-file-reader.c:2138
 msgid "Possible compressed data corruption: compressed spaces appear in numeric field."
-msgstr ""
+msgstr "Mogelijke gecomprimeerde data corruptie: gecomprimeerde spaties komen voor in numeriek veld."
 
-#: src/data/sys-file-reader.c:1943
+#: src/data/sys-file-reader.c:2192
 #, c-format
-msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)"
-msgstr ""
-
-#: src/data/sys-file-reader.c:2035
-#, c-format
-msgid "Variable index %d not in valid range 1...%d."
-msgstr "Variabele index %d niet in geldig bereik 1...%d."
-
-#: src/data/sys-file-reader.c:2040
-#, c-format
-msgid "Variable index %d refers to long string continuation."
-msgstr "Variabele index %d verwijst naar lange-tekenreeks voortzetting."
+msgid "Possible compressed data corruption: string contains compressed integer (opcode %d)."
+msgstr "Mogelijke gecomprimeerde data corruptie: tekenreeks bevat gecomprimeerde integer (opcode %d)."
 
-#: src/data/sys-file-reader.c:2108
+#: src/data/sys-file-reader.c:2286
 #, c-format
 msgid "Suppressed %d additional related warnings."
 msgstr "Onderdrukt %d extra gerelateerde waarschuwingen."
 
-#: src/data/sys-file-reader.c:2153 src/data/sys-file-reader.c:2170
+#: src/data/sys-file-reader.c:2332 src/data/sys-file-reader.c:2349
 #, c-format
 msgid "Dictionary record refers to unknown variable %s."
 msgstr "Bibliotheek record refereert aan onbekende variabele %s."
 
-#: src/data/sys-file-reader.c:2231
+#: src/data/sys-file-reader.c:2411
 #, c-format
 msgid "Expecting digit at offset %zu in MRSETS record."
-msgstr ""
+msgstr "Verwacht cijfer op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:2238
+#: src/data/sys-file-reader.c:2419
 #, c-format
 msgid "Expecting space at offset %zu in MRSETS record."
-msgstr ""
+msgstr "Verwacht spatie op offset %zu in MRSETS record."
 
-#: src/data/sys-file-reader.c:2245
+#: src/data/sys-file-reader.c:2427
 #, c-format
 msgid "%zu-byte string starting at offset %zu exceeds record length %zu."
-msgstr ""
+msgstr "%zu-byte tekenreeks beginnend op offset %zu overschrijdt record lengte %zu."
 
-#: src/data/sys-file-reader.c:2255
+#: src/data/sys-file-reader.c:2437
 #, c-format
 msgid "Expecting space at offset %zu following %zu-byte string."
-msgstr ""
+msgstr "Verwacht spatie op offset %zu achter %zu-byte tekenreeks."
+
+#: src/data/sys-file-reader.c:2478
+#, c-format
+msgid "`%s' near offset 0x%llx: "
+msgstr "`%s' nabij offset 0x%llx: "
+
+#: src/data/sys-file-reader.c:2481
+#, c-format
+msgid "`%s': "
+msgstr "`%s': "
 
-#: src/data/sys-file-reader.c:2349 tests/dissect-sysfile.c:1356
+#: src/data/sys-file-reader.c:2538 tests/dissect-sysfile.c:1356
 #, c-format
 msgid "System error: %s."
 msgstr "Systeemfout: %s."
 
-#: src/data/sys-file-reader.c:2351 tests/dissect-sysfile.c:1358
+#: src/data/sys-file-reader.c:2540 tests/dissect-sysfile.c:1358
 msgid "Unexpected end of file."
 msgstr "Onverwacht einde-bestand."
 
-#: src/data/sys-file-writer.c:179
+#: src/data/sys-file-writer.c:186
 #, c-format
 msgid "Unknown system file version %d. Treating as version %d."
 msgstr "Onbekende systeembestand versie %d. Behandeld als versie %d."
 
-#: src/data/sys-file-writer.c:985
+#: src/data/sys-file-writer.c:1015
 #, c-format
 msgid "An I/O error occurred writing system file `%s'."
 msgstr "Een I/O fout is opgetreden tijdens het schrijven van systeembestand '%s'."
 
-#: src/data/variable.c:206
-#, c-format
-msgid "Character `%c' (in %s) may not appear as the first character in a variable name."
-msgstr "Teken '%c' (in %s) mag niet als eerste teken in een variabelennaam voorkomen."
-
-#: src/data/variable.c:218
-#, c-format
-msgid "Character `%c' (in %s) may not appear in a variable name."
-msgstr "Teken '%c' (in %s) mag niet in een variabelennaam voorkomen."
-
-#: src/data/variable.c:244
-msgid "Variable name cannot be empty string."
-msgstr "Variabelennaam kan geen lege tekenreeks zijn."
-
-#: src/data/variable.c:250
-#, c-format
-msgid "Variable name %s exceeds %d-character limit."
-msgstr "Variabelennaam %s overschrijdt de limiet van %d tekens."
-
-#: src/data/variable.c:258
+#: src/data/variable.c:601
 #, c-format
-msgid "`%s' may not be used as a variable name because it is a reserved word."
-msgstr "'%s' mag niet gebruikt worden als variabelennaam omdat het een gereserveerd woord is."
+msgid "Truncating variable label for variable `%s' to %d bytes."
+msgstr "Afkappen variabelelabel voor variabele `%s' tot %d bytes."
 
-#: src/language/syntax-file.c:100
-#, c-format
-msgid "Reading `%s': %s."
-msgstr "Lezen '%s': %s."
-
-#: src/language/syntax-file.c:117
-#, c-format
-msgid "Closing `%s': %s."
-msgstr "Sluiten '%s': %s."
-
-#: src/language/syntax-file.c:138
-#, c-format
-msgid "Opening `%s': %s."
-msgstr "Openen '%s': %s."
-
-#: src/language/command.c:197 src/language/expressions/parse.c:1270
-#: src/language/utilities/set.q:213
+#: src/language/command.c:196 src/language/expressions/parse.c:1294
+#: src/language/utilities/set.q:196
 #, c-format
 msgid "%s is not yet implemented."
 msgstr "%s is nog niet geïmplementeerd."
 
-#: src/language/command.c:202
+#: src/language/command.c:201
 #, c-format
 msgid "%s may be used only in testing mode."
 msgstr "%s mag alleen in testmodus gebruikt worden."
 
-#: src/language/command.c:207
+#: src/language/command.c:206
 #, c-format
 msgid "%s may be used only in enhanced syntax mode."
 msgstr "%s mag alleen in uitgebreide syntaxmodus gebruikt worden."
 
-#: src/language/command.c:231
-msgid "Error encountered while ERROR=STOP is effective."
-msgstr "Fout tegengekomen terwijl ERROR=STOP is actief."
-
-#: src/language/command.c:476
+#: src/language/command.c:334
 msgid "expecting command name"
 msgstr "opdrachtnaam verwacht"
 
-#: src/language/command.c:490
+#: src/language/command.c:336
 #, c-format
-msgid "Unknown command %s."
-msgstr "Onbekende opdracht %s."
+msgid "Unknown command `%s'."
+msgstr "Onbekende opdracht `%s'."
 
-#: src/language/command.c:615
+#: src/language/command.c:369
 #, c-format
-msgid "%s is allowed only before the active file has been defined."
-msgstr "%s is alleen toegestaan voordat het actieve bestand is gedefinieerd."
+msgid "%s is allowed only before the active dataset has been defined."
+msgstr "%s is alleen toegestaan voordat de actieve dataset is gedefinieerd."
 
-#: src/language/command.c:619
+#: src/language/command.c:373
 #, c-format
-msgid "%s is allowed only after the active file has been defined."
-msgstr "%s is alleen toegestaan nadat het actieve bestand is gedefinieerd."
+msgid "%s is allowed only after the active dataset has been defined."
+msgstr "%s is alleen toegestaan nadat de actieve dataset is gedefinieerd."
 
-#: src/language/command.c:623
+#: src/language/command.c:377
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM."
 msgstr "%s is alleen toegestaan binnen INPUT PROGRAM."
 
-#: src/language/command.c:627
+#: src/language/command.c:381
 #, c-format
 msgid "%s is allowed only inside FILE TYPE."
 msgstr "%s is alleen toegestaan binnen FILE TYPE."
 
-#: src/language/command.c:634
+#: src/language/command.c:388
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s is alleen toegestaan voordat het actieve bestand is gedefinieerd of binnen INPUT PROGRAMMA."
+msgid "%s is allowed only before the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s is alleen toegestaan voordat de actieve dataset is gedefinieerd of binnen INPUT PROGRAMMA."
 
-#: src/language/command.c:638
+#: src/language/command.c:392
 #, c-format
-msgid "%s is allowed only before the active file has been defined or inside FILE TYPE."
-msgstr "%s is alleen toegestaan voordat het actieve bestand is gedefinieerd of binnen FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined or inside FILE TYPE."
+msgstr "%s is alleen toegestaan voordat de actieve dataset is gedefinieerd of binnen FILE TYPE."
 
-#: src/language/command.c:642
+#: src/language/command.c:396
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside INPUT PROGRAM."
-msgstr "%s is alleen toegestaan nadat het actieve bestand is gedefinieerd of binnen INPUT PROGRAMMA."
+msgid "%s is allowed only after the active dataset has been defined or inside INPUT PROGRAM."
+msgstr "%s is alleen toegestaan nadat de actieve dataset is gedefinieerd of binnen INPUT PROGRAM."
 
-#: src/language/command.c:646
+#: src/language/command.c:400
 #, c-format
-msgid "%s is allowed only after the active file has been defined or inside FILE TYPE."
-msgstr "%s is alleen toegestaan nadat het actieve bestand is gedefinieerd of binnen FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined or inside FILE TYPE."
+msgstr "%s is alleen toegestaan nadat het actieve dataset is gedefinieerd of binnen FILE TYPE."
 
-#: src/language/command.c:650
+#: src/language/command.c:404
 #, c-format
 msgid "%s is allowed only inside INPUT PROGRAM or inside FILE TYPE."
 msgstr "%s is alleen toegestaan binnen INPUT PROGRAM of binnen FILE TYPE."
 
-#: src/language/command.c:656
+#: src/language/command.c:410
 #, c-format
-msgid "%s is allowed only after the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s is alleen toegestaan nadat het actieve bestand is gedefinieerd, binnen INPUT PROGRAM of binnen FILE TYPE."
+msgid "%s is allowed only after the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s is alleen toegestaan nadat de actieve dataset is gedefinieerd, binnen INPUT PROGRAM, of binnen FILE TYPE."
 
-#: src/language/command.c:661
+#: src/language/command.c:415
 #, c-format
-msgid "%s is allowed only before the active file has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
-msgstr "%s is alleen toegestaan voordat het actieve bestand is gedefinieerd, binnen INPUT PROGRAM of binnen FILE TYPE."
+msgid "%s is allowed only before the active dataset has been defined, inside INPUT PROGRAM, or inside FILE TYPE."
+msgstr "%s is alleen toegestaan voordat de actieve dataset is gedefinieerd, binnen INPUT PROGRAM, of binnen FILE TYPE."
 
-#: src/language/command.c:679 src/language/command.c:681
+#: src/language/command.c:433 src/language/command.c:436
 #, c-format
 msgid "%s is not allowed inside %s."
 msgstr "%s is niet toegestaan binnen %s."
 
-#: src/language/command.c:760 src/language/utilities/host.c:128
-#: src/language/utilities/permissions.c:101
+#: src/language/command.c:518 src/language/utilities/host.c:130
+#: src/language/utilities/permissions.c:104
 msgid "This command not allowed when the SAFER option is set."
 msgstr "Deze opdracht is niet toegestaan als de SAFER optie is gezet."
 
-#: src/language/command.c:772
+#: src/language/command.c:534
 #, c-format
 msgid "Error removing `%s': %s."
 msgstr "Fout bij verwijderen '%s': %s."
 
-#: src/language/lexer/lexer.c:263
-#, c-format
-msgid "%s does not form a valid number."
-msgstr "%s vormt geen geldig nummer."
-
-#: src/language/lexer/lexer.c:369
-#, c-format
-msgid "Bad character in input: `%s'."
-msgstr "Foutief teken in invoer: '%s'."
-
-#: src/language/lexer/lexer.c:402
+#: src/language/lexer/lexer.c:276
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr "Subopdracht %s mag slechts een keer gespecificeerd worden."
 
-#: src/language/lexer/lexer.c:410
+#: src/language/lexer/lexer.c:284
 #, c-format
 msgid "missing required subcommand %s"
 msgstr "mis vereiste subopdracht %s"
 
-#: src/language/lexer/lexer.c:423
-#, fuzzy
-msgid "Syntax error at end of file"
-msgstr "Syntaxfout in datumveld."
-
-#: src/language/lexer/lexer.c:425
-#, fuzzy
-msgid "Syntax error at end of command"
-msgstr "Syntaxfout in datumveld."
+#: src/language/lexer/lexer.c:302
+msgid "Syntax error at end of input"
+msgstr "Syntaxfout bij het einde van de invoer"
 
-#: src/language/lexer/lexer.c:429
-#, fuzzy, c-format
-msgid "Syntax error at `%s'"
-msgstr "Syntaxfout op %s."
-
-#: src/language/lexer/lexer.c:457 src/language/xforms/select-if.c:60
-#: src/language/stats/autorecode.c:161 src/language/stats/npar.c:310
-#: src/language/data-io/print-space.c:73
+#: src/language/lexer/lexer.c:323 src/language/xforms/select-if.c:60
+#: src/language/stats/autorecode.c:162 src/language/stats/npar.c:414
+#: src/language/data-io/print-space.c:72
 msgid "expecting end of command"
 msgstr "verwacht einde-van-opdracht "
 
-#: src/language/lexer/lexer.c:579 src/language/lexer/lexer.c:596
+#: src/language/lexer/lexer.c:494 src/language/lexer/lexer.c:511
 #, c-format
 msgid "expecting `%s'"
 msgstr "verwacht '%s'"
 
-#: src/language/lexer/lexer.c:610
+#: src/language/lexer/lexer.c:525
 msgid "expecting string"
 msgstr "tekenreeks verwacht"
 
-#: src/language/lexer/lexer.c:624
+#: src/language/lexer/lexer.c:539
 msgid "expecting integer"
 msgstr "verwacht integer"
 
-#: src/language/lexer/lexer.c:637
+#: src/language/lexer/lexer.c:552
 msgid "expecting number"
 msgstr "nummer verwacht"
 
-#: src/language/lexer/lexer.c:649
+#: src/language/lexer/lexer.c:564
 msgid "expecting identifier"
-msgstr "verwacht herkenningsteken"
+msgstr "verwacht identificator"
 
-#: src/language/lexer/lexer.c:1042
-msgid "binary"
-msgstr "binair"
+#: src/language/lexer/lexer.c:1187
+msgid "Syntax error at end of command"
+msgstr "Syntaxfout bij het einde van de opdracht"
 
-#: src/language/lexer/lexer.c:1047
-msgid "octal"
-msgstr "octaal"
+#: src/language/lexer/lexer.c:1196
+#, c-format
+msgid "Syntax error at `%s'"
+msgstr "Syntaxfout op `%s'"
 
-#: src/language/lexer/lexer.c:1052
-msgid "hex"
-msgstr "hexadecimaal"
+#: src/language/lexer/lexer.c:1199
+msgid "Syntax error"
+msgstr "Syntaxfout"
 
-#: src/language/lexer/lexer.c:1062
+#: src/language/lexer/lexer.c:1363
 #, c-format
-msgid "String of %s digits has %zu characters, which is not a multiple of %d."
-msgstr "Tekenreeks van %s cijfers bestaat uit %zu tekens, dat geen meervoud van %d is."
+msgid "String of hex digits has %d characters, which is not a multiple of 2"
+msgstr "Tekenreeks van hex cijfers heeft %d tekens, dat is geen meervoud van 2"
 
-#: src/language/lexer/lexer.c:1091
+#: src/language/lexer/lexer.c:1370
 #, c-format
-msgid "`%c' is not a valid %s digit."
-msgstr "'%c' is geen geldig %s cijfer."
+msgid "`%c' is not a valid hex digit"
+msgstr "'%c' is geen geldig hex cijfer"
 
-#: src/language/lexer/lexer.c:1125
-msgid "Unterminated string constant."
-msgstr "Geen einde aan tekenreeksconstante."
+#: src/language/lexer/lexer.c:1375
+#, c-format
+msgid "Unicode string contains %d bytes, which is not in the valid range of 1 to 8 bytes"
+msgstr "Unicode tekenreeks bevat %d bytes, wat niet valt in de geldige range van 1 tot 8 bytes"
 
-#: src/language/lexer/lexer.c:1179
-msgid "Unexpected end of file in string concatenation."
-msgstr "Onverwacht bestandseinde in tekenreeks samenvoeging."
+#: src/language/lexer/lexer.c:1381
+#, c-format
+msgid "U+%04X is not a valid Unicode code point"
+msgstr "U+%04X is geen geldige Unicode code punt"
 
-#: src/language/lexer/lexer.c:1187
-msgid "String expected following `+'."
-msgstr "Tekenreeks verwacht achter '+'."
+#: src/language/lexer/lexer.c:1386
+msgid "Unterminated string constant"
+msgstr "Geen einde aan tekenreeksconstante"
+
+#: src/language/lexer/lexer.c:1390
+#, c-format
+msgid "Missing exponent following `%s'"
+msgstr "Ontbrekende exponent achter `%s'"
+
+#: src/language/lexer/lexer.c:1395
+msgid "Unexpected `.' in middle of command"
+msgstr "Onverwachte `.' in het midden van opdracht"
+
+#: src/language/lexer/lexer.c:1401
+#, c-format
+msgid "Bad character %s in input"
+msgstr "Foutief teken  %s in invoer"
+
+#: src/language/lexer/lexer.c:1495
+#, c-format
+msgid "Opening `%s': %s."
+msgstr "Openen '%s': %s."
+
+#: src/language/lexer/lexer.c:1525
+#, c-format
+msgid "Error reading `%s': %s."
+msgstr "Fout bij lezen '%s': %s."
+
+#: src/language/lexer/lexer.c:1539
+#, c-format
+msgid "Error closing `%s': %s."
+msgstr "Fout bij sluiten `%s': %s."
 
-#: src/language/lexer/format-parser.c:88
+#: src/language/lexer/format-parser.c:79
 msgid "expecting valid format specifier"
 msgstr "verwacht geldige indelingsspecificator"
 
-#: src/language/lexer/format-parser.c:107
-#: src/language/lexer/format-parser.c:126
-#: src/language/data-io/placement-parser.c:226
+#: src/language/lexer/format-parser.c:118
+#: src/language/lexer/format-parser.c:138
+#: src/language/data-io/placement-parser.c:225
 #, c-format
 msgid "Unknown format type `%s'."
 msgstr "Onbekend opmaaktype '%s'."
 
-#: src/language/lexer/format-parser.c:121
+#: src/language/lexer/format-parser.c:133
 msgid "expecting format type"
 msgstr "verwacht opmaaktype"
 
-#: src/language/lexer/value-parser.c:64
+#: src/language/lexer/value-parser.c:65
 #, c-format
 msgid "Low end of range (%g) is below high end (%g).  The range will be treated as reversed."
 msgstr "Ondergrens van bereik (%g) is lager dan bovengrens (%g). Het bereik wordt behandeld als omgekeerd."
 
-#: src/language/lexer/value-parser.c:72
+#: src/language/lexer/value-parser.c:73
 #, c-format
 msgid "Ends of range are equal (%g)."
 msgstr "Eindes van bereik zijn gelijk (%g)."
 
-#: src/language/lexer/value-parser.c:80
+#: src/language/lexer/value-parser.c:81
 msgid "LO or LOWEST must be part of a range."
 msgstr "LO of LOWEST moet een onderdeel van een bereik zijn."
 
@@ -1322,69 +1313,75 @@ msgstr "System-missing waarde is hier niet geldig."
 msgid "expecting number or data string"
 msgstr "nummer of gegevenstekenreeks verwacht"
 
-#: src/language/lexer/variable-parser.c:65
+#: src/language/lexer/variable-parser.c:67
 msgid "expecting variable name"
 msgstr "variabelennaam werd verwacht"
 
-#: src/language/lexer/variable-parser.c:75
+#: src/language/lexer/variable-parser.c:77
 #, c-format
 msgid "%s is not a variable name."
 msgstr "%s is geen variabelennaam."
 
-#: src/language/lexer/variable-parser.c:178
+#: src/language/lexer/variable-parser.c:180
 #, c-format
 msgid "%s is not a numeric variable.  It will not be included in the variable list."
 msgstr "%s is geen numerieke variabele. Het wordt niet opgenomen in de variabelenlijst."
 
-#: src/language/lexer/variable-parser.c:181
+#: src/language/lexer/variable-parser.c:183
 #, c-format
 msgid "%s is not a string variable.  It will not be included in the variable list."
 msgstr "%s is geen tekenreeksvariabele. Het wordt niet opgenomen in de variabelenlijst."
 
-#: src/language/lexer/variable-parser.c:185
+#: src/language/lexer/variable-parser.c:187
 #, c-format
 msgid "Scratch variables (such as %s) are not allowed here."
 msgstr "Scratch variabelen (zoals %s) zijn hier niet toegestaan."
 
-#: src/language/lexer/variable-parser.c:189
+#: src/language/lexer/variable-parser.c:191
 #, c-format
 msgid "%s and %s are not the same type.  All variables in this variable list must be of the same type.  %s will be omitted from the list."
 msgstr "%s en %s zijn niet van hetzelfde type. Alle variabelen in deze variabelenlijst dienen van hetzelfde type te zijn.  %s wordt overgeslagen voor de lijst."
 
-#: src/language/lexer/variable-parser.c:195
+#: src/language/lexer/variable-parser.c:197
 #, c-format
 msgid "%s and %s are string variables with different widths.  All variables in this variable list must have the same width.  %s will be omitted from the list."
 msgstr "%s en %s hebben verschillende breedtes. Alle variabelen in deze variabelenlijst dienen dezelfde breedte te hebben.  %s wordt overgeslagen voor de lijst."
 
-#: src/language/lexer/variable-parser.c:200
-#: src/language/lexer/variable-parser.c:496
+#: src/language/lexer/variable-parser.c:202
+#: src/language/lexer/variable-parser.c:404
 #, c-format
 msgid "Variable %s appears twice in variable list."
 msgstr "Variabele %s komt 2 keer in de variabelenlijst voor."
 
-#: src/language/lexer/variable-parser.c:313
+#: src/language/lexer/variable-parser.c:315
 #, c-format
 msgid "%s TO %s is not valid syntax since %s precedes %s in the dictionary."
 msgstr "%s TO %s is geen geldige syntax omdat %s voor %s in het woordenboek staat."
 
-#: src/language/lexer/variable-parser.c:321
+#: src/language/lexer/variable-parser.c:323
 #, c-format
 msgid "When using the TO keyword to specify several variables, both variables must be from the same variable dictionaries, of either ordinary, scratch, or system variables.  %s is a %s variable, whereas %s is %s."
 msgstr "Wanneer het sleutelwoord TO wordt gebruikt om verscheidene variabelen te specificeren, moeten beide variabelen van het zelfde variabelenwoordenboeken, of gewone- scratch- of systeemvariabelen zijn. %s is een %s variabele, terwijl %s %s. is."
 
-#: src/language/lexer/variable-parser.c:395
-msgid "incorrect use of TO convention"
-msgstr "foutief gebruik van TO conventie"
+#: src/language/lexer/variable-parser.c:381
+#, c-format
+msgid "`%s' cannot be used with TO because it does not end in a digit."
+msgstr "`%s' kan niet gebruikt worden met TO omdat niet eindigt met een cijfer."
+
+#: src/language/lexer/variable-parser.c:389
+#, c-format
+msgid "Numeric suffix on `%s' is larger than supported with TO."
+msgstr "Numeriek achtervoegsel op `%s' is langer dan ondersteunt met TO."
 
-#: src/language/lexer/variable-parser.c:450
+#: src/language/lexer/variable-parser.c:465
 msgid "Scratch variables not allowed here."
 msgstr "Scratch variabelen niet toegestaan hier."
 
-#: src/language/lexer/variable-parser.c:472
+#: src/language/lexer/variable-parser.c:497
 msgid "Prefixes don't match in use of TO convention."
 msgstr "Prefixen komen niet overeen in het gebruik van TO conventie."
 
-#: src/language/lexer/variable-parser.c:477
+#: src/language/lexer/variable-parser.c:502
 msgid "Bad bounds in use of TO convention."
 msgstr "Slechte grenzen in het gebruik van TO conventie."
 
@@ -1403,7 +1400,7 @@ msgstr "Tijdens uitvoeren van COMPUTE: %g is geen geldige waarde als een index i
 msgid "There is no vector named %s."
 msgstr "Er is geen vector genaamd %s."
 
-#: src/language/xforms/count.c:123
+#: src/language/xforms/count.c:125
 msgid "Destination cannot be a string variable."
 msgstr "Bestemming kan geen tekenreeksvariabele zijn."
 
@@ -1416,38 +1413,38 @@ msgstr "De steekproef factor moet exclusief tussen 0 en 1 liggen."
 msgid "Cannot sample %d observations from a population of %d."
 msgstr "Kan niet %d observaties bemonsteren van een populatie van %d."
 
-#: src/language/xforms/recode.c:250
+#: src/language/xforms/recode.c:255
 msgid "Inconsistent target variable types.  Target variables must be all numeric or all string."
 msgstr "Inconsistent doelvariabelen-types.  Doelvariabelen moeten allemaal numeriek of allemaal tekenreeks zijn."
 
-#: src/language/xforms/recode.c:271
+#: src/language/xforms/recode.c:276
 msgid "CONVERT requires string input values and numeric output values."
 msgstr "CONVERT vereist tekenreeks invoerwaardes en numerieke uitvoerwaardes."
 
-#: src/language/xforms/recode.c:326
+#: src/language/xforms/recode.c:333
 msgid "THRU is not allowed with string variables."
 msgstr "THRU is niet toegestaan met tekenreeksvariabelen."
 
-#: src/language/xforms/recode.c:406
+#: src/language/xforms/recode.c:416
 msgid "expecting output value"
 msgstr "verwacht uitvoerwaarde"
 
-#: src/language/xforms/recode.c:463
+#: src/language/xforms/recode.c:473
 #, c-format
 msgid "%zu variable(s) cannot be recoded into %zu variable(s).  Specify the same number of variables as source and target variables."
 msgstr "%zu variabel(en) kunnen niet gehercodeerd worden in %zu variabel(en).  Specificeer hetzelfde aantal variabelen als bron- en als doelvariabelen."
 
-#: src/language/xforms/recode.c:478
+#: src/language/xforms/recode.c:488
 #, c-format
 msgid "There is no variable named %s.  (All string variables specified on INTO must already exist.  Use the STRING command to create a string variable.)"
 msgstr "Er is geen variabele genaamd %s.  (Alle tekenreeksvariabelen gespecificeerd bij INTO dienen al te bestaan.  Gebruik de STRING opdracht om een tekenreeks variabele aan te maken.)"
 
-#: src/language/xforms/recode.c:494
+#: src/language/xforms/recode.c:504
 #, c-format
 msgid "INTO is required with %s input values and %s output values."
 msgstr "INTO is vereist met %s invoerwaardes en %s uitvoerwaardes."
 
-#: src/language/xforms/recode.c:507
+#: src/language/xforms/recode.c:517
 #, c-format
 msgid "Type mismatch.  Cannot store %s data in %s variable %s."
 msgstr "Type fout. Kan %s gegevens niet in %s variabele %s opslaan."
@@ -1464,17 +1461,17 @@ msgstr "De filtervariabele moet numeriek zijn."
 msgid "The filter variable may not be scratch."
 msgstr "De filtervariabele mag niet scratch zijn."
 
-#: src/language/control/control-stack.c:27
+#: src/language/control/control-stack.c:31
 #, c-format
 msgid "%s without %s."
 msgstr "%s zonder %s."
 
-#: src/language/control/control-stack.c:55
+#: src/language/control/control-stack.c:59
 #, c-format
 msgid "This command must appear inside %s...%s, without intermediate %s...%s."
 msgstr "Deze opdracht moet binnen %s...%s voorkomen, zonder tussenliggende %s...%s."
 
-#: src/language/control/control-stack.c:72
+#: src/language/control/control-stack.c:76
 #, c-format
 msgid "This command cannot appear outside %s...%s."
 msgstr "Deze opdracht kan niet voorkomen buiten %s...%s."
@@ -1487,62 +1484,54 @@ msgstr "Deze opdracht mag niet volgen op ELSE in DO IF...END IF."
 msgid "Only one index clause may be specified."
 msgstr "Slechts een index clausule mag gespecificeerd worden."
 
-#: src/language/control/temporary.c:45
-msgid "This command may only appear once between procedures and procedure-like commands."
-msgstr "Deze opdracht mag slechts 1 keer voorkomen tussen procedures en procedure-achtige opdrachten."
-
-#: src/language/control/repeat.c:172
+#: src/language/control/repeat.c:115
 #, c-format
 msgid "Dummy variable name `%s' hides dictionary variable `%s'."
 msgstr "Dummy-variabelennaam '%s' verbergt woordenboekvariabele '%s'."
 
-#: src/language/control/repeat.c:177
+#: src/language/control/repeat.c:119
 #, c-format
 msgid "Dummy variable name `%s' is given twice."
 msgstr "Dummy-variabelennaam '%s' is twee keer opgegeven."
 
-#: src/language/control/repeat.c:223
+#: src/language/control/repeat.c:162
 #, c-format
-msgid "Dummy variable `%.*s' had %d substitutions, so `%.*s' must also, but %d were specified."
-msgstr "Dummy variabele '%.*s' heeft %d vervangingen, dus '%.*s' moet dat ook, maar %d zijn er gespecificeerd."
+msgid "Dummy variable `%s' had %zu substitutions, so `%s' must also, but %zu were specified."
+msgstr "Dummy variabele `%s'  heeft %zu vervangingen, dus `%s'  moet dat ook, maar %zu zijn er gespecificeerd."
 
-#: src/language/control/repeat.c:310
-msgid "DO REPEAT without END REPEAT."
-msgstr ""
+#: src/language/control/repeat.c:366
+msgid "Ranges may only have integer bounds."
+msgstr "Bereiken mogen alleen integer grenzen hebben."
 
-#: src/language/control/repeat.c:338
-msgid "DO REPEAT may not nest in compatibility mode."
-msgstr "DO REPEAT mag niet nesten in compatibiliteitsmodus."
-
-#: src/language/control/repeat.c:440
-msgid "Ranges may only have integer bounds"
-msgstr "Bereiken mogen alleen integer grenzen hebben"
-
-#: src/language/control/repeat.c:449
+#: src/language/control/repeat.c:380
 #, c-format
-msgid "%g TO %g is an invalid range."
-msgstr "%g TO %g is een ongeldig bereik."
+msgid "%ld TO %ld is an invalid range."
+msgstr "%ld TO %ld is een ongeldig bereik."
 
-#: src/language/control/repeat.c:484
+#: src/language/control/repeat.c:414
 msgid "String expected."
 msgstr "Tekenreeks verwacht."
 
-#: src/language/control/repeat.c:503
+#: src/language/control/repeat.c:431
 msgid "No matching DO REPEAT."
 msgstr "Geen overeenkomende DO REPEAT."
 
-#: src/language/dictionary/attributes.c:108
+#: src/language/control/temporary.c:45
+msgid "This command may only appear once between procedures and procedure-like commands."
+msgstr "Deze opdracht mag slechts 1 keer voorkomen tussen procedures en procedure-achtige opdrachten."
+
+#: src/language/dictionary/attributes.c:104
 msgid "Attribute array index must be between 1 and 65535."
 msgstr "Attribuut tabel index moet minimaal 1 en maximaal 65535 zijn."
 
-#: src/language/dictionary/attributes.c:189
-#: src/language/data-io/get-data.c:314 src/language/data-io/get-data.c:352
+#: src/language/dictionary/attributes.c:200
+#: src/language/data-io/get-data.c:324 src/language/data-io/get-data.c:362
 #: src/language/data-io/get.c:99 src/language/data-io/save-translate.c:118
 #: src/language/data-io/save-translate.c:135
 #: src/language/data-io/save-translate.c:148
-#: src/language/data-io/save-translate.c:194
-#: src/language/data-io/save-translate.c:208
-#: src/language/data-io/save-translate.c:226 src/language/data-io/save.c:216
+#: src/language/data-io/save-translate.c:196
+#: src/language/data-io/save-translate.c:210
+#: src/language/data-io/save-translate.c:228 src/language/data-io/save.c:216
 #: src/language/data-io/save.c:231 src/language/data-io/save.c:259
 #, c-format
 msgid "expecting %s or %s"
@@ -1553,7 +1542,7 @@ msgstr "%s of %s verwacht"
 msgid "Variable %s is %s in target file, but %s in source file."
 msgstr "Variabele %s is %s in doelbestand, maar %s in bronbestand."
 
-#: src/language/dictionary/apply-dictionary.c:114
+#: src/language/dictionary/apply-dictionary.c:110
 msgid "No matching variables found between the source and target files."
 msgstr "Geen overeenkomende variabelen gevonden tussen het bron- en het doelbestand."
 
@@ -1561,29 +1550,29 @@ msgstr "Geen overeenkomende variabelen gevonden tussen het bron- en het doelbest
 msgid "DELETE VARIABLES may not be used after TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "DELETE VARIABLES mag niet gebruikt worden na TEMPORARY. Tijdelijke transformaties worden permanent gemaakt."
 
-#: src/language/dictionary/delete-variables.c:48
-msgid "DELETE VARIABLES may not be used to delete all variables from the active file dictionary.  Use NEW FILE instead."
+#: src/language/dictionary/delete-variables.c:47
+msgid "DELETE VARIABLES may not be used to delete all variables from the active dataset dictionary.  Use NEW FILE instead."
 msgstr "DELETE VARIABLES mag niet gebruikt om alle variabelen van het actieve bestandwoordenboek te verwijderen. Gebruik NEW FILE in de plaats."
 
-#: src/language/dictionary/formats.c:90
+#: src/language/dictionary/formats.c:87
 msgid "`(' expected after variable list."
 msgstr "'(' verwacht na variabelenlijst."
 
-#: src/language/dictionary/formats.c:100 src/language/dictionary/numeric.c:74
+#: src/language/dictionary/formats.c:97 src/language/dictionary/numeric.c:75
 msgid "`)' expected after output format."
 msgstr "')' verwacht na uitvoerindeling."
 
-#: src/language/dictionary/missing-values.c:69
+#: src/language/dictionary/missing-values.c:70
 #, c-format
 msgid "Cannot mix numeric variables (e.g. %s) and string variables (e.g. %s) within a single list."
 msgstr "Kan numerieke variabelen (b.v. %s) en tekenreeksvariabelen (b.v. %s) niet mixen binnen een enkele lijst."
 
-#: src/language/dictionary/missing-values.c:113
+#: src/language/dictionary/missing-values.c:119
 #, c-format
 msgid "Truncating missing value to maximum acceptable length (%d bytes)."
 msgstr "Afkappen ontbrekende-waarde naar maximale acceptabele lengte (%d bytes)."
 
-#: src/language/dictionary/missing-values.c:135
+#: src/language/dictionary/missing-values.c:142
 #, c-format
 msgid "Missing values provided are too long to assign to variable of width %d."
 msgstr "De opgegeven ontbrekende-waarde zijn te lang om toe te kennen aan een variabele van breedte %d."
@@ -1593,8 +1582,8 @@ msgid "MODIFY VARS may not be used after TEMPORARY.  Temporary transformations w
 msgstr "MODIFY VARS mag niet gebruikt worden na TEMPORARY. Tijdelijke transformaties zullen permanent gemaakt worden."
 
 #: src/language/dictionary/modify-variables.c:113
-#: src/language/dictionary/modify-variables.c:176
-#: src/language/data-io/inpt-pgm.c:288
+#: src/language/dictionary/modify-variables.c:177
+#: src/language/data-io/inpt-pgm.c:280
 #, c-format
 msgid "%s subcommand may be given at most once."
 msgstr "%s-subopdracht mag maximaal 1 keer gegeven worden."
@@ -1604,7 +1593,7 @@ msgid "Cannot specify ALL after specifying a set of variables."
 msgstr "Kan niet ALL opgeven na het specificeren van een set van variabelen."
 
 #: src/language/dictionary/modify-variables.c:146
-#: src/language/dictionary/modify-variables.c:189
+#: src/language/dictionary/modify-variables.c:190
 #, c-format
 msgid "`(' expected on %s subcommand."
 msgstr "'(' verwacht in %s-subopdracht."
@@ -1613,183 +1602,178 @@ msgstr "'(' verwacht in %s-subopdracht."
 msgid "`)' expected following variable names on REORDER subcommand."
 msgstr "')' verwacht achter variabelennamen in REORDER-subopdracht."
 
-#: src/language/dictionary/modify-variables.c:198
+#: src/language/dictionary/modify-variables.c:199
 msgid "`=' expected between lists of new and old variable names on RENAME subcommand."
 msgstr "'=' verwacht tussen lijst van nieuwe en oude variabelennamen in RENAME-subopdracht."
 
-#: src/language/dictionary/modify-variables.c:207
-#: src/language/dictionary/rename-variables.c:76
+#: src/language/dictionary/modify-variables.c:208
+#: src/language/dictionary/rename-variables.c:77
 #, c-format
 msgid "Differing number of variables in old name list (%zu) and in new name list (%zu)."
 msgstr "Verschillend aantal variabelen in oude naamlijst (%zu) en in de nieuwe naamlijst (%zu)."
 
-#: src/language/dictionary/modify-variables.c:218
+#: src/language/dictionary/modify-variables.c:219
 msgid "`)' expected after variable lists on RENAME subcommand."
 msgstr "')' verwacht na variabelenlijst in RENAME-subopdracht."
 
-#: src/language/dictionary/modify-variables.c:232
+#: src/language/dictionary/modify-variables.c:234
 msgid "KEEP subcommand may be given at most once.  It may not be given in conjunction with the DROP subcommand."
 msgstr "KEEP-subopdracht mag slechts eenmaal gegeven worden. Het mag niet gegeven worden in combinatie met de DROP-subopdracht."
 
-#: src/language/dictionary/modify-variables.c:275
+#: src/language/dictionary/modify-variables.c:277
 msgid "DROP subcommand may be given at most once.  It may not be given in conjunction with the KEEP subcommand."
 msgstr "DROP subopdracht mag slechts eenmaal gegeven worden. Het mag niet gegeven worden in combinatie met de KEEP-subopdracht."
 
-#: src/language/dictionary/modify-variables.c:301
+#: src/language/dictionary/modify-variables.c:303
 #, c-format
 msgid "Unrecognized subcommand name `%s'."
 msgstr "Niet-herkende subopdrachtnaam '%s'."
 
-#: src/language/dictionary/modify-variables.c:303
+#: src/language/dictionary/modify-variables.c:305
 msgid "Subcommand name expected."
 msgstr "Subopdrachtnaam verwacht."
 
-#: src/language/dictionary/modify-variables.c:311
+#: src/language/dictionary/modify-variables.c:313
 msgid "`/' or `.' expected."
 msgstr "'/' of '.' verwacht."
 
-#: src/language/dictionary/mrsets.c:98
-#, c-format
-msgid "%s is not a valid name for a multiple response set.  Multiple response set names must begin with `$'."
-msgstr ""
-
-#: src/language/dictionary/mrsets.c:120
+#: src/language/dictionary/mrsets.c:116
 #, c-format
 msgid "VARIABLES specified only variable %s on %s, but at least two variables are required."
-msgstr ""
+msgstr "VARIABLES specificeert alleen variabele %s op %s, maar tenminste twee variabelen zijn nodig."
 
-#: src/language/dictionary/mrsets.c:153
+#: src/language/dictionary/mrsets.c:149
 msgid "Numeric VALUE must be an integer."
 msgstr "Numerieke VALUE moet een integer zijn ."
 
-#: src/language/dictionary/mrsets.c:207 src/language/dictionary/mrsets.c:213
-#: src/language/dictionary/mrsets.c:223
+#: src/language/dictionary/mrsets.c:208 src/language/dictionary/mrsets.c:214
+#: src/language/dictionary/mrsets.c:224
 #, c-format
 msgid "Required %s specification missing from %s subcommand."
-msgstr ""
+msgstr "Benodigde %s specificatie ontbreekt bij %s subopdracht."
 
-#: src/language/dictionary/mrsets.c:231 src/language/dictionary/mrsets.c:269
+#: src/language/dictionary/mrsets.c:232 src/language/dictionary/mrsets.c:270
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies a string VALUE, but the variables specified for this group are numeric."
-msgstr ""
+msgstr "MDGROUP subopdracht voor groep %s specificeert een tekenreeks VALUE, maar de gespecificeerde variabelen voor deze groep zijn numeriek."
 
-#: src/language/dictionary/mrsets.c:255
+#: src/language/dictionary/mrsets.c:256
 #, c-format
 msgid "VALUE string on MDGROUP subcommand for group %s is %d bytes long, but it must be no longer than the narrowest variable in the group, which is %s with a width of %d bytes."
-msgstr ""
+msgstr "VALUE tekenreeks op MDGROUP subopdracht voor groep %s is %d bytes lang, maar het mag niet langer dan de smalste variabele in the groep zijn, dit is %s met een breedte van of %d bytes."
 
-#: src/language/dictionary/mrsets.c:281
+#: src/language/dictionary/mrsets.c:282
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies LABELSOURCE=VARLABEL but not CATEGORYLABELS=COUNTEDVALUES.  Ignoring LABELSOURCE."
-msgstr ""
+msgstr "MDGROUP subopdracht voor groep %s specificeert LABELSOURCE=VARLABEL maar niet CATEGORYLABELS=COUNTEDVALUES.  Negeert LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:287
+#: src/language/dictionary/mrsets.c:288
 #, c-format
 msgid "MDGROUP subcommand for group %s specifies both LABEL and LABELSOURCE, but only one of these subcommands may be used at a time.  Ignoring LABELSOURCE."
-msgstr ""
+msgstr "MDGROUP subopdracht voor groep %s specificeert beiden LABEL en LABELSOURCE, maar slechts een van deze subopdrachten mag tegelijkertijd gebruikt worden.  Negeert LABELSOURCE."
 
-#: src/language/dictionary/mrsets.c:327
+#: src/language/dictionary/mrsets.c:328
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s have the same variable label.  Categories represented by these variables will not be distinguishable in output."
 msgstr ""
 
-#: src/language/dictionary/mrsets.c:357
+#: src/language/dictionary/mrsets.c:358
 #, c-format
 msgid "Variable %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) has no value label for its counted value.  This category will not be distinguishable in output."
 msgstr ""
 
-#: src/language/dictionary/mrsets.c:370
+#: src/language/dictionary/mrsets.c:371
 #, c-format
 msgid "Variables %s and %s specified as part of multiple dichotomy group %s (which has CATEGORYLABELS=COUNTEDVALUES) have the same value label for the the group's counted value.  These categories will not be distinguishable in output."
 msgstr ""
 
-#: src/language/dictionary/mrsets.c:427
+#: src/language/dictionary/mrsets.c:428
 #, c-format
 msgid "Variables specified on MCGROUP should have the same categories, but %s and %s (and possibly others) in multiple category group %s have different value labels for value %s."
 msgstr ""
 
-#: src/language/dictionary/mrsets.c:484
+#: src/language/dictionary/mrsets.c:486
 #, c-format
 msgid "No multiple response set named %s."
 msgstr "Geen meerdere-antwoord-set genaamd %s."
 
-#: src/language/dictionary/mrsets.c:538
-msgid "The active file dictionary does not contain any multiple response sets."
-msgstr "Het actieve bestandswoordenboek bevat geen meerdere-antwoord-sets."
+#: src/language/dictionary/mrsets.c:540
+msgid "The active dataset dictionary does not contain any multiple response sets."
+msgstr "Het actieve dataset-woordenboek bevat geen meerdere-antwoord-sets."
 
-#: src/language/dictionary/mrsets.c:548
+#: src/language/dictionary/mrsets.c:550
 msgid "Multiple Response Sets"
-msgstr ""
+msgstr "Meervoudige Response Sets"
 
-#: src/language/dictionary/mrsets.c:549 src/ui/gui/psppire-var-sheet.c:534
-#: src/ui/gui/psppire-var-store.c:832
+#: src/language/dictionary/mrsets.c:551 src/ui/gui/psppire-var-sheet.c:534
+#: src/ui/gui/psppire-var-store.c:833
 msgid "Name"
 msgstr "Naam"
 
-#: src/language/dictionary/mrsets.c:550 src/ui/gui/variable-info.ui:8
+#: src/language/dictionary/mrsets.c:552 src/ui/gui/variable-info.ui:8
 msgid "Variables"
 msgstr "Variabelen"
 
-#: src/language/dictionary/mrsets.c:551
+#: src/language/dictionary/mrsets.c:553
 msgid "Details"
 msgstr "Aflopende frequentie "
 
-#: src/language/dictionary/mrsets.c:565
+#: src/language/dictionary/mrsets.c:567
 msgid "Multiple dichotomy set"
 msgstr ""
 
-#: src/language/dictionary/mrsets.c:566
+#: src/language/dictionary/mrsets.c:568
 msgid "Multiple category set"
-msgstr ""
+msgstr "Meervoudige categorie set"
 
-#: src/language/dictionary/mrsets.c:568
+#: src/language/dictionary/mrsets.c:570
 #: src/language/dictionary/split-file.c:84
-#: src/language/dictionary/sys-file-info.c:343
-#: src/language/dictionary/sys-file-info.c:582
-#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:836
+#: src/language/dictionary/sys-file-info.c:336
+#: src/language/dictionary/sys-file-info.c:575
+#: src/ui/gui/psppire-var-sheet.c:538 src/ui/gui/psppire-var-store.c:837
 #: src/ui/gui/compute.ui:467 src/ui/gui/crosstabs.ui:292
 msgid "Label"
 msgstr "Label"
 
-#: src/language/dictionary/mrsets.c:572
+#: src/language/dictionary/mrsets.c:574
 msgid "Label source"
 msgstr "Label bron"
 
-#: src/language/dictionary/mrsets.c:574
+#: src/language/dictionary/mrsets.c:576
 msgid "First variable label among variables"
 msgstr "Eerste variabele label tussen variabelen"
 
-#: src/language/dictionary/mrsets.c:575
+#: src/language/dictionary/mrsets.c:577
 msgid "Provided by user"
 msgstr "Verstrekt door gebruiker"
 
-#: src/language/dictionary/mrsets.c:576
+#: src/language/dictionary/mrsets.c:578
 msgid "Counted value"
 msgstr "Getelde waarde "
 
-#: src/language/dictionary/mrsets.c:582
+#: src/language/dictionary/mrsets.c:590
 msgid "Category label source"
-msgstr ""
+msgstr "categorie label bron"
 
-#: src/language/dictionary/mrsets.c:584
+#: src/language/dictionary/mrsets.c:592
 msgid "Variable labels"
 msgstr "Variabelelabels"
 
-#: src/language/dictionary/mrsets.c:585
+#: src/language/dictionary/mrsets.c:593
 msgid "Value labels of counted value"
 msgstr "Waardelabel van getelde waarde"
 
-#: src/language/dictionary/numeric.c:67
+#: src/language/dictionary/numeric.c:68
 #, c-format
 msgid "Format type %s may not be used with a numeric variable."
 msgstr "Opmaaktype %s mag niet gebruikt worden met een numerieke variabele."
 
-#: src/language/dictionary/numeric.c:86 src/language/dictionary/numeric.c:155
+#: src/language/dictionary/numeric.c:87 src/language/dictionary/numeric.c:157
 #, c-format
 msgid "There is already a variable named %s."
 msgstr "Er bestaat al een variabele genaamd %s."
 
-#: src/language/dictionary/numeric.c:140
+#: src/language/dictionary/numeric.c:142
 #, c-format
 msgid "Format type %s may not be used with a string variable."
 msgstr "Opmaaktype %s mag niet gebruikt worden met een tekenreeksvariabele."
@@ -1806,22 +1790,23 @@ msgstr "'(' verwacht."
 msgid "`=' expected between lists of new and old variable names."
 msgstr "'=' verwacht tussen lijst met nieuwe en oude variabelennamen."
 
-#: src/language/dictionary/rename-variables.c:87
+#: src/language/dictionary/rename-variables.c:88
 msgid "`)' expected after variable names."
 msgstr "')' verwacht achter variabelennamen."
 
-#: src/language/dictionary/rename-variables.c:97
+#: src/language/dictionary/rename-variables.c:98
 #, c-format
 msgid "Renaming would duplicate variable name %s."
 msgstr "Hernoemen zou variabelennaam %s dupliceren."
 
 #: src/language/dictionary/split-file.c:83
-#: src/language/dictionary/sys-file-info.c:428
-#: src/language/dictionary/sys-file-info.c:581
-#: src/language/stats/reliability.c:758 src/language/stats/reliability.c:769
-#: src/language/stats/crosstabs.q:1206 src/language/stats/crosstabs.q:1233
-#: src/language/stats/crosstabs.q:1256 src/language/stats/crosstabs.q:1281
-#: src/language/stats/examine.q:1841 src/language/stats/frequencies.q:813
+#: src/language/dictionary/sys-file-info.c:421
+#: src/language/dictionary/sys-file-info.c:574
+#: src/language/stats/cochran.c:170 src/language/stats/reliability.c:753
+#: src/language/stats/reliability.c:764 src/language/stats/crosstabs.q:1234
+#: src/language/stats/crosstabs.q:1261 src/language/stats/crosstabs.q:1284
+#: src/language/stats/crosstabs.q:1309 src/language/stats/examine.q:1840
+#: src/language/stats/frequencies.q:821
 msgid "Value"
 msgstr "Waarde"
 
@@ -1846,6 +1831,14 @@ msgstr "Aangemaakt:"
 msgid "Integer Format:"
 msgstr "Integeropmaak"
 
+#: src/language/dictionary/sys-file-info.c:108
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#: src/language/dictionary/sys-file-info.c:109
+msgid "Little Endian"
+msgstr "Little Endian"
+
 #: src/language/dictionary/sys-file-info.c:110
 #: src/language/dictionary/sys-file-info.c:118
 #: src/language/dictionary/sys-file-info.c:123
@@ -1891,7 +1884,7 @@ msgid "Type:"
 msgstr "Type:"
 
 #: src/language/dictionary/sys-file-info.c:127
-#: src/ui/gui/psppire-data-window.c:635
+#: src/ui/gui/psppire-data-window.c:509
 msgid "System File"
 msgstr "Systeembestand"
 
@@ -1925,155 +1918,148 @@ msgid "Charset:"
 msgstr "Tekenset:"
 
 #: src/language/dictionary/sys-file-info.c:150
-#: src/language/dictionary/sys-file-info.c:343
+#: src/language/dictionary/sys-file-info.c:336
 msgid "Description"
 msgstr "Omschrijving"
 
 #: src/language/dictionary/sys-file-info.c:151
-#: src/language/dictionary/sys-file-info.c:345
-#: src/language/dictionary/sys-file-info.c:662
+#: src/language/dictionary/sys-file-info.c:338
+#: src/language/dictionary/sys-file-info.c:645
 msgid "Position"
 msgstr "Positie"
 
 #: src/language/dictionary/sys-file-info.c:198
-msgid "The active file does not have a file label."
-msgstr "Het actieve bestand heeft geen bestandlabel."
+msgid "The active dataset does not have a file label."
+msgstr "De actieve dataset heeft geen bestandslabel."
 
-#: src/language/dictionary/sys-file-info.c:201
-msgid "File label:"
-msgstr "Bestandlabel:"
+#: src/language/dictionary/sys-file-info.c:200
+#, c-format
+msgid "File label: %s"
+msgstr "Bestandlabel: %s"
 
-#: src/language/dictionary/sys-file-info.c:276
+#: src/language/dictionary/sys-file-info.c:274
 msgid "No variables to display."
 msgstr "Geen variabelen om te tonen."
 
-#: src/language/dictionary/sys-file-info.c:290
+#: src/language/dictionary/sys-file-info.c:288
 msgid "Macros not supported."
 msgstr "Macro's worden niet ondersteund."
 
-#: src/language/dictionary/sys-file-info.c:299
-msgid "The active file dictionary does not contain any documents."
-msgstr "Het actieve bestandwoordenboek bevat geen documenten."
+#: src/language/dictionary/sys-file-info.c:297
+msgid "The active dataset dictionary does not contain any documents."
+msgstr "Het actieve dataset-woordenboek bevat geen documenten."
 
-#: src/language/dictionary/sys-file-info.c:307
-msgid "Documents in the active file:"
-msgstr "Documenten in het actieve bestand:"
+#: src/language/dictionary/sys-file-info.c:304
+msgid "Documents in the active dataset:"
+msgstr "Documenten in de actieve dataset:"
 
-#: src/language/dictionary/sys-file-info.c:427
+#: src/language/dictionary/sys-file-info.c:420
 msgid "Attribute"
 msgstr "Attribuut"
 
-#: src/language/dictionary/sys-file-info.c:483
+#: src/language/dictionary/sys-file-info.c:476
 #, c-format
 msgid "Format: %s"
 msgstr "Indeling: %s"
 
-#: src/language/dictionary/sys-file-info.c:490
+#: src/language/dictionary/sys-file-info.c:483
 #, c-format
 msgid "Print Format: %s"
 msgstr "Afdrukindeling: %s"
 
-#: src/language/dictionary/sys-file-info.c:494
+#: src/language/dictionary/sys-file-info.c:487
 #, c-format
 msgid "Write Format: %s"
 msgstr "Schrijfindeling: %s"
 
-#: src/language/dictionary/sys-file-info.c:507
+#: src/language/dictionary/sys-file-info.c:500
 #, c-format
 msgid "Measure: %s"
 msgstr "Meting: %s"
 
-#: src/language/dictionary/sys-file-info.c:508
+#: src/language/dictionary/sys-file-info.c:501
 #: src/ui/gui/psppire-var-sheet.c:111
 msgid "Nominal"
 msgstr "Nominaal"
 
-#: src/language/dictionary/sys-file-info.c:509
+#: src/language/dictionary/sys-file-info.c:502
 #: src/ui/gui/psppire-var-sheet.c:112
 msgid "Ordinal"
 msgstr "Ordinaal"
 
-#: src/language/dictionary/sys-file-info.c:510
+#: src/language/dictionary/sys-file-info.c:503
 #: src/ui/gui/psppire-var-sheet.c:113
 msgid "Scale"
 msgstr "Schaal"
 
-#: src/language/dictionary/sys-file-info.c:513
+#: src/language/dictionary/sys-file-info.c:506
 #, c-format
 msgid "Display Alignment: %s"
 msgstr "Toongroepering: %s"
 
-#: src/language/dictionary/sys-file-info.c:514
+#: src/language/dictionary/sys-file-info.c:507
 #: src/ui/gui/psppire-var-sheet.c:104
 msgid "Left"
 msgstr "Links"
 
-#: src/language/dictionary/sys-file-info.c:515
+#: src/language/dictionary/sys-file-info.c:508
 #: src/ui/gui/psppire-var-sheet.c:106
 msgid "Center"
 msgstr "Centreer"
 
-#: src/language/dictionary/sys-file-info.c:516
+#: src/language/dictionary/sys-file-info.c:509
 #: src/ui/gui/psppire-var-sheet.c:105
 msgid "Right"
 msgstr "Rechts"
 
-#: src/language/dictionary/sys-file-info.c:519
+#: src/language/dictionary/sys-file-info.c:512
 #, c-format
 msgid "Display Width: %d"
 msgstr "Toonbreedte: %d"
 
-#: src/language/dictionary/sys-file-info.c:533
+#: src/language/dictionary/sys-file-info.c:526
 msgid "Missing Values: "
 msgstr "Ontbrekende waardes: "
 
-#: src/language/dictionary/sys-file-info.c:642
+#: src/language/dictionary/sys-file-info.c:625
 msgid "No vectors defined."
 msgstr "Geen vectoren gedefinieerd."
 
-#: src/language/dictionary/sys-file-info.c:661
+#: src/language/dictionary/sys-file-info.c:644
 msgid "Vector"
 msgstr "Vector"
 
-#: src/language/dictionary/sys-file-info.c:664
+#: src/language/dictionary/sys-file-info.c:647
 msgid "Print Format"
 msgstr "Afdrukindeling"
 
-#: src/language/dictionary/value-labels.c:149
-msgid "Truncating value label to 60 characters."
-msgstr "Waardelabel is afgekapt tot 60 tekens."
-
-#: src/language/dictionary/variable-label.c:58
-msgid "Truncating variable label to 255 characters."
-msgstr "Variabelenlabel is afgekapt tot 255 tekens."
+#: src/language/dictionary/value-labels.c:154
+#, c-format
+msgid "Truncating value label to %d bytes."
+msgstr "Afkappen waarde label tot %d bytes."
 
-#: src/language/dictionary/vector.c:64
+#: src/language/dictionary/vector.c:65
 #, c-format
 msgid "A vector named %s already exists."
 msgstr "Een vector genaamd %s bestaat al."
 
-#: src/language/dictionary/vector.c:72
+#: src/language/dictionary/vector.c:73
 #, c-format
 msgid "Vector name %s is given twice."
 msgstr "Vector genaamd %s is 2 keer opgegeven."
 
-#: src/language/dictionary/vector.c:96
+#: src/language/dictionary/vector.c:97
 msgid "A slash must separate each vector specification in VECTOR's long form."
 msgstr "Een '/' moet elke vector specificatie scheiden in VECTOR's lange vorm."
 
-#: src/language/dictionary/vector.c:129
+#: src/language/dictionary/vector.c:130
 msgid "Vectors must have at least one element."
 msgstr "Vectoren moeten tenminste 1 element bevatten."
 
-#: src/language/dictionary/vector.c:150
+#: src/language/dictionary/vector.c:151
 msgid "expecting vector length"
 msgstr "vectorlengte verwacht"
 
-#: src/language/dictionary/vector.c:166
-#, c-format
-msgid "%s is too long for a variable name."
-msgstr "%s is te lang voor een variabelennaam."
-
 #: src/language/dictionary/vector.c:171
 #, c-format
 msgid "%s is an existing variable name."
@@ -2091,290 +2077,268 @@ msgstr "De wegingvariabele moet numeriek zijn."
 msgid "The weighting variable may not be scratch."
 msgstr "De wegingvariabele mag geen scratch zijn."
 
-#: src/language/tests/float-format.c:124
-#, c-format
-msgid "%zu-byte string needed but %zu-byte string supplied."
-msgstr "%zu-byte tekenreeks nodig maar %zu-byte tekenreeks gegeven."
-
-#: src/language/tests/float-format.c:136
-msgid "Hexadecimal floating constant too long."
-msgstr "Hexadecimale drijvende constante te lang."
-
-#: src/language/tests/float-format.c:201
-#, c-format
-msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
-msgstr "%s conversie van %s van %s naar %s zou %s moeten produceren maar produceerde in werkelijkheid %s."
-
-#: src/language/tests/float-format.c:247
-msgid "Too many values in single command."
-msgstr "Te veel waardes in enkele opdracht."
-
-#: src/language/tests/moments-test.c:47
+#: src/language/tests/moments-test.c:50
 msgid "expecting weight value"
 msgstr "verwacht wegingwaarde"
 
-#: src/language/utilities/cd.c:41
+#: src/language/utilities/cd.c:45
 #, c-format
 msgid "Cannot change directory to %s:  %s "
 msgstr "Kan map niet veranderen in %s: %s "
 
-#: src/language/utilities/date.c:32
+#: src/language/utilities/date.c:33
 msgid "Only USE ALL is currently implemented."
 msgstr "Alleen USE ALL is op dit moment geïmplementeerd."
 
-#: src/language/utilities/host.c:85
+#: src/language/utilities/host.c:87
 #, c-format
 msgid "Couldn't fork: %s."
 msgstr ""
 
-#: src/language/utilities/host.c:100
+#: src/language/utilities/host.c:102
 msgid "Interactive shell not supported on this platform."
 msgstr "Interactieve-shell niet ondersteund op dit platform."
 
-#: src/language/utilities/host.c:112
+#: src/language/utilities/host.c:114
 msgid "Command shell not supported on this platform."
 msgstr "Opdracht-shell niet ondersteund op dit platform."
 
-#: src/language/utilities/host.c:118
+#: src/language/utilities/host.c:120
 #, c-format
 msgid "Error executing command: %s."
 msgstr "Fout tijdens uitvoeren opdracht: %s."
 
-#: src/language/utilities/title.c:103
+#: src/language/utilities/title.c:97
 #, c-format
 msgid "   (Entered %s)"
 msgstr "   (Ingevoerd %s)"
 
-#: src/language/utilities/include.c:94 src/language/utilities/include.c:112
-#: src/language/utilities/include.c:130
-#, fuzzy, c-format
-msgid "expecting %s or %s after %s"
-msgstr "%s of %s verwacht"
-
-#: src/language/utilities/include.c:138
-#, c-format
-msgid "Unexpected token: `%s'."
-msgstr "Onverwacht symbool: '%s'."
-
-#: src/language/utilities/include.c:183
+#: src/language/utilities/include.c:65
 msgid "expecting file name"
 msgstr "bestandsnaam verwacht"
 
-#: src/language/utilities/include.c:195
+#: src/language/utilities/include.c:75
 #, c-format
 msgid "Can't find `%s' in include file search path."
 msgstr "Kan '%s' niet vinden in include-bestand zoekpad."
 
-#: src/language/utilities/include.c:203
+#: src/language/utilities/include.c:109
 #, c-format
-msgid "Unable to open `%s': %s."
-msgstr "Onmogelijk om te openen '%s': %s."
+msgid "expecting %s, %s, or %s after %s"
+msgstr "verwacht %s, %s, of %s na %s"
 
-#: src/language/utilities/permissions.c:76
+#: src/language/utilities/include.c:127 src/language/utilities/include.c:145
+#, c-format
+msgid "expecting %s or %s after %s"
+msgstr "verwacht %s of %s na %s"
+
+#: src/language/utilities/permissions.c:78
 #, c-format
 msgid "Expecting %s or %s."
 msgstr "Verwacht %s of %s."
 
-#: src/language/utilities/permissions.c:109
+#: src/language/utilities/permissions.c:113
 #, c-format
 msgid "Cannot stat %s: %s"
 msgstr ""
 
-#: src/language/utilities/permissions.c:122
+#: src/language/utilities/permissions.c:127
 #, c-format
 msgid "Cannot change mode of %s: %s"
 msgstr "Kan modus van %s niet veranderen: %s"
 
-#: src/language/stats/aggregate.c:94
+#: src/language/stats/aggregate.c:95
 msgid "Sum of values"
 msgstr "Som van waardes"
 
-#: src/language/stats/aggregate.c:95
+#: src/language/stats/aggregate.c:96
 msgid "Mean average"
 msgstr ""
 
-#: src/language/stats/aggregate.c:96
+#: src/language/stats/aggregate.c:97
 msgid "Median average"
 msgstr "Mediaan gemiddelde"
 
-#: src/language/stats/aggregate.c:97 src/ui/gui/descriptives-dialog.c:41
-#: src/ui/gui/frequencies-dialog.c:42
+#: src/language/stats/aggregate.c:98 src/ui/gui/descriptives-dialog.c:40
+#: src/ui/gui/frequencies-dialog.c:41
 msgid "Standard deviation"
 msgstr "Standarddeviatie"
 
-#: src/language/stats/aggregate.c:98
+#: src/language/stats/aggregate.c:99
 msgid "Maximum value"
 msgstr "Maximum waarde"
 
-#: src/language/stats/aggregate.c:99
+#: src/language/stats/aggregate.c:100
 msgid "Minimum value"
 msgstr "Minimum waarde"
 
-#: src/language/stats/aggregate.c:100
+#: src/language/stats/aggregate.c:101
 msgid "Percentage greater than"
-msgstr ""
+msgstr "Percentage groter dan"
 
-#: src/language/stats/aggregate.c:101
+#: src/language/stats/aggregate.c:102
 msgid "Percentage less than"
 msgstr "Percentage kleiner dan"
 
-#: src/language/stats/aggregate.c:102
+#: src/language/stats/aggregate.c:103
 msgid "Percentage included in range"
 msgstr ""
 
-#: src/language/stats/aggregate.c:103
+#: src/language/stats/aggregate.c:104
 msgid "Percentage excluded from range"
 msgstr ""
 
-#: src/language/stats/aggregate.c:104
+#: src/language/stats/aggregate.c:105
 msgid "Fraction greater than"
 msgstr ""
 
-#: src/language/stats/aggregate.c:105
+#: src/language/stats/aggregate.c:106
 msgid "Fraction less than"
 msgstr "Fractie kleiner dan"
 
-#: src/language/stats/aggregate.c:106
+#: src/language/stats/aggregate.c:107
 msgid "Fraction included in range"
 msgstr ""
 
-#: src/language/stats/aggregate.c:107
+#: src/language/stats/aggregate.c:108
 msgid "Fraction excluded from range"
 msgstr ""
 
-#: src/language/stats/aggregate.c:108
+#: src/language/stats/aggregate.c:109
 msgid "Number of cases"
 msgstr "Aantal cases"
 
-#: src/language/stats/aggregate.c:109
+#: src/language/stats/aggregate.c:110
 msgid "Number of cases (unweighted)"
 msgstr "Aantal cases (ongewogen)"
 
-#: src/language/stats/aggregate.c:110
+#: src/language/stats/aggregate.c:111
 msgid "Number of missing values"
 msgstr "Aantal missende waardes"
 
-#: src/language/stats/aggregate.c:111
+#: src/language/stats/aggregate.c:112
 msgid "Number of missing values (unweighted)"
 msgstr "Aantal ontbrekende waardes (ongewogen)"
 
-#: src/language/stats/aggregate.c:112
+#: src/language/stats/aggregate.c:113
 msgid "First non-missing value"
 msgstr "Eerste niet-ontbrekende waarde"
 
-#: src/language/stats/aggregate.c:113
+#: src/language/stats/aggregate.c:114
 msgid "Last non-missing value"
 msgstr "Laatste niet-ontbrekende waarde"
 
-#: src/language/stats/aggregate.c:225 src/language/data-io/get-data.c:461
-#, fuzzy, c-format
+#: src/language/stats/aggregate.c:226 src/language/data-io/get-data.c:473
+#, c-format
 msgid "expecting %s"
-msgstr "verwacht '%s'"
+msgstr "verwacht  %s"
 
-#: src/language/stats/aggregate.c:256
+#: src/language/stats/aggregate.c:257
 msgid "When PRESORTED is specified, specifying sorting directions with (A) or (D) has no effect.  Output data will be sorted the same way as the input data."
 msgstr "Als PRESORTED is gespecificeerd, heeft specificeren van sorteervolgorde met (A) of (D) geen effect. Uitvoergegevens zullen hetzelfde gesorteerd zijn als de invoergegevens."
 
-#: src/language/stats/aggregate.c:450
+#: src/language/stats/aggregate.c:447
 msgid "expecting aggregation function"
 msgstr "aggregatie-functie verwacht"
 
-#: src/language/stats/aggregate.c:462
+#: src/language/stats/aggregate.c:459
 #, c-format
 msgid "Unknown aggregation function %s."
 msgstr "Onbekende aggregatie functie %s."
 
-#: src/language/stats/aggregate.c:514
+#: src/language/stats/aggregate.c:513
 #, c-format
 msgid "Missing argument %zu to %s."
 msgstr "Mis argument %zu naar %s."
 
-#: src/language/stats/aggregate.c:523
+#: src/language/stats/aggregate.c:522
 #, c-format
 msgid "Arguments to %s must be of same type as source variables."
 msgstr "Argumenten naar %s moeten van hetzelfde type zijn als bronvariabelen."
 
-#: src/language/stats/aggregate.c:542
+#: src/language/stats/aggregate.c:541
 #, c-format
 msgid "Number of source variables (%zu) does not match number of target variables (%zu)."
 msgstr "Aantal bronvariabelen (%zu) komt niet overeen met aantal doelvariabelen (%zu)."
 
-#: src/language/stats/aggregate.c:558
+#: src/language/stats/aggregate.c:557
 #, c-format
 msgid "The value arguments passed to the %s function are out-of-order.  They will be treated as if they had been specified in the correct order."
 msgstr "De volgorde van de geldige argumenten doorgegeven aan de %s functie klopt niet. Ze worden behandeld alsof ze in de correcte volgorde waren opgegeven."
 
-#: src/language/stats/aggregate.c:632
+#: src/language/stats/aggregate.c:631
 #, c-format
 msgid "Variable name %s is not unique within the aggregate file dictionary, which contains the aggregate variables and the break variables."
 msgstr "Variabelennaam %s is niet uniek binnen het aggregate-bestandwoordenboek, dat de aggregate- en break-variabelen bevat."
 
-#: src/language/stats/autorecode.c:127
+#: src/language/stats/autorecode.c:128
 #, c-format
 msgid "Source variable count (%zu) does not match target variable count (%zu)."
 msgstr "Bron-variabelenteller (%zu) komt niet overeen met doel-variabelenteller (%zu)."
 
-#: src/language/stats/autorecode.c:139
+#: src/language/stats/autorecode.c:140
 #, c-format
 msgid "Target variable %s duplicates existing variable %s."
 msgstr "Doelvariabele %s dupliceert bestaande variabele %s."
 
-#: src/language/stats/binomial.c:139
+#: src/language/stats/binomial.c:136
 #, c-format
 msgid "Variable %s is not dichotomous"
 msgstr "Variabele %s is niet dichotomisch "
 
-#: src/language/stats/binomial.c:190 src/ui/gui/binomial.ui:13
+#: src/language/stats/binomial.c:187 src/ui/gui/binomial.ui:13
 msgid "Binomial Test"
 msgstr "Binomiaal Test"
 
-#: src/language/stats/binomial.c:220
+#: src/language/stats/binomial.c:217
 msgid "Group1"
 msgstr "Groep1 "
 
-#: src/language/stats/binomial.c:221
+#: src/language/stats/binomial.c:218
 msgid "Group2"
 msgstr "Groep2"
 
-#: src/language/stats/binomial.c:222 src/language/stats/chisquare.c:177
-#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1464
-#: src/language/stats/glm.c:343 src/language/stats/kruskal-wallis.c:294
-#: src/language/stats/oneway.c:776 src/language/stats/oneway.c:946
-#: src/language/stats/reliability.c:538 src/language/stats/sign.c:93
-#: src/language/stats/wilcoxon.c:255 src/ui/gui/crosstabs-dialog.c:60
-#: src/language/stats/crosstabs.q:815 src/language/stats/crosstabs.q:1143
-#: src/language/stats/crosstabs.q:1522 src/language/stats/examine.q:1105
-#: src/language/stats/frequencies.q:871 src/language/stats/regression.q:291
+#: src/language/stats/binomial.c:219 src/language/stats/chisquare.c:177
+#: src/language/stats/chisquare.c:236 src/language/stats/factor.c:1460
+#: src/language/stats/kruskal-wallis.c:292
+#: src/language/stats/mann-whitney.c:188 src/language/stats/oneway.c:616
+#: src/language/stats/oneway.c:786 src/language/stats/reliability.c:533
+#: src/language/stats/sign.c:95 src/language/stats/wilcoxon.c:255
+#: src/ui/gui/crosstabs-dialog.c:59 src/language/stats/crosstabs.q:832
+#: src/language/stats/crosstabs.q:1176 src/language/stats/crosstabs.q:1560
+#: src/language/stats/examine.q:1104 src/language/stats/frequencies.q:879
+#: src/language/stats/regression.q:293
 msgid "Total"
 msgstr "Totaal"
 
-#: src/language/stats/binomial.c:255 src/language/stats/chisquare.c:199
-#: src/language/stats/crosstabs.q:1231 src/language/stats/crosstabs.q:1278
+#: src/language/stats/binomial.c:252 src/language/stats/chisquare.c:199
+#: src/language/stats/crosstabs.q:1259 src/language/stats/crosstabs.q:1306
 msgid "Category"
 msgstr "Categorie"
 
-#: src/language/stats/binomial.c:256 src/language/stats/correlations.c:119
-#: src/language/stats/correlations.c:227
-#: src/language/stats/kruskal-wallis.c:259
-#: src/language/stats/npar-summary.c:120 src/language/stats/oneway.c:846
-#: src/language/stats/reliability.c:541 src/language/stats/sign.c:72
-#: src/language/stats/wilcoxon.c:238 src/language/stats/crosstabs.q:822
-#: src/language/stats/examine.q:1176 src/language/stats/frequencies.q:1034
-#: src/language/stats/t-test.q:505 src/language/stats/t-test.q:525
-#: src/language/stats/t-test.q:625 src/language/stats/t-test.q:1101
+#: src/language/stats/binomial.c:253 src/language/stats/cochran.c:211
+#: src/language/stats/correlations.c:120 src/language/stats/correlations.c:228
+#: src/language/stats/friedman.c:275 src/language/stats/kruskal-wallis.c:257
+#: src/language/stats/mann-whitney.c:190 src/language/stats/npar-summary.c:123
+#: src/language/stats/oneway.c:686 src/language/stats/reliability.c:536
+#: src/language/stats/sign.c:74 src/language/stats/wilcoxon.c:238
+#: src/language/stats/crosstabs.q:839 src/language/stats/examine.q:1175
+#: src/language/stats/frequencies.q:1041 src/language/stats/t-test.q:509
+#: src/language/stats/t-test.q:529 src/language/stats/t-test.q:629
+#: src/language/stats/t-test.q:1105
 msgid "N"
 msgstr "N"
 
-#: src/language/stats/binomial.c:257
+#: src/language/stats/binomial.c:254
 msgid "Observed Prop."
-msgstr ""
+msgstr "Observed Prop."
 
-#: src/language/stats/binomial.c:258
+#: src/language/stats/binomial.c:255
 msgid "Test Prop."
-msgstr ""
+msgstr "Test Prop."
 
-#: src/language/stats/binomial.c:261 src/language/stats/crosstabs.q:1211
-#: src/language/stats/crosstabs.q:1213
+#: src/language/stats/binomial.c:258 src/language/stats/crosstabs.q:1239
+#: src/language/stats/crosstabs.q:1241
 #, c-format
 msgid "Exact Sig. (%d-tailed)"
 msgstr ""
@@ -2393,649 +2357,705 @@ msgid "Expected N"
 msgstr "Verwacht N"
 
 #: src/language/stats/chisquare.c:163 src/language/stats/chisquare.c:202
-#: src/ui/gui/crosstabs-dialog.c:62 src/language/stats/regression.q:290
+#: src/ui/gui/crosstabs-dialog.c:61 src/language/stats/regression.q:292
 msgid "Residual"
 msgstr "Overblijvend"
 
-#: src/language/stats/chisquare.c:195 src/language/stats/sign.c:60
-#: src/ui/gui/frequencies.ui:9 src/ui/gui/frequencies.ui:669
+#: src/language/stats/chisquare.c:195 src/language/stats/cochran.c:159
+#: src/language/stats/sign.c:62 src/ui/gui/frequencies.ui:9
+#: src/ui/gui/frequencies.ui:669
 msgid "Frequencies"
 msgstr "Frequenties"
 
-#: src/language/stats/chisquare.c:249 src/language/stats/kruskal-wallis.c:312
-#: src/language/stats/sign.c:112 src/language/stats/wilcoxon.c:304
+#: src/language/stats/chisquare.c:249 src/language/stats/cochran.c:208
+#: src/language/stats/friedman.c:272 src/language/stats/kruskal-wallis.c:310
+#: src/language/stats/mann-whitney.c:251 src/language/stats/sign.c:114
+#: src/language/stats/wilcoxon.c:304
 msgid "Test Statistics"
 msgstr "Test Statistieken"
 
-#: src/language/stats/chisquare.c:263 src/language/stats/kruskal-wallis.c:315
+#: src/language/stats/chisquare.c:263 src/language/stats/friedman.c:282
+#: src/language/stats/kruskal-wallis.c:313
 msgid "Chi-Square"
 msgstr "Chi-Square"
 
-#: src/language/stats/chisquare.c:264 src/language/stats/glm.c:308
-#: src/language/stats/kruskal-wallis.c:318 src/language/stats/oneway.c:753
-#: src/language/stats/oneway.c:1165 src/language/stats/crosstabs.q:1207
-#: src/language/stats/regression.q:284 src/language/stats/t-test.q:752
-#: src/language/stats/t-test.q:923 src/language/stats/t-test.q:1010
+#: src/language/stats/chisquare.c:264 src/language/stats/cochran.c:217
+#: src/language/stats/friedman.c:285 src/language/stats/kruskal-wallis.c:316
+#: src/language/stats/oneway.c:593 src/language/stats/oneway.c:1002
+#: src/language/stats/crosstabs.q:1235 src/language/stats/regression.q:286
+#: src/language/stats/t-test.q:756 src/language/stats/t-test.q:927
+#: src/language/stats/t-test.q:1014
 msgid "df"
 msgstr "df"
 
-#: src/language/stats/chisquare.c:265 src/language/stats/kruskal-wallis.c:321
+#: src/language/stats/chisquare.c:265 src/language/stats/cochran.c:220
+#: src/language/stats/friedman.c:288 src/language/stats/kruskal-wallis.c:319
 msgid "Asymp. Sig."
-msgstr ""
+msgstr "Asymp. Sig."
+
+#: src/language/stats/cochran.c:109
+msgid "More than two values encountered.  Cochran Q test will not be run."
+msgstr "Meer dan 2 waardes gevonden.  Cochran Q test wordt niet uitgevoerd."
+
+#: src/language/stats/cochran.c:172
+#, c-format
+msgid "Success (%g)"
+msgstr "Succes (%g)"
+
+#: src/language/stats/cochran.c:173
+#, c-format
+msgid "Failure (%g)"
+msgstr "Fout (%g)"
+
+#: src/language/stats/cochran.c:214
+msgid "Cochran's Q"
+msgstr "Cochran's Q"
 
-#: src/language/stats/correlations.c:96 src/language/stats/factor.c:1728
-#: src/language/stats/npar-summary.c:106
+#: src/language/stats/correlations.c:97 src/language/stats/factor.c:1724
+#: src/language/stats/npar-summary.c:109
 msgid "Descriptive Statistics"
 msgstr "Descriptieve Statistieken"
 
-#: src/language/stats/correlations.c:117 src/language/stats/descriptives.c:101
-#: src/language/stats/factor.c:1749 src/language/stats/npar-summary.c:123
-#: src/language/stats/oneway.c:847 src/ui/gui/descriptives-dialog.c:40
-#: src/ui/gui/frequencies-dialog.c:41 src/language/stats/examine.q:1444
-#: src/language/stats/frequencies.q:105 src/language/stats/t-test.q:506
-#: src/language/stats/t-test.q:526 src/language/stats/t-test.q:624
-#: src/language/stats/t-test.q:917
+#: src/language/stats/correlations.c:118 src/language/stats/descriptives.c:102
+#: src/language/stats/factor.c:1745 src/language/stats/npar-summary.c:126
+#: src/language/stats/oneway.c:687 src/ui/gui/descriptives-dialog.c:39
+#: src/ui/gui/frequencies-dialog.c:40 src/language/stats/examine.q:1443
+#: src/language/stats/frequencies.q:105 src/language/stats/t-test.q:510
+#: src/language/stats/t-test.q:530 src/language/stats/t-test.q:628
+#: src/language/stats/t-test.q:921
 msgid "Mean"
 msgstr "Gemiddelde "
 
-#: src/language/stats/correlations.c:118 src/language/stats/factor.c:1750
-#: src/language/stats/npar-summary.c:126 src/language/stats/oneway.c:848
-#: src/language/stats/examine.q:1479 src/language/stats/t-test.q:507
-#: src/language/stats/t-test.q:527 src/language/stats/t-test.q:626
-#: src/language/stats/t-test.q:918
+#: src/language/stats/correlations.c:119 src/language/stats/factor.c:1746
+#: src/language/stats/npar-summary.c:129 src/language/stats/oneway.c:688
+#: src/language/stats/examine.q:1478 src/language/stats/t-test.q:511
+#: src/language/stats/t-test.q:531 src/language/stats/t-test.q:630
+#: src/language/stats/t-test.q:922
 msgid "Std. Deviation"
 msgstr "Std. Deviatie"
 
-#: src/language/stats/correlations.c:190 src/language/stats/factor.c:1622
+#: src/language/stats/correlations.c:191 src/language/stats/factor.c:1618
 msgid "Correlations"
 msgstr "Correlatie"
 
-#: src/language/stats/correlations.c:216
+#: src/language/stats/correlations.c:217
 msgid "Pearson Correlation"
 msgstr "Pearson Correlatie"
 
-#: src/language/stats/correlations.c:218 src/language/stats/oneway.c:1166
-#: src/language/stats/t-test.q:753 src/language/stats/t-test.q:924
-#: src/language/stats/t-test.q:1011
+#: src/language/stats/correlations.c:219 src/language/stats/oneway.c:1003
+#: src/language/stats/t-test.q:757 src/language/stats/t-test.q:928
+#: src/language/stats/t-test.q:1015
 msgid "Sig. (2-tailed)"
-msgstr ""
+msgstr "Sig. (2-tailed)"
 
-#: src/language/stats/correlations.c:218 src/language/stats/factor.c:1634
+#: src/language/stats/correlations.c:219 src/language/stats/factor.c:1630
 msgid "Sig. (1-tailed)"
-msgstr ""
+msgstr "Sig. (1-tailed)"
 
-#: src/language/stats/correlations.c:222
+#: src/language/stats/correlations.c:223
 msgid "Cross-products"
 msgstr ""
 
-#: src/language/stats/correlations.c:223
+#: src/language/stats/correlations.c:224
 msgid "Covariance"
 msgstr "Covariantie"
 
-#: src/language/stats/correlations.c:454 src/language/stats/descriptives.c:361
-#: src/language/data-io/list.q:91
+#: src/language/stats/correlations.c:456 src/language/stats/descriptives.c:363
+#: src/language/data-io/list.q:90
 msgid "No variables specified."
 msgstr "Geen variabelen gespecificeerd."
 
-#: src/language/stats/descriptives.c:102 src/language/stats/frequencies.q:106
-#: src/language/stats/t-test.q:508 src/language/stats/t-test.q:528
-#: src/language/stats/t-test.q:627
+#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:106
+#: src/language/stats/t-test.q:512 src/language/stats/t-test.q:532
+#: src/language/stats/t-test.q:631
 msgid "S.E. Mean"
 msgstr "S.E. Mean"
 
-#: src/language/stats/descriptives.c:103 src/language/stats/frequencies.q:109
+#: src/language/stats/descriptives.c:104 src/language/stats/frequencies.q:109
 msgid "Std Dev"
 msgstr "Std Dev"
 
-#: src/language/stats/descriptives.c:104 src/ui/gui/descriptives-dialog.c:47
-#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1474
+#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/frequencies-dialog.c:45 src/language/stats/examine.q:1473
 #: src/language/stats/frequencies.q:110
 msgid "Variance"
 msgstr "Variatie"
 
-#: src/language/stats/descriptives.c:105 src/ui/gui/descriptives-dialog.c:48
-#: src/ui/gui/frequencies-dialog.c:51 src/language/stats/examine.q:1510
+#: src/language/stats/descriptives.c:106 src/ui/gui/descriptives-dialog.c:47
+#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/examine.q:1509
 #: src/language/stats/frequencies.q:111
 msgid "Kurtosis"
 msgstr "Kurtosis"
 
-#: src/language/stats/descriptives.c:106 src/language/stats/frequencies.q:112
+#: src/language/stats/descriptives.c:107 src/language/stats/frequencies.q:112
 msgid "S.E. Kurt"
 msgstr "S.E. Kurt"
 
-#: src/language/stats/descriptives.c:107 src/ui/gui/descriptives-dialog.c:49
-#: src/ui/gui/frequencies-dialog.c:47 src/language/stats/examine.q:1505
+#: src/language/stats/descriptives.c:108 src/ui/gui/descriptives-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:46 src/language/stats/examine.q:1504
 #: src/language/stats/frequencies.q:113
 msgid "Skewness"
 msgstr "Skewness"
 
-#: src/language/stats/descriptives.c:108 src/language/stats/frequencies.q:114
+#: src/language/stats/descriptives.c:109 src/language/stats/frequencies.q:114
 msgid "S.E. Skew"
 msgstr "S.E. Skew"
 
-#: src/language/stats/descriptives.c:109 src/ui/gui/descriptives-dialog.c:44
-#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/examine.q:1494
+#: src/language/stats/descriptives.c:110 src/ui/gui/descriptives-dialog.c:43
+#: src/ui/gui/frequencies-dialog.c:48 src/language/stats/examine.q:1493
 #: src/language/stats/frequencies.q:115
 msgid "Range"
 msgstr "Bereik"
 
-#: src/language/stats/descriptives.c:110 src/language/stats/npar-summary.c:129
-#: src/language/stats/oneway.c:861 src/ui/gui/descriptives-dialog.c:42
-#: src/ui/gui/frequencies-dialog.c:43 src/language/stats/examine.q:1484
+#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:132
+#: src/language/stats/oneway.c:701 src/ui/gui/descriptives-dialog.c:41
+#: src/ui/gui/frequencies-dialog.c:42 src/language/stats/examine.q:1483
 #: src/language/stats/frequencies.q:116
 msgid "Minimum"
 msgstr "Minimum"
 
-#: src/language/stats/descriptives.c:111 src/language/stats/npar-summary.c:132
-#: src/language/stats/oneway.c:862 src/ui/gui/descriptives-dialog.c:43
-#: src/ui/gui/frequencies-dialog.c:44 src/language/stats/examine.q:1489
+#: src/language/stats/descriptives.c:112 src/language/stats/npar-summary.c:135
+#: src/language/stats/oneway.c:702 src/ui/gui/descriptives-dialog.c:42
+#: src/ui/gui/frequencies-dialog.c:43 src/language/stats/examine.q:1488
 #: src/language/stats/frequencies.q:117
 msgid "Maximum"
 msgstr "Maximum"
 
-#: src/language/stats/descriptives.c:112 src/ui/gui/descriptives-dialog.c:45
-#: src/ui/gui/frequencies-dialog.c:54 src/language/stats/frequencies.q:118
+#: src/language/stats/descriptives.c:113 src/ui/gui/descriptives-dialog.c:44
+#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/frequencies.q:118
 msgid "Sum"
 msgstr "Som"
 
-#: src/language/stats/descriptives.c:343
+#: src/language/stats/descriptives.c:345
 #, c-format
 msgid "Z-score variable name %s would be a duplicate variable name."
 msgstr "Z-score-variabelennaam %s zou een dubbele variabelennaam zijn."
 
-#: src/language/stats/descriptives.c:450
+#: src/language/stats/descriptives.c:457
 msgid "expecting statistic name: reverting to default"
 msgstr "statistische naam verwacht: teruggezet op standaardwaarde"
 
-#: src/language/stats/descriptives.c:523
+#: src/language/stats/descriptives.c:539
 msgid "Ran out of generic names for Z-score variables.  There are only 126 generic names: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 msgstr "Generieke namen voor Z-score-variabelen zijn uitgeput.  Er zijn slechts 126 generieke namen: ZSC001-ZSC0999, STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."
 
-#: src/language/stats/descriptives.c:555
+#: src/language/stats/descriptives.c:568
 msgid "Mapping of variables to corresponding Z-scores."
 msgstr "Mappen van variabelen naar corresponderende Z-scores."
 
-#: src/language/stats/descriptives.c:559 src/language/stats/glm.c:304
+#: src/language/stats/descriptives.c:572
 msgid "Source"
 msgstr "Bron"
 
-#: src/language/stats/descriptives.c:560
+#: src/language/stats/descriptives.c:573
 msgid "Target"
 msgstr "Doel"
 
-#: src/language/stats/descriptives.c:670
+#: src/language/stats/descriptives.c:684
 #, c-format
 msgid "Z-score of %s"
 msgstr "Z-score van %s"
 
-#: src/language/stats/descriptives.c:884
+#: src/language/stats/descriptives.c:898
 msgid "Valid N"
 msgstr "Geldige N"
 
-#: src/language/stats/descriptives.c:885
+#: src/language/stats/descriptives.c:899
 msgid "Missing N"
 msgstr "Missende N"
 
-#: src/language/stats/descriptives.c:913
+#: src/language/stats/descriptives.c:927
 #, c-format
 msgid "Valid cases = %g; cases with missing value(s) = %g."
 msgstr "Geldige cases = %g; cases met ontbrekende-waarde(s) = %g."
 
-#: src/language/stats/factor.c:805
+#: src/language/stats/factor.c:801
 msgid "Factor analysis on a single variable is not useful."
 msgstr "Factor analyse op een enkele variabele is niet zinvol."
 
-#: src/language/stats/factor.c:1208
+#: src/language/stats/factor.c:1204
 msgid "Component Number"
 msgstr "Component-nummer "
 
-#: src/language/stats/factor.c:1208
+#: src/language/stats/factor.c:1204
 msgid "Factor Number"
 msgstr "Factor Nummer"
 
-#: src/language/stats/factor.c:1239
+#: src/language/stats/factor.c:1235
 msgid "Communalities"
 msgstr ""
 
-#: src/language/stats/factor.c:1245
+#: src/language/stats/factor.c:1241
 msgid "Initial"
 msgstr "Initieel "
 
-#: src/language/stats/factor.c:1248
+#: src/language/stats/factor.c:1244
 msgid "Extraction"
 msgstr "Extractie"
 
-#: src/language/stats/factor.c:1312 src/language/stats/factor.c:1439
+#: src/language/stats/factor.c:1308 src/language/stats/factor.c:1435
 msgid "Component"
 msgstr "Component"
 
-#: src/language/stats/factor.c:1317 src/language/stats/factor.c:1441
+#: src/language/stats/factor.c:1313 src/language/stats/factor.c:1437
 msgid "Factor"
 msgstr "Factor"
 
-#: src/language/stats/factor.c:1349 src/language/stats/factor.c:1497
-#: src/ui/gui/psppire-data-store.c:755 src/ui/gui/psppire-var-store.c:699
-#: src/ui/gui/psppire-var-store.c:709 src/ui/gui/psppire-var-store.c:719
-#: src/ui/gui/psppire-var-store.c:825
+#: src/language/stats/factor.c:1345 src/ui/gui/psppire-data-store.c:755
+#: src/ui/gui/psppire-var-store.c:699 src/ui/gui/psppire-var-store.c:709
+#: src/ui/gui/psppire-var-store.c:719 src/ui/gui/psppire-var-store.c:826
 #, c-format
 msgid "%d"
 msgstr "%d"
 
-#: src/language/stats/factor.c:1414
+#: src/language/stats/factor.c:1410
 msgid "Total Variance Explained"
 msgstr ""
 
-#: src/language/stats/factor.c:1446
+#: src/language/stats/factor.c:1442
 msgid "Initial Eigenvalues"
 msgstr ""
 
-#: src/language/stats/factor.c:1452
+#: src/language/stats/factor.c:1448
 msgid "Extraction Sums of Squared Loadings"
 msgstr ""
 
-#: src/language/stats/factor.c:1458
+#: src/language/stats/factor.c:1454
 msgid "Rotation Sums of Squared Loadings"
 msgstr ""
 
-#: src/language/stats/factor.c:1466
+#: src/language/stats/factor.c:1462
 #, no-c-format
 msgid "% of Variance"
 msgstr "% van Variatie"
 
-#: src/language/stats/factor.c:1467
+#: src/language/stats/factor.c:1463
 msgid "Cumulative %"
 msgstr "Cumulatieve %"
 
-#: src/language/stats/factor.c:1580
+#: src/language/stats/factor.c:1493
+#, c-format
+msgid "%zu"
+msgstr ""
+
+#: src/language/stats/factor.c:1576
 msgid "Correlation Matrix"
 msgstr "Correlatie-Matrix"
 
-#: src/language/stats/factor.c:1668
+#: src/language/stats/factor.c:1664
 msgid "Determinant"
 msgstr "Determinant"
 
-#: src/language/stats/factor.c:1699
+#: src/language/stats/factor.c:1695
 msgid "The dataset contains no complete observations. No analysis will be performed."
-msgstr ""
+msgstr "De dataset bevat geen complete observaties. Er wordt geen analyse uitgevoerd."
 
-#: src/language/stats/factor.c:1751
+#: src/language/stats/factor.c:1747
 msgid "Analysis N"
 msgstr "Analyses N"
 
-#: src/language/stats/factor.c:1784
+#: src/language/stats/factor.c:1780
 msgid "The FACTOR criteria result in zero factors extracted. Therefore no analysis will be performed."
-msgstr ""
+msgstr "De FACTOR criteria resulteerd in nul factors geëxtraheerd. Daarom wordt er geen analyse uitgevoerd."
 
-#: src/language/stats/factor.c:1790
+#: src/language/stats/factor.c:1786
 msgid "The FACTOR criteria result in more factors than variables, which is not meaningful. No analysis will be performed."
-msgstr ""
+msgstr "De FACTOR criteria resulteren in meer factoren dan variabelen, wat niet betekenisvol is. Geen analyse wordt uitgevoerd."
 
-#: src/language/stats/factor.c:1873
+#: src/language/stats/factor.c:1869
 msgid "Component Matrix"
 msgstr "Component-Matrix"
 
-#: src/language/stats/factor.c:1873
+#: src/language/stats/factor.c:1869
 msgid "Factor Matrix"
 msgstr "Factor-Matrix:"
 
-#: src/language/stats/factor.c:1879
+#: src/language/stats/factor.c:1875
 msgid "Rotated Component Matrix"
 msgstr "Geroteerde componentmatrix"
 
-#: src/language/stats/factor.c:1879
+#: src/language/stats/factor.c:1875
 msgid "Rotated Factor Matrix"
 msgstr "Geroteerde factormatrix:"
 
-#: src/language/stats/flip.c:98
+#: src/language/stats/flip.c:99
 msgid "FLIP ignores TEMPORARY.  Temporary transformations will be made permanent."
 msgstr "FLIP negeert TEMPORARY. Tijdelijke transformaties worden permanent gemaakt."
 
-#: src/language/stats/flip.c:150
+#: src/language/stats/flip.c:151
 msgid "Could not create temporary file for FLIP."
 msgstr "Kon geen tijdelijk bestand voor FLIP aanmaken."
 
-#: src/language/stats/flip.c:325
+#: src/language/stats/flip.c:326
 #, c-format
 msgid "Error rewinding FLIP file: %s."
 msgstr "Fout tijdens terugdraaien FLIP bestand: %s."
 
-#: src/language/stats/flip.c:332
+#: src/language/stats/flip.c:333
 msgid "Error creating FLIP source file."
 msgstr "Fout tijdens het creëren van FLIP bronbestand."
 
-#: src/language/stats/flip.c:345
+#: src/language/stats/flip.c:346
 #, c-format
 msgid "Error reading FLIP file: %s."
 msgstr "Fout tijdens lezen FLIP bestand: %s."
 
-#: src/language/stats/flip.c:347
+#: src/language/stats/flip.c:348
 msgid "Unexpected end of file reading FLIP file."
 msgstr "Onverwacht einde-bestand tijdens lezen FLIP bestand."
 
-#: src/language/stats/flip.c:363
+#: src/language/stats/flip.c:364
 #, c-format
 msgid "Error seeking FLIP source file: %s."
 msgstr "Fout tijdens zoeken FLIP bronbestand: %s."
 
-#: src/language/stats/flip.c:371
+#: src/language/stats/flip.c:372
 #, c-format
 msgid "Error writing FLIP source file: %s."
 msgstr "Fout tijdens schrijven FLIP bronbestand: %s."
 
-#: src/language/stats/flip.c:386
+#: src/language/stats/flip.c:387
 #, c-format
 msgid "Error rewinding FLIP source file: %s."
 msgstr "Fout tijdens terugdraaien FLIP bronbestand: %s."
 
-#: src/language/stats/flip.c:419
+#: src/language/stats/flip.c:420
 #, c-format
 msgid "Error reading FLIP temporary file: %s."
 msgstr "Fout tijdens lezen FLIP tijdelijk bestand: %s."
 
-#: src/language/stats/flip.c:422
+#: src/language/stats/flip.c:423
 msgid "Unexpected end of file reading FLIP temporary file."
 msgstr "Onverwacht einde-bestand tijdens lezen FLIP tijdelijk bestand."
 
-#: src/language/stats/glm.c:108
-#, fuzzy
-msgid "Multivariate analysis is not yet implemented"
-msgstr "%s is nog niet geïmplementeerd."
-
-#: src/language/stats/glm.c:291
-msgid "Tests of Between-Subjects Effects"
-msgstr ""
+#: src/language/stats/friedman.c:227 src/language/stats/kruskal-wallis.c:242
+#: src/language/stats/mann-whitney.c:171 src/language/stats/wilcoxon.c:225
+msgid "Ranks"
+msgstr "Rangschikking"
 
-#. TRANSLATORS: The parameter is a roman numeral
-#: src/language/stats/glm.c:307
-#, c-format
-msgid "Type %s Sum of Squares"
-msgstr ""
+#: src/language/stats/friedman.c:238 src/language/stats/kruskal-wallis.c:256
+#: src/language/stats/mann-whitney.c:196 src/language/stats/wilcoxon.c:239
+msgid "Mean Rank"
+msgstr "Mean Rank"
 
-#: src/language/stats/glm.c:309 src/language/stats/oneway.c:754
-#: src/language/stats/regression.q:285
-msgid "Mean Square"
-msgstr ""
+#: src/language/stats/friedman.c:279
+msgid "Kendall's W"
+msgstr "Kendall's W"
 
-#: src/language/stats/glm.c:310 src/language/stats/oneway.c:755
-#: src/language/stats/regression.q:286 src/language/stats/t-test.q:749
-msgid "F"
-msgstr "F"
+#: src/language/stats/mann-whitney.c:202 src/language/stats/wilcoxon.c:240
+msgid "Sum of Ranks"
+msgstr "Som van Rangen"
 
-#: src/language/stats/glm.c:311 src/language/stats/t-test.q:750
-#: src/language/stats/t-test.q:1103
-msgid "Sig."
-msgstr ""
+#: src/language/stats/mann-whitney.c:264
+msgid "Mann-Whitney U"
+msgstr "Mann-Whitney U"
 
-#: src/language/stats/glm.c:314
-msgid "Corrected Model"
-msgstr ""
+#: src/language/stats/mann-whitney.c:265
+msgid "Wilcoxon W"
+msgstr "Wilcoxon W"
 
-#: src/language/stats/glm.c:323
-#, fuzzy
-msgid "Intercept"
-msgstr "Percentage"
-
-#: src/language/stats/glm.c:337
-#, fuzzy
-msgid "Error"
-msgstr "fout"
+#: src/language/stats/mann-whitney.c:266 src/language/stats/runs.c:396
+#: src/language/stats/wilcoxon.c:317
+msgid "Z"
+msgstr "Z"
 
-#: src/language/stats/glm.c:350
-#, fuzzy
-msgid "Corrected Total"
-msgstr "Coëfficiënt Totaal: "
+#: src/language/stats/mann-whitney.c:267 src/language/stats/runs.c:399
+#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1237
+msgid "Asymp. Sig. (2-tailed)"
+msgstr "Asymp. Sig. (2-tailed)"
 
-#: src/language/stats/kruskal-wallis.c:244 src/language/stats/wilcoxon.c:225
-msgid "Ranks"
-msgstr "Rangschikking"
+#: src/language/stats/mann-whitney.c:271 src/language/stats/sign.c:133
+#: src/language/stats/wilcoxon.c:322
+msgid "Exact Sig. (2-tailed)"
+msgstr "Exact Sig. (2-tailed)"
 
-#: src/language/stats/kruskal-wallis.c:258 src/language/stats/wilcoxon.c:239
-msgid "Mean Rank"
-msgstr ""
+#: src/language/stats/mann-whitney.c:272 src/language/stats/sign.c:139
+#: src/language/stats/wilcoxon.c:326
+msgid "Point Probability"
+msgstr "Point Probability"
 
-#: src/language/stats/npar.c:233 src/language/stats/npar.c:260
-#, fuzzy, c-format
+#: src/language/stats/npar.c:337 src/language/stats/npar.c:364
+#, c-format
 msgid "The %s subcommand may be given only once."
-msgstr "%s-subopdracht mag maximaal 1 keer gegeven worden."
+msgstr "De %s subopdracht mag maar 1 keer gegeven worden."
 
-#: src/language/stats/npar.c:343
+#: src/language/stats/npar.c:447
 msgid "NPAR subcommand not currently implemented."
-msgstr ""
+msgstr "NPAR subopdracht is op dit moment nog niet geïmplementeerd."
+
+#: src/language/stats/npar.c:601
+msgid "Expecting MEAN, MEDIAN, MODE or number"
+msgstr "Verwacht MEAN, MEDIAN, MODE of nummer"
 
-#: src/language/stats/npar.c:496
+#: src/language/stats/npar.c:751
 #, c-format
 msgid "The specified value of HI (%d) is lower than the specified value of LO (%d)"
 msgstr "De opgegeven waarde van HI (%d) is lager dan de opgegeven waarde van LO (%d)"
 
-#: src/language/stats/npar.c:551
+#: src/language/stats/npar.c:801
 #, c-format
 msgid "%d expected values were given, but the specified range (%d-%d) requires exactly %d values."
 msgstr "%d verwachte waardes waren opgegeven, maar het opgegeven bereik (%d-%d) vereist precies %d waardes."
 
-#: src/language/stats/npar.c:690 src/language/stats/t-test.q:380
+#: src/language/stats/npar.c:941 src/language/stats/t-test.q:384
 #, c-format
 msgid "PAIRED was specified but the number of variables preceding WITH (%zu) did not match the number following (%zu)."
 msgstr "PAIRED was opgegeven maar het aantal variabelen voor WITH (%zu) komt niet overeen met het aantal er achter (%zu)."
 
-#: src/language/stats/npar-summary.c:139 src/language/stats/examine.q:1996
-#: src/language/stats/examine.q:2013 src/language/stats/frequencies.q:1050
+#: src/language/stats/npar-summary.c:142 src/language/stats/examine.q:1995
+#: src/language/stats/examine.q:2012 src/language/stats/frequencies.q:1057
 #: src/ui/gui/examine.ui:345
 msgid "Percentiles"
 msgstr "Percentiles"
 
-#: src/language/stats/npar-summary.c:143
+#: src/language/stats/npar-summary.c:146
 msgid "25th"
 msgstr "25ste"
 
-#: src/language/stats/npar-summary.c:146
+#: src/language/stats/npar-summary.c:149
 msgid "50th (Median)"
 msgstr "50ste (Mediaan)"
 
-#: src/language/stats/npar-summary.c:149
+#: src/language/stats/npar-summary.c:152
 msgid "75th"
 msgstr "75ste"
 
-#: src/language/stats/oneway.c:692
+#: src/language/stats/oneway.c:542
 msgid "Number of contrast coefficients must equal the number of groups"
 msgstr ""
 
-#: src/language/stats/oneway.c:701
+#: src/language/stats/oneway.c:551
 #, c-format
 msgid "Coefficients for contrast %zu do not total zero"
 msgstr ""
 
-#: src/language/stats/oneway.c:752 src/language/stats/regression.q:283
+#: src/language/stats/oneway.c:592 src/language/stats/regression.q:285
 msgid "Sum of Squares"
-msgstr ""
+msgstr "Sum of Squares"
+
+#: src/language/stats/oneway.c:594 src/language/stats/regression.q:287
+msgid "Mean Square"
+msgstr "Mean Square"
+
+#: src/language/stats/oneway.c:595 src/language/stats/regression.q:288
+#: src/language/stats/t-test.q:753
+msgid "F"
+msgstr "F"
 
-#: src/language/stats/oneway.c:756 src/language/stats/oneway.c:1001
-#: src/language/stats/regression.q:201 src/language/stats/regression.q:287
+#: src/language/stats/oneway.c:596 src/language/stats/oneway.c:841
+#: src/language/stats/regression.q:203 src/language/stats/regression.q:289
 msgid "Significance"
 msgstr "Significantie "
 
-#: src/language/stats/oneway.c:774
+#: src/language/stats/oneway.c:614
 msgid "Between Groups"
 msgstr "Tussen groepen"
 
-#: src/language/stats/oneway.c:775
+#: src/language/stats/oneway.c:615
 msgid "Within Groups"
 msgstr "Binnen groepen"
 
-#: src/language/stats/oneway.c:808 src/language/stats/regression.q:312
+#: src/language/stats/oneway.c:648 src/language/stats/regression.q:314
 msgid "ANOVA"
 msgstr "ANOVA"
 
-#: src/language/stats/oneway.c:849 src/language/stats/oneway.c:1163
-#: src/language/stats/roc.c:975 src/language/stats/examine.q:1641
-#: src/language/stats/regression.q:198
+#: src/language/stats/oneway.c:689 src/language/stats/oneway.c:1000
+#: src/language/stats/roc.c:975 src/language/stats/examine.q:1640
+#: src/language/stats/regression.q:200
 msgid "Std. Error"
 msgstr "Std. Fout"
 
-#: src/language/stats/oneway.c:855 src/language/stats/examine.q:1449
+#: src/language/stats/oneway.c:695 src/language/stats/examine.q:1448
 #, c-format
 msgid "%g%% Confidence Interval for Mean"
 msgstr ""
 
-#: src/language/stats/oneway.c:858 src/language/stats/roc.c:978
-#: src/language/stats/examine.q:1455
+#: src/language/stats/oneway.c:698 src/language/stats/roc.c:978
+#: src/language/stats/examine.q:1454
 msgid "Lower Bound"
 msgstr "Benedengrens"
 
-#: src/language/stats/oneway.c:859 src/language/stats/roc.c:979
-#: src/language/stats/examine.q:1460
+#: src/language/stats/oneway.c:699 src/language/stats/roc.c:979
+#: src/language/stats/examine.q:1459
 msgid "Upper Bound"
 msgstr "Bovengrens"
 
-#: src/language/stats/oneway.c:864 src/language/stats/examine.q:1635
+#: src/language/stats/oneway.c:704 src/language/stats/examine.q:1634
 #: src/ui/gui/descriptives.ui:8 src/ui/gui/examine.ui:319
 msgid "Descriptives"
 msgstr "Descriptieve"
 
-#: src/language/stats/oneway.c:998
+#: src/language/stats/oneway.c:838
 msgid "Levene Statistic"
-msgstr ""
+msgstr "Levene Statistiek"
 
-#: src/language/stats/oneway.c:999
+#: src/language/stats/oneway.c:839
 msgid "df1"
 msgstr "df1"
 
-#: src/language/stats/oneway.c:1000
+#: src/language/stats/oneway.c:840
 msgid "df2"
 msgstr "df2"
 
-#: src/language/stats/oneway.c:1003
+#: src/language/stats/oneway.c:843
 msgid "Test of Homogeneity of Variances"
 msgstr ""
 
-#: src/language/stats/oneway.c:1079
+#: src/language/stats/oneway.c:916
 msgid "Contrast Coefficients"
 msgstr "Contrastcoëfficiënten"
 
-#: src/language/stats/oneway.c:1081 src/language/stats/oneway.c:1161
+#: src/language/stats/oneway.c:918 src/language/stats/oneway.c:998
 msgid "Contrast"
 msgstr "Contrast"
 
-#: src/language/stats/oneway.c:1159
+#: src/language/stats/oneway.c:996
 msgid "Contrast Tests"
 msgstr "Contrasttesten"
 
-#: src/language/stats/oneway.c:1162
+#: src/language/stats/oneway.c:999
 msgid "Value of Contrast"
 msgstr ""
 
-#: src/language/stats/oneway.c:1164 src/language/stats/regression.q:200
-#: src/language/stats/t-test.q:751 src/language/stats/t-test.q:922
-#: src/language/stats/t-test.q:1009
+#: src/language/stats/oneway.c:1001 src/language/stats/regression.q:202
+#: src/language/stats/t-test.q:755 src/language/stats/t-test.q:926
+#: src/language/stats/t-test.q:1013
 msgid "t"
 msgstr "t"
 
-#: src/language/stats/oneway.c:1216
+#: src/language/stats/oneway.c:1053
 msgid "Assume equal variances"
 msgstr "Veronderstelt gelijke variantie"
 
-#: src/language/stats/oneway.c:1220
+#: src/language/stats/oneway.c:1057
 msgid "Does not assume equal"
 msgstr "Veronderstelt niet gelijk"
 
-#: src/language/stats/reliability.c:146
-msgid "Reliabilty on a single variable is not useful."
-msgstr "betrouwbaarheids analyse op een enkele variabele is niet zinvol."
+#: src/language/stats/quick-cluster.c:369
+msgid "Number of clusters may not be larger than the number of cases."
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:411
+msgid "Final Cluster Centers"
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:415
+msgid "Initial Cluster Centers"
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:418
+#: src/language/stats/quick-cluster.c:472
+msgid "Cluster"
+msgstr ""
+
+#: src/language/stats/quick-cluster.c:470
+msgid "Number of Cases in each Cluster"
+msgstr "Aantal cases in elke cluster"
+
+#: src/language/stats/quick-cluster.c:484 src/language/stats/reliability.c:527
+#: src/language/stats/crosstabs.q:830 src/language/stats/examine.q:1102
+#: src/language/stats/frequencies.q:1042
+msgid "Valid"
+msgstr "Geldig"
+
+#: src/language/stats/quick-cluster.c:515
+msgid "Variables cannot be parsed"
+msgstr "Variabelen kunnen niet ontleed worden"
 
-#: src/language/stats/reliability.c:506 src/language/stats/examine.q:1159
+#: src/language/stats/reliability.c:141
+msgid "Reliability on a single variable is not useful."
+msgstr "Betrouwbaarheidsanalyse op een enkele variabele is niet zinvol."
+
+#: src/language/stats/reliability.c:501 src/language/stats/examine.q:1158
 msgid "Case Processing Summary"
 msgstr "Case Bewerkingsoverzicht"
 
-#: src/language/stats/reliability.c:529 src/language/stats/crosstabs.q:812
-#: src/language/stats/examine.q:1164
+#: src/language/stats/reliability.c:524 src/language/stats/crosstabs.q:829
+#: src/language/stats/examine.q:1163
 msgid "Cases"
 msgstr "Cases"
 
-#: src/language/stats/reliability.c:532 src/language/stats/crosstabs.q:813
-#: src/language/stats/examine.q:1103 src/language/stats/frequencies.q:1035
-msgid "Valid"
-msgstr "Geldig"
-
-#: src/language/stats/reliability.c:535
+#: src/language/stats/reliability.c:530
 msgid "Excluded"
 msgstr "Uitgesloten"
 
-#: src/language/stats/reliability.c:543
+#: src/language/stats/reliability.c:538
 msgid "%"
 msgstr "%"
 
-#: src/language/stats/reliability.c:588
+#: src/language/stats/reliability.c:583
 msgid "Item-Total Statistics"
 msgstr "Item-Totaal Statistieken"
 
-#: src/language/stats/reliability.c:610
+#: src/language/stats/reliability.c:605
 msgid "Scale Mean if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.c:613
+#: src/language/stats/reliability.c:608
 msgid "Scale Variance if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.c:616
+#: src/language/stats/reliability.c:611
 msgid "Corrected Item-Total Correlation"
 msgstr ""
 
-#: src/language/stats/reliability.c:619
+#: src/language/stats/reliability.c:614
 msgid "Cronbach's Alpha if Item Deleted"
 msgstr ""
 
-#: src/language/stats/reliability.c:693
+#: src/language/stats/reliability.c:688
 msgid "Reliability Statistics"
 msgstr "Betrouwbaarheids Statistieken"
 
-#: src/language/stats/reliability.c:733 src/language/stats/reliability.c:752
+#: src/language/stats/reliability.c:728 src/language/stats/reliability.c:747
 msgid "Cronbach's Alpha"
 msgstr "Cronbach's Alpha"
 
-#: src/language/stats/reliability.c:736 src/language/stats/reliability.c:761
-#: src/language/stats/reliability.c:772
+#: src/language/stats/reliability.c:731 src/language/stats/reliability.c:756
+#: src/language/stats/reliability.c:767
 msgid "N of Items"
 msgstr "N van Items"
 
-#: src/language/stats/reliability.c:755
+#: src/language/stats/reliability.c:750
 msgid "Part 1"
 msgstr "Deel 1"
 
-#: src/language/stats/reliability.c:766
+#: src/language/stats/reliability.c:761
 msgid "Part 2"
 msgstr "Deel 2"
 
-#: src/language/stats/reliability.c:777
+#: src/language/stats/reliability.c:772
 msgid "Total N of Items"
 msgstr "Totaal N van Items"
 
-#: src/language/stats/reliability.c:780
+#: src/language/stats/reliability.c:775
 msgid "Correlation Between Forms"
 msgstr "Correlatie Tussen Formulieren"
 
-#: src/language/stats/reliability.c:784
+#: src/language/stats/reliability.c:779
 msgid "Spearman-Brown Coefficient"
 msgstr "Spearman-Brown Coefficient"
 
-#: src/language/stats/reliability.c:787
+#: src/language/stats/reliability.c:782
 msgid "Equal Length"
 msgstr "Gelijke lengte"
 
-#: src/language/stats/reliability.c:790
+#: src/language/stats/reliability.c:785
 msgid "Unequal Length"
 msgstr "Ongelijke lengte"
 
-#: src/language/stats/reliability.c:794
+#: src/language/stats/reliability.c:789
 msgid "Guttman Split-Half Coefficient"
 msgstr "Guttman Split-Half Coëfficiënt"
 
 #: src/language/stats/roc.c:955
 msgid "Area Under the Curve"
-msgstr ""
+msgstr "Area Under the Curve"
 
 #: src/language/stats/roc.c:957
 #, c-format
 msgid "Area Under the Curve (%s)"
-msgstr ""
+msgstr "Area Under the Curve (%s"
 
 #: src/language/stats/roc.c:962
 msgid "Area"
@@ -3043,7 +3063,7 @@ msgstr ""
 
 #: src/language/stats/roc.c:976
 msgid "Asymptotic Sig."
-msgstr ""
+msgstr "Asymptotic Sig."
 
 #: src/language/stats/roc.c:983
 #, c-format
@@ -3052,7 +3072,7 @@ msgstr "Asymp. %g%% Betrouwbaarheidsinterval"
 
 #: src/language/stats/roc.c:989
 msgid "Variable under test"
-msgstr ""
+msgstr "Variabele die wordt getest"
 
 #: src/language/stats/roc.c:1048
 msgid "Case Summary"
@@ -3068,7 +3088,7 @@ msgstr "Gewicht"
 
 #: src/language/stats/roc.c:1073
 msgid "Valid N (listwise)"
-msgstr ""
+msgstr "Valid N (listwise)"
 
 #: src/language/stats/roc.c:1076
 msgid "Positive"
@@ -3080,12 +3100,12 @@ msgstr "Negatief"
 
 #: src/language/stats/roc.c:1105
 msgid "Coordinates of the Curve"
-msgstr ""
+msgstr "Coordinates of the Curve"
 
 #: src/language/stats/roc.c:1107
 #, c-format
 msgid "Coordinates of the Curve (%s)"
-msgstr ""
+msgstr "Coordinates of the Curve (%s)"
 
 #: src/language/stats/roc.c:1115
 msgid "Test variable"
@@ -3103,29 +3123,62 @@ msgstr "Gevoeligheid"
 msgid "1 - Specificity"
 msgstr ""
 
-#: src/language/stats/sign.c:90
+#: src/language/stats/runs.c:167
+#, c-format
+msgid "Multiple modes exist for varible `%s'.  Using %g as the threshold value."
+msgstr "Meerdere modes bestaan voor variabele `%s'.  Gebruik %g als de drempel waarde."
+
+#: src/language/stats/runs.c:322
+msgid "Runs Test"
+msgstr "Uitvoeren Test "
+
+#: src/language/stats/runs.c:367
+msgid "Test Value"
+msgstr "Testwaarde"
+
+#: src/language/stats/runs.c:371
+msgid "Test Value (mode)"
+msgstr "Testwaarde (mode)"
+
+#: src/language/stats/runs.c:375
+msgid "Test Value (mean)"
+msgstr "Testwaarde (mean) "
+
+#: src/language/stats/runs.c:379
+msgid "Test Value (median)"
+msgstr "Testwaarde  (median)"
+
+#: src/language/stats/runs.c:384
+msgid "Cases < Test Value"
+msgstr "Cases < Testwaarde"
+
+#: src/language/stats/runs.c:387
+msgid "Cases >= Test Value"
+msgstr "Cases >= Testwaarde "
+
+#: src/language/stats/runs.c:390
+msgid "Total Cases"
+msgstr "Totaal cases"
+
+#: src/language/stats/runs.c:393
+msgid "Number of Runs"
+msgstr "Aantal Runs"
+
+#: src/language/stats/sign.c:92
 msgid "Negative Differences"
 msgstr "Negatieve Verschillen"
 
-#: src/language/stats/sign.c:91
+#: src/language/stats/sign.c:93
 msgid "Positive Differences"
 msgstr "Positieve Verschillen"
 
-#: src/language/stats/sign.c:92 src/language/stats/wilcoxon.c:254
+#: src/language/stats/sign.c:94 src/language/stats/wilcoxon.c:254
 msgid "Ties"
 msgstr ""
 
-#: src/language/stats/sign.c:131 src/language/stats/wilcoxon.c:322
-msgid "Exact Sig. (2-tailed)"
-msgstr ""
-
-#: src/language/stats/sign.c:134 src/language/stats/wilcoxon.c:323
+#: src/language/stats/sign.c:136 src/language/stats/wilcoxon.c:323
 msgid "Exact Sig. (1-tailed)"
-msgstr ""
-
-#: src/language/stats/sign.c:137 src/language/stats/wilcoxon.c:326
-msgid "Point Probability"
-msgstr ""
+msgstr "Exact Sig. (1-tailed)"
 
 #: src/language/stats/sort-cases.c:64
 msgid "Buffer limit must be at least 2."
@@ -3144,10 +3197,6 @@ msgstr "')' verwacht."
 msgid "Variable %s specified twice in sort criteria."
 msgstr "Variabele %s 2 keer opgegeven in sorteer criteria."
 
-#: src/language/stats/wilcoxon.c:240
-msgid "Sum of Ranks"
-msgstr "Som van Rangen"
-
 #: src/language/stats/wilcoxon.c:252
 msgid "Negative Ranks"
 msgstr "Negatieve Rangen"
@@ -3156,98 +3205,90 @@ msgstr "Negatieve Rangen"
 msgid "Positive Ranks"
 msgstr "Positieve Rangen"
 
-#: src/language/stats/wilcoxon.c:317
-msgid "Z"
-msgstr "Z"
-
-#: src/language/stats/wilcoxon.c:318 src/language/stats/crosstabs.q:1209
-msgid "Asymp. Sig. (2-tailed)"
-msgstr ""
+#: src/language/data-io/combine-files.c:212
+msgid "Cannot specify the active dataset since none has been defined."
+msgstr "Kan de actieve dataset niet specificeren omdat er geen gedefinieerd is."
 
-#: src/language/data-io/combine-files.c:210
-msgid "Cannot specify the active file since no active file has been defined."
-msgstr "Kan het actieve bestand niet specificeren omdat er geen actief bestand is gedefinieerd."
-
-#: src/language/data-io/combine-files.c:216
-msgid "This command may not be used after TEMPORARY when the active file is an input source.  Temporary transformations will be made permanent."
+#: src/language/data-io/combine-files.c:218
+msgid "This command may not be used after TEMPORARY when the active dataset is an input source.  Temporary transformations will be made permanent."
 msgstr "Deze opdracht mag niet gebruikt worden na TEMPORARY als het actieve bestand een invoer bron is. Tijdelijke transformaties zullen permanent worden."
 
-#: src/language/data-io/combine-files.c:250
+#: src/language/data-io/combine-files.c:252
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr "Meerdere IN subopdrachten voor een enkele FILE of TABLE."
 
-#: src/language/data-io/combine-files.c:302
+#: src/language/data-io/combine-files.c:304
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr "Bestand %s mist BY variabele %s."
 
-#: src/language/data-io/combine-files.c:305
+#: src/language/data-io/combine-files.c:307
 #, c-format
-msgid "Active file lacks BY variable %s."
-msgstr "Actief bestand mist BY variabele %s."
+msgid "Active dataset lacks BY variable %s."
+msgstr "Actieve dataset mist BY variabele %s."
 
-#: src/language/data-io/combine-files.c:376
+#: src/language/data-io/combine-files.c:379
 msgid "The BY subcommand is required."
 msgstr "De BY subopdracht is verplicht."
 
-#: src/language/data-io/combine-files.c:381
-#: src/language/data-io/combine-files.c:386
+#: src/language/data-io/combine-files.c:384
+#: src/language/data-io/combine-files.c:389
 #, c-format
 msgid "BY is required when %s is specified."
 msgstr "BY is noodzakelijk als %s is gespecificeerd."
 
-#: src/language/data-io/combine-files.c:513
+#: src/language/data-io/combine-files.c:514
 msgid "Combining files with incompatible encodings. String data may not be represented correctly."
 msgstr "Combineren van bestanden met incompatibele codering. Tekenreeks gegevens worden mogelijk niet correct weergegeven."
 
-#: src/language/data-io/combine-files.c:545
+#: src/language/data-io/combine-files.c:555
 #, c-format
 msgid "Variable %s in file %s has different type or width from the same variable in earlier file."
 msgstr "Variabele %s in bestand %s heeft een ander type of breedte dan dezelfde variabele in eerder bestand."
 
-#: src/language/data-io/combine-files.c:551
+#: src/language/data-io/combine-files.c:561
 #, c-format
 msgid "In file %s, %s is numeric."
 msgstr "In bestand %s, %s is numeriek."
 
-#: src/language/data-io/combine-files.c:554
+#: src/language/data-io/combine-files.c:564
 #, c-format
 msgid "In file %s, %s is a string variable with width %d."
 msgstr "In bestand %s, %s is een tekenreeksvariabele met breedte %d."
 
-#: src/language/data-io/combine-files.c:559
+#: src/language/data-io/combine-files.c:569
 #, c-format
 msgid "In an earlier file, %s was numeric."
 msgstr "In een eerder bestand, %s was numeriek."
 
-#: src/language/data-io/combine-files.c:562
+#: src/language/data-io/combine-files.c:572
 #, c-format
 msgid "In an earlier file, %s was a string variable with width %d."
 msgstr "In een eerder bestand, %s was een tekenreeks met breedte %d."
 
-#: src/language/data-io/combine-files.c:601
+#: src/language/data-io/combine-files.c:612
 #, c-format
 msgid "Variable name %s specified on %s subcommand duplicates an existing variable name."
 msgstr "Variabelennaam %s gespecificeerd in %s-subopdracht dupliceert een bestaande variabelennaam."
 
-#: src/language/data-io/combine-files.c:762
+#: src/language/data-io/combine-files.c:774
 #, c-format
 msgid "Encountered %zu sets of duplicate cases in the master file."
 msgstr "Gevonden% zu sets van dubbele cases in het master-bestand."
 
-#: src/language/data-io/data-list.c:137
+#: src/language/data-io/data-list.c:140
 msgid "The END subcommand may only be used within INPUT PROGRAM."
 msgstr "De END-subopdracht mag alleen binnen INPUT PROGRAM gebruikt worden."
 
-#: src/language/data-io/data-list.c:143
+#: src/language/data-io/data-list.c:146
 msgid "The END subcommand may only be specified once."
 msgstr "De END-subopdracht mag slechts 1 keer gespecificeerd worden."
 
-#: src/language/data-io/data-list.c:181
+#: src/language/data-io/data-list.c:184
 msgid "Only one of FIXED, FREE, or LIST may be specified."
 msgstr "Slechts 1 van FIXED, FREE of LIST mag gespecificeerd worden."
 
-#: src/language/data-io/data-list.c:243
+#: src/language/data-io/data-list.c:245
 msgid "Encoding should not be specified for inline data. It will be ignored."
 msgstr "Codering dient niet opgegeven te worden voor inline-gegevens. Het wordt genegeerd."
 
@@ -3260,7 +3301,7 @@ msgid "At least one variable must be specified."
 msgstr "Tenminste 1 variabele moet gespecificeerd worden."
 
 #: src/language/data-io/data-list.c:368 src/language/data-io/data-list.c:457
-#: src/language/data-io/get-data.c:529
+#: src/language/data-io/get-data.c:540
 #, c-format
 msgid "%s is a duplicate variable name."
 msgstr "%s is een dubbele variabelennaam."
@@ -3285,53 +3326,53 @@ msgstr "Kan variabele %s niet plaatsen in record %d als RECORDS=%d is gespecific
 msgid "Quoted string extends beyond end of line."
 msgstr "Geciteerde tekenreeks loopt door na regeleinde."
 
-#: src/language/data-io/data-parser.c:515
-#, fuzzy, c-format
+#: src/language/data-io/data-parser.c:516
+#, c-format
 msgid "Data for variable %s is not valid as format %s: %s"
-msgstr "%s variabele %s heeft ongeldig %s opmaak %s."
+msgstr "Data voor variabele %s is niet geldig als opmaak %s: %s"
 
-#: src/language/data-io/data-parser.c:544
+#: src/language/data-io/data-parser.c:545
 #, c-format
 msgid "Partial case of %d of %d records discarded."
 msgstr "Gedeeltelijke case van %d van %d records genegeerd."
 
-#: src/language/data-io/data-parser.c:601
+#: src/language/data-io/data-parser.c:602
 #, c-format
 msgid "Partial case discarded.  The first variable missing was %s."
 msgstr "Gedeeltelijke case overgeslagen. De eerste gemiste variabele was %s."
 
-#: src/language/data-io/data-parser.c:643
+#: src/language/data-io/data-parser.c:644
 #, c-format
 msgid "Missing value(s) for all variables from %s onward.  These will be filled with the system-missing value or blanks, as appropriate."
 msgstr "Ontbrekende-waarde(s) voor alle variabelen vanaf %s. Deze worden gevuld met de geschikte system-missing waarde of spatie."
 
-#: src/language/data-io/data-parser.c:663
+#: src/language/data-io/data-parser.c:664
 msgid "Record ends in data not part of any field."
 msgstr "Record eindigt in gegeven dat geen onderdeel is van een veld."
 
-#: src/language/data-io/data-parser.c:683 src/language/data-io/print.c:404
+#: src/language/data-io/data-parser.c:684 src/language/data-io/print.c:404
 msgid "Record"
 msgstr "Record"
 
-#: src/language/data-io/data-parser.c:684 src/language/data-io/print.c:405
-#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:839
+#: src/language/data-io/data-parser.c:685 src/language/data-io/print.c:405
+#: src/ui/gui/psppire-var-sheet.c:541 src/ui/gui/psppire-var-store.c:840
 #: src/ui/gui/crosstabs.ui:89
 msgid "Columns"
 msgstr "Kolommen"
 
-#: src/language/data-io/data-parser.c:685
-#: src/language/data-io/data-parser.c:722 src/language/data-io/print.c:406
+#: src/language/data-io/data-parser.c:686
+#: src/language/data-io/data-parser.c:723 src/language/data-io/print.c:406
 msgid "Format"
 msgstr "Indeling"
 
-#: src/language/data-io/data-parser.c:703
+#: src/language/data-io/data-parser.c:704
 #, c-format
 msgid "Reading %d record from %s."
 msgid_plural "Reading %d records from %s."
 msgstr[0] "Lezen %d record van %s."
 msgstr[1] "Lezen %d records van %s."
 
-#: src/language/data-io/data-parser.c:737
+#: src/language/data-io/data-parser.c:738
 #, c-format
 msgid "Reading free-form data from %s."
 msgstr "Lezen vrije-vorm gegeven van %s."
@@ -3343,59 +3384,59 @@ msgstr "Lezen vrije-vorm gegeven van %s."
 msgid "data file"
 msgstr "gegevensbestand"
 
-#: src/language/data-io/data-reader.c:149
+#: src/language/data-io/data-reader.c:148
 #, c-format
 msgid "Could not open `%s' for reading as a data file: %s."
 msgstr "Kon '%s' niet openen voor het lezen als gegevensbestand: %s."
 
-#: src/language/data-io/data-reader.c:191
-msgid "Unexpected end-of-file while reading data in BEGIN DATA.  This probably indicates a missing or misformatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
-msgstr "Onverwacht einde-bestand tijdens het lezen van gegevens in BEGIN DATA. Dit geeft waarschijnlijk aan dat de END DATA opdracht ontbreekt of verkeerd geschreven is. END DATA dient alleen op één regel met precies één spatie tussen de woorden voor te komen."
+#: src/language/data-io/data-reader.c:198
+msgid "Missing END DATA while reading inline data.  This probably indicates a missing or incorrectly formatted END DATA command.  END DATA must appear by itself on a single line with exactly one space between words."
+msgstr "Mis END DATA tijdens het lezen van inline data.  Dit geeft waarschijnlijk een ontbrekend of incorrect gespecificeerd END DATA opdracht aan.  END DATA moet alleen op een enkele regel met precies een spatie tussen de woorden voorkomen."
 
-#: src/language/data-io/data-reader.c:216
+#: src/language/data-io/data-reader.c:219
 #, c-format
 msgid "Error reading file %s: %s."
 msgstr "Fout tijdens lezen bestand %s: %s."
 
-#: src/language/data-io/data-reader.c:219
+#: src/language/data-io/data-reader.c:222
 #, c-format
 msgid "Unexpected end of file reading %s."
 msgstr "Onverwacht einde tijdens lezen van bestand %s."
 
-#: src/language/data-io/data-reader.c:228
+#: src/language/data-io/data-reader.c:231
 #, c-format
 msgid "Unexpected end of file in partial record reading %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:288
+#: src/language/data-io/data-reader.c:291
 #, c-format
 msgid "Corrupt block descriptor word at offset 0x%lx in %s."
-msgstr ""
+msgstr "Corrupt blok beschrijvend woord op offset 0x%lx in %s."
 
-#: src/language/data-io/data-reader.c:289
+#: src/language/data-io/data-reader.c:292
 #, c-format
 msgid "Corrupt record descriptor word at offset 0x%lx in %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:302
+#: src/language/data-io/data-reader.c:305
 #, c-format
 msgid "Corrupt record size at offset 0x%lx in %s."
 msgstr ""
 
-#: src/language/data-io/data-reader.c:444
+#: src/language/data-io/data-reader.c:445
 msgid "Record exceeds remaining block length."
 msgstr "Record overschrijdt resterende bloklengte."
 
-#: src/language/data-io/data-reader.c:518
+#: src/language/data-io/data-reader.c:519
 #, c-format
 msgid "Attempt to read beyond end-of-file on file %s."
 msgstr "Poging om te lezen na einde-bestand in bestand %s."
 
-#: src/language/data-io/data-reader.c:521
+#: src/language/data-io/data-reader.c:522
 msgid "Attempt to read beyond END DATA."
 msgstr "Poging om te lezen na END DATA."
 
-#: src/language/data-io/data-reader.c:703
+#: src/language/data-io/data-reader.c:706
 msgid "This command is not valid here since the current input program does not access the inline file."
 msgstr "Deze opdracht is hier niet geldig omdat het huidige invoerprogramma het inline-bestand niet benaderd."
 
@@ -3409,90 +3450,107 @@ msgstr "Een fout is opgetreden tijdens het openen van '%s' voor schrijven als ge
 msgid "I/O error occurred writing data file `%s'."
 msgstr "I/O fout opgetreden tijdens schrijven gegevensbestand '%s'."
 
+#: src/language/data-io/dataset.c:63
+#, c-format
+msgid "There is no dataset named %s."
+msgstr "Er is geen dataset genaamd %s."
+
+#: src/language/data-io/dataset.c:257
+msgid "Dataset"
+msgstr "Dataset"
+
+#: src/language/data-io/dataset.c:265
+msgid "unnamed dataset"
+msgstr ""
+
+#: src/language/data-io/dataset.c:269
+msgid "(active dataset)"
+msgstr "(actieve dataset)"
+
 #: src/language/data-io/get-data.c:64
 #, c-format
-msgid "Unsupported TYPE %s"
-msgstr "Niet ondersteund TYPE %s"
+msgid "Unsupported TYPE %s."
+msgstr "Niet ondersteund TYPE %s."
 
-#: src/language/data-io/get-data.c:259
+#: src/language/data-io/get-data.c:268
 #, c-format
 msgid "%s is allowed only with %s arrangement, but %s arrangement was stated or implied earlier in this command."
 msgstr "%s is alleen toegestaan met %s regeling, maar %s regeling was eerder opgegeven of geïmpliceerd in deze opdracht."
 
-#: src/language/data-io/get-data.c:327
+#: src/language/data-io/get-data.c:337
 msgid "Value of FIRSTCASE must be 1 or greater."
 msgstr "Waarde van FIRSTCASE moet 1 of groter zijn."
 
-#: src/language/data-io/get-data.c:365
+#: src/language/data-io/get-data.c:375
 msgid "Value of FIXCASE must be at least 1."
 msgstr "Waarde van FIXCASE moet tenminste 1 zijn."
 
-#: src/language/data-io/get-data.c:385
+#: src/language/data-io/get-data.c:395
 msgid "Value of FIRST must be at least 1."
 msgstr "Waarde van FIRST moet tenminste 1 zijn."
 
-#: src/language/data-io/get-data.c:397
+#: src/language/data-io/get-data.c:407
 msgid "Value of PERCENT must be between 1 and 100."
 msgstr "Waarde van PERCENT moet tussen 1 en 100 zijn."
 
-#: src/language/data-io/get-data.c:446
+#: src/language/data-io/get-data.c:458
 msgid "In compatible syntax mode, the QUALIFIER string must contain exactly one character."
 msgstr "In compatibele syntaxmodus, dient de QUALIFIER tekenreeks precies één teken te bevatten."
 
-#: src/language/data-io/get-data.c:483
-#: src/language/data-io/placement-parser.c:378
+#: src/language/data-io/get-data.c:493
+#: src/language/data-io/placement-parser.c:377
 #, c-format
 msgid "The record number specified, %ld, is at or before the previous record, %d.  Data fields must be listed in order of increasing record number."
 msgstr "Het opgegeven recordnummer, %ld, is op of voor het huidige record, %d. Gegevensvelden dienen opgegeven te worden in oplopende recordnummer volgorde."
 
-#: src/language/data-io/get-data.c:492
+#: src/language/data-io/get-data.c:502
 #, c-format
 msgid "The record number specified, %ld, exceeds the number of records per case specified on FIXCASE, %d."
 msgstr "Het gespecificeerde recordnummer, %ld, overschrijdt het aantal records per case zoals gespecificeerd in FIXCASE, %d."
 
-#: src/language/data-io/inpt-pgm.c:130
+#: src/language/data-io/inpt-pgm.c:118
 msgid "Unexpected end-of-file within INPUT PROGRAM."
 msgstr "Onverwacht einde-bestand binnen INPUT PROGRAM."
 
-#: src/language/data-io/inpt-pgm.c:143
+#: src/language/data-io/inpt-pgm.c:131
 msgid "Input program did not create any variables."
 msgstr "Invoerprogramma heeft geen variabelen gecreëerd."
 
-#: src/language/data-io/inpt-pgm.c:338
+#: src/language/data-io/inpt-pgm.c:330
 msgid "REREAD: Column numbers must be positive finite numbers.  Column set to 1."
 msgstr "REREAD: Kolomnummers moeten positieve eindige nummers zijn. Kolom is op 1 gezet."
 
-#: src/language/data-io/placement-parser.c:87
+#: src/language/data-io/placement-parser.c:86
 #, c-format
 msgid "Number of variables specified (%zu) differs from number of variable formats (%zu)."
 msgstr "Aantal gespecificeerde variabelen (%zu) verschilt van aantal variabele formats (%zu)."
 
-#: src/language/data-io/placement-parser.c:97
+#: src/language/data-io/placement-parser.c:96
 msgid "SPSS-like or Fortran-like format specification expected after variable names."
-msgstr "SPSS-achtig of Fortran-achtig format-specificatie verwacht na variabele naam."
+msgstr "SPSS-achtig of Fortran-achtig format-specificatie verwacht na variabelennaam."
 
-#: src/language/data-io/placement-parser.c:119
+#: src/language/data-io/placement-parser.c:118
 #, c-format
 msgid "The %d columns %d-%d can't be evenly divided into %zu fields."
 msgstr "De %d kolommen %d-%d kunnen niet gelijk verdeeld worden in %zu velden."
 
-#: src/language/data-io/placement-parser.c:305
+#: src/language/data-io/placement-parser.c:302
 msgid "Column positions for fields must be positive."
 msgstr "Kolomposities voor velden moeten positief zijn."
 
-#: src/language/data-io/placement-parser.c:307
+#: src/language/data-io/placement-parser.c:304
 msgid "Column positions for fields must not be negative."
 msgstr "Kolomposities voor velden mogen niet negatief zijn."
 
-#: src/language/data-io/placement-parser.c:344
+#: src/language/data-io/placement-parser.c:343
 msgid "The ending column for a field must be greater than the starting column."
 msgstr "De eindkolom van een veld moet groter zijn dan de startkolom."
 
-#: src/language/data-io/print-space.c:116
+#: src/language/data-io/print-space.c:115
 msgid "The expression on PRINT SPACE evaluated to the system-missing value."
 msgstr "De expressie bij PRINT SPACE evalueerde tot de system-missing waarde."
 
-#: src/language/data-io/print-space.c:119
+#: src/language/data-io/print-space.c:118
 #, c-format
 msgid "The expression on PRINT SPACE evaluated to %g."
 msgstr "De expressie bij PRINT SPACE evalueerde tot %g."
@@ -3520,100 +3578,100 @@ msgid_plural "Writing %zu records."
 msgstr[0] "Schrijven van %zu record."
 msgstr[1] "Schrijven van %zu records."
 
-#: src/language/data-io/save-translate.c:164
-#: src/language/data-io/save-translate.c:178
+#: src/language/data-io/save-translate.c:165
+#: src/language/data-io/save-translate.c:180
 #, c-format
 msgid "The %s string must contain exactly one character."
 msgstr "De %s tekenreeks dient exact één teken te bevatten."
 
-#: src/language/data-io/save-translate.c:248
+#: src/language/data-io/save-translate.c:250
 #, c-format
 msgid "Output file `%s' exists but REPLACE was not specified."
-msgstr ""
+msgstr "Uitvoerbestand `%s' bestaat maar REPLACE was niet opgegeven."
 
-#: src/language/data-io/trim.c:88
+#: src/language/data-io/trim.c:89
 #, c-format
 msgid "Cannot rename %s as %s because there already exists a variable named %s.  To rename variables with overlapping names, use a single RENAME subcommand such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, `/RENAME (A B C=B C A)'."
 msgstr "Kan %s niet hernoemen naar  %s omdat er al een variabele met de naam %s bestaat.  Om variabelen met overlappende naam te hernoemen gebruik een enkel RENAME-subopdracht zoals '/RENAME (A=B)(B=C)(C=A)', of equivalent achtig, '/RENAME (A B C=B C A)'."
 
-#: src/language/data-io/trim.c:114
+#: src/language/data-io/trim.c:115
 msgid "`=' expected after variable list."
 msgstr "'=' verwacht na variabelenlijst."
 
-#: src/language/data-io/trim.c:122
+#: src/language/data-io/trim.c:123
 #, c-format
 msgid "Number of variables on left side of `=' (%zu) does not match number of variables on right side (%zu), in parenthesized group %d of RENAME subcommand."
 msgstr "Aantal variabelen aan linker zijde van `=' (%zu) komt niet overeen met het aantal variabelen aan rechter zijde (%zu), in tussengevoegde groep %d van RENAME-subopdracht."
 
-#: src/language/data-io/trim.c:135
+#: src/language/data-io/trim.c:136
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr "Gevraagde hernoeming dupliceert variabelennaam %s."
 
-#: src/language/data-io/trim.c:166
+#: src/language/data-io/trim.c:167
 msgid "Cannot DROP all variables from dictionary."
 msgstr "Kan niet alle variabelen DROP-en uit woordenboek."
 
-#: src/language/expressions/evaluate.c:149
+#: src/language/expressions/evaluate.c:152
 msgid "expecting number or string"
 msgstr "verwacht nummer of tekenreeks"
 
-#: src/language/expressions/evaluate.c:163
+#: src/language/expressions/evaluate.c:166
 #, c-format
 msgid "Duplicate variable name %s."
 msgstr "Dubbele variabelennaam %s."
 
-#: src/language/expressions/helpers.c:38
+#: src/language/expressions/helpers.c:41
 msgid "One of the arguments to a DATE function is not an integer.  The result will be system-missing."
 msgstr "Een van de variabelen voor een DATE functie is geen integer. Het resultaat zal system-missing zijn."
 
-#: src/language/expressions/helpers.c:66
+#: src/language/expressions/helpers.c:69
 msgid "The week argument to DATE.WKYR is not an integer.  The result will be system-missing."
 msgstr "Het week argument voor DATE.WKYR is geen integer.  Het resultaat zal system-missing zijn."
 
-#: src/language/expressions/helpers.c:72
+#: src/language/expressions/helpers.c:75
 msgid "The week argument to DATE.WKYR is outside the acceptable range of 1 to 53.  The result will be system-missing."
 msgstr "Het week argument voor DATE.WKYR is buiten het acceptabele bereik van 1 tot 53.  Het resultaat zal system-missing zijn."
 
-#: src/language/expressions/helpers.c:94
+#: src/language/expressions/helpers.c:97
 msgid "The day argument to DATE.YRDAY is not an integer.  The result will be system-missing."
 msgstr "Het dag argument voor DATE.WKYR is geen integer.  Het resultaat zal system-missing zijn."
 
-#: src/language/expressions/helpers.c:100
+#: src/language/expressions/helpers.c:103
 msgid "The day argument to DATE.YRDAY is outside the acceptable range of 1 to 366.  The result will be system-missing."
 msgstr "Het dag argument voor DATE.WKYR is buiten het acceptabele bereik van 1 tot 366.  Het resultaat zal system-missing zijn."
 
-#: src/language/expressions/helpers.c:122
+#: src/language/expressions/helpers.c:125
 msgid "The year argument to YRMODA is greater than 47516.  The result will be system-missing."
 msgstr "Het jaar argument voor YRMODA is groter dan 47516.  Het resultaat zal system-missing zijn."
 
 #. TRANSLATORS: Don't translate the the actual unit names `weeks', `days' etc
 #. They must remain in their original English.
-#: src/language/expressions/helpers.c:177
+#: src/language/expressions/helpers.c:180
 #, c-format
 msgid "Unrecognized date unit `%.*s'.  Valid date units are `years', `quarters', `months', `weeks', `days', `hours', `minutes', and `seconds'."
 msgstr "Niet-herkende datum eenheid '%.*s'.  Geldige datum eenheden zijn 'years', 'quarters', 'months', 'weeks', 'days', 'hours', 'minutes', en 'seconds'."
 
-#: src/language/expressions/helpers.c:327
+#: src/language/expressions/helpers.c:330
 msgid "Invalid DATESUM method.  Valid choices are `closest' and `rollover'."
 msgstr "Ongeldige DATESUM methode. Geldige keuzes zijn 'closest' en 'rollover'."
 
-#: src/language/expressions/parse.c:259
+#: src/language/expressions/parse.c:260
 #, c-format
 msgid "Type mismatch: expression has %s type, but a numeric value is required here."
 msgstr "Type ongelijk: expressie heeft type %s, maar een numerieke waarde is hier vereist."
 
-#: src/language/expressions/parse.c:271
+#: src/language/expressions/parse.c:272
 #, c-format
 msgid "Type mismatch: expression has %s type, but a string value is required here."
 msgstr "Type ongelijk: expressie heeft type %s, maar een tekenreeks waarde is hier vereist."
 
-#: src/language/expressions/parse.c:433
+#: src/language/expressions/parse.c:434
 #, c-format
 msgid "Type mismatch while applying %s operator: cannot convert %s to %s."
 msgstr "Type ongelijk tijdens het uitvoeren van %s operator: kan %s niet naar %s converteren."
 
-#: src/language/expressions/parse.c:649
+#: src/language/expressions/parse.c:648
 msgid "Chaining relational operators (e.g. `a < b < c') will not produce the mathematically expected result.  Use the AND logical operator to fix the problem (e.g. `a < b AND b < c').  If chaining is really intended, parentheses will disable this warning (e.g. `(a < b) < c'.)"
 msgstr ""
 
@@ -3621,75 +3679,75 @@ msgstr ""
 msgid "The exponentiation operator (`**') is left-associative, even though right-associative semantics are more useful.  That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'.  To disable this warning, insert parentheses."
 msgstr ""
 
-#: src/language/expressions/parse.c:815
+#: src/language/expressions/parse.c:830
 #, c-format
 msgid "Unknown system variable %s."
 msgstr "Onbekende systeemvariabele %s."
 
-#: src/language/expressions/parse.c:863
+#: src/language/expressions/parse.c:878
 #, c-format
 msgid "Unknown identifier %s."
-msgstr "Onbekende herkenningsteken %s."
+msgstr "Onbekende identificator %s."
 
-#: src/language/expressions/parse.c:1076
+#: src/language/expressions/parse.c:1100
 #, c-format
 msgid "%s must have at least %d arguments in list."
 msgstr "%s heeft tenminste %d argumenten nodig in lijst."
 
-#: src/language/expressions/parse.c:1085
+#: src/language/expressions/parse.c:1109
 #, c-format
 msgid "%s must have an even number of arguments in list."
 msgstr "%s heeft een even aantal argumenten in lijst nodig."
 
-#: src/language/expressions/parse.c:1088
+#: src/language/expressions/parse.c:1112
 #, c-format
 msgid "%s must have multiple of %d arguments in list."
 msgstr "%s heeft meerdere %d argumenten in lijst nodig."
 
-#: src/language/expressions/parse.c:1098
+#: src/language/expressions/parse.c:1122
 #, c-format
 msgid "%s function does not accept a minimum valid argument count."
 msgstr "%s functie accepteert geen minimaal geldige argumenten teller."
 
-#: src/language/expressions/parse.c:1107
+#: src/language/expressions/parse.c:1131
 #, c-format
 msgid "%s requires at least %d valid arguments in list."
 msgstr "%s vereist tenminste %d geldige argumenten in lijst."
 
-#: src/language/expressions/parse.c:1113
+#: src/language/expressions/parse.c:1137
 #, c-format
 msgid "With %s, using minimum valid argument count of %d does not make sense when passing only %d arguments in list."
 msgstr "Met %s, heeft het gebruik van de minimum geldige argumenttelling van %d geen zin wanneer een lijst van slechts %d wordt doorgegeven."
 
-#: src/language/expressions/parse.c:1167
+#: src/language/expressions/parse.c:1191
 #, c-format
 msgid "Type mismatch invoking %s as "
 msgstr "Type ongelijk bij aanroep %s als "
 
-#: src/language/expressions/parse.c:1172
+#: src/language/expressions/parse.c:1196
 msgid "Function invocation "
 msgstr "Functieaanroep "
 
-#: src/language/expressions/parse.c:1174
+#: src/language/expressions/parse.c:1198
 msgid " does not match any known function.  Candidates are:"
 msgstr " komt niet overeen met een geldige functie. Kandidaten zijn:"
 
-#: src/language/expressions/parse.c:1204
+#: src/language/expressions/parse.c:1228
 #, c-format
 msgid "No function or vector named %s."
 msgstr "Geen functie of vector genaamd %s."
 
-#: src/language/expressions/parse.c:1247
+#: src/language/expressions/parse.c:1271
 #, c-format
 msgid "expecting `,' or `)' invoking %s function"
 msgstr "verwacht ',' of ')' bij aanroep %s functie"
 
-#: src/language/expressions/parse.c:1267
+#: src/language/expressions/parse.c:1291
 #, c-format
 msgid "%s is a PSPP extension."
 msgstr "%s is een PSPP extensie."
 
-#: src/language/expressions/parse.c:1276
+#: src/language/expressions/parse.c:1300
 #, c-format
 msgid "%s may not appear after TEMPORARY."
 msgstr "%s mag niet voorkomen na TEMPORARY."
@@ -3714,32 +3772,32 @@ msgstr "onverwacht einde-bestand bij het lezen van tijdelijk bestand"
 msgid "writing to temporary file"
 msgstr "schrijven naar tijdelijk bestand"
 
-#: src/libpspp/message.c:145
+#: src/libpspp/message.c:172
 msgid "error"
 msgstr "fout"
 
-#: src/libpspp/message.c:148
+#: src/libpspp/message.c:175
 msgid "warning"
 msgstr "waarschuwing"
 
-#: src/libpspp/message.c:152
+#: src/libpspp/message.c:179
 msgid "note"
 msgstr "aantekening"
 
-#: src/libpspp/message.c:251
+#: src/libpspp/message.c:279
 #, c-format
 msgid "Notes (%d) exceed limit (%d).  Suppressing further notes."
 msgstr "Notities (%d) overschrijdt limiet (%d).  Onderdruk verdere notitties."
 
-#: src/libpspp/message.c:259
-#, fuzzy, c-format
+#: src/libpspp/message.c:287
+#, c-format
 msgid "Warnings (%d) exceed limit (%d).  Syntax processing will be halted."
-msgstr "Notities (%d) overschrijdt limiet (%d).  Onderdruk verdere notitties."
+msgstr "Waarschuwingen (%d) overschrijdt limiet (%d).  Syntax bewerking wordt gestopt."
 
-#: src/libpspp/message.c:262
-#, fuzzy, c-format
+#: src/libpspp/message.c:290
+#, c-format
 msgid "Errors (%d) exceed limit (%d).  Syntax processing will be halted."
-msgstr "Notities (%d) overschrijdt limiet (%d).  Onderdruk verdere notitties."
+msgstr "Fouten (%d) overschrijdt limiet (%d).  Syntax bewerking wordt gestopt."
 
 #: src/libpspp/zip-writer.c:91
 #, c-format
@@ -3753,7 +3811,7 @@ msgstr "%s: schrijven mislukt"
 
 #: src/math/percentiles.c:36
 msgid "HAverage"
-msgstr ""
+msgstr "HAverage"
 
 #: src/math/percentiles.c:37
 msgid "Weighted Average"
@@ -3771,61 +3829,60 @@ msgstr "Empirisch"
 msgid "Empirical with averaging"
 msgstr "Empirisch met gemiddelde"
 
-#: src/output/ascii.c:279
+#: src/output/ascii.c:298
 #, c-format
 msgid "%s: %s must be positive integer or `auto'"
 msgstr "%s: %s dient positief integer of 'auto' te zijn"
 
-#: src/output/ascii.c:312
+#: src/output/ascii.c:331
 #, c-format
 msgid "ascii: page excluding margins and headers must be at least %d characters wide by %d lines long, but as configured is only %d characters by %d lines"
 msgstr "ascii: pagina exclusief marges en koppen moet tenminste %d tekens breed en %d regels lang zijn, maar geconfigureerd is slechts %d tekens bij %d regels"
 
-#: src/output/ascii.c:361
+#: src/output/ascii.c:377
 #, c-format
 msgid "ascii: closing output file `%s'"
 msgstr "ascii: sluiten uitvoerbestand '%s'"
 
-#: src/output/ascii.c:504
+#: src/output/ascii.c:520
 #, c-format
 msgid "See %s for a chart."
 msgstr "Zie %s voor een diagram."
 
-#: src/output/ascii.c:807
+#: src/output/ascii.c:1102
 #, c-format
 msgid "ascii: opening output file `%s'"
 msgstr "ascii: openen uitvoerbestand '%s'"
 
-#: src/output/ascii.c:914
+#: src/output/ascii.c:1173
 #, c-format
 msgid "%s - Page %d"
 msgstr "%s - Pagina %d"
 
-#: src/output/csv.c:87 src/output/html.c:106 src/output/journal.c:93
+#: src/output/csv.c:97 src/output/html.c:104 src/output/journal.c:93
 #: src/output/msglog.c:66
 #, c-format
 msgid "error opening output file `%s'"
 msgstr "fout tijdens openen uitvoerbestand '%s'"
 
 #. TRANSLATORS: Don't translate the words `terminal' or `listing'.
-#: src/output/driver.c:331
+#: src/output/driver.c:319
 #, c-format
 msgid "%s is not a valid device type (the choices are `terminal' and `listing')"
 msgstr "%s is geen valide apparaattype (de keuzes zijn 'terminal' en 'listing')"
 
-#: src/output/driver.c:344
+#: src/output/driver.c:332
 #, c-format
 msgid "%s: unknown option `%s'"
 msgstr "%s: onbekende optie '%s'"
 
-#: src/output/html.c:114
+#: src/output/html.c:112
 msgid "PSPP Output"
 msgstr "PSPP-uitvoer"
 
-#: src/output/html.c:258
-#, fuzzy
+#: src/output/html.c:238
 msgid "No description"
-msgstr "Omschrijving"
+msgstr "Geen omschrijving"
 
 #: src/output/journal.c:67
 #, c-format
@@ -3902,17 +3959,17 @@ msgstr "%s: '%s' is '%s'  maar een integer tussen %d en %d is noodzakelijk"
 msgid "%s: `%s' is `%s' but a file name that contains `#' is required."
 msgstr "%s: '%s' is '%s' maar een bestandsnaam die  '#' bevat is noodzakelijk."
 
-#: src/output/tab.c:206
+#: src/output/tab.c:207
 #, c-format
 msgid "bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
 
-#: src/output/tab.c:244
+#: src/output/tab.c:245
 #, c-format
 msgid "bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in table size (%d,%d)\n"
 msgstr ""
 
-#: src/output/tab.c:288
+#: src/output/tab.c:289
 #, c-format
 msgid "bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n"
 msgstr ""
@@ -3942,7 +3999,7 @@ msgstr "De gedefinieerde pagina is niet lang genoeg om tenminste %d regels van h
 msgid "error drawing output for %s driver: %s"
 msgstr "fout tijdens tekenen uitvoer voor %s driver: %s "
 
-#: src/output/cairo.c:1041
+#: src/output/cairo.c:1073
 #, c-format
 msgid "error writing output file `%s': %s"
 msgstr "fout tijdens schrijven uitvoerbestand '%s': %s"
@@ -3958,7 +4015,7 @@ msgstr "Waargenomen Waarde"
 
 #: src/output/charts/np-plot-cairo.c:39
 msgid "Expected Normal"
-msgstr ""
+msgstr "Verwacht Normal"
 
 #: src/output/charts/np-plot-cairo.c:64
 #, c-format
@@ -3967,14 +4024,14 @@ msgstr "Detrended Normal Q-Q Plot van %s"
 
 #: src/output/charts/np-plot-cairo.c:66
 msgid "Dev from Normal"
-msgstr ""
+msgstr "Dev van Normal"
 
 #: src/output/charts/plot-hist-cairo.c:110
 msgid "HISTOGRAM"
 msgstr "HISTOGRAM"
 
 #: src/output/charts/plot-hist-cairo.c:112
-#: src/language/stats/frequencies.q:814
+#: src/language/stats/frequencies.q:822
 msgid "Frequency"
 msgstr "Frequenties"
 
@@ -3984,44 +4041,43 @@ msgstr "ROC Curve"
 
 #: src/output/charts/scree-cairo.c:36
 msgid "Scree Plot"
-msgstr ""
+msgstr "Scree Plot"
 
 #: src/output/charts/scree-cairo.c:38
 msgid "Eigenvalue"
-msgstr ""
+msgstr "Eigenvalue"
 
 #: src/output/odt.c:94
 msgid "error creating temporary file"
 msgstr "fout tijdens aanmaken tijdelijk bestand"
 
-#: src/ui/source-init-opts.c:80
+#: src/ui/source-init-opts.c:77
 msgid "Algorithm must be either `compatible' or `enhanced'."
 msgstr "Algoritme moet of 'compatible' of 'enhanced' zijn."
 
-#: src/ui/source-init-opts.c:107
+#: src/ui/source-init-opts.c:104
 msgid "Syntax must be either `compatible' or `enhanced'."
 msgstr "Syntax moet of 'compatible' of 'enhanced' zijn."
 
-#: src/ui/terminal/main.c:146
+#: src/ui/terminal/main.c:148
+msgid "Error encountered while ERROR=STOP is effective."
+msgstr "Fout tegengekomen terwijl ERROR=STOP is actief."
+
+#: src/ui/terminal/main.c:154
 msgid "Stopping syntax file processing here to avoid a cascade of dependent command failures."
 msgstr "Stop syntaxbestand uitvoering hier om een cascade van afhankelijke opdrachtfouten te voorkomen."
 
-#: src/ui/terminal/terminal.c:62
-#, c-format
-msgid "could not access definition for terminal `%s'"
-msgstr "kon definitie voor terminal '%s' niet benaderen"
-
-#: src/ui/terminal/terminal-opts.c:120
+#: src/ui/terminal/terminal-opts.c:122
 #, c-format
 msgid "%s: output option missing `='"
 msgstr "%s: ontbrekende uitvoer-optie '='"
 
-#: src/ui/terminal/terminal-opts.c:127
+#: src/ui/terminal/terminal-opts.c:129
 #, c-format
 msgid "%s: output option specified more than once"
 msgstr "%s: uitvoer-optie meer dan 1 keer gespecificeerd"
 
-#: src/ui/terminal/terminal-opts.c:187
+#: src/ui/terminal/terminal-opts.c:171
 #, c-format
 msgid ""
 "PSPP, a program for statistical analysis of sample data.\n"
@@ -4047,9 +4103,11 @@ msgid ""
 "                            calculated from broken algorithms\n"
 "  -x, --syntax={compatible|enhanced}\n"
 "                            set to `compatible' to disable PSPP extensions\n"
+"  -b, --batch               interpret syntax in batch mode\n"
 "  -i, --interactive         interpret syntax in interactive mode\n"
+"  --syntax-encoding=ENCODING  specify encoding for syntax files\n"
 "  -s, --safer               don't allow some unsafe operations\n"
-"Default search path:%s\n"
+"Default search path: %s\n"
 "\n"
 "Informative output:\n"
 "  -h, --help                display this help and exit\n"
@@ -4058,115 +4116,120 @@ msgid ""
 "Non-option arguments are interpreted as syntax files to execute.\n"
 msgstr ""
 
-#: src/ui/gui/aggregate-dialog.c:162
+#: src/ui/terminal/terminal.c:62
+#, c-format
+msgid "could not access definition for terminal `%s'"
+msgstr "kon definitie voor terminal '%s' niet benaderen"
+
+#: src/ui/gui/aggregate-dialog.c:161
 msgid "Aggregate destination file"
 msgstr "Aggregatie doelbestand"
 
-#: src/ui/gui/aggregate-dialog.c:173 src/ui/gui/psppire-data-window.c:403
-#: src/ui/gui/psppire-data-window.c:615
+#: src/ui/gui/aggregate-dialog.c:172 src/ui/gui/psppire-data-window.c:489
+#: src/ui/gui/psppire-window.c:763
 msgid "System Files (*.sav)"
 msgstr "Systeembestanden (*.sav)"
 
-#: src/ui/gui/aggregate-dialog.c:179 src/ui/gui/psppire-data-window.c:409
-#: src/ui/gui/psppire-data-window.c:621
+#: src/ui/gui/aggregate-dialog.c:178 src/ui/gui/psppire-data-window.c:495
+#: src/ui/gui/psppire-window.c:769
 msgid "Portable Files (*.por) "
 msgstr "Overdraagbaar (Portable) bestanden (*.por)"
 
-#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1205
-#: src/language/stats/crosstabs.q:1232 src/language/stats/crosstabs.q:1255
-#: src/language/stats/crosstabs.q:1279 src/language/stats/examine.q:1638
+#: src/ui/gui/checkbox-treeview.c:92 src/language/stats/crosstabs.q:1233
+#: src/language/stats/crosstabs.q:1260 src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1307 src/language/stats/examine.q:1637
 msgid "Statistic"
 msgstr "Statistiek"
 
-#: src/ui/gui/comments-dialog.c:58
+#: src/ui/gui/comments-dialog.c:57
 #, c-format
 msgid "Column Number: %d"
 msgstr "Kolomnummer: %d"
 
-#: src/ui/gui/crosstabs-dialog.c:41
+#: src/ui/gui/crosstabs-dialog.c:40
 msgid "Chisq"
 msgstr "Chisq"
 
-#: src/ui/gui/crosstabs-dialog.c:42 src/language/stats/crosstabs.q:1768
+#: src/ui/gui/crosstabs-dialog.c:41 src/language/stats/crosstabs.q:1806
 msgid "Phi"
 msgstr "Phi"
 
-#: src/ui/gui/crosstabs-dialog.c:43
+#: src/ui/gui/crosstabs-dialog.c:42
 msgid "CC"
 msgstr "CC"
 
-#: src/ui/gui/crosstabs-dialog.c:44 src/language/stats/crosstabs.q:1906
+#: src/ui/gui/crosstabs-dialog.c:43 src/language/stats/crosstabs.q:1944
 msgid "Lambda"
 msgstr "Lambda"
 
-#: src/ui/gui/crosstabs-dialog.c:45
+#: src/ui/gui/crosstabs-dialog.c:44
 msgid "UC"
 msgstr "UC"
 
-#: src/ui/gui/crosstabs-dialog.c:46
+#: src/ui/gui/crosstabs-dialog.c:45
 msgid "BTau"
 msgstr "BTau"
 
-#: src/ui/gui/crosstabs-dialog.c:47
+#: src/ui/gui/crosstabs-dialog.c:46
 msgid "CTau"
 msgstr "CTau"
 
-#: src/ui/gui/crosstabs-dialog.c:48
+#: src/ui/gui/crosstabs-dialog.c:47
 msgid "Risk"
-msgstr ""
+msgstr "Risk"
 
-#: src/ui/gui/crosstabs-dialog.c:49 src/language/stats/crosstabs.q:1773
+#: src/ui/gui/crosstabs-dialog.c:48 src/language/stats/crosstabs.q:1811
 msgid "Gamma"
 msgstr "Gamma"
 
-#: src/ui/gui/crosstabs-dialog.c:50
+#: src/ui/gui/crosstabs-dialog.c:49
 msgid "D"
 msgstr "D"
 
-#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1776
+#: src/ui/gui/crosstabs-dialog.c:50 src/language/stats/crosstabs.q:1814
 msgid "Kappa"
 msgstr "Kappa"
 
-#: src/ui/gui/crosstabs-dialog.c:52 src/language/stats/crosstabs.q:1910
+#: src/ui/gui/crosstabs-dialog.c:51 src/language/stats/crosstabs.q:1948
 msgid "Eta"
 msgstr "Eta"
 
-#: src/ui/gui/crosstabs-dialog.c:53
+#: src/ui/gui/crosstabs-dialog.c:52
 msgid "Corr"
 msgstr "Corr"
 
-#: src/ui/gui/crosstabs-dialog.c:54 src/ui/gui/crosstabs-dialog.c:65
-#: src/ui/gui/crosstabs-dialog.c:100 src/ui/gui/crosstabs-dialog.c:108
+#: src/ui/gui/crosstabs-dialog.c:53 src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:99 src/ui/gui/crosstabs-dialog.c:107
 #: src/ui/gui/psppire-var-store.c:612 src/ui/gui/var-display.c:16
 #: src/ui/gui/variable-info-dialog.c:41
 msgid "None"
 msgstr "Geen"
 
-#: src/ui/gui/crosstabs-dialog.c:57
+#: src/ui/gui/crosstabs-dialog.c:56
 msgid "Count"
 msgstr "Aantal"
 
-#: src/ui/gui/crosstabs-dialog.c:58
+#: src/ui/gui/crosstabs-dialog.c:57
 msgid "Row"
 msgstr "Rij"
 
-#: src/ui/gui/crosstabs-dialog.c:59
+#: src/ui/gui/crosstabs-dialog.c:58
 msgid "Column"
 msgstr "Kolom"
 
-#: src/ui/gui/crosstabs-dialog.c:61
+#: src/ui/gui/crosstabs-dialog.c:60
 msgid "Expected"
 msgstr "Verwacht"
 
-#: src/ui/gui/crosstabs-dialog.c:63
+#: src/ui/gui/crosstabs-dialog.c:62
 msgid "Std. Residual"
-msgstr ""
+msgstr "Std. Residual"
 
-#: src/ui/gui/crosstabs-dialog.c:64
+#: src/ui/gui/crosstabs-dialog.c:63
 msgid "Adjusted Std. Residual"
-msgstr ""
+msgstr "Adjusted Std. Residual"
 
-#: src/ui/gui/descriptives-dialog.c:46
+#: src/ui/gui/descriptives-dialog.c:45
 msgid "Standard error"
 msgstr "Standaardfout"
 
@@ -4175,28 +4238,28 @@ msgstr "Standaardfout"
 msgid "Bad regular expression: %s"
 msgstr "Onjuiste regulaire expressie: %s"
 
-#: src/ui/gui/factor-dialog.c:344
+#: src/ui/gui/factor-dialog.c:343
 #, c-format
 msgid "Eigenvalues over %4.2f times the mean eigenvalue"
 msgstr ""
 
-#: src/ui/gui/frequencies-dialog.c:45
+#: src/ui/gui/frequencies-dialog.c:44
 msgid "Standard error of the mean"
 msgstr ""
 
-#: src/ui/gui/frequencies-dialog.c:48
+#: src/ui/gui/frequencies-dialog.c:47
 msgid "Standard error of the skewness"
 msgstr ""
 
-#: src/ui/gui/frequencies-dialog.c:50 src/language/stats/frequencies.q:108
+#: src/ui/gui/frequencies-dialog.c:49 src/language/stats/frequencies.q:108
 msgid "Mode"
 msgstr "Modus"
 
-#: src/ui/gui/frequencies-dialog.c:52
+#: src/ui/gui/frequencies-dialog.c:51
 msgid "Standard error of the kurtosis"
 msgstr ""
 
-#: src/ui/gui/frequencies-dialog.c:53 src/language/stats/examine.q:1469
+#: src/ui/gui/frequencies-dialog.c:52 src/language/stats/examine.q:1468
 #: src/language/stats/frequencies.q:107
 msgid "Median"
 msgstr "Mediaan"
@@ -4224,7 +4287,7 @@ msgstr "_Hulp"
 msgid "_Reference Manual"
 msgstr "_Handleiding"
 
-#: src/ui/gui/main.c:99
+#: src/ui/gui/main.c:82
 #, c-format
 msgid ""
 "PSPPIRE, a GUI for PSPP, a program for statistical analysis of sample data.\n"
@@ -4245,7 +4308,7 @@ msgid ""
 "                            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"
+"Default search path: %s\n"
 "\n"
 "Informative output:\n"
 "  -h, --help                display this help and exit\n"
@@ -4262,24 +4325,24 @@ msgstr "Onjuiste waarde voor variabelentype"
 msgid "Incorrect range specification"
 msgstr "Onjuiste bereikspecificatie"
 
-#: src/ui/gui/oneway-anova-dialog.c:313
+#: src/ui/gui/oneway-anova-dialog.c:300
 #, c-format
 msgid "Contrast %d of %d"
-msgstr ""
+msgstr "Contrast %d van %d"
 
-#: src/ui/gui/psppire.c:224
+#: src/ui/gui/psppire.c:191
 msgid "_Reset"
 msgstr "_Herstel"
 
-#: src/ui/gui/psppire.c:225
+#: src/ui/gui/psppire.c:192
 msgid "_Select"
 msgstr "_Selecteer"
 
-#: src/ui/gui/psppire-data-editor.c:951
+#: src/ui/gui/psppire-data-editor.c:970
 msgid "Data View"
 msgstr "Gegevensweergave"
 
-#: src/ui/gui/psppire-data-editor.c:954
+#: src/ui/gui/psppire-data-editor.c:973
 msgid "Variable View"
 msgstr "Variabelenweergave"
 
@@ -4287,71 +4350,73 @@ msgstr "Variabelenweergave"
 msgid "var"
 msgstr "var"
 
-#: src/ui/gui/psppire-data-window.c:213
+#: src/ui/gui/psppire-data-window.c:202
 msgid "Transformations Pending"
 msgstr "Transformaties uitstaand"
 
-#: src/ui/gui/psppire-data-window.c:229
+#: src/ui/gui/psppire-data-window.c:218
 msgid "Filter off"
 msgstr "Filter uit"
 
-#: src/ui/gui/psppire-data-window.c:243
+#: src/ui/gui/psppire-data-window.c:232
 #, c-format
 msgid "Filter by %s"
 msgstr "Filter op %s"
 
-#: src/ui/gui/psppire-data-window.c:264
+#: src/ui/gui/psppire-data-window.c:253
 msgid "No Split"
 msgstr "Geen splits"
 
-#: src/ui/gui/psppire-data-window.c:273
+#: src/ui/gui/psppire-data-window.c:262
 msgid "Split by "
 msgstr "Splits op "
 
-#: src/ui/gui/psppire-data-window.c:301
+#: src/ui/gui/psppire-data-window.c:290
 msgid "Weights off"
 msgstr "Weging uit"
 
-#: src/ui/gui/psppire-data-window.c:315
+#: src/ui/gui/psppire-data-window.c:304
 #, c-format
 msgid "Weight by %s"
 msgstr "Weeg op %s"
 
-#: src/ui/gui/psppire-data-window.c:383
-msgid "Open"
-msgstr "Open"
-
-#: src/ui/gui/psppire-data-window.c:393
-msgid "Data and Syntax Files"
-msgstr "Gegevens- en Syntax-bestanden"
-
-#: src/ui/gui/psppire-data-window.c:415 src/ui/gui/psppire-syntax-window.c:501
-msgid "Syntax Files (*.sps) "
-msgstr "Syntaxbestanden (*.sps)"
+#: src/ui/gui/psppire-data-window.c:481 src/ui/gui/aggregate.ui:448
+msgid "Save"
+msgstr "Opslaan"
 
-#: src/ui/gui/psppire-data-window.c:421 src/ui/gui/psppire-data-window.c:627
-#: src/ui/gui/psppire-syntax-window.c:507
+#: src/ui/gui/psppire-data-window.c:501 src/ui/gui/psppire-syntax-window.c:508
+#: src/ui/gui/psppire-window.c:781
 msgid "All Files"
 msgstr "Alle bestanden"
 
-#: src/ui/gui/psppire-data-window.c:607 src/ui/gui/aggregate.ui:448
-msgid "Save"
-msgstr "Opslaan"
-
-#: src/ui/gui/psppire-data-window.c:640
+#: src/ui/gui/psppire-data-window.c:514
 msgid "Portable File"
 msgstr "Overdraagbaar bestand"
 
-#: src/ui/gui/psppire-data-window.c:777
+#: src/ui/gui/psppire-data-window.c:571
+msgid "Delete Existing Dataset?"
+msgstr "Verwijder bestaande dataset?"
+
+#: src/ui/gui/psppire-data-window.c:575
+#, c-format
+msgid "Renaming \"%s\" to \"%s\" will delete destroy the existing dataset named \"%s\".  Are you sure that you want to do this?"
+msgstr ""
+
+#: src/ui/gui/psppire-data-window.c:603
+#, c-format
+msgid "Please enter a new name for dataset \"%s\":"
+msgstr "Voer aub een nieuwe naam voor de dateset \"%s\" in:"
+
+#: src/ui/gui/psppire-data-window.c:605
+msgid "Rename Dataset"
+msgstr "Hernoem dataset"
+
+#: src/ui/gui/psppire-data-window.c:684
 msgid "Font Selection"
 msgstr "Font selectie"
 
 #. TRANSLATORS: This will form a filename.  Please avoid whitespace.
-#: src/ui/gui/psppire-data-window.c:1271
-msgid "PSPP-data"
-msgstr ""
-
-#: src/ui/gui/psppire-data-window.c:1272
+#: src/ui/gui/psppire-data-window.c:1287
 msgid "Data Editor"
 msgstr "Gegevensbewerker"
 
@@ -4362,108 +4427,108 @@ msgstr "Gegevensbewerker"
 #. - The first character may not be a digit
 #. - The final charactor may not be '.' or '_'
 #.
-#: src/ui/gui/psppire-dict.c:366
+#: src/ui/gui/psppire-dict.c:367
 #, c-format
 msgid "VAR%05d"
-msgstr ""
+msgstr "VAR%05d"
 
-#: src/ui/gui/psppire-output-window.c:456
+#: src/ui/gui/psppire-output-window.c:467
 msgid "Infer file type from extension"
-msgstr ""
+msgstr "Bepaal bestandstype a.h.v. extensie"
 
-#: src/ui/gui/psppire-output-window.c:457
+#: src/ui/gui/psppire-output-window.c:468
 msgid "PDF (*.pdf)"
 msgstr "PDF (*.pdf)"
 
-#: src/ui/gui/psppire-output-window.c:458
+#: src/ui/gui/psppire-output-window.c:469
 msgid "HTML (*.html)"
 msgstr "HTML (*.html)"
 
-#: src/ui/gui/psppire-output-window.c:459
+#: src/ui/gui/psppire-output-window.c:470
 msgid "OpenDocument (*.odt)"
 msgstr "OpenDocument (*.odt)"
 
-#: src/ui/gui/psppire-output-window.c:460
+#: src/ui/gui/psppire-output-window.c:471
 msgid "Text (*.txt)"
 msgstr "Text (*.txt)"
 
-#: src/ui/gui/psppire-output-window.c:461
+#: src/ui/gui/psppire-output-window.c:472
 msgid "PostScript (*.ps)"
 msgstr "PostScript (*.ps)"
 
-#: src/ui/gui/psppire-output-window.c:462
+#: src/ui/gui/psppire-output-window.c:473
 msgid "Comma-Separated Values (*.csv)"
 msgstr "Komma-Gescheiden-Waarde (*.csv)"
 
-#: src/ui/gui/psppire-output-window.c:563
+#: src/ui/gui/psppire-output-window.c:574
 msgid "Export Output"
 msgstr "Exporteer Uitvoer"
 
-#: src/ui/gui/psppire-output-window.c:817
+#: src/ui/gui/psppire-output-window.c:828
 msgid "failed to create temporary directory"
-msgstr "aanmaken van tijdelijk bestand is mislukt"
+msgstr "aanmaken van tijdelijke map is mislukt"
 
 #. TRANSLATORS: This will form a filename.  Please avoid whitespace.
-#: src/ui/gui/psppire-output-window.c:1048
+#: src/ui/gui/psppire-output-window.c:1059
 msgid "Output"
 msgstr "Uitvoer"
 
-#: src/ui/gui/psppire-output-window.c:1049
+#: src/ui/gui/psppire-output-window.c:1060
 msgid "Output Viewer"
 msgstr "Uitvoer Viewer"
 
-#: src/ui/gui/psppire-syntax-window.c:474
+#: src/ui/gui/psppire-syntax-window.c:475
 #, c-format
 msgid "Saved file `%s'"
 msgstr "Opslaan bestand '%s'"
 
-#: src/ui/gui/psppire-syntax-window.c:493
+#: src/ui/gui/psppire-syntax-window.c:494
 msgid "Save Syntax"
 msgstr "Sla Syntax op"
 
-#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
-#: src/ui/gui/psppire-syntax-window.c:745
-msgid "Syntax"
-msgstr "Syntax"
+#: src/ui/gui/psppire-syntax-window.c:502 src/ui/gui/psppire-window.c:775
+msgid "Syntax Files (*.sps) "
+msgstr "Syntaxbestanden (*.sps)"
 
-#: src/ui/gui/psppire-syntax-window.c:746
+#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
+#: src/ui/gui/psppire-syntax-window.c:733
 msgid "Syntax Editor"
 msgstr "Syntaxbewerker"
 
-#: src/ui/gui/psppire-syntax-window.c:760
+#: src/ui/gui/psppire-syntax-window.c:747
 #, c-format
 msgid "Cannot load syntax file `%s'"
 msgstr "Kan syntaxbestand '%s' niet laden"
 
-#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:833
-#: src/language/stats/crosstabs.q:1280 src/ui/gui/compute.ui:599
+#: src/ui/gui/psppire-var-sheet.c:535 src/ui/gui/psppire-var-store.c:834
+#: src/language/stats/crosstabs.q:1308 src/ui/gui/compute.ui:599
 msgid "Type"
 msgstr "Type"
 
-#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:834
+#: src/ui/gui/psppire-var-sheet.c:536 src/ui/gui/psppire-var-store.c:835
 #: src/ui/gui/compute.ui:517
 msgid "Width"
 msgstr "Breedte"
 
-#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:835
+#: src/ui/gui/psppire-var-sheet.c:537 src/ui/gui/psppire-var-store.c:836
 msgid "Decimals"
 msgstr "Decimalen"
 
-#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:837
+#: src/ui/gui/psppire-var-sheet.c:539 src/ui/gui/psppire-var-store.c:838
 msgid "Values"
 msgstr "Waardes"
 
-#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:838
-#: src/language/stats/crosstabs.q:814 src/language/stats/examine.q:1104
-#: src/language/stats/frequencies.q:864 src/language/stats/frequencies.q:1036
+#: src/ui/gui/psppire-var-sheet.c:540 src/ui/gui/psppire-var-store.c:839
+#: src/language/stats/crosstabs.q:831 src/language/stats/examine.q:1103
+#: src/language/stats/frequencies.q:872 src/language/stats/frequencies.q:1043
 msgid "Missing"
 msgstr "Ontbrekend"
 
-#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:840
+#: src/ui/gui/psppire-var-sheet.c:542 src/ui/gui/psppire-var-store.c:841
 msgid "Align"
 msgstr "Uitlijnen"
 
-#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:841
+#: src/ui/gui/psppire-var-sheet.c:543 src/ui/gui/psppire-var-store.c:842
 msgid "Measure"
 msgstr "Meting"
 
@@ -4494,183 +4559,181 @@ msgstr "Aangepast"
 #: src/ui/gui/psppire-var-store.c:755
 #, c-format
 msgid "{%s,`%s'}_"
-msgstr ""
-
-#: src/ui/gui/psppire-window.c:97
-#, c-format
-msgid "%s %s PSPPIRE %s"
-msgstr "%s %s PSPPIRE %s"
-
-#. TRANSLATORS: This will form a filename.  Please avoid whitespace.
-#: src/ui/gui/psppire-window.c:247
-msgid "Untitled"
-msgstr "Zonder titel"
+msgstr "{%s,`%s'}_"
 
-#: src/ui/gui/psppire-window.c:469
+#: src/ui/gui/psppire-window.c:549
 #, c-format
 msgid "Save the changes to `%s' before closing?"
 msgstr "Opslaan van de aanpassingen in '%s' voor het afsluiten?"
 
-#: src/ui/gui/psppire-window.c:476
+#: src/ui/gui/psppire-window.c:556
 #, c-format
 msgid "If you don't save, changes from the last %ld seconds will be permanently lost."
 msgstr "Als u niet opslaat zullen de aanpassingen van de laatste %ld seconden permanent verloren gaan."
 
-#: src/ui/gui/psppire-window.c:480
+#: src/ui/gui/psppire-window.c:560
 msgid "Close _without saving"
 msgstr "Sluit _zonder opslaan"
 
-#: src/ui/gui/recode-dialog.c:887
+#: src/ui/gui/psppire-window.c:743
+msgid "Open"
+msgstr "Open"
+
+#: src/ui/gui/psppire-window.c:753
+msgid "Data and Syntax Files"
+msgstr "Gegevens- en Syntax-bestanden"
+
+#: src/ui/gui/recode-dialog.c:886
 msgid "Recode into Different Variables"
 msgstr "Hercodeer in Andere Variabelen"
 
-#: src/ui/gui/recode-dialog.c:890 src/ui/gui/recode.ui:692
+#: src/ui/gui/recode-dialog.c:889 src/ui/gui/recode.ui:692
 msgid "Recode into Same Variables"
 msgstr "Hercodeer in Zelfde Variabelen"
 
-#: src/ui/gui/recode-dialog.c:904 src/ui/gui/recode-dialog.c:1000
+#: src/ui/gui/recode-dialog.c:903 src/ui/gui/recode-dialog.c:999
 msgid "New"
 msgstr "Nieuw"
 
-#: src/ui/gui/recode-dialog.c:919 src/ui/gui/recode-dialog.c:992
+#: src/ui/gui/recode-dialog.c:918 src/ui/gui/recode-dialog.c:991
 msgid "Old"
 msgstr "Oud"
 
-#: src/ui/gui/recode-dialog.c:1249
+#: src/ui/gui/recode-dialog.c:1236
 msgid "Recode into Different Variables: Old and New Values "
 msgstr "Hercodeer in Andere Variabelen: Oude en Nieuwe Waardes "
 
-#: src/ui/gui/recode-dialog.c:1250
+#: src/ui/gui/recode-dialog.c:1237
 msgid "Recode into Same Variables: Old and New Values"
 msgstr "Hercodeer in Zelfde Variabelen: Oude en Nieuwe Waardes "
 
-#: src/ui/gui/regression-dialog.c:42
+#: src/ui/gui/regression-dialog.c:41
 msgid "Coeff"
 msgstr "Coeff"
 
-#: src/ui/gui/regression-dialog.c:43 src/language/stats/regression.q:155
+#: src/ui/gui/regression-dialog.c:42 src/language/stats/regression.q:157
 msgid "R"
 msgstr "R"
 
-#: src/ui/gui/regression-dialog.c:44
+#: src/ui/gui/regression-dialog.c:43
 msgid "Anova"
 msgstr "Anova"
 
-#: src/ui/gui/regression-dialog.c:45
+#: src/ui/gui/regression-dialog.c:44
 msgid "Bcov"
 msgstr "Bcov"
 
-#: src/ui/gui/select-cases-dialog.c:82
+#: src/ui/gui/select-cases-dialog.c:81
 #, c-format
 msgid "Approximately %3d%% of all cases."
 msgstr "Ongeveer %3d%% van alle cases."
 
-#: src/ui/gui/select-cases-dialog.c:83
+#: src/ui/gui/select-cases-dialog.c:82
 #, c-format
 msgid "Exactly %3d cases from the first %3d cases."
 msgstr "Precies %3d cases van de eerste %3d cases."
 
-#: src/ui/gui/select-cases-dialog.c:222
+#: src/ui/gui/select-cases-dialog.c:221
 #, c-format
 msgid "%d thru %d"
 msgstr "%d tot %d"
 
-#: src/ui/gui/text-data-import-dialog.c:461
+#: src/ui/gui/text-data-import-dialog.c:453
 #, c-format
 msgid "Could not open `%s': %s"
 msgstr "Kon '%s': %s niet openen"
 
-#: src/ui/gui/text-data-import-dialog.c:477
+#: src/ui/gui/text-data-import-dialog.c:469
 #, c-format
 msgid "Error reading `%s': %s"
 msgstr "Fout bij lezen '%s': %s"
 
-#: src/ui/gui/text-data-import-dialog.c:480
+#: src/ui/gui/text-data-import-dialog.c:472
 #, c-format
 msgid "Failed to read `%s', because it contains a line over %d bytes long and therefore appears not to be a text file."
 msgstr "Lezen van '%s' mislukt omdat het een regel bevat die meer dan %d bytes lang is en daarom is het geen tekstbestand."
 
-#: src/ui/gui/text-data-import-dialog.c:494
+#: src/ui/gui/text-data-import-dialog.c:486
 #, c-format
 msgid "`%s' is empty."
 msgstr "'%s' is leeg."
 
-#: src/ui/gui/text-data-import-dialog.c:539
+#: src/ui/gui/text-data-import-dialog.c:531
 msgid "Import Delimited Text Data"
 msgstr "Importeer Gescheiden Tekstgegevens"
 
-#: src/ui/gui/text-data-import-dialog.c:590
+#: src/ui/gui/text-data-import-dialog.c:582
 msgid "Importing Delimited Text Data"
 msgstr "Importeren Gescheiden Tekstgegevens"
 
-#: src/ui/gui/text-data-import-dialog.c:739
+#: src/ui/gui/text-data-import-dialog.c:731
 #, c-format
 msgid "Only the first %4d cases"
 msgstr "Alleen de eerste %4d cases"
 
-#: src/ui/gui/text-data-import-dialog.c:749
-#, fuzzy, c-format
+#: src/ui/gui/text-data-import-dialog.c:741
+#, c-format
 msgid "Only the first %3d %% of file (approximately)"
-msgstr "% van bestand (ongeveer)"
+msgstr "Alleen de eerste %3d %% van bestand (ongeveer)"
 
-#: src/ui/gui/text-data-import-dialog.c:774
+#: src/ui/gui/text-data-import-dialog.c:766
 msgid ""
 "This assistant will guide you through the process of importing data into PSPP from a text file with one line per case,  in which fields are separated by tabs, commas, or other delimiters.\n"
 "\n"
 msgstr "De assistent zal je begeleiden door het proces van het importeren van gegevens in PSPP van een tekstbestand met 1 regel per case, waarin velden zijn gescheiden door tabs, komma's of andere scheidingstekens.\n"
 
-#: src/ui/gui/text-data-import-dialog.c:780
+#: src/ui/gui/text-data-import-dialog.c:772
 #, c-format
 msgid "The selected file contains %zu line of text.  "
 msgid_plural "The selected file contains %zu lines of text.  "
 msgstr[0] "Het geselecteerde bestand bevat %zu regel tekst.  "
 msgstr[1] "Het geselecteerde bestand bevat %zu regels tekst. "
 
-#: src/ui/gui/text-data-import-dialog.c:788
+#: src/ui/gui/text-data-import-dialog.c:780
 #, c-format
 msgid "The selected file contains approximately %lu line of text.  "
 msgid_plural "The selected file contains approximately %lu lines of text.  "
 msgstr[0] "Het geselecteerde bestand bevat ongeveer %lu regel tekst. "
 msgstr[1] "Het geselecteerde bestand bevat ongeveer %lu regels tekst. "
 
-#: src/ui/gui/text-data-import-dialog.c:794
+#: src/ui/gui/text-data-import-dialog.c:786
 #, c-format
 msgid "Only the first %zu line of the file will be shown for preview purposes in the following screens.  "
 msgid_plural "Only the first %zu lines of the file will be shown for preview purposes in the following screens.  "
 msgstr[0] "Alleen de eerste %zu regel van het bestand worden getoond voor voorbeeld doeleinden in de volgende schermen.  "
 msgstr[1] "Alleen de eerste %zu regels van het bestand worden getoond voor voorbeeld doeleinden in de volgende schermen.  "
 
-#: src/ui/gui/text-data-import-dialog.c:801
+#: src/ui/gui/text-data-import-dialog.c:793
 msgid "You may choose below how much of the file should actually be imported."
 msgstr "Hieronder kunt u kiezen hoeveel van het bestand daadwerkelijk geïmporteerd moet worden."
 
-#: src/ui/gui/text-data-import-dialog.c:884
+#: src/ui/gui/text-data-import-dialog.c:876
 msgid "Text"
 msgstr "Tekst"
 
-#: src/ui/gui/text-data-import-dialog.c:1550
-#: src/ui/gui/text-data-import-dialog.c:1794
+#: src/ui/gui/text-data-import-dialog.c:1540
+#: src/ui/gui/text-data-import-dialog.c:1786
 msgid "This input line has too few separators to fill in this field."
 msgstr "Deze invoerregel heeft te weinig scheidingstekens om dit veld te vullen."
 
-#: src/ui/gui/text-data-import-dialog.c:1785
-#, fuzzy, c-format
+#: src/ui/gui/text-data-import-dialog.c:1777
+#, c-format
 msgid "Cannot parse field content `%.*s' as format %s: %s"
-msgstr "Veldinhoud '%.*s' kan niet opgedeeld worden in opmaak %s."
+msgstr "Kan veldinhoud `%.*s' niet ontleden als opmaak %s: %s"
 
-#: src/ui/gui/text-data-import-dialog.c:1938
+#: src/ui/gui/text-data-import-dialog.c:1930
 msgid "Line"
-msgstr ""
+msgstr "Regel"
 
 #: src/ui/gui/t-test-options.c:60
 #, c-format
 msgid "Confidence Interval: %2d %%"
 msgstr "Betrouwbaarheidsinterval: %2d %%"
 
-#: src/ui/gui/val-labs-dialog.c:515
-#, fuzzy, c-format
+#: src/ui/gui/val-labs-dialog.c:519
+#, c-format
 msgid "%s = `%s'"
-msgstr "%s & %s"
+msgstr "%s = `%s'"
 
 #: src/ui/gui/variable-info-dialog.c:77
 #, c-format
@@ -4687,26 +4750,26 @@ msgstr "Type: %s\n"
 msgid "Missing Values: %s\n"
 msgstr "Ontbrekende-Waardes: %s\n"
 
-#: src/ui/gui/variable-info-dialog.c:93
+#: src/ui/gui/variable-info-dialog.c:92
 #, c-format
 msgid "Measurement Level: %s\n"
 msgstr "Meetniveau: %s\n"
 
-#: src/ui/gui/variable-info-dialog.c:106
+#: src/ui/gui/variable-info-dialog.c:105
 msgid "Value Labels:\n"
 msgstr "Waardelabels:\n"
 
-#: src/ui/gui/variable-info-dialog.c:116
+#: src/ui/gui/variable-info-dialog.c:115
 #, c-format
 msgid "%s %s\n"
 msgstr "%s %s\n"
 
-#: src/ui/gui/weight-cases-dialog.c:81 src/ui/gui/psppire.ui:52
+#: src/ui/gui/weight-cases-dialog.c:80 src/ui/gui/psppire.ui:52
 #: src/ui/gui/psppire.ui:155
 msgid "Do not weight cases"
 msgstr "Weeg cases niet"
 
-#: src/ui/gui/weight-cases-dialog.c:87
+#: src/ui/gui/weight-cases-dialog.c:86
 #, c-format
 msgid "Weight cases by %s"
 msgstr "Weeg cases per %s"
@@ -4716,6 +4779,31 @@ msgstr "Weeg cases per %s"
 msgid "Unrecognized record type 7, subtype %d."
 msgstr "Niet-herkend recordtype 7, subtype %d."
 
+#: tests/dissect-sysfile.c:595
+#, c-format
+msgid "Bad size (%zu) or count (%zu) field on record type 7, subtype 3."
+msgstr "Onjuiste lengte (%zu) of aantal (%zu) veld in recordtype 7, subtype 3."
+
+#: tests/dissect-sysfile.c:626
+#, c-format
+msgid "Bad size (%zu) or count (%zu) on extension 4."
+msgstr "Onjuiste lengte (%zu) of aantal (%zu) bij extensie 4."
+
+#: tests/dissect-sysfile.c:692
+#, c-format
+msgid "Missing space following `%c' at offset %zu in MRSETS record"
+msgstr "Ontbrekende spatie achter `%c' op offset %zu in MRSETS record"
+
+#: tests/dissect-sysfile.c:701
+#, c-format
+msgid "Unexpected label source value `%s' following `E' at offset %zu in MRSETS record"
+msgstr "Onverwachte labelbron waarde `%s' achter `E' op offset %zu in MRSETS record"
+
+#: tests/dissect-sysfile.c:759
+#, c-format
+msgid "Bad size %zu on extension 11."
+msgstr "Onjuiste lengte %zu voor extensie 11."
+
 #: tests/dissect-sysfile.c:851
 #, c-format
 msgid "%s: Error parsing attribute value %s[%d]"
@@ -4736,713 +4824,729 @@ msgstr "Onjuiste lengte %zu voor vergroot aantal cases."
 msgid "Bad count %zu for extended number of cases."
 msgstr ""
 
-#: src/language/utilities/set.q:188
+#: tests/dissect-sysfile.c:937
+#, c-format
+msgid "Variable name length in long string value label record (%d) exceeds %d-byte limit."
+msgstr "Variabele naam lengte in lange tekenreeks waarde label record (%d) overschrijdt %d-byte limiet."
+
+#: src/language/utilities/set.q:171
 msgid "WORKSPACE must be at least 1MB"
 msgstr "WORKSPACE moet minstens 1MB zijn"
 
-#: src/language/utilities/set.q:194 src/language/utilities/set.q:196
-#: src/language/utilities/set.q:198 src/language/utilities/set.q:200
-#: src/language/utilities/set.q:202 src/language/utilities/set.q:204
-#: src/language/utilities/set.q:206 src/language/utilities/set.q:208
-#: src/language/utilities/set.q:210
+#: src/language/utilities/set.q:177 src/language/utilities/set.q:179
+#: src/language/utilities/set.q:181 src/language/utilities/set.q:183
+#: src/language/utilities/set.q:185 src/language/utilities/set.q:187
+#: src/language/utilities/set.q:189 src/language/utilities/set.q:191
+#: src/language/utilities/set.q:193
 #, c-format
 msgid "%s is obsolete."
 msgstr "%s is verouderd."
 
-#: src/language/utilities/set.q:216
+#: src/language/utilities/set.q:199
 msgid "Active file compression is not implemented."
 msgstr "Actief bestand compressie is niet geïmplementeerd."
 
-#: src/language/utilities/set.q:334
+#: src/language/utilities/set.q:317
 msgid "EPOCH must be 1500 or later."
 msgstr "EPOCH moet 1500 of later zijn."
 
-#: src/language/utilities/set.q:341
+#: src/language/utilities/set.q:324
 msgid "expecting AUTOMATIC or year"
 msgstr "AUTOMATIC of jaar verwacht"
 
-#: src/language/utilities/set.q:369
+#: src/language/utilities/set.q:352
 msgid "LENGTH must be at least 1."
 msgstr "LENGTH moet tenminste 1 zijn."
 
-#: src/language/utilities/set.q:405
+#: src/language/utilities/set.q:388
 #, c-format
-msgid "%s is not a recognised encoding or locale name"
+msgid "%s is not a recognized encoding or locale name"
 msgstr "%s is geen herkende codering of lokale naam"
 
-#: src/language/utilities/set.q:467
+#: src/language/utilities/set.q:449
 msgid "WIDTH must be at least 40."
 msgstr "WIDTH moet tenminste 40 zijn."
 
-#: src/language/utilities/set.q:494
+#: src/language/utilities/set.q:476
 #, c-format
 msgid "FORMAT requires numeric output format as an argument.  Specified format %s is of type string."
 msgstr "FORMAT vereist numerieke uitvoeropmaak als een argument. Opgegeven opmaak %s is van het type tekenreeks."
 
-#: src/language/utilities/set.q:711
+#: src/language/utilities/set.q:690
 msgid "ISL (32-bit IEEE 754 single, little-endian)"
 msgstr "ISL (32-bit IEEE 754 single, little-endian)"
 
-#: src/language/utilities/set.q:714
+#: src/language/utilities/set.q:693
 msgid "ISB (32-bit IEEE 754 single, big-endian)"
 msgstr "ISB (32-bit IEEE 754 single, big-endian)"
 
-#: src/language/utilities/set.q:717
+#: src/language/utilities/set.q:696
 msgid "IDL (64-bit IEEE 754 double, little-endian)"
 msgstr "IDL (64-bit IEEE 754 double, little-endian)"
 
-#: src/language/utilities/set.q:720
+#: src/language/utilities/set.q:699
 msgid "IDB (64-bit IEEE 754 double, big-endian)"
 msgstr "IDB (64-bit IEEE 754 double, big-endian)"
 
-#: src/language/utilities/set.q:724
+#: src/language/utilities/set.q:703
 msgid "VF (32-bit VAX F, VAX-endian)"
 msgstr "VF (32-bit VAX F, VAX-endian)"
 
-#: src/language/utilities/set.q:727
+#: src/language/utilities/set.q:706
 msgid "VD (64-bit VAX D, VAX-endian)"
 msgstr "VD (64-bit VAX D, VAX-endian)"
 
-#: src/language/utilities/set.q:730
+#: src/language/utilities/set.q:709
 msgid "VG (64-bit VAX G, VAX-endian)"
 msgstr "VG (64-bit VAX G, VAX-endian)"
 
-#: src/language/utilities/set.q:734
+#: src/language/utilities/set.q:713
 msgid "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 msgstr "ZS (32-bit IBM Z hexadecimal short, big-endian)"
 
-#: src/language/utilities/set.q:737
+#: src/language/utilities/set.q:716
 msgid "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 msgstr "ZL (64-bit IBM Z hexadecimal long, big-endian)"
 
-#: src/language/utilities/set.q:839
+#: src/language/utilities/set.q:817
 #, c-format
 msgid "%s is %s."
 msgstr "%s van %s."
 
-#: src/language/utilities/set.q:942
+#: src/language/utilities/set.q:920
 #, c-format
 msgid "Too many PRESERVE commands without a RESTORE: at most %d levels of saved settings are allowed."
-msgstr ""
+msgstr "Te veel PRESERVE opdrachten zonder een RESTORE: maximaal %d niveaus van saved settings zijn toegestaand."
 
-#: src/language/utilities/set.q:961
+#: src/language/utilities/set.q:939
 msgid "RESTORE without matching PRESERVE."
-msgstr ""
+msgstr "RESTORE zonder overeenkomende PRESERVE."
 
-#: src/language/stats/crosstabs.q:289
+#: src/language/stats/crosstabs.q:295
 msgid "Missing mode REPORT not allowed in general mode.  Assuming MISSING=TABLE."
 msgstr "Missing modus REPORT niet toegestaan in algemene modus.  MISSING=TABLE aangenomen."
 
-#: src/language/stats/crosstabs.q:399
+#: src/language/stats/crosstabs.q:405
 msgid "Too many cross-tabulation variables or dimensions."
 msgstr "Te veel cross-tabulation variabelen of dimensies."
 
-#: src/language/stats/crosstabs.q:466
+#: src/language/stats/crosstabs.q:472
 msgid "VARIABLES must be specified before TABLES."
 msgstr "VARIABLES dient voor TABLES gespecificeerd te worden."
 
-#: src/language/stats/crosstabs.q:500
+#: src/language/stats/crosstabs.q:506
 #, c-format
 msgid "Maximum value (%ld) less than minimum value (%ld)."
 msgstr "Maximumwaarde (%ld) is kleiner dan minimumwaarde (%ld)."
 
-#: src/language/stats/crosstabs.q:810
+#: src/language/stats/crosstabs.q:827
 msgid "Summary."
 msgstr "Overzicht."
 
-#: src/language/stats/crosstabs.q:823 src/language/stats/examine.q:1179
-#: src/language/stats/frequencies.q:815
+#: src/language/stats/crosstabs.q:840 src/language/stats/examine.q:1178
+#: src/language/stats/frequencies.q:823
 msgid "Percent"
 msgstr "Percentage"
 
-#: src/language/stats/crosstabs.q:1101
+#. TRANSLATORS: The %s here describes a crosstabulation.  It takes the
+#. form "var1 * var2 * var3 * ...".
+#: src/language/stats/crosstabs.q:936
+#, c-format
+msgid "Crosstabulation %s contained no non-missing cases."
+msgstr "Kruistabulatie %s bevat geen non-missing cases."
+
+#: src/language/stats/crosstabs.q:1134
 msgid "count"
 msgstr "aantal"
 
-#: src/language/stats/crosstabs.q:1102
+#: src/language/stats/crosstabs.q:1135
 msgid "row %"
 msgstr "rij %"
 
-#: src/language/stats/crosstabs.q:1103
+#: src/language/stats/crosstabs.q:1136
 msgid "column %"
 msgstr "kolom %"
 
-#: src/language/stats/crosstabs.q:1104
+#: src/language/stats/crosstabs.q:1137
 msgid "total %"
 msgstr "totaal %"
 
-#: src/language/stats/crosstabs.q:1105
+#: src/language/stats/crosstabs.q:1138
 msgid "expected"
 msgstr "verwacht"
 
-#: src/language/stats/crosstabs.q:1106
+#: src/language/stats/crosstabs.q:1139
 msgid "residual"
 msgstr "overblijvend"
 
-#: src/language/stats/crosstabs.q:1107
+#: src/language/stats/crosstabs.q:1140
 msgid "std. resid."
-msgstr ""
+msgstr "std. resid."
 
-#: src/language/stats/crosstabs.q:1108
+#: src/language/stats/crosstabs.q:1141
 msgid "adj. resid."
-msgstr ""
+msgstr "adj. resid."
 
-#: src/language/stats/crosstabs.q:1202
+#: src/language/stats/crosstabs.q:1230
 msgid "Chi-square tests."
 msgstr "Chi-square tests."
 
-#: src/language/stats/crosstabs.q:1228
+#: src/language/stats/crosstabs.q:1256
 msgid "Symmetric measures."
 msgstr "Symmetrische metingen."
 
-#: src/language/stats/crosstabs.q:1234 src/language/stats/crosstabs.q:1282
+#: src/language/stats/crosstabs.q:1262 src/language/stats/crosstabs.q:1310
 msgid "Asymp. Std. Error"
-msgstr ""
+msgstr "Asymp. Std. Error"
 
-#: src/language/stats/crosstabs.q:1235 src/language/stats/crosstabs.q:1283
+#: src/language/stats/crosstabs.q:1263 src/language/stats/crosstabs.q:1311
 msgid "Approx. T"
-msgstr ""
+msgstr "Approx. T"
 
-#: src/language/stats/crosstabs.q:1236 src/language/stats/crosstabs.q:1284
+#: src/language/stats/crosstabs.q:1264 src/language/stats/crosstabs.q:1312
 msgid "Approx. Sig."
-msgstr ""
+msgstr "Approx. Sig."
 
-#: src/language/stats/crosstabs.q:1250
+#: src/language/stats/crosstabs.q:1278
 msgid "Risk estimate."
-msgstr ""
+msgstr "Risk estimate."
 
-#: src/language/stats/crosstabs.q:1254
+#: src/language/stats/crosstabs.q:1282
 #, c-format
 msgid "95%% Confidence Interval"
 msgstr "95%% Betrouwbaarheidsinterval"
 
-#: src/language/stats/crosstabs.q:1257 src/language/stats/t-test.q:756
-#: src/language/stats/t-test.q:920 src/language/stats/t-test.q:1013
+#: src/language/stats/crosstabs.q:1285 src/language/stats/t-test.q:760
+#: src/language/stats/t-test.q:924 src/language/stats/t-test.q:1017
 msgid "Lower"
 msgstr "Lager"
 
-#: src/language/stats/crosstabs.q:1258 src/language/stats/t-test.q:757
-#: src/language/stats/t-test.q:921 src/language/stats/t-test.q:1014
+#: src/language/stats/crosstabs.q:1286 src/language/stats/t-test.q:761
+#: src/language/stats/t-test.q:925 src/language/stats/t-test.q:1018
 msgid "Upper"
 msgstr "Hoger"
 
-#: src/language/stats/crosstabs.q:1275
+#: src/language/stats/crosstabs.q:1303
 msgid "Directional measures."
 msgstr "Directionele metingen."
 
-#: src/language/stats/crosstabs.q:1702
+#: src/language/stats/crosstabs.q:1740
 msgid "Pearson Chi-Square"
 msgstr "Pearson Chi-Square"
 
-#: src/language/stats/crosstabs.q:1703
+#: src/language/stats/crosstabs.q:1741
 msgid "Likelihood Ratio"
 msgstr "Waarschijnlijkheidsratio"
 
-#: src/language/stats/crosstabs.q:1704
+#: src/language/stats/crosstabs.q:1742
 msgid "Fisher's Exact Test"
 msgstr "Fisher's Exact Test"
 
-#: src/language/stats/crosstabs.q:1705
+#: src/language/stats/crosstabs.q:1743
 msgid "Continuity Correction"
 msgstr "Continuïteitscorrectie"
 
-#: src/language/stats/crosstabs.q:1706
+#: src/language/stats/crosstabs.q:1744
 msgid "Linear-by-Linear Association"
-msgstr ""
+msgstr "Linear-by-Linear Association"
 
-#: src/language/stats/crosstabs.q:1741 src/language/stats/crosstabs.q:1816
-#: src/language/stats/crosstabs.q:1881
+#: src/language/stats/crosstabs.q:1779 src/language/stats/crosstabs.q:1854
+#: src/language/stats/crosstabs.q:1919
 msgid "N of Valid Cases"
-msgstr ""
+msgstr "N van Geldige Cases"
 
-#: src/language/stats/crosstabs.q:1760 src/language/stats/crosstabs.q:1899
+#: src/language/stats/crosstabs.q:1798 src/language/stats/crosstabs.q:1937
 msgid "Nominal by Nominal"
-msgstr ""
+msgstr "Nominal by Nominal"
 
-#: src/language/stats/crosstabs.q:1761 src/language/stats/crosstabs.q:1900
+#: src/language/stats/crosstabs.q:1799 src/language/stats/crosstabs.q:1938
 msgid "Ordinal by Ordinal"
-msgstr ""
+msgstr "Ordinal by Ordinal"
 
-#: src/language/stats/crosstabs.q:1762
+#: src/language/stats/crosstabs.q:1800
 msgid "Interval by Interval"
-msgstr ""
+msgstr "Interval by Interval"
 
-#: src/language/stats/crosstabs.q:1763
+#: src/language/stats/crosstabs.q:1801
 msgid "Measure of Agreement"
-msgstr ""
+msgstr "Mate van overeenkomst"
 
-#: src/language/stats/crosstabs.q:1769
+#: src/language/stats/crosstabs.q:1807
 msgid "Cramer's V"
 msgstr "Cramer's V"
 
-#: src/language/stats/crosstabs.q:1770
+#: src/language/stats/crosstabs.q:1808
 msgid "Contingency Coefficient"
-msgstr ""
+msgstr "Contingency Coefficient"
 
-#: src/language/stats/crosstabs.q:1771
+#: src/language/stats/crosstabs.q:1809
 msgid "Kendall's tau-b"
 msgstr "Kendall's tau-b"
 
-#: src/language/stats/crosstabs.q:1772
+#: src/language/stats/crosstabs.q:1810
 msgid "Kendall's tau-c"
 msgstr "Kendall's tau-c"
 
-#: src/language/stats/crosstabs.q:1774
+#: src/language/stats/crosstabs.q:1812
 msgid "Spearman Correlation"
 msgstr "Spearman Correlatie"
 
-#: src/language/stats/crosstabs.q:1775
+#: src/language/stats/crosstabs.q:1813
 msgid "Pearson's R"
 msgstr "Pearson's R"
 
-#: src/language/stats/crosstabs.q:1854
+#: src/language/stats/crosstabs.q:1892
 #, c-format
 msgid "Odds Ratio for %s (%g / %g)"
-msgstr ""
+msgstr "Odds Ratio voor %s (%g / %g)"
 
-#: src/language/stats/crosstabs.q:1857
+#: src/language/stats/crosstabs.q:1895
 #, c-format
 msgid "Odds Ratio for %s (%.*s / %.*s)"
-msgstr ""
+msgstr "Odds Ratio for %s (%.*s / %.*s)"
 
-#: src/language/stats/crosstabs.q:1865
+#: src/language/stats/crosstabs.q:1903
 #, c-format
 msgid "For cohort %s = %g"
 msgstr "Voor cohort %s = %g"
 
-#: src/language/stats/crosstabs.q:1868
+#: src/language/stats/crosstabs.q:1906
 #, c-format
 msgid "For cohort %s = %.*s"
 msgstr "Voor cohort %s = %.*s"
 
-#: src/language/stats/crosstabs.q:1901
+#: src/language/stats/crosstabs.q:1939
 msgid "Nominal by Interval"
-msgstr ""
+msgstr "Nominal by Interval"
 
-#: src/language/stats/crosstabs.q:1907
+#: src/language/stats/crosstabs.q:1945
 msgid "Goodman and Kruskal tau"
 msgstr "Goodman and Kruskal tau"
 
-#: src/language/stats/crosstabs.q:1908
+#: src/language/stats/crosstabs.q:1946
 msgid "Uncertainty Coefficient"
 msgstr "Onzekerheidscoëfficiënt"
 
-#: src/language/stats/crosstabs.q:1909
+#: src/language/stats/crosstabs.q:1947
 msgid "Somers' d"
 msgstr "Somers' d"
 
-#: src/language/stats/crosstabs.q:1915
+#: src/language/stats/crosstabs.q:1953
 msgid "Symmetric"
 msgstr "Symmetrisch"
 
-#: src/language/stats/crosstabs.q:1916 src/language/stats/crosstabs.q:1917
+#: src/language/stats/crosstabs.q:1954 src/language/stats/crosstabs.q:1955
 #, c-format
 msgid "%s Dependent"
 msgstr "%s Afhankelijk"
 
-#: src/language/stats/examine.q:356
+#: src/language/stats/examine.q:355
 msgid "Not creating NP plot because data set is empty."
 msgstr "Niet aanmaken van NP plot omdat gegevens set leeg is."
 
-#: src/language/stats/examine.q:442 src/language/stats/examine.q:949
+#: src/language/stats/examine.q:441 src/language/stats/examine.q:948
 msgid "Not creating plot because data set is empty."
 msgstr "Niet aanmaken van plot omdat gegevens set leeg is."
 
-#: src/language/stats/examine.q:454
+#: src/language/stats/examine.q:453
 #, c-format
 msgid "Boxplot of %s vs. %s"
-msgstr ""
+msgstr "Boxplot van %s vs. %s"
 
-#: src/language/stats/examine.q:458
+#: src/language/stats/examine.q:457
 #, c-format
 msgid "Boxplot of %s"
-msgstr ""
+msgstr "Boxplot van %s"
 
-#: src/language/stats/examine.q:647 src/language/stats/examine.q:660
+#: src/language/stats/examine.q:646 src/language/stats/examine.q:659
 #, c-format
 msgid "%s and %s are mutually exclusive"
 msgstr "%s en %s zijn wederzijds exclusief"
 
-#: src/language/stats/examine.q:1464
+#: src/language/stats/examine.q:1463
 msgid "5% Trimmed Mean"
-msgstr ""
+msgstr "5% Trimmed Mean"
 
-#: src/language/stats/examine.q:1499
+#: src/language/stats/examine.q:1498
 msgid "Interquartile Range"
-msgstr ""
+msgstr "Interquartile Range"
 
-#: src/language/stats/examine.q:1821
+#: src/language/stats/examine.q:1820
 msgid "Highest"
 msgstr "Hoogste"
 
-#: src/language/stats/examine.q:1826
+#: src/language/stats/examine.q:1825
 msgid "Lowest"
 msgstr "Laagste"
 
-#: src/language/stats/examine.q:1833
+#: src/language/stats/examine.q:1832
 msgid "Extreme Values"
 msgstr "Extreme Waardes"
 
-#: src/language/stats/examine.q:1837 src/language/data-io/list.q:158
+#: src/language/stats/examine.q:1836 src/language/data-io/list.q:157
 msgid "Case Number"
 msgstr "Case Nummer"
 
-#: src/language/stats/examine.q:1957
+#: src/language/stats/examine.q:1956
 msgid "Tukey's Hinges"
 msgstr "Tukey's Hinges"
 
-#: src/language/stats/examine.q:2003
+#: src/language/stats/examine.q:2002
 #, c-format
 msgid "%g"
 msgstr "%g"
 
-#: src/language/stats/frequencies.q:382
+#: src/language/stats/frequencies.q:381
 msgid "Bar charts are not implemented."
 msgstr "Staafdiagrammen nog niet geïmplementeerd."
 
-#: src/language/stats/frequencies.q:399
+#: src/language/stats/frequencies.q:398
 #, c-format
 msgid "MAX for histogram must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
 msgstr "MAX voor histogram moet groter of gelijk aan MIN zijn, maar MIN was opgegeven als %.15g en MAX als %.15g. MIN en MAX worden genegeerd."
 
-#: src/language/stats/frequencies.q:420
+#: src/language/stats/frequencies.q:419
 #, c-format
 msgid "MAX for pie chart must be greater than or equal to MIN, but MIN was specified as %.15g and MAX as %.15g.  MIN and MAX will be ignored."
 msgstr "MAX voor taartdiagram moet groter of gelijk aan MIN zijn, maar MIN was opgegeven als %.15g en MAX als %.15g. MIN en MAX worden genegeerd."
 
-#: src/language/stats/frequencies.q:703
+#: src/language/stats/frequencies.q:702
 msgid "`)' expected after GROUPED interval list."
 msgstr "')' verwacht na GROUPED interval lijst."
 
-#: src/language/stats/frequencies.q:723
+#: src/language/stats/frequencies.q:722
 #, c-format
 msgid "Variables %s specified multiple times on GROUPED subcommand."
 msgstr "Variabele %s is meerdere keren gespecificeerd in GROUPED-subopdracht."
 
-#: src/language/stats/frequencies.q:733
+#: src/language/stats/frequencies.q:732
 #, c-format
 msgid "Variables %s specified on GROUPED but not on VARIABLES."
 msgstr "Variabele %s gespecificeerd bij GROUPED maar niet bij VARIABLES."
 
-#: src/language/stats/frequencies.q:812
+#: src/language/stats/frequencies.q:820
 msgid "Value Label"
 msgstr "Waardelabel"
 
-#: src/language/stats/frequencies.q:816
+#: src/language/stats/frequencies.q:824
 msgid "Valid Percent"
 msgstr "Geldig Percentage"
 
-#: src/language/stats/frequencies.q:817
+#: src/language/stats/frequencies.q:825
 msgid "Cum Percent"
 msgstr "Cum Percentage"
 
-#: src/language/stats/frequencies.q:1008
+#: src/language/stats/frequencies.q:1015
 #, c-format
 msgid "No valid data for variable %s; statistics not displayed."
 msgstr "Geen geldige gegevens voor variabele %s; statistieken worden niet getoond."
 
-#: src/language/stats/frequencies.q:1054
+#: src/language/stats/frequencies.q:1061
 msgid "50 (Median)"
 msgstr "50 (Mediaan)"
 
-#: src/language/stats/frequencies.q:1209
+#: src/language/stats/frequencies.q:1217
 #, c-format
 msgid "Omitting pie chart for %s, which has only %d unique values."
-msgstr ""
+msgstr "Weglaten cirkeldiagram voor %s, die heeft slechts %d unieke waardes."
 
-#: src/language/stats/frequencies.q:1212
+#: src/language/stats/frequencies.q:1220
 #, c-format
 msgid "Omitting pie chart for %s, which has over 50 unique values."
-msgstr ""
+msgstr "Weglaten cirkeldiagram %s, die heeft meer dan 50 unieke waardes."
 
-#: src/language/stats/rank.q:220
+#: src/language/stats/rank.q:219
 #, c-format
 msgid "%s of %s by %s"
 msgstr "%s van %s per %s"
 
-#: src/language/stats/rank.q:225
+#: src/language/stats/rank.q:224
 #, c-format
 msgid "%s of %s"
 msgstr "%s van %s"
 
-#: src/language/stats/rank.q:600
+#: src/language/stats/rank.q:599
 msgid "Cannot create new rank variable.  All candidates in use."
 msgstr "Kan geen rang variabele creëren. Alle kandidaten zijn in gebruik."
 
-#: src/language/stats/rank.q:693
+#: src/language/stats/rank.q:694
 msgid "Variables Created By RANK"
 msgstr "Variabelen gecreëerd door RANK"
 
-#: src/language/stats/rank.q:717
+#: src/language/stats/rank.q:718
 #, c-format
 msgid "%s into %s(%s of %s using %s BY %s)"
 msgstr "%s in %s(%s van %s gebruikt %s PER %s)"
 
-#: src/language/stats/rank.q:727
+#: src/language/stats/rank.q:728
 #, c-format
 msgid "%s into %s(%s of %s BY %s)"
 msgstr "%s in %s(%s van %s PER %s)"
 
-#: src/language/stats/rank.q:740
+#: src/language/stats/rank.q:741
 #, c-format
 msgid "%s into %s(%s of %s using %s)"
 msgstr "%s in %s(%s van %s gebruikt %s"
 
-#: src/language/stats/rank.q:749
+#: src/language/stats/rank.q:750
 #, c-format
 msgid "%s into %s(%s of %s)"
 msgstr "%s in %s(%s van %s)"
 
-#: src/language/stats/rank.q:761
+#: src/language/stats/rank.q:762
 msgid "FRACTION has been specified, but NORMAL and PROPORTION rank functions have not been requested.  The FRACTION subcommand will be ignored."
 msgstr "FRACTION is gespecificeerd maar NORMAL en PROPORTION rangschik functies zijn niet gevraagd. De FRACTION-subopdracht wordt genegeerd."
 
-#: src/language/stats/rank.q:852
+#: src/language/stats/rank.q:853
 #, c-format
 msgid "Variable %s already exists."
 msgstr "Variabele %s bestaat al."
 
-#: src/language/stats/rank.q:857
+#: src/language/stats/rank.q:858
 msgid "Too many variables in INTO clause."
 msgstr "Te veel variabelen in INTO clausule."
 
-#: src/language/stats/regression.q:156
+#: src/language/stats/regression.q:158
 msgid "R Square"
 msgstr "R Square"
 
-#: src/language/stats/regression.q:157
+#: src/language/stats/regression.q:159
 msgid "Adjusted R Square"
-msgstr ""
+msgstr "Adjusted R Square"
 
-#: src/language/stats/regression.q:158
+#: src/language/stats/regression.q:160
 msgid "Std. Error of the Estimate"
-msgstr ""
+msgstr "Std. Error of the Estimate"
 
-#: src/language/stats/regression.q:163
+#: src/language/stats/regression.q:165
 msgid "Model Summary"
-msgstr ""
+msgstr "Model Summary"
 
-#: src/language/stats/regression.q:197
+#: src/language/stats/regression.q:199
 msgid "B"
 msgstr "B"
 
-#: src/language/stats/regression.q:199
+#: src/language/stats/regression.q:201
 msgid "Beta"
 msgstr "Beta"
 
-#: src/language/stats/regression.q:202
+#: src/language/stats/regression.q:204
 msgid "(Constant)"
 msgstr "(Constante)"
 
-#: src/language/stats/regression.q:254
+#: src/language/stats/regression.q:256
 msgid "Coefficients"
 msgstr "Coëfficiënten"
 
-#: src/language/stats/regression.q:289 src/ui/gui/regression.ui:7
+#: src/language/stats/regression.q:291 src/ui/gui/regression.ui:7
 msgid "Regression"
 msgstr "Regressie"
 
-#: src/language/stats/regression.q:370
+#: src/language/stats/regression.q:372
 msgid "Model"
 msgstr "Model"
 
-#: src/language/stats/regression.q:371
+#: src/language/stats/regression.q:373
 msgid "Covariances"
 msgstr "Covarianties"
 
-#: src/language/stats/regression.q:386
+#: src/language/stats/regression.q:388
 msgid "Coefficient Correlations"
 msgstr "Coëfficiëntcorrelaties"
 
-#: src/language/stats/regression.q:793
+#: src/language/stats/regression.q:787
 msgid "The dependent variable is equal to the independent variable.The least squares line is therefore Y=X.Standard errors and related statistics may be meaningless."
 msgstr ""
 
-#: src/language/stats/regression.q:940
+#: src/language/stats/regression.q:934
 msgid "REGRESSION requires numeric variables."
 msgstr "REGRESSION vereist numerieke variabelen."
 
-#: src/language/stats/regression.q:1015
+#: src/language/stats/regression.q:1009
 msgid "No valid data found. This command was skipped."
 msgstr "Geen geldige gegevens gevonden. Deze opdracht is overgeslagen."
 
-#: src/language/stats/t-test.q:190
+#: src/language/stats/t-test.q:192
 msgid "Exactly one of TESTVAL, GROUPS and PAIRS subcommands must be specified."
 msgstr "Precies 1 van de TESTVAL-, GROUPS- en PAIRS-subopdrachten moet zijn gespecificeerd."
 
-#: src/language/stats/t-test.q:211
+#: src/language/stats/t-test.q:213
 msgid "VARIABLES subcommand may not be used with PAIRS."
 msgstr "VARIABLES-subopdracht mag niet gebruikt worden met PAIRS."
 
-#: src/language/stats/t-test.q:230
+#: src/language/stats/t-test.q:232
 msgid "One or more VARIABLES must be specified."
 msgstr "Een of meer VARIABLES moeten gespecificeerd zijn."
 
-#: src/language/stats/t-test.q:324
+#: src/language/stats/t-test.q:328
 msgid "When applying GROUPS to a string variable, two values must be specified."
 msgstr "Bij het toepassen van GROUPS op een tekenreeksvariabele moeten twee waardes opgegeven zijn."
 
-#: src/language/stats/t-test.q:395
+#: src/language/stats/t-test.q:399
 msgid "At least two variables must be specified on PAIRS."
 msgstr "Tenminste 2 variabelen moeten opgegeven worden bij PAIRS."
 
-#: src/language/stats/t-test.q:503
+#: src/language/stats/t-test.q:507
 msgid "One-Sample Statistics"
-msgstr ""
+msgstr "One-Sample Statistics"
 
-#: src/language/stats/t-test.q:522
+#: src/language/stats/t-test.q:526
 msgid "Group Statistics"
-msgstr ""
+msgstr "Group Statistics"
 
-#: src/language/stats/t-test.q:621
+#: src/language/stats/t-test.q:625
 msgid "Paired Sample Statistics"
-msgstr ""
+msgstr "Paired Sample Statistics"
 
-#: src/language/stats/t-test.q:641 src/language/stats/t-test.q:944
-#: src/language/stats/t-test.q:1111
+#: src/language/stats/t-test.q:645 src/language/stats/t-test.q:948
+#: src/language/stats/t-test.q:1115
 #, c-format
 msgid "Pair %d"
-msgstr ""
+msgstr "Pair %d"
 
-#: src/language/stats/t-test.q:737
+#: src/language/stats/t-test.q:741
 msgid "Independent Samples Test"
-msgstr ""
+msgstr "Independent Samples Test"
 
-#: src/language/stats/t-test.q:745
+#: src/language/stats/t-test.q:749
 msgid "Levene's Test for Equality of Variances"
-msgstr ""
+msgstr "Levene's Test for Equality of Variances"
 
-#: src/language/stats/t-test.q:747
+#: src/language/stats/t-test.q:751
 msgid "t-test for Equality of Means"
-msgstr ""
+msgstr "t-test for Equality of Means"
+
+#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1107
+msgid "Sig."
+msgstr "Sig."
 
-#: src/language/stats/t-test.q:754 src/language/stats/t-test.q:1012
+#: src/language/stats/t-test.q:758 src/language/stats/t-test.q:1016
 msgid "Mean Difference"
 msgstr "Gemiddeld verschil"
 
-#: src/language/stats/t-test.q:755
+#: src/language/stats/t-test.q:759
 msgid "Std. Error Difference"
-msgstr ""
+msgstr "Std. Error Difference"
 
-#: src/language/stats/t-test.q:760 src/language/stats/t-test.q:914
-#: src/language/stats/t-test.q:1004
+#: src/language/stats/t-test.q:764 src/language/stats/t-test.q:918
+#: src/language/stats/t-test.q:1008
 #, c-format
 msgid "%g%% Confidence Interval of the Difference"
-msgstr ""
+msgstr "%g%% Confidence Interval of the Difference"
 
-#: src/language/stats/t-test.q:814
+#: src/language/stats/t-test.q:818
 msgid "Equal variances assumed"
-msgstr ""
+msgstr "Equal variances assumed"
 
-#: src/language/stats/t-test.q:860
+#: src/language/stats/t-test.q:864
 msgid "Equal variances not assumed"
-msgstr ""
+msgstr "Equal variances not assumed"
 
-#: src/language/stats/t-test.q:904
+#: src/language/stats/t-test.q:908
 msgid "Paired Samples Test"
-msgstr ""
+msgstr "Paired Samples Test"
 
-#: src/language/stats/t-test.q:907
+#: src/language/stats/t-test.q:911
 msgid "Paired Differences"
-msgstr ""
+msgstr "Paired Differences"
 
-#: src/language/stats/t-test.q:919
+#: src/language/stats/t-test.q:923
 msgid "Std. Error Mean"
-msgstr ""
+msgstr "Std. Error Mean"
 
-#: src/language/stats/t-test.q:993
+#: src/language/stats/t-test.q:997
 msgid "One-Sample Test"
 msgstr "One-Sample Test"
 
-#: src/language/stats/t-test.q:998
+#: src/language/stats/t-test.q:1002
 #, c-format
 msgid "Test Value = %f"
 msgstr "Testwaarde = %f"
 
-#: src/language/stats/t-test.q:1098
+#: src/language/stats/t-test.q:1102
 msgid "Paired Samples Correlations"
-msgstr ""
+msgstr "Paired Samples Correlations"
 
-#: src/language/stats/t-test.q:1102
+#: src/language/stats/t-test.q:1106
 msgid "Correlation"
 msgstr "Correlatie"
 
-#: src/language/stats/t-test.q:1113
+#: src/language/stats/t-test.q:1117
 #, c-format
 msgid "%s & %s"
 msgstr "%s & %s"
 
-#: src/language/data-io/file-handle.q:65
+#: src/language/data-io/file-handle.q:70
 #, c-format
 msgid "File handle %s is already defined.  Use CLOSE FILE HANDLE before redefining a file handle."
 msgstr "Bestands-handle %s is al gedefinieerd. Gebruik CLOSE FILE HANDLE voor het opnieuw definiëren van een bestands-handle."
 
-#: src/language/data-io/file-handle.q:120
+#: src/language/data-io/file-handle.q:122
 msgid "RECFORM must be specified with MODE=360."
 msgstr "RECFORM moet opgegeven worden met MODE=360."
 
-#: src/language/data-io/file-handle.q:131
+#: src/language/data-io/file-handle.q:133
 #, c-format
 msgid "The specified file mode requires LRECL.  Assuming %zu-character records."
 msgstr "De gespecificeerd bestandsmodus vereist LRECL. Records van %zu-teken worden verondersteld."
 
-#: src/language/data-io/file-handle.q:135
+#: src/language/data-io/file-handle.q:137
 #, c-format
-msgid "Record length (%ld) must be between 1 and %lu bytes.  Assuming %d-character records."
-msgstr "Recordlengte (%ld) moet tussen 1 en %lu bytes zijn. Records van %d tekens worden verondersteld."
+msgid "Record length (%ld) must be between 1 and %lu bytes.  Assuming %zu-character records."
+msgstr "Recordlengte (%ld) moet tussen 1 en %lu bytes zijn. Records van %zu tekens worden verondersteld."
 
-#: src/language/data-io/file-handle.q:177
+#: src/language/data-io/file-handle.q:178
 msgid "file"
 msgstr "bestand"
 
-#: src/language/data-io/file-handle.q:179
+#: src/language/data-io/file-handle.q:180
 msgid "inline file"
 msgstr "inline-bestand"
 
-#: src/language/data-io/file-handle.q:205
+#: src/language/data-io/file-handle.q:228
 msgid "expecting a file name or handle name"
 msgstr "bestands- of handle-naam verwacht"
 
-#: src/language/data-io/file-handle.q:225
+#: src/language/data-io/file-handle.q:243
 #, c-format
 msgid "Handle for %s not allowed here."
 msgstr "Handle voor %s is hier niet toegestaan."
 
-#: src/language/data-io/list.q:99
+#: src/language/data-io/list.q:98
 #, c-format
 msgid "The first case (%ld) specified precedes the last case (%ld) specified.  The values will be swapped."
 msgstr "De eerste gespecificeerde case (%ld) gaat vooraf aan de laatste gespecificeerde case (%ld). De waardes worden verwisseld."
 
-#: src/language/data-io/list.q:107
+#: src/language/data-io/list.q:106
 #, c-format
 msgid "The first case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "De eerste case (%ld) om weer te geven is kleiner dan 1. De waarde is op 1 gezet."
 
-#: src/language/data-io/list.q:113
+#: src/language/data-io/list.q:112
 #, c-format
 msgid "The last case (%ld) to list is less than 1.  The value is being reset to 1."
 msgstr "De laatste case (%ld) om weer te geven is kleiner dan 1. De waarde is op 1 gezet."
 
-#: src/language/data-io/list.q:119
+#: src/language/data-io/list.q:118
 #, c-format
 msgid "The step value %ld is less than 1.  The value is being reset to 1."
 msgstr "De stap waarde %ld is kleiner dan 1. De waarde is op 1 gezet."
 
 #: src/ui/gui/aggregate.ui:7
 msgid "Aggregate Data"
-msgstr ""
+msgstr "Aggregate Data"
 
 #: src/ui/gui/aggregate.ui:100
 msgid "_Break variable(s)"
-msgstr ""
+msgstr "_Break variabele(n)"
 
 #: src/ui/gui/aggregate.ui:136
 msgid "Variable Name: "
-msgstr "Variabelenaam: "
+msgstr "Variabelennaam: "
 
 #: src/ui/gui/aggregate.ui:161
 msgid "Variable Label: "
-msgstr "Variabelelabels: "
+msgstr "Variabelenlabels: "
 
 #: src/ui/gui/aggregate.ui:190
 msgid "Function: "
@@ -5450,11 +5554,11 @@ msgstr "Functie: "
 
 #: src/ui/gui/aggregate.ui:253
 msgid "Argument 1: "
-msgstr ""
+msgstr "Argument 1: "
 
 #: src/ui/gui/aggregate.ui:282
 msgid "Argument 2: "
-msgstr ""
+msgstr "Argument 2: "
 
 #: src/ui/gui/aggregate.ui:328
 msgid "Aggregated variables"
@@ -5470,7 +5574,7 @@ msgstr "_Vervang de huidige dataset met de geaggregeerde variabelen"
 
 #: src/ui/gui/aggregate.ui:391
 msgid "_Write a new data file containing only the aggregated variables"
-msgstr ""
+msgstr "_Schrijf een nieuw data bestand dat alleen de geaggregeerde variabelen bevat"
 
 #: src/ui/gui/aggregate.ui:428
 msgid "label"
@@ -5482,11 +5586,11 @@ msgstr "Bestand is _al gesorteerd op break variabele(n)."
 
 #: src/ui/gui/aggregate.ui:487
 msgid "Sort file before a_ggregating"
-msgstr ""
+msgstr "Sorteer bestand voor a_ggregeren"
 
 #: src/ui/gui/aggregate.ui:508
 msgid "Options for very large datasets"
-msgstr ""
+msgstr "Opties voor erg grote datasets"
 
 #: src/ui/gui/binomial.ui:57 src/ui/gui/chi-square.ui:57
 msgid "_Test Variable List:"
@@ -5502,11 +5606,11 @@ msgstr "_Knippunt:"
 
 #: src/ui/gui/binomial.ui:178
 msgid "Define Dichotomy"
-msgstr ""
+msgstr "Define Dichotomy"
 
 #: src/ui/gui/binomial.ui:197
 msgid "Test _Proportion:"
-msgstr ""
+msgstr "Test _Proportion:"
 
 #: src/ui/gui/compute.ui:8
 msgid "Compute Variable"
@@ -5567,11 +5671,11 @@ msgstr "Correlatie-Coëfficiënt"
 
 #: src/ui/gui/correlation.ui:182
 msgid "_Two-tailed"
-msgstr ""
+msgstr "_Two-tailed"
 
 #: src/ui/gui/correlation.ui:198
 msgid "One-tai_led"
-msgstr ""
+msgstr "One-tai_led"
 
 #: src/ui/gui/correlation.ui:220
 msgid "Test of Significance"
@@ -5579,7 +5683,7 @@ msgstr "Test van Significantie "
 
 #: src/ui/gui/correlation.ui:232
 msgid "_Flag significant correlations"
-msgstr ""
+msgstr "_Markeer significante correlaties"
 
 #: src/ui/gui/crosstabs.ui:7
 msgid "Crosstabs"
@@ -5759,17 +5863,17 @@ msgstr "Ga naar Case Nummer:"
 
 #: src/ui/gui/factor.ui:22
 msgid "Principal Components Analysis"
-msgstr ""
+msgstr "Principal Components Analysis"
 
 #: src/ui/gui/factor.ui:26
 msgid "Principal Axis Factoring"
-msgstr ""
+msgstr "Principal Axis Factoring"
 
 #: src/ui/gui/factor.ui:29
 msgid "Factor Analysis"
 msgstr "Factoranalyse"
 
-#: src/ui/gui/factor.ui:55
+#: src/ui/gui/factor.ui:55 src/ui/gui/data-editor.ui:343
 msgid "_Descriptives..."
 msgstr "_Descriptieven..."
 
@@ -5783,7 +5887,7 @@ msgstr "_Rotaties..."
 
 #: src/ui/gui/factor.ui:200
 msgid "Factor Analysis: Extraction"
-msgstr ""
+msgstr "Factor Analyse: Extractie"
 
 #: src/ui/gui/factor.ui:224
 msgid "Method: "
@@ -5798,16 +5902,16 @@ msgid "Covariance matrix"
 msgstr "Covariantie-matrix"
 
 #: src/ui/gui/factor.ui:308
-msgid "Analyse"
+msgid "Analyze"
 msgstr "Analyseer"
 
 #: src/ui/gui/factor.ui:332
-msgid "Unrotatated factor solution"
-msgstr ""
+msgid "Unrotated factor solution"
+msgstr "Niet geroteerde factor oplossing"
 
 #: src/ui/gui/factor.ui:346
 msgid "Scree plot"
-msgstr ""
+msgstr "Scree plot"
 
 #: src/ui/gui/factor.ui:365 src/ui/gui/roc.ui:286
 msgid "Display"
@@ -5835,15 +5939,15 @@ msgstr "_Geen"
 
 #: src/ui/gui/factor.ui:590
 msgid "_Varimax"
-msgstr ""
+msgstr "_Varimax"
 
 #: src/ui/gui/factor.ui:606
 msgid "_Quartimax"
-msgstr ""
+msgstr "_Quartimax"
 
 #: src/ui/gui/factor.ui:622
 msgid "_Equimax"
-msgstr ""
+msgstr "_Equimax"
 
 #: src/ui/gui/factor.ui:645
 msgid "Method"
@@ -5855,7 +5959,7 @@ msgstr "_Toon geroteerde oplossing"
 
 #: src/ui/gui/find.ui:8
 msgid "Find Case"
-msgstr "Vind case"
+msgstr "Zoek case"
 
 #: src/ui/gui/find.ui:88
 msgid "Variable:"
@@ -5969,7 +6073,7 @@ msgstr "Teken histogrammen"
 
 #: src/ui/gui/frequencies.ui:645
 msgid "Superimpose normal curve"
-msgstr ""
+msgstr "Superimpose normal curve"
 
 #: src/ui/gui/frequencies.ui:661
 msgid "Scale:"
@@ -5995,9 +6099,33 @@ msgstr "Voeg taartpunten voor ontbrekende waarden toe"
 msgid "<b>Pie Charts</b>"
 msgstr "<b>Taartdiagrammen</b>"
 
+#: src/ui/gui/k-related.ui:7
+msgid "Tests for Several Related Samples"
+msgstr ""
+
+#: src/ui/gui/k-related.ui:94
+msgid "_Test Variables:"
+msgstr "_Testvariabelen:"
+
+#: src/ui/gui/k-related.ui:122
+msgid "_Friedman"
+msgstr "_Friedman"
+
+#: src/ui/gui/k-related.ui:136
+msgid "_Kendall's W"
+msgstr "_Kendall's W"
+
+#: src/ui/gui/k-related.ui:150
+msgid "_Cochran's Q"
+msgstr "_Cochran's Q"
+
+#: src/ui/gui/k-related.ui:169
+msgid "Test Type"
+msgstr "Testtype"
+
 #: src/ui/gui/oneway.ui:8
 msgid "One-Way ANOVA"
-msgstr ""
+msgstr "One-Way ANOVA"
 
 #: src/ui/gui/oneway.ui:31
 msgid "_Factor:"
@@ -6007,7 +6135,7 @@ msgstr "_Factor:"
 msgid "Dependent _Variable(s):"
 msgstr "Afhankelijke _Variabel(en):"
 
-#: src/ui/gui/oneway.ui:184 src/ui/gui/data-editor.ui:332
+#: src/ui/gui/oneway.ui:184
 msgid "_Descriptives"
 msgstr "_Descriptieven"
 
@@ -6017,11 +6145,11 @@ msgstr "_Homogeniteit"
 
 #: src/ui/gui/oneway.ui:238
 msgid "_Contrasts..."
-msgstr ""
+msgstr "_Contrasts..."
 
 #: src/ui/gui/oneway.ui:292
 msgid "One-Way ANOVA: Contrasts"
-msgstr ""
+msgstr "One-Way ANOVA: Contrasts"
 
 #: src/ui/gui/oneway.ui:369
 msgid "_Coefficients:"
@@ -6033,7 +6161,7 @@ msgstr "Coëfficiënt Totaal: "
 
 #: src/ui/gui/oneway.ui:452
 msgid "Contrast 1 of 1"
-msgstr ""
+msgstr "Contrast 1 of 1"
 
 #: src/ui/gui/psppire.ui:7
 msgid "Weight Cases"
@@ -6125,7 +6253,7 @@ msgstr ""
 
 #: src/ui/gui/rank.ui:410
 msgid "Savage score"
-msgstr ""
+msgstr "Savage score"
 
 #: src/ui/gui/rank.ui:424
 msgid "Rank"
@@ -6137,11 +6265,11 @@ msgstr "Ntiles"
 
 #: src/ui/gui/rank.ui:481
 msgid "Proportion Estimates"
-msgstr ""
+msgstr "Proportion Estimates"
 
 #: src/ui/gui/rank.ui:494
 msgid "Normal Scores"
-msgstr ""
+msgstr "Normal Scores"
 
 #: src/ui/gui/rank.ui:529
 msgid "Blom"
@@ -6161,7 +6289,7 @@ msgstr "Van der Wärden"
 
 #: src/ui/gui/rank.ui:591
 msgid "Proportion Estimation Formula"
-msgstr ""
+msgstr "Proportion Estimation Formula"
 
 #: src/ui/gui/rank.ui:625
 msgid "Rank Cases: Ties"
@@ -6369,11 +6497,11 @@ msgstr "Testvariabele:"
 
 #: src/ui/gui/roc.ui:147
 msgid "_State Variable:"
-msgstr ""
+msgstr "_Status variabele:"
 
 #: src/ui/gui/roc.ui:172
 msgid "_Value of state variable:"
-msgstr ""
+msgstr "Waarde van status variabele:"
 
 #: src/ui/gui/roc.ui:209
 msgid "ROC C_urve"
@@ -6381,7 +6509,7 @@ msgstr "ROC C_urve"
 
 #: src/ui/gui/roc.ui:227
 msgid "_With diagonal reference line"
-msgstr ""
+msgstr "Met diagonale referentie lijn"
 
 #: src/ui/gui/roc.ui:251
 msgid "Standard _Error and Confidence Interval"
@@ -6699,320 +6827,466 @@ msgid "_File"
 msgstr "_Bestand"
 
 #: src/ui/gui/data-editor.ui:35 src/ui/gui/syntax-editor.ui:22
-#: src/ui/gui/syntax-editor.ui:40
 msgid "_Syntax"
 msgstr "_Syntax"
 
-#: src/ui/gui/data-editor.ui:41 src/ui/gui/data-editor.ui:214
-#: src/ui/gui/data-editor.ui:226 src/ui/gui/syntax-editor.ui:28
-#: src/ui/gui/syntax-editor.ui:46
+#: src/ui/gui/data-editor.ui:41 src/ui/gui/data-editor.ui:224
+#: src/ui/gui/data-editor.ui:237 src/ui/gui/syntax-editor.ui:28
 msgid "_Data"
 msgstr "_Gegevens"
 
-#: src/ui/gui/data-editor.ui:53
-msgid "_Import Delimited Text Data"
-msgstr "Gescheiden tekstgegevens _importeren"
+#: src/ui/gui/data-editor.ui:48 src/ui/gui/syntax-editor.ui:35
+msgid "_Open..."
+msgstr "_Open..."
+
+#: src/ui/gui/data-editor.ui:54
+msgid "_Import Delimited Text Data..."
+msgstr "Gescheiden tekstgegevens _importeren..."
+
+#: src/ui/gui/data-editor.ui:61
+msgid "_Rename Dataset..."
+msgstr "Hernoem Dataset..."
+
+#: src/ui/gui/data-editor.ui:74 src/ui/gui/syntax-editor.ui:48
+msgid "Save _As..."
+msgstr "Opslaan _als..."
 
-#: src/ui/gui/data-editor.ui:72
+#: src/ui/gui/data-editor.ui:80
 msgid "D_isplay Data File Information"
 msgstr "Gegevensbestand_informatie tonen"
 
-#: src/ui/gui/data-editor.ui:79
+#: src/ui/gui/data-editor.ui:87
 msgid "Working File"
 msgstr "Werkbestand"
 
-#: src/ui/gui/data-editor.ui:85
-msgid "External File"
-msgstr "Extern bestand"
+#: src/ui/gui/data-editor.ui:93
+msgid "External File..."
+msgstr "Extern bestand..."
 
-#: src/ui/gui/data-editor.ui:91
+#: src/ui/gui/data-editor.ui:99
 msgid "Recently Used Da_ta"
 msgstr "Recent gebruikte _gegevens"
 
-#: src/ui/gui/data-editor.ui:97
+#: src/ui/gui/data-editor.ui:105
 msgid "Recently Used _Files"
 msgstr "Recent gebruikte _bestanden"
 
 # Standaard snelleter voor Bewerken is de w.
-#: src/ui/gui/data-editor.ui:109 src/ui/gui/output-viewer.ui:28
-#: src/ui/gui/syntax-editor.ui:70
+#: src/ui/gui/data-editor.ui:117 src/ui/gui/output-viewer.ui:29
+#: src/ui/gui/syntax-editor.ui:60
 msgid "_Edit"
 msgstr "Be_werken"
 
-#: src/ui/gui/data-editor.ui:115
+#: src/ui/gui/data-editor.ui:123
 msgid "Insert Variable"
 msgstr "Invoegen variabele"
 
-#: src/ui/gui/data-editor.ui:116
+#: src/ui/gui/data-editor.ui:124
 msgid "Create a new variable at the current position"
 msgstr "Creëer een nieuwe variabele op de huidige positie"
 
-#: src/ui/gui/data-editor.ui:123
+#: src/ui/gui/data-editor.ui:131
 msgid "Insert Cases"
 msgstr "Invoegen cases"
 
-#: src/ui/gui/data-editor.ui:124
+#: src/ui/gui/data-editor.ui:132
 msgid "Create a new case at the current position"
 msgstr "Creëer een nieuwe case op de huidige positie"
 
-#: src/ui/gui/data-editor.ui:130
-msgid "Go To Case"
-msgstr "Ga naar case"
+#: src/ui/gui/data-editor.ui:138
+msgid "Go To Case..."
+msgstr "Ga naar case..."
 
-#: src/ui/gui/data-editor.ui:132
+#: src/ui/gui/data-editor.ui:140
 msgid "Jump to a case in the data sheet"
 msgstr "Spring naar een Case in het Gegevensblad"
 
-#: src/ui/gui/data-editor.ui:158
+#: src/ui/gui/data-editor.ui:166
 msgid "Cl_ear Variables"
 msgstr "Wis _variabelen"
 
-#: src/ui/gui/data-editor.ui:159
+#: src/ui/gui/data-editor.ui:167
 msgid "Delete the variables at the selected position(s)"
 msgstr "Verwijder de variabele op de geselecteerde positie(s)"
 
-#: src/ui/gui/data-editor.ui:167
+#: src/ui/gui/data-editor.ui:175
 msgid "_Clear Cases"
 msgstr "Wis _cases"
 
-#: src/ui/gui/data-editor.ui:168
+#: src/ui/gui/data-editor.ui:176
 msgid "Delete the cases at the selected position(s)"
 msgstr "Verwijder de cases op de geselecteerde positie(s)"
 
-#: src/ui/gui/data-editor.ui:180
+#: src/ui/gui/data-editor.ui:183
+msgid "_Find..."
+msgstr "Zoek..."
+
+#: src/ui/gui/data-editor.ui:189
 msgid "_View"
-msgstr "Beel_d"
+msgstr "Beeld"
 
-#: src/ui/gui/data-editor.ui:187
+#: src/ui/gui/data-editor.ui:196
 msgid "_Status Bar"
 msgstr "_Statusbalk"
 
-#: src/ui/gui/data-editor.ui:200
+#: src/ui/gui/data-editor.ui:203
+msgid "_Font..."
+msgstr "_Font..."
+
+#: src/ui/gui/data-editor.ui:210
 msgid "_Grid Lines"
 msgstr "_Rasterlijnen"
 
-#: src/ui/gui/data-editor.ui:206
+#: src/ui/gui/data-editor.ui:216
 msgid "Value _Labels"
 msgstr "Waarde_labels"
 
-#: src/ui/gui/data-editor.ui:207
+#: src/ui/gui/data-editor.ui:217
 msgid "Show/hide value labels"
 msgstr "Toon/verberg waardelabels"
 
-#: src/ui/gui/data-editor.ui:220 src/ui/gui/data-editor.ui:434
+#: src/ui/gui/data-editor.ui:230
 msgid "_Variables"
 msgstr "_Variabelen"
 
-#: src/ui/gui/data-editor.ui:231
-msgid "_Sort Cases"
-msgstr "_Sorteer Cases"
+#: src/ui/gui/data-editor.ui:242
+msgid "_Sort Cases..."
+msgstr "_Sorteer cases..."
 
-#: src/ui/gui/data-editor.ui:234
-msgid "Sort cases in the active file"
-msgstr "Sorteer cases in het actieve bestand"
+#: src/ui/gui/data-editor.ui:245
+msgid "Sort cases in the active dataset"
+msgstr "Sorteer cases in de actieve dataset"
 
-#: src/ui/gui/data-editor.ui:241
-msgid "_Transpose"
-msgstr "_Herschikken"
+#: src/ui/gui/data-editor.ui:252
+msgid "_Transpose..."
+msgstr "_Herschikken..."
 
-#: src/ui/gui/data-editor.ui:242
+#: src/ui/gui/data-editor.ui:253
 msgid "Transpose the cases with the variables"
 msgstr "Herschik de cases met de variabelen"
 
-#: src/ui/gui/data-editor.ui:249
-msgid "_Aggregate"
-msgstr "_Aggregeer"
+#: src/ui/gui/data-editor.ui:260
+msgid "_Aggregate..."
+msgstr "_Aggregeer..."
 
-#: src/ui/gui/data-editor.ui:255
-msgid "S_plit File"
-msgstr "S_plits bestand"
+#: src/ui/gui/data-editor.ui:266
+msgid "S_plit File..."
+msgstr "S_plits bestand..."
 
-#: src/ui/gui/data-editor.ui:256
-msgid "Split the active file"
-msgstr "Splits het actieve bestand"
+#: src/ui/gui/data-editor.ui:267
+msgid "Split the active dataset"
+msgstr "Splits de actieve dataset"
 
-#: src/ui/gui/data-editor.ui:263
-msgid "Select _Cases"
-msgstr "Selecteer _cases"
+#: src/ui/gui/data-editor.ui:274
+msgid "Select _Cases..."
+msgstr "Selecteer _cases..."
 
-#: src/ui/gui/data-editor.ui:269
-msgid "_Weight Cases"
-msgstr "_Weeg cases"
+#: src/ui/gui/data-editor.ui:280
+msgid "_Weight Cases..."
+msgstr "_Weeg cases..."
 
-#: src/ui/gui/data-editor.ui:270
+#: src/ui/gui/data-editor.ui:281
 msgid "Weight cases by variable"
 msgstr "Weeg cases per variabele"
 
-#: src/ui/gui/data-editor.ui:277
+#: src/ui/gui/data-editor.ui:288
 msgid "_Transform"
 msgstr "_Transformeren"
 
-#: src/ui/gui/data-editor.ui:283
-msgid "_Compute"
-msgstr "_Berekenen"
+#: src/ui/gui/data-editor.ui:294
+msgid "_Compute..."
+msgstr "_Berekenen..."
 
-#: src/ui/gui/data-editor.ui:289
-msgid "Ran_k Cases"
-msgstr "Rangschi_k cases"
+#: src/ui/gui/data-editor.ui:300
+msgid "Ran_k Cases..."
+msgstr "Rangschi_k cases..."
 
-#: src/ui/gui/data-editor.ui:295
-msgid "Recode into _Same Variables"
-msgstr "Hercodeer in _Zelfde Variabelen"
+#: src/ui/gui/data-editor.ui:306
+msgid "Recode into _Same Variables..."
+msgstr "Hercodeer in _zelfde variabelen..."
 
-#: src/ui/gui/data-editor.ui:301
-msgid "Recode into _Different Variables"
-msgstr "Hercodeer in _Andere Variabelen"
+#: src/ui/gui/data-editor.ui:312
+msgid "Recode into _Different Variables..."
+msgstr "Hercodeer in _andere variabelen..."
 
-#: src/ui/gui/data-editor.ui:307
+#: src/ui/gui/data-editor.ui:318
 msgid "_Run Pending Transforms"
-msgstr "_uitvoeren uitstaande Transformaties"
+msgstr "_Uitvoeren uitstaande transformaties"
 
-#: src/ui/gui/data-editor.ui:314
+#: src/ui/gui/data-editor.ui:325
 msgid "_Analyze"
 msgstr "_Analyseer"
 
-#: src/ui/gui/data-editor.ui:320
+#: src/ui/gui/data-editor.ui:331
 msgid "_Descriptive Statistics"
 msgstr "_Descriptieve statistieken"
 
-#: src/ui/gui/data-editor.ui:326
-msgid "_Frequencies"
-msgstr "_Frequenties"
+#: src/ui/gui/data-editor.ui:337
+msgid "_Frequencies..."
+msgstr "_Frequenties..."
 
-#: src/ui/gui/data-editor.ui:338
-msgid "_Explore"
-msgstr "_Onderzoek"
+#: src/ui/gui/data-editor.ui:349
+msgid "_Explore..."
+msgstr "_Onderzoek..."
 
-#: src/ui/gui/data-editor.ui:344
-msgid "_Crosstabs"
-msgstr "_Kruistabellen"
+#: src/ui/gui/data-editor.ui:355
+msgid "_Crosstabs..."
+msgstr "_Kruistabellen..."
 
-#: src/ui/gui/data-editor.ui:350
+#: src/ui/gui/data-editor.ui:361
 msgid "Compare _Means"
-msgstr ""
+msgstr "Compare _Means"
 
-#: src/ui/gui/data-editor.ui:356
-msgid "_One Sample T Test"
-msgstr ""
+#: src/ui/gui/data-editor.ui:367
+msgid "_One Sample T Test..."
+msgstr "_One Sample T Test..."
 
-#: src/ui/gui/data-editor.ui:362
-msgid "_Independent Samples T Test"
-msgstr ""
+#: src/ui/gui/data-editor.ui:373
+msgid "_Independent Samples T Test..."
+msgstr "_Independent Samples T Test..."
 
-#: src/ui/gui/data-editor.ui:368
-msgid "_Paired Samples T Test"
-msgstr ""
+#: src/ui/gui/data-editor.ui:379
+msgid "_Paired Samples T Test..."
+msgstr "_Paired Samples T Test..."
 
-#: src/ui/gui/data-editor.ui:374
-msgid "One Way _ANOVA"
-msgstr ""
+#: src/ui/gui/data-editor.ui:385
+msgid "One Way _ANOVA..."
+msgstr "One Way _ANOVA..."
 
-#: src/ui/gui/data-editor.ui:380
+#: src/ui/gui/data-editor.ui:391
 msgid "Bivariate _Correlation..."
 msgstr "Bivariate _correlatie..."
 
-#: src/ui/gui/data-editor.ui:386
-msgid "Factor _Analysis"
-msgstr "Factor _analyses"
+#: src/ui/gui/data-editor.ui:397
+msgid "Factor _Analysis..."
+msgstr "Factor _Analyses..."
 
-#: src/ui/gui/data-editor.ui:392
-msgid "Re_liability"
-msgstr "Betrouwbaarheid"
+#: src/ui/gui/data-editor.ui:403
+msgid "Re_liability..."
+msgstr "Betrouwbaarheid..."
 
-#: src/ui/gui/data-editor.ui:398
-msgid "Linear _Regression"
-msgstr "Lineare _regressie"
+#: src/ui/gui/data-editor.ui:409
+msgid "Linear _Regression..."
+msgstr "Lineare _regressie..."
 
-#: src/ui/gui/data-editor.ui:404
+#: src/ui/gui/data-editor.ui:415
 msgid "_Non-Parametric Statistics"
-msgstr ""
+msgstr "_Non-Parametric Statistics"
+
+#: src/ui/gui/data-editor.ui:421
+msgid "_Chi-Square..."
+msgstr "_Chi-Square..."
 
-#: src/ui/gui/data-editor.ui:410
-msgid "_Chi-Square"
-msgstr "_Chi-Square"
+#: src/ui/gui/data-editor.ui:427
+msgid "_Binomial..."
+msgstr "_Binomiaal..."
 
-#: src/ui/gui/data-editor.ui:416
-msgid "_Binomial"
-msgstr "_Binomiaal"
+#: src/ui/gui/data-editor.ui:433
+msgid "K Related _Samples..."
+msgstr "K Related _Samples..."
 
-#: src/ui/gui/data-editor.ui:422
+#: src/ui/gui/data-editor.ui:439
 msgid "ROC Cur_ve..."
 msgstr "ROC Cur_ve..."
 
-#: src/ui/gui/data-editor.ui:428
+#: src/ui/gui/data-editor.ui:445
 msgid "_Utilities"
 msgstr "E_xtra"
 
-#: src/ui/gui/data-editor.ui:435
+#: src/ui/gui/data-editor.ui:451
+msgid "_Variables..."
+msgstr "_Variabelen..."
+
+#: src/ui/gui/data-editor.ui:452
 msgid "Jump to variable"
 msgstr "Spring naar variabele"
 
-#: src/ui/gui/data-editor.ui:442
-msgid "Data File _Comments"
-msgstr "Gegevensbestand _commentaren"
+#: src/ui/gui/data-editor.ui:459
+msgid "Data File _Comments..."
+msgstr "Gegevensbestand _commentaren..."
 
-#: src/ui/gui/data-editor.ui:448 src/ui/gui/output-viewer.ui:46
-#: src/ui/gui/syntax-editor.ui:135
+#: src/ui/gui/data-editor.ui:465 src/ui/gui/output-viewer.ui:47
+#: src/ui/gui/syntax-editor.ui:125
 msgid "_Windows"
 msgstr "_Vensters"
 
-#: src/ui/gui/data-editor.ui:454 src/ui/gui/output-viewer.ui:52
-#: src/ui/gui/syntax-editor.ui:141
+#: src/ui/gui/data-editor.ui:471 src/ui/gui/output-viewer.ui:53
+#: src/ui/gui/syntax-editor.ui:131
 msgid "_Minimize All Windows"
 msgstr "_Minimaliseer alle vensters"
 
-#: src/ui/gui/data-editor.ui:460
+#: src/ui/gui/data-editor.ui:477
 msgid "_Split"
 msgstr "_Splitsen"
 
-#: src/ui/gui/data-editor.ui:635
+#: src/ui/gui/data-editor.ui:654
 msgid "Information Area"
 msgstr "Informatiegebied"
 
-#: src/ui/gui/data-editor.ui:657
+#: src/ui/gui/data-editor.ui:676
 msgid "Processor Area"
 msgstr "Processorgebied"
 
-#: src/ui/gui/data-editor.ui:682
+#: src/ui/gui/data-editor.ui:701
 msgid "Case Counter Area"
 msgstr "Case-tellergebied"
 
-#: src/ui/gui/data-editor.ui:707
+#: src/ui/gui/data-editor.ui:726
 msgid "Filter Use Status Area"
 msgstr "Filtergebruik statusgebied"
 
-#: src/ui/gui/data-editor.ui:733
+#: src/ui/gui/data-editor.ui:752
 msgid "Weight Status Area"
 msgstr "Weging statusgebied"
 
-#: src/ui/gui/data-editor.ui:759
+#: src/ui/gui/data-editor.ui:778
 msgid "Split File Status Area"
 msgstr "Splitsbestand statusgebied"
 
-#: src/ui/gui/output-viewer.ui:22
-msgid "_Export"
-msgstr "_Exporteer"
+#: src/ui/gui/output-viewer.ui:16
+msgid "_Print..."
+msgstr "Afdrukken..."
 
-#: src/ui/gui/syntax-editor.ui:104
+#: src/ui/gui/output-viewer.ui:23
+msgid "_Export..."
+msgstr "_Exporteer..."
+
+#: src/ui/gui/syntax-editor.ui:94
 msgid "_Run"
 msgstr "Uitvoe_ren"
 
-#: src/ui/gui/syntax-editor.ui:110
+#: src/ui/gui/syntax-editor.ui:100
 msgid "All"
 msgstr "Alles"
 
-#: src/ui/gui/syntax-editor.ui:116
+#: src/ui/gui/syntax-editor.ui:106
 msgid "Selection"
 msgstr "Selectie"
 
-#: src/ui/gui/syntax-editor.ui:122
+#: src/ui/gui/syntax-editor.ui:112
 msgid "Current Line"
 msgstr "Huidige regel"
 
-#: src/ui/gui/syntax-editor.ui:129
+#: src/ui/gui/syntax-editor.ui:119
 msgid "To End"
 msgstr "Naar einde"
 
+#~ msgid "scratch file"
+#~ msgstr "scratchbestand"
+
+#~ msgid "Variable suffix too large."
+#~ msgstr "Variabelen-achtervoegsel te lang."
+
+#~ msgid "Missing space following `%c' at UTF-8 offset %zu in MRSETS record."
+#~ msgstr "Ontbrekende spatie achter`%c' op UTF-8 offset %zu in MRSETS record."
+
+#~ msgid "Unexpected label source value `%s' following `E' at UTF-8 offset %zu in MRSETS record."
+#~ msgstr "Onverwacht label bronwaarde `%s' achter `E' in UTF-8 offset %zu in MRSETS record."
+
+#~ msgid "PSPP-data"
+#~ msgstr "PSPP-data"
+
+#~ msgid "Syntax"
+#~ msgstr "Syntax"
+
+#~ msgid "%s %s PSPPIRE %s"
+#~ msgstr "%s %s PSPPIRE %s"
+
+#~ msgid "Untitled"
+#~ msgstr "Zonder titel"
+
+#~ msgid "Cannot create variable name from %s"
+#~ msgstr "Kan geen variabelennaam creëren van %s"
+
+#~ msgid "Duplicate variable name %s in position %d."
+#~ msgstr "Dubbele variabelennaam %s op positie %d."
+
+#~ msgid "Recoded variable name duplicates an existing `%s' within system file."
+#~ msgstr "Gehercodeerde variabelennaam dupliceert een bestaande '%s' binnen systeembestand."
+
+#, fuzzy
+#~ msgid "Variable name begins with invalid character `%c'."
+#~ msgstr "Variabele index %d niet in geldig bereik 1...%d."
+
+#~ msgid "Duplicate variable name `%s' within system file."
+#~ msgstr "Dubbele variabelennaam '%s' binnen systeembestand."
+
+#~ msgid "Document line contains null byte."
+#~ msgstr "Documentregel bevat null byte."
+
+#~ msgid "Duplicate long variable name `%s' within system file."
+#~ msgstr "Dubbele lange variabelennaam '%s' binnen systeembestand."
+
+#~ msgid "Invalid number of labels: %d.  Ignoring labels."
+#~ msgstr "Ongeldig aantal labels: %d. Labels worden genegeerd."
+
+#~ msgid "Reading `%s': %s."
+#~ msgstr "Lezen '%s': %s."
+
+#~ msgid "Closing `%s': %s."
+#~ msgstr "Sluiten '%s': %s."
+
+#~ msgid "%s does not form a valid number."
+#~ msgstr "%s vormt geen geldig nummer."
+
+#~ msgid "binary"
+#~ msgstr "binair"
+
+#~ msgid "octal"
+#~ msgstr "octaal"
+
+#~ msgid "hex"
+#~ msgstr "hexadecimaal"
+
+#~ msgid "Unexpected end of file in string concatenation."
+#~ msgstr "Onverwacht bestandseinde in tekenreeks samenvoeging."
+
+#~ msgid "incorrect use of TO convention"
+#~ msgstr "foutief gebruik van TO conventie"
+
+#~ msgid "DO REPEAT may not nest in compatibility mode."
+#~ msgstr "DO REPEAT mag niet nesten in compatibiliteitsmodus."
+
+#~ msgid "%s is too long for a variable name."
+#~ msgstr "%s is te lang voor een variabelennaam."
+
+#~ msgid "%zu-byte string needed but %zu-byte string supplied."
+#~ msgstr "%zu-byte tekenreeks nodig maar %zu-byte tekenreeks gegeven."
+
+#~ msgid "Hexadecimal floating constant too long."
+#~ msgstr "Hexadecimale drijvende constante te lang."
+
+#~ msgid "%s conversion of %s from %s to %s should have produced %s but actually produced %s."
+#~ msgstr "%s conversie van %s van %s naar %s zou %s moeten produceren maar produceerde in werkelijkheid %s."
+
+#~ msgid "Too many values in single command."
+#~ msgstr "Te veel waardes in enkele opdracht."
+
+#~ msgid "Unexpected token: `%s'."
+#~ msgstr "Onverwacht symbool: '%s'."
+
+#~ msgid "Unable to open `%s': %s."
+#~ msgstr "Onmogelijk om te openen '%s': %s."
+
+#, fuzzy
+#~ msgid "Multivariate analysis is not yet implemented"
+#~ msgstr "%s is nog niet geïmplementeerd."
+
+#, fuzzy
+#~ msgid "Intercept"
+#~ msgstr "Percentage"
+
+#, fuzzy
+#~ msgid "Error"
+#~ msgstr "fout"
+
+#, fuzzy
+#~ msgid "Corrected Total"
+#~ msgstr "Coëfficiënt Totaal: "
+
+#~ msgid "Analyse"
+#~ msgstr "Analyseer"
+
 #~ msgid "column %d"
 #~ msgstr "kolom %d"
 
@@ -7058,10 +7332,6 @@ msgstr "Naar einde"
 #~ msgid "in expression"
 #~ msgstr "in expressie"
 
-#, fuzzy
-#~ msgid "Missing space following `E' at offset %zu in MRSETS record"
-#~ msgstr "Dubbele variabelenaam %s op offset %zu in MRSETS record."
-
 #~ msgid "expecting BY"
 #~ msgstr "BY verwacht"
 
@@ -7119,9 +7389,6 @@ msgstr "Naar einde"
 #~ msgid "Sort Descending"
 #~ msgstr "Sorteer aflopend"
 
-#~ msgid "_Fonts"
-#~ msgstr "_Fonts"
-
 #~ msgid "Variable %s has label of invalid length %zu."
 #~ msgstr "Variabele %s heeft label van ongeldige lengte %zu."
 
index 807c4fe90e95aab67a2b91bd0226820feecd462a..50feb6892e936f4fbf9ea54d14f90707c11acf67 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011 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 "any-reader.h"
+
+#include "data/any-reader.h"
+
 #include <assert.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include "file-handle-def.h"
-#include "file-name.h"
-#include "por-file-reader.h"
-#include "sys-file-reader.h"
-#include <libpspp/str.h>
-#include "scratch-reader.h"
-#include "xalloc.h"
+
+#include "data/dataset-reader.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/por-file-reader.h"
+#include "data/sys-file-reader.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -107,8 +111,8 @@ any_reader_open (struct file_handle *handle, struct dictionary **dict)
       msg (SE, _("The inline file is not allowed here."));
       return NULL;
 
-    case FH_REF_SCRATCH:
-      return scratch_reader_open (handle, dict);
+    case FH_REF_DATASET:
+      return dataset_reader_open (handle, dict);
     }
   NOT_REACHED ();
 }
index 94dff952f1ea6a42dbd8a154d62e4c39c4a48f72..61d6ffc8a26ec5c53501f0dc38aa20078cad8280 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011 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 "any-writer.h"
+
+#include "data/any-writer.h"
+
 #include <assert.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include "file-handle-def.h"
-#include "file-name.h"
-#include "por-file-writer.h"
-#include "sys-file-writer.h"
-#include <libpspp/str.h>
-#include "scratch-writer.h"
-#include "xalloc.h"
+
+#include "data/dataset-writer.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/por-file-writer.h"
+#include "data/sys-file-writer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -63,8 +67,8 @@ any_writer_open (struct file_handle *handle, struct dictionary *dict)
       msg (ME, _("The inline file is not allowed here."));
       return NULL;
 
-    case FH_REF_SCRATCH:
-      return scratch_writer_open (handle, dict);
+    case FH_REF_DATASET:
+      return dataset_writer_open (handle, dict);
     }
 
   NOT_REACHED ();
index d99e945b014def2836ec1eb57ea33631fc5086d4..7fc546ee23771e7382232b88c92555289aa8df80 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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/attributes.h>
+#include "data/attributes.h"
+
 #include <assert.h>
 #include <string.h>
-#include <libpspp/array.h>
-#include <libpspp/hash-functions.h>
-#include "xalloc.h"
+
+#include "libpspp/array.h"
+#include "libpspp/hash-functions.h"
+
+#include "gl/xalloc.h"
 
 /* A custom attribute of the sort maintained by the DATAFILE
    ATTRIBUTE and VARIABLE ATTRIBUTE commands.
index 87cb7726f8e01a2846299e5da069cba41bbaa244..61b68f116094c0451f704bd3785897a43099c6bd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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,7 +17,7 @@
 #ifndef DATA_ATTRIBUTES_H
 #define DATA_ATTRIBUTES_H 1
 
-#include <libpspp/hmapx.h>
+#include "libpspp/hmapx.h"
 
 /* This header supports custom attribute of the sort maintained
    by the DATAFILE ATTRIBUTE and VARIABLE ATTRIBUTE commands.
index 10fbed3d9e2c60cf83ffc603c6064dc55f3870de..81a9d9c5259bf87838cfe68260eb68eb28fa44d0 100644 (file)
@@ -48,6 +48,12 @@ src_data_libdata_la_SOURCES = \
        src/data/data-in.h \
        src/data/data-out.c \
        src/data/data-out.h \
+       src/data/dataset.c \
+       src/data/dataset.h \
+       src/data/dataset-reader.c \
+       src/data/dataset-reader.h \
+       src/data/dataset-writer.c \
+       src/data/dataset-writer.h \
        src/data/datasheet.c \
        src/data/datasheet.h \
        src/data/dict-class.c \
@@ -66,6 +72,7 @@ src_data_libdata_la_SOURCES = \
        src/data/gnumeric-reader.c \
        src/data/gnumeric-reader.h \
        src/data/identifier.c \
+       src/data/identifier2.c \
        src/data/identifier.h \
        src/data/lazy-casereader.c \
        src/data/lazy-casereader.h \
@@ -75,26 +82,21 @@ src_data_libdata_la_SOURCES = \
        src/data/make-file.h \
        src/data/mrset.c \
        src/data/mrset.h \
-       src/data/procedure.c \
-       src/data/procedure.h \
        src/data/por-file-reader.c \
        src/data/por-file-reader.h \
        src/data/por-file-writer.c \
        src/data/por-file-writer.h \
        src/data/psql-reader.c \
        src/data/psql-reader.h \
-       src/data/scratch-handle.c \
-       src/data/scratch-handle.h \
-       src/data/scratch-reader.c \
-       src/data/scratch-reader.h \
-       src/data/scratch-writer.c \
-       src/data/scratch-writer.h \
+       src/data/session.c \
+       src/data/session.h \
        src/data/settings.c \
        src/data/settings.h \
        src/data/short-names.c \
        src/data/short-names.h \
        src/data/subcase.c \
        src/data/subcase.h \
+       src/data/sys-file-encoding.c \
        src/data/sys-file-private.c \
        src/data/sys-file-private.h \
        src/data/sys-file-reader.c \
@@ -114,4 +116,6 @@ src_data_libdata_la_SOURCES = \
        src/data/vector.c \
        src/data/vector.h
 
-EXTRA_DIST += src/data/OChangeLog
+EXTRA_DIST += \
+       src/data/OChangeLog \
+       src/data/sys-file-encoding.pl
index ef6aa6755e4a922171fa863020091cf8094e5405..a2bb7e600004c6cd025c90e0c26641e12fe30ce0 100644 (file)
@@ -1,9 +1,28 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2006, 2007, 2008, 2010, 2011 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 "calendar.h"
+
+#include "data/calendar.h"
+
 #include <assert.h>
 #include <stdbool.h>
-#include <data/settings.h>
-#include <data/val-type.h>
+
+#include "data/settings.h"
+#include "data/val-type.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 49297d1349f5c50661e904408f6135684786e710..c54e6753fe74bab580984479e4573dabe9988c04 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, 2011 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/case-map.h>
+#include "data/case-map.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <data/case.h>
-#include <libpspp/assertion.h>
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "data/case.h"
+#include "libpspp/assertion.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A case map. */
 struct case_map
index 37cb4a60748a4b60e2416476a0ed629ff8f90620..46272bbed693011e14c4d324092932c40e053229 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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/case-matcher.h>
+#include "data/case-matcher.h"
 
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/subcase.h>
-#include <data/value.h>
-#include <libpspp/assertion.h>
+#include "data/case.h"
+#include "data/subcase.h"
+#include "data/value.h"
+#include "libpspp/assertion.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 struct case_matcher_input
   {
index 58e437ad1b45686000c0b320e028e0f0d8ad641a..907a926f9ece6281de146af02adbd880a5570d23 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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/case-tmpfile.h>
+#include "data/case-tmpfile.h"
 
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/taint.h>
-#include <libpspp/ext-array.h>
+#include "libpspp/assertion.h"
+#include "libpspp/taint.h"
+#include "libpspp/ext-array.h"
 
-#include "error.h"
-#include "xalloc.h"
+#include "gl/error.h"
+#include "gl/xalloc.h"
 
 /* A temporary file that stores an array of cases. */
 struct case_tmpfile
index bbf736e3d13080f365c2932e4d65294ef63d2549..3659e5805e1e8a73c9a17c381c8ae8e1eff10768 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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,7 +29,7 @@
 #ifndef DATA_CASE_TMPFILE_H
 #define DATA_CASE_TMPFILE_H 1
 
-#include <data/case.h>
+#include "data/case.h"
 
 struct caseproto;
 
index dc4029268ebf981bc10d96ecccf7c88eb53dd71a..bb6f7c0a8e05c735f9b17cd0aab309993e4d7a21 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2009, 2010, 2011 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/case.h>
+#include "data/case.h"
 
 #include <limits.h>
 #include <stddef.h>
 #include <stdlib.h>
 
-#include <data/value.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+/* Set this flag to 1 to copy cases instead of ref counting them.
+   This is sometimes helpful in debugging situations. */
+#define DEBUG_CASEREFS 0
+
+#if DEBUG_CASEREFS
+#warning "Caseref debug enabled.  CASES ARE NOT BEING SHARED!!"
+#endif
 
 static size_t case_size (const struct caseproto *);
 static bool variable_matches_case (const struct ccase *,
@@ -80,6 +88,19 @@ case_clone (const struct ccase *c)
   return case_unshare (case_ref (c));
 }
 
+/* Increments case C's reference count and returns C.  Afterward,
+   case C is shared among its reference count holders. */
+struct ccase *
+case_ref (const struct ccase *c_)
+{
+  struct ccase *c = CONST_CAST (struct ccase *, c_);
+  c->ref_cnt++;
+#if DEBUG_CASEREFS
+  c = case_unshare__ (c);
+#endif
+  return c;
+}
+
 /* Returns an estimate of the number of bytes of memory that
    would be consumed in creating a case based on PROTO.  The
    estimate includes typical overhead from malloc() in addition
index d00c2ad37badd69cc80f9991d99a70bf8d88084c..1f5e192f3d748ec0050f3d00c5f6006b156434e7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2009, 2010, 2011 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,8 +21,9 @@
 #include <stddef.h>
 #include <stdbool.h>
 #include <stdlib.h>
-#include <libpspp/compiler.h>
-#include <data/caseproto.h>
+
+#include "libpspp/compiler.h"
+#include "data/caseproto.h"
 
 struct variable;
 
@@ -61,7 +62,7 @@ struct ccase *case_try_create (const struct caseproto *) MALLOC_LIKE;
 struct ccase *case_clone (const struct ccase *) MALLOC_LIKE;
 
 static inline struct ccase *case_unshare (struct ccase *) WARN_UNUSED_RESULT;
-static inline struct ccase *case_ref (const struct ccase *);
+struct ccase *case_ref (const struct ccase *) WARN_UNUSED_RESULT;
 static inline void case_unref (struct ccase *);
 static inline bool case_is_shared (const struct ccase *);
 
@@ -130,16 +131,6 @@ case_unshare (struct ccase *c)
   return c;
 }
 
-/* Increments case C's reference count and returns C.  Afterward,
-   case C is shared among its reference count holders. */
-static inline struct ccase *
-case_ref (const struct ccase *c_)
-{
-  struct ccase *c = CONST_CAST (struct ccase *, c_);
-  c->ref_cnt++;
-  return c;
-}
-
 /* Decrements case C's reference count.  Frees C if its
    reference count drops to 0.
 
index dee1488e9e297145f22782518dd16887315c389e..52238c8c610dff3593eaf6c82553f5e21d8215a7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/casegrouper.h>
+#include "data/casegrouper.h"
 
 #include <stdlib.h>
 
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/subcase.h>
-#include <libpspp/taint.h>
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dictionary.h"
+#include "data/subcase.h"
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A casegrouper. */
 struct casegrouper
index 572f9160292e670f1a60ae99c226b2ad13b064de..021db396d15fe10b45cd74a0c9de3bf09f3143d1 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, 2011 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/caseinit.h>
+#include "data/caseinit.h"
 
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <data/case.h>
-#include <data/dictionary.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
+#include "data/case.h"
+#include "data/dictionary.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 \f
 /* Initializer list: a set of values to write to locations within
    a case. */
@@ -53,7 +53,7 @@ struct init_list
 /* A bitmap of the "left" status of variables. */
 enum leave_class
   {
-    LEAVE_REINIT = 0x001,       /* Reinitalize for every case. */
+    LEAVE_REINIT = 0x001,       /* Reinitialize for every case. */
     LEAVE_LEFT = 0x002          /* Keep the value from one case to the next. */
   };
 
@@ -65,6 +65,22 @@ init_list_create (struct init_list *list)
   list->cnt = 0;
 }
 
+/* Initializes NEW as a copy of OLD. */
+static void
+init_list_clone (struct init_list *new, const struct init_list *old)
+{
+  size_t i;
+
+  new->values = xmemdup (old->values, old->cnt * sizeof *old->values);
+  new->cnt = old->cnt;
+
+  for (i = 0; i < new->cnt; i++)
+    {
+      struct init_value *iv = &new->values[i];
+      value_clone (&iv->value, &iv->value, iv->width);
+    }
+}
+
 /* Frees the storage associated with LIST. */
 static void
 init_list_destroy (struct init_list *list)
@@ -198,6 +214,17 @@ caseinit_create (void)
   return ci;
 }
 
+/* Creates and returns a copy of OLD. */
+struct caseinit *
+caseinit_clone (struct caseinit *old)
+{
+  struct caseinit *new = xmalloc (sizeof *new);
+  init_list_clone (&new->preinited_values, &old->preinited_values);
+  init_list_clone (&new->reinit_values, &old->reinit_values);
+  init_list_clone (&new->left_values, &old->left_values);
+  return new;
+}
+
 /* Clears the contents of case initializer CI. */
 void
 caseinit_clear (struct caseinit *ci)
index 66226f5683c806728ca36fccc8dcc96d5a18dfa7..9f566218428f45c354e13c09a86c083a2e83fabf 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
 /* Case initializer.
 
    The procedure code has to resize cases provided by the active
-   file data source, to provide room for any other variables that
+   dataset data source, to provide room for any other variables that
    should go in the case, fill in the values of "left" variables,
    and initialize the values of other non-left variable to zero
    or spaces.  Then, when we're done with that case, we have to
    save the values of "left" variables to copy into the next case
-   read from the active file.
+   read from the active dataset.
 
    The caseinit data structure provides a little help for
    tracking what data to initialize or to copy from case to
@@ -36,6 +36,7 @@ struct ccase;
 
 /* Creation and destruction. */
 struct caseinit *caseinit_create (void);
+struct caseinit *caseinit_clone (struct caseinit *);
 void caseinit_clear (struct caseinit *);
 void caseinit_destroy (struct caseinit *);
 
index 9837013acb8bee86cb6d30bf0876a706a05dbc71..d62af283de2945cc2139f980d8c4dea5a0a431b2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/caseproto.h>
-#include <data/val-type.h>
-#include <data/value.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/pool.h>
+#include "data/caseproto.h"
 
-#include "minmax.h"
+#include "data/val-type.h"
+#include "data/value.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/pool.h"
+
+#include "gl/minmax.h"
 
 static struct caseproto *caseproto_unshare (struct caseproto *);
 static bool try_init_long_strings (const struct caseproto *,
index b0f45c418c47aae8017b0469a5307cff6b9cd7f6..0bc02812d18590aeb3ba4ca664445f8134d488bf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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 <stdlib.h>
-#include <data/value.h>
-#include <libpspp/cast.h>
-#include <libpspp/compiler.h>
+
+#include "data/value.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
 
 /* Case prototype.
 
index da515c6dda4152f499a2acac3435c6fa944803ea..15fa4a5e6701605ec107fe43a599fab71d48f043 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/casereader.h>
+#include "data/casereader.h"
 
 #include <stdlib.h>
 
-#include <data/casereader-provider.h>
-#include <data/casewriter.h>
-#include <data/variable.h>
-#include <data/dictionary.h>
-#include <libpspp/taint.h>
-#include <libpspp/message.h>
+#include "data/casereader-provider.h"
+#include "data/casewriter.h"
+#include "data/variable.h"
+#include "data/dictionary.h"
+#include "libpspp/taint.h"
+#include "libpspp/message.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 116a3359b4408caf2a51912a45095ea3ffb5843d..d3d560f2088deaa734a512e5487e172aee92f4ad 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -16,8 +16,8 @@
 
 #include <config.h>
 
-#include <data/casereader-provider.h>
-#include <data/subcase.h>
+#include "data/casereader-provider.h"
+#include "data/subcase.h"
 
 #include "gl/xalloc.h"
 
index b8d53500504fb2c2595e894b9baf944a8651d0b7..f22cf4accff7b8063b9d812e39f077ea8e206533 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 @@
 #ifndef DATA_CASEREADER_PROVIDER_H
 #define DATA_CASEREADER_PROVIDER_H 1
 
-#include <data/casereader.h>
+#include "data/casereader.h"
 
 /* Casereader class for sequential data sources. */
 struct casereader_class
index d75a605b01349eef258f0fdbe9d04994553e68bc..26accb4107a1074fc7273b74ad9c3b0edae27e2f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <data/casereader-provider.h>
+#include "data/casereader-provider.h"
 
 #include "gl/xalloc.h"
 
index fc823049d570df34863291ab4b0650f2cba6d26b..062184691defe569321351b5f1304709fcfb2273 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/val-type.h>
-#include <data/casereader.h>
+
 #include <stdlib.h>
 
-#include <data/variable.h>
-#include <data/casereader-provider.h>
-#include <libpspp/taint.h>
+#include "data/casereader-provider.h"
+#include "data/casereader.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* Casereader that applies a user-supplied function to translate
    each case into another in an arbitrary fashion. */
index a2e789ae6f777c8fc3688c3dc9110180434f75f0..24afb972fc603fe889822df7e6c296ee06f65e81 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, 2011 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
 
    A casereader abstracts interfaces through which cases may be
    read.  A casereader may be a front-end for a system file, a
-   portable file, the active file in a data set, or anything else
-   on which a casereader interface has been overlaid.  Casereader
-   layering, in which a casereader acts as a filter or translator
-   on top of another casereader, is also supported.
+   portable file, a dataset, or anything else on which a
+   casereader interface has been overlaid.  Casereader layering,
+   in which a casereader acts as a filter or translator on top of
+   another casereader, is also supported.
 
    There is no central interface for obtaining casereaders: a
    casereader for reading a system file is obtained from the
@@ -51,9 +51,9 @@
 #ifndef DATA_CASEREADER_H
 #define DATA_CASEREADER_H 1
 
-#include <libpspp/compiler.h>
-#include <data/case.h>
-#include <data/missing-values.h>
+#include "libpspp/compiler.h"
+#include "data/case.h"
+#include "data/missing-values.h"
 
 struct dictionary;
 struct casereader;
index 936b6aa940051be14a422fde8a8773f22388eeb7..804a58aa517cbb344fb5a8f56b9616da5e5168b4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/casewindow.h>
+#include "data/casewindow.h"
 
 #include <stdlib.h>
 
-#include <data/case-tmpfile.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/deque.h>
-#include <libpspp/taint.h>
+#include "data/case-tmpfile.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/deque.h"
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A queue of cases. */
 struct casewindow
index b303c85dab5b53d99391a2698901a83065ea0a54..c7a863eaa89544f5ebf89f3e1b333530b8c75574 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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
@@ -28,7 +28,7 @@
 #ifndef DATA_CASEWINDOW_H
 #define DATA_CASEWINDOW_H 1
 
-#include <data/case.h>
+#include "data/case.h"
 
 struct caseproto;
 
index 7231a1f3bbfc1af5580547ae723090f03035f098..822edfd0da59ee284bb57f70c0f8613c81eca0b4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2011 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,7 +17,7 @@
 #ifndef DATA_CASEWRITER_PROVIDER_H
 #define DATA_CASEWRITER_PROVIDER_H 1
 
-#include <data/casewriter.h>
+#include "data/casewriter.h"
 
 struct casewriter_class
   {
index e80b9d68187b3f65e33b35051b0b6d891ca5f312..c750c7c73b21f69cdfd852bebfb4b7d3de39d40e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/casewriter.h>
-#include <data/casewriter-provider.h>
+#include "data/casewriter.h"
+#include "data/casewriter-provider.h"
 
 #include <stdlib.h>
 
-#include <libpspp/taint.h>
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 struct casewriter_translator
   {
index 7631d776d3d2ac59cf336eccde48446aa8832b80..6029fc0dbe561fae7db8870559a260da072146cc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/casewriter.h>
-#include <data/casewriter-provider.h>
+#include "data/casewriter.h"
+#include "data/casewriter-provider.h"
 
 #include <assert.h>
 #include <stdlib.h>
 
-#include <data/casereader.h>
-#include <data/casereader-provider.h>
-#include <data/casewindow.h>
-#include <data/settings.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/taint.h>
+#include "data/casereader.h"
+#include "data/casereader-provider.h"
+#include "data/casewindow.h"
+#include "data/settings.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A casewriter. */
 struct casewriter
index 146cc654608f754e2f7178c9738c477c7644627b..ffe7798a8f15d67267c5363ee15b80c4f62b227a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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
@@ -18,8 +18,8 @@
 #define DATA_CASEWRITER_H 1
 
 #include <stdbool.h>
-#include <data/transformations.h>
-#include <libpspp/compiler.h>
+#include "data/transformations.h"
+#include "libpspp/compiler.h"
 
 struct casewriter;
 
index 70568c3e1d4dfe35fc10857d0aaf6ee1fe654c72..cbc617b3d2a2634e77fe35ac1d02be2039308591 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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
@@ -45,6 +45,8 @@
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/ftoastr.h"
+#include "gl/minmax.h"
 #include "gl/unlocked-io.h"
 #include "gl/xalloc.h"
 
@@ -120,9 +122,7 @@ csv_writer_open (struct file_handle *fh, const struct dictionary *dict,
 
   w->opts = *opts;
 
-  w->encoding = (dict_get_encoding (dict)
-                 ? xstrdup (dict_get_encoding (dict))
-                 : NULL);
+  w->encoding = xstrdup (dict_get_encoding (dict));
 
   w->n_csv_vars = dict_get_var_cnt (dict);
   w->csv_vars = xnmalloc (w->n_csv_vars, sizeof *w->csv_vars);
@@ -280,7 +280,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
     csv_output_format (w, cv, value);
   else
     {
-      char s[128];
+      char s[MAX (DBL_STRLEN_BOUND, 128)];
 
       switch (cv->format.type)
         {
@@ -306,7 +306,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
         case FMT_RBHEX:
         case FMT_WKDAY:
         case FMT_MONTH:
-          snprintf (s, sizeof s, "%.*g", DBL_DIG + 1, value->f);
+          dtoastr (s, sizeof s, 0, 0, value->f);
           if (w->opts.decimal != '.')
             {
               char *cp = strchr (s, '.');
index d36aefb5e8144bb1e2207fb613d2ec6d897b63c2..e72d1b6ad4e1fd45ff5026f301bd3ee034e4b4b3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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
@@ -37,7 +37,6 @@
 #include "libpspp/compiler.h"
 #include "libpspp/i18n.h"
 #include "libpspp/integer-format.h"
-#include "libpspp/legacy-encoding.h"
 #include "libpspp/misc.h"
 #include "libpspp/str.h"
 #include "settings.h"
@@ -116,7 +115,7 @@ data_in (struct substring input, const char *input_encoding,
       /* We're going to parse these into numbers.  For this purpose we want to
          deal with them in the local "C" encoding.  Any character not in that
          encoding wouldn't be valid anyhow. */
-      dest_encoding = LEGACY_NATIVE;
+      dest_encoding = C_ENCODING;
     }
   else if (cat & (FMT_CAT_BINARY | FMT_CAT_LEGACY))
     {
@@ -130,7 +129,7 @@ data_in (struct substring input, const char *input_encoding,
         {
           /* We want the hex digits in the local "C" encoding, even though the
              result may not be in that encoding. */
-          dest_encoding = LEGACY_NATIVE;
+          dest_encoding = C_ENCODING;
         }
       else
         {
@@ -245,7 +244,7 @@ has_implied_decimals (struct substring input, const char *input_encoding,
       return false;
     }
 
-  s = recode_string (LEGACY_NATIVE, input_encoding,
+  s = recode_string (C_ENCODING, input_encoding,
                      ss_data (input), ss_length (input));
   retval = (format == FMT_Z
             ? strchr (s, '.') == NULL
@@ -299,46 +298,46 @@ parse_number (struct data_in *i)
   ds_extend (&tmp, 64);
 
   /* Prefix character may precede sign. */
-  if (!ss_is_empty (style->prefix))
+  if (style->prefix.s[0] != '\0')
     {
-      ss_match_char (&i->input, ss_first (style->prefix));
+      ss_match_byte (&i->input, style->prefix.s[0]);
       ss_ltrim (&i->input, ss_cstr (CC_SPACES));
     }
 
   /* Sign. */
-  if (ss_match_char (&i->input, '-'))
+  if (ss_match_byte (&i->input, '-'))
     {
-      ds_put_char (&tmp, '-');
+      ds_put_byte (&tmp, '-');
       ss_ltrim (&i->input, ss_cstr (CC_SPACES));
     }
   else
     {
-      ss_match_char (&i->input, '+');
+      ss_match_byte (&i->input, '+');
       ss_ltrim (&i->input, ss_cstr (CC_SPACES));
     }
 
   /* Prefix character may follow sign. */
-  if (!ss_is_empty (style->prefix))
+  if (style->prefix.s[0] != '\0')
     {
-      ss_match_char (&i->input, ss_first (style->prefix));
+      ss_match_byte (&i->input, style->prefix.s[0]);
       ss_ltrim (&i->input, ss_cstr (CC_SPACES));
     }
 
   /* Digits before decimal point. */
   while (c_isdigit (ss_first (i->input)))
     {
-      ds_put_char (&tmp, ss_get_char (&i->input));
+      ds_put_byte (&tmp, ss_get_byte (&i->input));
       if (style->grouping != 0)
-        ss_match_char (&i->input, style->grouping);
+        ss_match_byte (&i->input, style->grouping);
     }
 
   /* Decimal point and following digits. */
-  if (ss_match_char (&i->input, style->decimal))
+  if (ss_match_byte (&i->input, style->decimal))
     {
       explicit_decimals = true;
-      ds_put_char (&tmp, '.');
+      ds_put_byte (&tmp, '.');
       while (c_isdigit (ss_first (i->input)))
-        ds_put_char (&tmp, ss_get_char (&i->input));
+        ds_put_byte (&tmp, ss_get_byte (&i->input));
     }
 
   /* Exponent. */
@@ -347,28 +346,28 @@ parse_number (struct data_in *i)
       && strchr ("eEdD-+", ss_first (i->input)))
     {
       explicit_decimals = true;
-      ds_put_char (&tmp, 'e');
+      ds_put_byte (&tmp, 'e');
 
       if (strchr ("eEdD", ss_first (i->input)))
         {
           ss_advance (&i->input, 1);
-          ss_match_char (&i->input, ' ');
+          ss_match_byte (&i->input, ' ');
         }
 
       if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
         {
-          if (ss_get_char (&i->input) == '-')
-            ds_put_char (&tmp, '-');
-          ss_match_char (&i->input, ' ');
+          if (ss_get_byte (&i->input) == '-')
+            ds_put_byte (&tmp, '-');
+          ss_match_byte (&i->input, ' ');
         }
 
       while (c_isdigit (ss_first (i->input)))
-        ds_put_char (&tmp, ss_get_char (&i->input));
+        ds_put_byte (&tmp, ss_get_byte (&i->input));
     }
 
   /* Suffix character. */
-  if (!ss_is_empty (style->suffix))
-    ss_match_char (&i->input, ss_first (style->suffix));
+  if (style->suffix.s[0] != '\0')
+    ss_match_byte (&i->input, style->suffix.s[0]);
 
   if (!ss_is_empty (i->input))
     {
@@ -420,7 +419,7 @@ parse_N (struct data_in *i)
   int c;
 
   i->output->f = 0;
-  while ((c = ss_get_char (&i->input)) != EOF)
+  while ((c = ss_get_byte (&i->input)) != EOF)
     {
       if (!c_isdigit (c))
         return xstrdup (_("All characters in field must be digits."));
@@ -439,7 +438,7 @@ parse_PIBHEX (struct data_in *i)
 
   n = 0.0;
 
-  while ((c = ss_get_char (&i->input)) != EOF)
+  while ((c = ss_get_byte (&i->input)) != EOF)
     {
       if (!c_isxdigit (c))
         return xstrdup (_("Unrecognized character in field."));
@@ -460,8 +459,8 @@ parse_RBHEX (struct data_in *i)
   memset (&d, 0, sizeof d);
   for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
     {
-      int hi = ss_get_char (&i->input);
-      int lo = ss_get_char (&i->input);
+      int hi = ss_get_byte (&i->input);
+      int lo = ss_get_byte (&i->input);
       if (lo == EOF)
         return xstrdup (_("Field must have even length."));
       else if (!c_isxdigit (hi) || !c_isxdigit (lo))
@@ -520,22 +519,22 @@ parse_Z (struct data_in *i)
   ds_init_empty (&tmp);
   ds_extend (&tmp, 64);
 
-  ds_put_char (&tmp, '+');
+  ds_put_byte (&tmp, '+');
   while (!ss_is_empty (i->input))
     {
-      int c = ss_get_char (&i->input);
+      int c = ss_get_byte (&i->input);
       if (c_isdigit (c) && !got_final_digit)
-        ds_put_char (&tmp, c);
+        ds_put_byte (&tmp, c);
       else if (is_z_digit (c) && !got_final_digit)
         {
-          ds_put_char (&tmp, z_digit_value (c) + '0');
+          ds_put_byte (&tmp, z_digit_value (c) + '0');
           if (is_negative_z_digit (c))
             ds_data (&tmp)[0] = '-';
           got_final_digit = true;
         }
       else if (c == '.' && !got_dot)
         {
-          ds_put_char (&tmp, '.');
+          ds_put_byte (&tmp, '.');
           got_dot = true;
         }
       else
@@ -623,7 +622,7 @@ parse_PIB (struct data_in *i)
 static void
 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
 {
-  int c = ss_get_char (s);
+  int c = ss_get_byte (s);
   assert (c != EOF);
   *high_nibble = (c >> 4) & 15;
   *low_nibble = c & 15;
@@ -721,8 +720,8 @@ parse_AHEX (struct data_in *i)
 
   for (j = 0; ; j++)
     {
-      int hi = ss_get_char (&i->input);
-      int lo = ss_get_char (&i->input);
+      int hi = ss_get_byte (&i->input);
+      int lo = ss_get_byte (&i->input);
       if (hi == EOF)
         break;
       else if (lo == EOF)
@@ -799,11 +798,11 @@ parse_time_units (struct data_in *i, double seconds_per_unit,
 
   if (*time_sign == SIGN_NO_TIME)
     {
-      if (ss_match_char (&i->input, '-'))
+      if (ss_match_byte (&i->input, '-'))
         *time_sign = SIGN_NEGATIVE;
       else
         {
-          ss_match_char (&i->input, '+');
+          ss_match_byte (&i->input, '+');
           *time_sign = SIGN_POSITIVE;
         }
     }
@@ -839,7 +838,7 @@ static struct substring
 parse_name_token (struct data_in *i)
 {
   struct substring token;
-  ss_get_chars (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
+  ss_get_bytes (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
   return token;
 }
 
@@ -949,7 +948,7 @@ parse_yday (struct data_in *i, long *yday)
   struct substring num_s;
   long num;
 
-  ss_get_chars (&i->input, 3, &num_s);
+  ss_get_bytes (&i->input, 3, &num_s);
   if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
     return xstrdup (_("Julian day must have exactly three digits."));
   else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
@@ -1041,11 +1040,11 @@ parse_minute_second (struct data_in *i, double *time)
   /* Parse seconds. */
   cp = buf;
   while (c_isdigit (ss_first (i->input)))
-    *cp++ = ss_get_char (&i->input);
-  if (ss_match_char (&i->input, settings_get_decimal_char (FMT_F)))
+    *cp++ = ss_get_byte (&i->input);
+  if (ss_match_byte (&i->input, settings_get_decimal_char (FMT_F)))
     *cp++ = '.';
   while (c_isdigit (ss_first (i->input)))
-    *cp++ = ss_get_char (&i->input);
+    *cp++ = ss_get_byte (&i->input);
   *cp = '\0';
 
   *time += strtod (buf, NULL);
@@ -1192,8 +1191,8 @@ parse_date (struct data_in *i)
           break;
         default:
           assert (count == 1);
-          if (!ss_match_char (&i->input, c_toupper (ch))
-              && !ss_match_char (&i->input, c_tolower (ch)))
+          if (!ss_match_byte (&i->input, c_toupper (ch))
+              && !ss_match_byte (&i->input, c_tolower (ch)))
             error = xasprintf (_("`%c' expected in date field."), ch);
           else
             error = NULL;
index ceb023e99887a75028a7a6cf3c764face86357f0..452b1421d726a7dfa302019502b9cf0369043aa2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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,7 +19,6 @@
 
 #include <stdbool.h>
 #include "data/format.h"
-#include "libpspp/legacy-encoding.h"
 #include "libpspp/str.h"
 
 union value;
index 94a6130adb154bd06b61901414e4209498cbf106..df447a6a12cac594c38937725030767c44d7999e 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, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include "data-out.h"
+#include "data/data-out.h"
 
 #include <ctype.h>
 #include <float.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <time.h>
-
-#include <data/calendar.h>
-#include <data/format.h>
-#include <data/settings.h>
-#include <data/value.h>
-
-#include <libpspp/assertion.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <libpspp/pool.h>
-#include <libpspp/i18n.h>
-
-#include "minmax.h"
+#include <unistr.h>
+
+#include "data/calendar.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/float-format.h"
+#include "libpspp/i18n.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -92,55 +93,103 @@ static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
 #include "format.def"
     };
 
-/* Similar to data_out. Additionally recodes the output from
-   native form into the given legacy character ENCODING.
-   OUTPUT must be provided by the caller and must be at least
-   FORMAT->w long. No null terminator is appended to OUTPUT.
-*/
+/* Converts the INPUT value, encoded in INPUT_ENCODING, according to format
+   specification FORMAT, appending the output to OUTPUT in OUTPUT_ENCODING.
+   However, binary formats (FMT_P, FMT_PK, FMT_IB, FMT_PIB, FMT_RB) yield the
+   binary results, which may not be properly encoded for OUTPUT_ENCODING.
+
+   VALUE must be the correct width for FORMAT, that is, its width must be
+   fmt_var_width(FORMAT).
+
+   INPUT_ENCODING can normally be obtained by calling dict_get_encoding() on
+   the dictionary with which INPUT is associated.  ENCODING is only important
+   when FORMAT's type is FMT_A. */
 void
-data_out_legacy (const union value *input, const char *encoding,
-                 const struct fmt_spec *format, char *output)
+data_out_recode (const union value *input, const char *input_encoding,
+                 const struct fmt_spec *format,
+                 struct string *output, const char *output_encoding)
 {
   assert (fmt_check_output (format));
+  if (format->type == FMT_A)
+    {
+      char *in = CHAR_CAST (char *, value_str (input, format->w));
+      char *out = recode_string (output_encoding, input_encoding,
+                                 in, format->w);
+      ds_put_cstr (output, out);
+      free (out);
+    }
+  else if (fmt_get_category (format->type) == FMT_CAT_BINARY)
+    converters[format->type] (input, format,
+                              ds_put_uninit (output, format->w));
+  else
+    {
+      char *utf8_encoded = data_out (input, input_encoding, format);
+      char *output_encoded = recode_string (output_encoding, UTF8,
+                                            utf8_encoded, -1);
+      ds_put_cstr (output, output_encoded);
+      free (output_encoded);
+      free (utf8_encoded);
+    }
+}
+
+static char *
+binary_to_utf8 (const char *in, struct pool *pool)
+{
+  uint8_t *out = pool_alloc_unaligned (pool, strlen (in) * 2 + 1);
+  uint8_t *p = out;
 
-  converters[format->type] (input, format, output);
-  if (0 != strcmp (encoding, LEGACY_NATIVE)
-      && fmt_get_category (format->type) != FMT_CAT_BINARY)
+  while (*in != '\0')
     {
-      char *s  = recode_string (encoding, LEGACY_NATIVE, output, format->w );
-      memcpy (output, s, format->w);
-      free (s);
+      uint8_t byte = *in++;
+      int mblen = u8_uctomb (p, byte, 2);
+      assert (mblen > 0);
+      p += mblen;
     }
+  *p = '\0';
+
+  return CHAR_CAST (char *, out);
 }
 
-/* Converts the INPUT value into a UTF8 encoded string, according
-   to format specification FORMAT. 
+/* Converts the INPUT value into a UTF-8 encoded string, according to format
+   specification FORMAT.
 
-   VALUE must be the correct width for FORMAT, that is, its
-   width must be fmt_var_width(FORMAT).
+   VALUE must be the correct width for FORMAT, that is, its width must be
+   fmt_var_width(FORMAT).
 
-   ENCODING must be the encoding of INPUT.  Normally this can
-   be obtained by calling dict_get_encoding on the dictionary
-   with which INPUT is associated.
+   ENCODING must be the encoding of INPUT.  Normally this can be obtained by
+   calling dict_get_encoding() on the dictionary with which INPUT is
+   associated.  ENCODING is only important when FORMAT's type is FMT_A.
 
-   The return value is dynamically allocated, and must be freed
-   by the caller.  If POOL is non-null, then the return value is
-   allocated on that pool.
-*/
+   The return value is dynamically allocated, and must be freed by the caller.
+   If POOL is non-null, then the return value is allocated on that pool.  */
 char *
 data_out_pool (const union value *input, const char *encoding,
               const struct fmt_spec *format, struct pool *pool)
 {
-  char *output = xmalloc (format->w + 1);
-  char *t ;
   assert (fmt_check_output (format));
+  if (format->type == FMT_A)
+    {
+      char *in = CHAR_CAST (char *, value_str (input, format->w));
+      return recode_string_pool (UTF8, encoding, in, format->w, pool);
+    }
+  else if (fmt_get_category (format->type) == FMT_CAT_BINARY)
+    {
+      char tmp[16];
 
-  converters[format->type] (input, format, output);
-  output[format->w] = '\0';
+      assert (format->w + 1 <= sizeof tmp);
+      converters[format->type] (input, format, tmp);
+      return binary_to_utf8 (tmp, pool);
+    }
+  else
+    {
+      const struct fmt_number_style *style = settings_get_style (format->type);
+      size_t size = format->w + style->extra_bytes + 1;
+      char *output;
 
-  t =  recode_string_pool (UTF8, encoding, output, format->w, pool);
-  free (output);
-  return t;
+      output = pool_alloc_unaligned (pool, size);
+      converters[format->type] (input, format, output);
+      return output;
+    }
 }
 
 char *
@@ -200,6 +249,8 @@ output_N (const union value *input, const struct fmt_spec *format,
       else
         output_overflow (format, output);
     }
+
+  output[format->w] = '\0';
 }
 
 /* Outputs Z format. */
@@ -211,11 +262,9 @@ output_Z (const union value *input, const struct fmt_spec *format,
   char buf[128];
   if (input->f == SYSMIS)
     output_missing (format, output);
-  else if (fabs (number) >= power10 (format->w)
-           || sprintf (buf, "%0*.0f", format->w,
-                       fabs (round (number))) != format->w)
-    output_overflow (format, output);
-  else
+  else if (fabs (number) < power10 (format->w)
+           && sprintf (buf, "%0*.0f", format->w,
+                       fabs (round (number))) == format->w)
     {
       if (number < 0 && strspn (buf, "0") < format->w)
         {
@@ -223,7 +272,10 @@ output_Z (const union value *input, const struct fmt_spec *format,
           *p = "}JKLMNOPQR"[*p - '0'];
         }
       memcpy (output, buf, format->w);
+      output[format->w] = '\0';
     }
+  else
+    output_overflow (format, output);
 }
 
 /* Outputs P format. */
@@ -266,6 +318,8 @@ output_IB (const union value *input, const struct fmt_spec *format,
                             settings_get_output_integer_format (),
                              output);
     }
+
+  output[format->w] = '\0';
 }
 
 /* Outputs PIB format. */
@@ -280,6 +334,8 @@ output_PIB (const union value *input, const struct fmt_spec *format,
   else
     output_binary_integer (number, format->w,
                           settings_get_output_integer_format (), output);
+
+  output[format->w] = '\0';
 }
 
 /* Outputs PIBHEX format. */
@@ -298,6 +354,7 @@ output_PIBHEX (const union value *input, const struct fmt_spec *format,
       output_binary_integer (number, format->w / 2, INTEGER_MSB_FIRST, tmp);
       output_hex (tmp, format->w / 2, output);
     }
+
 }
 
 /* Outputs RB format. */
@@ -307,6 +364,8 @@ output_RB (const union value *input, const struct fmt_spec *format,
 {
   double d = input->f;
   memcpy (output, &d, format->w);
+
+  output[format->w] = '\0';
 }
 
 /* Outputs RBHEX format. */
@@ -315,6 +374,7 @@ output_RBHEX (const union value *input, const struct fmt_spec *format,
               char *output)
 {
   double d = input->f;
+
   output_hex (&d, format->w / 2, output);
 }
 
@@ -451,6 +511,7 @@ output_date (const union value *input, const struct fmt_spec *format,
     }
 
   buf_copy_lpad (output, format->w, tmp, p - tmp, ' ');
+  output[format->w] = '\0';
   return;
 
  overflow:
@@ -474,13 +535,18 @@ output_WKDAY (const union value *input, const struct fmt_spec *format,
     };
 
   if (input->f >= 1 && input->f < 8)
-    buf_copy_str_rpad (output, format->w, weekdays[(int) input->f - 1], ' ');
+    {
+      buf_copy_str_rpad (output, format->w,
+                         weekdays[(int) input->f - 1], ' ');
+      output[format->w] = '\0';
+    }
   else
     {
       if (input->f != SYSMIS)
         msg (ME, _("Weekday number %f is not between 1 and 7."), input->f);
       output_missing (format, output);
     }
+
 }
 
 /* Outputs MONTH format. */
@@ -495,21 +561,25 @@ output_MONTH (const union value *input, const struct fmt_spec *format,
     };
 
   if (input->f >= 1 && input->f < 13)
-    buf_copy_str_rpad (output, format->w, months[(int) input->f - 1], ' ');
+    {
+      buf_copy_str_rpad (output, format->w, months[(int) input->f - 1], ' ');
+      output[format->w] = '\0';
+    }
   else
     {
       if (input->f != SYSMIS)
         msg (ME, _("Month number %f is not between 1 and 12."), input->f);
       output_missing (format, output);
     }
+
 }
 
 /* Outputs A format. */
 static void
-output_A (const union value *input, const struct fmt_spec *format,
-          char *output)
+output_A (const union value *input UNUSED,
+          const struct fmt_spec *format UNUSED, char *output UNUSED)
 {
-  memcpy (output, value_str (input, format->w), format->w);
+  NOT_REACHED ();
 }
 
 /* Outputs AHEX format. */
@@ -579,9 +649,9 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format,
          the negative suffix, plus (if negative) the negative
          prefix. */
       width = rounder_width (r, decimals, &integer_digits, &add_neg_prefix);
-      width += ss_length (style->neg_suffix);
+      width += style->neg_suffix.width;
       if (add_neg_prefix)
-        width += ss_length (style->neg_prefix);
+        width += style->neg_prefix.width;
       if (width > format->w)
         continue;
 
@@ -611,10 +681,9 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format,
       if (format->w > width)
         p = mempset (p, ' ', format->w - width);
       if (add_neg_prefix)
-        p = mempcpy (p, ss_data (style->neg_prefix),
-                     ss_length (style->neg_prefix));
+        p = stpcpy (p, style->neg_prefix.s);
       if (add_affixes)
-        p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix));
+        p = stpcpy (p, style->prefix.s);
       if (!add_grouping)
         p = mempcpy (p, magnitude, integer_digits);
       else
@@ -633,13 +702,15 @@ output_decimal (const struct rounder *r, const struct fmt_spec *format,
           p = mempcpy (p, &magnitude[integer_digits + 1], decimals);
         }
       if (add_affixes)
-        p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix));
+        p = stpcpy (p, style->suffix.s);
       if (add_neg_prefix)
-        p = mempcpy (p, ss_data (style->neg_suffix),
-                     ss_length (style->neg_suffix));
+        p = stpcpy (p, style->neg_suffix.s);
       else
-        p = mempset (p, ' ', ss_length (style->neg_suffix));
-      assert (p == output + format->w);
+        p = mempset (p, ' ', style->neg_suffix.width);
+
+      assert (p >= output + format->w);
+      assert (p <= output + format->w + style->extra_bytes);
+      *p = '\0';
 
       return true;
     }
@@ -657,12 +728,12 @@ output_scientific (double number, const struct fmt_spec *format,
   int width;
   int fraction_width;
   bool add_affixes;
-  char buf[64], *p;
+  char *p;
 
   /* Allocate minimum required space. */
-  width = 6 + ss_length (style->neg_suffix);
+  width = 6 + style->neg_suffix.width;
   if (number < 0)
-    width += ss_length (style->neg_prefix);
+    width += style->neg_prefix.width;
   if (width > format->w)
     return false;
 
@@ -681,14 +752,13 @@ output_scientific (double number, const struct fmt_spec *format,
   width += fraction_width;
 
   /* Format (except suffix). */
-  p = buf;
+  p = output;
   if (width < format->w)
     p = mempset (p, ' ', format->w - width);
   if (number < 0)
-    p = mempcpy (p, ss_data (style->neg_prefix),
-                 ss_length (style->neg_prefix));
+    p = stpcpy (p, style->neg_prefix.s);
   if (add_affixes)
-    p = mempcpy (p, ss_data (style->prefix), ss_length (style->prefix));
+    p = stpcpy (p, style->prefix.s);
   if (fraction_width > 0)
     sprintf (p, "%#.*E", fraction_width - 1, fabs (number));
   else
@@ -715,15 +785,15 @@ output_scientific (double number, const struct fmt_spec *format,
   /* Add suffixes. */
   p = strchr (p, '\0');
   if (add_affixes)
-    p = mempcpy (p, ss_data (style->suffix), ss_length (style->suffix));
+    p = stpcpy (p, style->suffix.s);
   if (number < 0)
-    p = mempcpy (p, ss_data (style->neg_suffix),
-                 ss_length (style->neg_suffix));
+    p = stpcpy (p, style->neg_suffix.s);
   else
-    p = mempset (p, ' ', ss_length (style->neg_suffix));
+    p = mempset (p, ' ', style->neg_suffix.width);
 
-  assert (p == buf + format->w);
-  memcpy (output, buf, format->w);
+  assert (p >= output + format->w);
+  assert (p <= output + format->w + style->extra_bytes);
+  *p = '\0';
 
   return true;
 }
@@ -973,6 +1043,8 @@ output_infinite (double number, const struct fmt_spec *format, char *output)
     }
   else
     output_overflow (format, output);
+
+  output[format->w] = '\0';
 }
 
 /* Formats OUTPUT as a missing value for the given FORMAT. */
@@ -990,6 +1062,8 @@ output_missing (const struct fmt_spec *format, char *output)
     }
   else
     output[format->w - 1] = '.';
+
+  output[format->w] = '\0';
 }
 
 /* Formats OUTPUT for overflow given FORMAT. */
@@ -997,6 +1071,7 @@ static void
 output_overflow (const struct fmt_spec *format, char *output)
 {
   memset (output, '*', format->w);
+  output[format->w] = '\0';
 }
 
 /* Converts the integer part of NUMBER to a packed BCD number
@@ -1011,6 +1086,8 @@ output_bcd_integer (double number, int digits, char *output)
   char decimal[64];
 
   assert (digits < sizeof decimal);
+
+  output[DIV_RND_UP (digits, 2)] = '\0';
   if (number != SYSMIS
       && number >= 0.
       && number < power10 (digits)
@@ -1060,4 +1137,5 @@ output_hex (const void *data_, size_t bytes, char *output)
       *output++ = hex_digits[data[i] >> 4];
       *output++ = hex_digits[data[i] & 15];
     }
+  *output = '\0';
 }
index 735679b41257b78d0918ae4c83e29c90eeb62546..7dff441289c76e6b155719d230f1e776762499e0 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, 2011 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 DATA_OUT_H 1
 
 #include <stdbool.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/legacy-encoding.h>
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
 
 struct fmt_spec;
+struct string;
 union value;
 
 char * data_out (const union value *, const char *encoding, const struct fmt_spec *);
 
 char * data_out_pool (const union value *, const char *encoding, const struct fmt_spec *, struct pool *pool);
 
-void data_out_legacy (const union value *input, const char *encoding,
-                     const struct fmt_spec *format, char *output);
+void data_out_recode (const union value *input, const char *input_encoding,
+                      const struct fmt_spec *,
+                      struct string *output, const char *output_encoding);
 
 #endif /* data-out.h */
diff --git a/src/data/dataset-reader.c b/src/data/dataset-reader.c
new file mode 100644 (file)
index 0000000..b679342
--- /dev/null
@@ -0,0 +1,62 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2006, 2010, 2011 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/dataset-reader.h"
+
+#include <stdlib.h>
+
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Opens FH, which must have referent type FH_REF_DATASET, and returns a
+   dataset_reader for it, or a null pointer on failure.  Stores a copy of the
+   dictionary for the dataset file into *DICT.  The caller takes ownership of
+   the casereader and the dictionary.  */
+struct casereader *
+dataset_reader_open (struct file_handle *fh, struct dictionary **dict)
+{
+  struct dataset *ds;
+
+  /* We don't bother doing fh_lock or fh_ref on the file handle,
+     as there's no advantage in this case, and doing these would
+     require us to keep track of the "struct file_handle" and
+     "struct fh_lock" and undo our work later. */
+  assert (fh_get_referent (fh) == FH_REF_DATASET);
+
+  ds = fh_get_dataset (fh);
+  if (ds == NULL || !dataset_has_source (ds))
+    {
+      msg (SE, _("Cannot read from dataset %s because no dictionary or data "
+                 "has been written to it yet."),
+           fh_get_name (fh));
+      return NULL;
+    }
+
+  *dict = dict_clone (dataset_dict (ds));
+  return casereader_clone (dataset_source (ds));
+}
diff --git a/src/data/dataset-reader.h b/src/data/dataset-reader.h
new file mode 100644 (file)
index 0000000..420b6b1
--- /dev/null
@@ -0,0 +1,27 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   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 DATASET_READER_H
+#define DATASET_READER_H 1
+
+#include <stdbool.h>
+
+struct dictionary;
+struct file_handle;
+struct casereader *dataset_reader_open (struct file_handle *,
+                                        struct dictionary **);
+
+#endif /* dataset-reader.h */
diff --git a/src/data/dataset-writer.c b/src/data/dataset-writer.c
new file mode 100644 (file)
index 0000000..c810cf2
--- /dev/null
@@ -0,0 +1,130 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2006, 2009-2011 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/dataset-writer.h"
+
+#include <stdlib.h>
+
+#include "data/case.h"
+#include "data/case-map.h"
+#include "data/casereader.h"
+#include "data/casewriter-provider.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/taint.h"
+
+#include "gl/xalloc.h"
+
+#define N_(msgid) (msgid)
+
+/* A dataset file writer. */
+struct dataset_writer
+  {
+    struct dataset *ds;                 /* Underlying dataset. */
+    struct fh_lock *lock;               /* Exclusive access to file handle. */
+    struct dictionary *dict;            /* Dictionary for subwriter. */
+    struct case_map *compactor;         /* Compacts into dictionary. */
+    struct casewriter *subwriter;       /* Data output. */
+  };
+
+static const struct casewriter_class dataset_writer_casewriter_class;
+
+/* Opens FH, which must have referent type FH_REF_DATASET, and
+   returns a dataset_writer for it, or a null pointer on
+   failure.  Cases stored in the dataset_writer will be expected
+   to be drawn from DICTIONARY. */
+struct casewriter *
+dataset_writer_open (struct file_handle *fh,
+                     const struct dictionary *dictionary)
+{
+  struct dataset_writer *writer;
+  struct casewriter *casewriter;
+  struct fh_lock *lock;
+
+  /* Get exclusive write access to handle. */
+  /* TRANSLATORS: this fragment will be interpolated into
+     messages in fh_lock() that identify types of files. */
+  lock = fh_lock (fh, FH_REF_DATASET, N_("dataset"), FH_ACC_WRITE, true);
+  if (lock == NULL)
+    return NULL;
+
+  /* Create writer. */
+  writer = xmalloc (sizeof *writer);
+  writer->lock = lock;
+  writer->ds = fh_get_dataset (fh);
+
+  writer->dict = dict_clone (dictionary);
+  dict_delete_scratch_vars (writer->dict);
+  if (dict_count_values (writer->dict, 0)
+      < dict_get_next_value_idx (writer->dict))
+    {
+      writer->compactor = case_map_to_compact_dict (writer->dict, 0);
+      dict_compact_values (writer->dict);
+    }
+  else
+    writer->compactor = NULL;
+  writer->subwriter = autopaging_writer_create (dict_get_proto (writer->dict));
+
+  casewriter = casewriter_create (dict_get_proto (writer->dict),
+                                  &dataset_writer_casewriter_class, writer);
+  taint_propagate (casewriter_get_taint (writer->subwriter),
+                   casewriter_get_taint (casewriter));
+  return casewriter;
+}
+
+/* Writes case C to WRITER. */
+static void
+dataset_writer_casewriter_write (struct casewriter *w UNUSED, void *writer_,
+                                 struct ccase *c)
+{
+  struct dataset_writer *writer = writer_;
+  casewriter_write (writer->subwriter,
+                    case_map_execute (writer->compactor, c));
+}
+
+/* Closes WRITER. */
+static void
+dataset_writer_casewriter_destroy (struct casewriter *w UNUSED, void *writer_)
+{
+  struct dataset_writer *writer = writer_;
+  struct casereader *reader = casewriter_make_reader (writer->subwriter);
+  if (!casereader_error (reader))
+    {
+      dataset_set_dict (writer->ds, writer->dict);
+      dataset_set_source (writer->ds, reader);
+    }
+  else
+    {
+      casereader_destroy (reader);
+      dict_destroy (writer->dict);
+    }
+
+  fh_unlock (writer->lock);
+  free (writer);
+}
+
+static const struct casewriter_class dataset_writer_casewriter_class =
+  {
+    dataset_writer_casewriter_write,
+    dataset_writer_casewriter_destroy,
+    NULL,
+  };
diff --git a/src/data/dataset-writer.h b/src/data/dataset-writer.h
new file mode 100644 (file)
index 0000000..429d688
--- /dev/null
@@ -0,0 +1,27 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   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 DATASET_WRITER_H
+#define DATASET_WRITER_H 1
+
+#include <stdbool.h>
+
+struct dictionary;
+struct file_handle;
+struct casewriter *dataset_writer_open (struct file_handle *,
+                                        const struct dictionary *);
+
+#endif /* dataset-writer.h */
diff --git a/src/data/dataset.c b/src/data/dataset.c
new file mode 100644 (file)
index 0000000..26c3a49
--- /dev/null
@@ -0,0 +1,939 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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/dataset.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "data/case.h"
+#include "data/case-map.h"
+#include "data/caseinit.h"
+#include "data/casereader.h"
+#include "data/casereader-provider.h"
+#include "data/casereader-shim.h"
+#include "data/casewriter.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/session.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "libpspp/deque.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "libpspp/taint.h"
+#include "libpspp/i18n.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+struct dataset {
+  /* A dataset is usually part of a session.  Within a session its name must
+     unique.  The name must either be a valid PSPP identifier or the empty
+     string.  (It must be unique within the session even if it is the empty
+     string; that is, there may only be a single dataset within a session with
+     the empty string as its name.) */
+  struct session *session;
+  char *name;
+  enum dataset_display display;
+
+  /* Cases are read from source,
+     their transformation variables are initialized,
+     pass through permanent_trns_chain (which transforms them into
+     the format described by permanent_dict),
+     are written to sink,
+     pass through temporary_trns_chain (which transforms them into
+     the format described by dict),
+     and are finally passed to the procedure. */
+  struct casereader *source;
+  struct caseinit *caseinit;
+  struct trns_chain *permanent_trns_chain;
+  struct dictionary *permanent_dict;
+  struct casewriter *sink;
+  struct trns_chain *temporary_trns_chain;
+  struct dictionary *dict;
+
+  /* If true, cases are discarded instead of being written to
+     sink. */
+  bool discard_output;
+
+  /* The transformation chain that the next transformation will be
+     added to. */
+  struct trns_chain *cur_trns_chain;
+
+  /* The case map used to compact a case, if necessary;
+     otherwise a null pointer. */
+  struct case_map *compactor;
+
+  /* Time at which proc was last invoked. */
+  time_t last_proc_invocation;
+
+  /* Cases just before ("lagging") the current one. */
+  int n_lag;                   /* Number of cases to lag. */
+  struct deque lag;             /* Deque of lagged cases. */
+  struct ccase **lag_cases;     /* Lagged cases managed by deque. */
+
+  /* Procedure data. */
+  enum
+    {
+      PROC_COMMITTED,           /* No procedure in progress. */
+      PROC_OPEN,                /* proc_open called, casereader still open. */
+      PROC_CLOSED               /* casereader from proc_open destroyed,
+                                   but proc_commit not yet called. */
+    }
+  proc_state;
+  casenumber cases_written;     /* Cases output so far. */
+  bool ok;                      /* Error status. */
+  struct casereader_shim *shim; /* Shim on proc_open() casereader. */
+
+  const struct dataset_callbacks *callbacks;
+  void *cb_data;
+
+  /* Uniquely distinguishes datasets. */
+  unsigned int seqno;
+};
+
+static void dataset_changed__ (struct dataset *);
+static void dataset_transformations_changed__ (struct dataset *,
+                                               bool non_empty);
+
+static void add_case_limit_trns (struct dataset *ds);
+static void add_filter_trns (struct dataset *ds);
+
+static void update_last_proc_invocation (struct dataset *ds);
+
+static void
+dict_callback (struct dictionary *d UNUSED, void *ds_)
+{
+  struct dataset *ds = ds_;
+  dataset_changed__ (ds);
+}
+\f
+static void
+dataset_create_finish__ (struct dataset *ds, struct session *session)
+{
+  static unsigned int seqno;
+
+  dict_set_change_callback (ds->dict, dict_callback, ds);
+  proc_cancel_all_transformations (ds);
+  dataset_set_session (ds, session);
+  ds->seqno = ++seqno;
+}
+
+/* Creates a new dataset named NAME, adds it to SESSION, and returns it.  If
+   SESSION already contains a dataset named NAME, it is deleted and replaced.
+   The dataset initially has an empty dictionary and no data source. */
+struct dataset *
+dataset_create (struct session *session, const char *name)
+{
+  struct dataset *ds;
+
+  ds = xzalloc (sizeof *ds);
+  ds->name = xstrdup (name);
+  ds->display = DATASET_FRONT;
+  ds->dict = dict_create (get_default_encoding ());
+
+  ds->caseinit = caseinit_create ();
+
+  dataset_create_finish__ (ds, session);
+
+  return ds;
+}
+
+/* Creates and returns a new dataset that has the same data and dictionary as
+   OLD named NAME, adds it to the same session as OLD, and returns the new
+   dataset.  If SESSION already contains a dataset named NAME, it is deleted
+   and replaced.
+
+   OLD must not have any active transformations or temporary state and must
+   not be in the middle of a procedure.
+
+   Callbacks are not cloned. */
+struct dataset *
+dataset_clone (struct dataset *old, const char *name)
+{
+  struct dataset *new;
+
+  assert (old->proc_state == PROC_COMMITTED);
+  assert (trns_chain_is_empty (old->permanent_trns_chain));
+  assert (old->permanent_dict == NULL);
+  assert (old->sink == NULL);
+  assert (old->temporary_trns_chain == NULL);
+
+  new = xzalloc (sizeof *new);
+  new->name = xstrdup (name);
+  new->display = DATASET_FRONT;
+  new->source = casereader_clone (old->source);
+  new->dict = dict_clone (old->dict);
+  new->caseinit = caseinit_clone (old->caseinit);
+  new->last_proc_invocation = old->last_proc_invocation;
+  new->ok = old->ok;
+
+  dataset_create_finish__ (new, old->session);
+
+  return new;
+}
+
+/* Destroys DS. */
+void
+dataset_destroy (struct dataset *ds)
+{
+  if (ds != NULL)
+    {
+      dataset_set_session (ds, NULL);
+      dataset_clear (ds);
+      dict_destroy (ds->dict);
+      caseinit_destroy (ds->caseinit);
+      trns_chain_destroy (ds->permanent_trns_chain);
+      dataset_transformations_changed__ (ds, false);
+      free (ds->name);
+      free (ds);
+    }
+}
+
+/* Discards the active dataset's dictionary, data, and transformations. */
+void
+dataset_clear (struct dataset *ds)
+{
+  assert (ds->proc_state == PROC_COMMITTED);
+
+  dict_clear (ds->dict);
+  fh_set_default_handle (NULL);
+
+  ds->n_lag = 0;
+
+  casereader_destroy (ds->source);
+  ds->source = NULL;
+
+  proc_cancel_all_transformations (ds);
+}
+
+const char *
+dataset_name (const struct dataset *ds)
+{
+  return ds->name;
+}
+
+void
+dataset_set_name (struct dataset *ds, const char *name)
+{
+  struct session *session = ds->session;
+  bool active = false;
+
+  if (session != NULL)
+    {
+      active = session_active_dataset (session) == ds;
+      if (active)
+        session_set_active_dataset (session, NULL);
+      dataset_set_session (ds, NULL);
+    }
+
+  free (ds->name);
+  ds->name = xstrdup (name);
+
+  if (session != NULL)
+    {
+      dataset_set_session (ds, session);
+      if (active)
+        session_set_active_dataset (session, ds);
+    }
+}
+
+struct session *
+dataset_session (const struct dataset *ds)
+{
+  return ds->session;
+}
+
+void
+dataset_set_session (struct dataset *ds, struct session *session)
+{
+  if (session != ds->session)
+    {
+      if (ds->session != NULL)
+        session_remove_dataset (ds->session, ds);
+      if (session != NULL)
+        session_add_dataset (session, ds);
+    }
+}
+
+/* Returns the dictionary within DS.  This is always nonnull, although it
+   might not contain any variables. */
+struct dictionary *
+dataset_dict (const struct dataset *ds)
+{
+  return ds->dict;
+}
+
+/* Replaces DS's dictionary by DICT, discarding any source and
+   transformations. */
+void
+dataset_set_dict (struct dataset *ds, struct dictionary *dict)
+{
+  assert (ds->proc_state == PROC_COMMITTED);
+  assert (ds->dict != dict);
+
+  dataset_clear (ds);
+
+  dict_destroy (ds->dict);
+  ds->dict = dict;
+  dict_set_change_callback (ds->dict, dict_callback, ds);
+}
+
+/* Returns the casereader that will be read when a procedure is executed on
+   DS.  This can be NULL if none has been set up yet. */
+const struct casereader *
+dataset_source (const struct dataset *ds)
+{
+  return ds->source;
+}
+
+/* Returns true if DS has a data source, false otherwise. */
+bool
+dataset_has_source (const struct dataset *ds)
+{
+  return dataset_source (ds) != NULL;
+}
+
+/* Replaces the active dataset's data by READER.  READER's cases must have an
+   appropriate format for DS's dictionary. */
+bool
+dataset_set_source (struct dataset *ds, struct casereader *reader)
+{
+  casereader_destroy (ds->source);
+  ds->source = reader;
+
+  caseinit_clear (ds->caseinit);
+  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
+
+  return reader == NULL || !casereader_error (reader);
+}
+
+/* Returns the data source from DS and removes it from DS.  Returns a null
+   pointer if DS has no data source. */
+struct casereader *
+dataset_steal_source (struct dataset *ds)
+{
+  struct casereader *reader = ds->source;
+  ds->source = NULL;
+
+  return reader;
+}
+
+/* Returns a number unique to DS.  It can be used to distinguish one dataset
+   from any other within a given program run, even datasets that do not exist
+   at the same time. */
+unsigned int
+dataset_seqno (const struct dataset *ds)
+{
+  return ds->seqno;
+}
+
+void
+dataset_set_callbacks (struct dataset *ds,
+                       const struct dataset_callbacks *callbacks,
+                       void *cb_data)
+{
+  ds->callbacks = callbacks;
+  ds->cb_data = cb_data;
+}
+
+enum dataset_display
+dataset_get_display (const struct dataset *ds)
+{
+  return ds->display;
+}
+
+void
+dataset_set_display (struct dataset *ds, enum dataset_display display)
+{
+  ds->display = display;
+}
+\f
+/* Returns the last time the data was read. */
+time_t
+time_of_last_procedure (struct dataset *ds)
+{
+  if (ds->last_proc_invocation == 0)
+    update_last_proc_invocation (ds);
+  return ds->last_proc_invocation;
+}
+\f
+/* Regular procedure. */
+
+/* Executes any pending transformations, if necessary.
+   This is not identical to the EXECUTE command in that it won't
+   always read the source data.  This can be important when the
+   source data is given inline within BEGIN DATA...END FILE. */
+bool
+proc_execute (struct dataset *ds)
+{
+  bool ok;
+
+  if ((ds->temporary_trns_chain == NULL
+       || trns_chain_is_empty (ds->temporary_trns_chain))
+      && trns_chain_is_empty (ds->permanent_trns_chain))
+    {
+      ds->n_lag = 0;
+      ds->discard_output = false;
+      dict_set_case_limit (ds->dict, 0);
+      dict_clear_vectors (ds->dict);
+      return true;
+    }
+
+  ok = casereader_destroy (proc_open (ds));
+  return proc_commit (ds) && ok;
+}
+
+static const struct casereader_class proc_casereader_class;
+
+/* Opens dataset DS for reading cases with proc_read.  If FILTER is true, then
+   cases filtered out with FILTER BY will not be included in the casereader
+   (which is usually desirable).  If FILTER is false, all cases will be
+   included regardless of FILTER BY settings.
+
+   proc_commit must be called when done. */
+struct casereader *
+proc_open_filtering (struct dataset *ds, bool filter)
+{
+  struct casereader *reader;
+
+  assert (ds->source != NULL);
+  assert (ds->proc_state == PROC_COMMITTED);
+
+  update_last_proc_invocation (ds);
+
+  caseinit_mark_for_init (ds->caseinit, ds->dict);
+
+  /* Finish up the collection of transformations. */
+  add_case_limit_trns (ds);
+  if (filter)
+    add_filter_trns (ds);
+  trns_chain_finalize (ds->cur_trns_chain);
+
+  /* Make permanent_dict refer to the dictionary right before
+     data reaches the sink. */
+  if (ds->permanent_dict == NULL)
+    ds->permanent_dict = ds->dict;
+
+  /* Prepare sink. */
+  if (!ds->discard_output)
+    {
+      struct dictionary *pd = ds->permanent_dict;
+      size_t compacted_value_cnt = dict_count_values (pd, 1u << DC_SCRATCH);
+      if (compacted_value_cnt < dict_get_next_value_idx (pd))
+        {
+          struct caseproto *compacted_proto;
+          compacted_proto = dict_get_compacted_proto (pd, 1u << DC_SCRATCH);
+          ds->compactor = case_map_to_compact_dict (pd, 1u << DC_SCRATCH);
+          ds->sink = autopaging_writer_create (compacted_proto);
+          caseproto_unref (compacted_proto);
+        }
+      else
+        {
+          ds->compactor = NULL;
+          ds->sink = autopaging_writer_create (dict_get_proto (pd));
+        }
+    }
+  else
+    {
+      ds->compactor = NULL;
+      ds->sink = NULL;
+    }
+
+  /* Allocate memory for lagged cases. */
+  ds->lag_cases = deque_init (&ds->lag, ds->n_lag, sizeof *ds->lag_cases);
+
+  ds->proc_state = PROC_OPEN;
+  ds->cases_written = 0;
+  ds->ok = true;
+
+  /* FIXME: use taint in dataset in place of `ok'? */
+  /* FIXME: for trivial cases we can just return a clone of
+     ds->source? */
+
+  /* Create casereader and insert a shim on top.  The shim allows us to
+     arbitrarily extend the casereader's lifetime, by slurping the cases into
+     the shim's buffer in proc_commit().  That is especially useful when output
+     table_items are generated directly from the procedure casereader (e.g. by
+     the LIST procedure) when we are using an output driver that keeps a
+     reference to the output items passed to it (e.g. the GUI output driver in
+     PSPPIRE). */
+  reader = casereader_create_sequential (NULL, dict_get_proto (ds->dict),
+                                         CASENUMBER_MAX,
+                                         &proc_casereader_class, ds);
+  ds->shim = casereader_shim_insert (reader);
+  return reader;
+}
+
+/* Opens dataset DS for reading cases with proc_read.
+   proc_commit must be called when done. */
+struct casereader *
+proc_open (struct dataset *ds)
+{
+  return proc_open_filtering (ds, true);
+}
+
+/* Returns true if a procedure is in progress, that is, if
+   proc_open has been called but proc_commit has not. */
+bool
+proc_is_open (const struct dataset *ds)
+{
+  return ds->proc_state != PROC_COMMITTED;
+}
+
+/* "read" function for procedure casereader. */
+static struct ccase *
+proc_casereader_read (struct casereader *reader UNUSED, void *ds_)
+{
+  struct dataset *ds = ds_;
+  enum trns_result retval = TRNS_DROP_CASE;
+  struct ccase *c;
+
+  assert (ds->proc_state == PROC_OPEN);
+  for (; ; case_unref (c))
+    {
+      casenumber case_nr;
+
+      assert (retval == TRNS_DROP_CASE || retval == TRNS_ERROR);
+      if (retval == TRNS_ERROR)
+        ds->ok = false;
+      if (!ds->ok)
+        return NULL;
+
+      /* Read a case from source. */
+      c = casereader_read (ds->source);
+      if (c == NULL)
+        return NULL;
+      c = case_unshare_and_resize (c, dict_get_proto (ds->dict));
+      caseinit_init_vars (ds->caseinit, c);
+
+      /* Execute permanent transformations.  */
+      case_nr = ds->cases_written + 1;
+      retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE,
+                                   &c, case_nr);
+      caseinit_update_left_vars (ds->caseinit, c);
+      if (retval != TRNS_CONTINUE)
+        continue;
+
+      /* Write case to collection of lagged cases. */
+      if (ds->n_lag > 0)
+        {
+          while (deque_count (&ds->lag) >= ds->n_lag)
+            case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
+          ds->lag_cases[deque_push_front (&ds->lag)] = case_ref (c);
+        }
+
+      /* Write case to replacement dataset. */
+      ds->cases_written++;
+      if (ds->sink != NULL)
+        casewriter_write (ds->sink,
+                          case_map_execute (ds->compactor, case_ref (c)));
+
+      /* Execute temporary transformations. */
+      if (ds->temporary_trns_chain != NULL)
+        {
+          retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE,
+                                       &c, ds->cases_written);
+          if (retval != TRNS_CONTINUE)
+            continue;
+        }
+
+      return c;
+    }
+}
+
+/* "destroy" function for procedure casereader. */
+static void
+proc_casereader_destroy (struct casereader *reader, void *ds_)
+{
+  struct dataset *ds = ds_;
+  struct ccase *c;
+
+  /* We are always the subreader for a casereader_buffer, so if we're being
+     destroyed then it's because the casereader_buffer has read all the cases
+     that it ever will. */
+  ds->shim = NULL;
+
+  /* Make sure transformations happen for every input case, in
+     case they have side effects, and ensure that the replacement
+     active dataset gets all the cases it should. */
+  while ((c = casereader_read (reader)) != NULL)
+    case_unref (c);
+
+  ds->proc_state = PROC_CLOSED;
+  ds->ok = casereader_destroy (ds->source) && ds->ok;
+  ds->source = NULL;
+  dataset_set_source (ds, NULL);
+}
+
+/* Must return false if the source casereader, a transformation,
+   or the sink casewriter signaled an error.  (If a temporary
+   transformation signals an error, then the return value is
+   false, but the replacement active dataset may still be
+   untainted.) */
+bool
+proc_commit (struct dataset *ds)
+{
+  if (ds->shim != NULL)
+    casereader_shim_slurp (ds->shim);
+
+  assert (ds->proc_state == PROC_CLOSED);
+  ds->proc_state = PROC_COMMITTED;
+
+  dataset_changed__ (ds);
+
+  /* Free memory for lagged cases. */
+  while (!deque_is_empty (&ds->lag))
+    case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
+  free (ds->lag_cases);
+
+  /* Dictionary from before TEMPORARY becomes permanent. */
+  proc_cancel_temporary_transformations (ds);
+
+  if (!ds->discard_output)
+    {
+      /* Finish compacting. */
+      if (ds->compactor != NULL)
+        {
+          case_map_destroy (ds->compactor);
+          ds->compactor = NULL;
+
+          dict_delete_scratch_vars (ds->dict);
+          dict_compact_values (ds->dict);
+        }
+
+      /* Old data sink becomes new data source. */
+      if (ds->sink != NULL)
+        ds->source = casewriter_make_reader (ds->sink);
+    }
+  else
+    {
+      ds->source = NULL;
+      ds->discard_output = false;
+    }
+  ds->sink = NULL;
+
+  caseinit_clear (ds->caseinit);
+  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
+
+  dict_clear_vectors (ds->dict);
+  ds->permanent_dict = NULL;
+  return proc_cancel_all_transformations (ds) && ds->ok;
+}
+
+/* Casereader class for procedure execution. */
+static const struct casereader_class proc_casereader_class =
+  {
+    proc_casereader_read,
+    proc_casereader_destroy,
+    NULL,
+    NULL,
+  };
+
+/* Updates last_proc_invocation. */
+static void
+update_last_proc_invocation (struct dataset *ds)
+{
+  ds->last_proc_invocation = time (NULL);
+}
+\f
+/* Returns a pointer to the lagged case from N_BEFORE cases before the
+   current one, or NULL if there haven't been that many cases yet. */
+const struct ccase *
+lagged_case (const struct dataset *ds, int n_before)
+{
+  assert (n_before >= 1);
+  assert (n_before <= ds->n_lag);
+
+  if (n_before <= deque_count (&ds->lag))
+    return ds->lag_cases[deque_front (&ds->lag, n_before - 1)];
+  else
+    return NULL;
+}
+\f
+/* Returns the current set of permanent transformations,
+   and clears the permanent transformations.
+   For use by INPUT PROGRAM. */
+struct trns_chain *
+proc_capture_transformations (struct dataset *ds)
+{
+  struct trns_chain *chain;
+
+  assert (ds->temporary_trns_chain == NULL);
+  chain = ds->permanent_trns_chain;
+  ds->cur_trns_chain = ds->permanent_trns_chain = trns_chain_create ();
+  dataset_transformations_changed__ (ds, false);
+
+  return chain;
+}
+
+/* Adds a transformation that processes a case with PROC and
+   frees itself with FREE to the current set of transformations.
+   The functions are passed AUX as auxiliary data. */
+void
+add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *free, void *aux)
+{
+  trns_chain_append (ds->cur_trns_chain, NULL, proc, free, aux);
+  dataset_transformations_changed__ (ds, true);
+}
+
+/* Adds a transformation that processes a case with PROC and
+   frees itself with FREE to the current set of transformations.
+   When parsing of the block of transformations is complete,
+   FINALIZE will be called.
+   The functions are passed AUX as auxiliary data. */
+void
+add_transformation_with_finalizer (struct dataset *ds,
+                                  trns_finalize_func *finalize,
+                                   trns_proc_func *proc,
+                                   trns_free_func *free, void *aux)
+{
+  trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux);
+  dataset_transformations_changed__ (ds, true);
+}
+
+/* Returns the index of the next transformation.
+   This value can be returned by a transformation procedure
+   function to indicate a "jump" to that transformation. */
+size_t
+next_transformation (const struct dataset *ds)
+{
+  return trns_chain_next (ds->cur_trns_chain);
+}
+
+/* Returns true if the next call to add_transformation() will add
+   a temporary transformation, false if it will add a permanent
+   transformation. */
+bool
+proc_in_temporary_transformations (const struct dataset *ds)
+{
+  return ds->temporary_trns_chain != NULL;
+}
+
+/* Marks the start of temporary transformations.
+   Further calls to add_transformation() will add temporary
+   transformations. */
+void
+proc_start_temporary_transformations (struct dataset *ds)
+{
+  if (!proc_in_temporary_transformations (ds))
+    {
+      add_case_limit_trns (ds);
+
+      ds->permanent_dict = dict_clone (ds->dict);
+
+      trns_chain_finalize (ds->permanent_trns_chain);
+      ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create ();
+      dataset_transformations_changed__ (ds, true);
+    }
+}
+
+/* Converts all the temporary transformations, if any, to
+   permanent transformations.  Further transformations will be
+   permanent.
+   Returns true if anything changed, false otherwise. */
+bool
+proc_make_temporary_transformations_permanent (struct dataset *ds)
+{
+  if (proc_in_temporary_transformations (ds))
+    {
+      trns_chain_finalize (ds->temporary_trns_chain);
+      trns_chain_splice (ds->permanent_trns_chain, ds->temporary_trns_chain);
+      ds->temporary_trns_chain = NULL;
+
+      dict_destroy (ds->permanent_dict);
+      ds->permanent_dict = NULL;
+
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Cancels all temporary transformations, if any.  Further
+   transformations will be permanent.
+   Returns true if anything changed, false otherwise. */
+bool
+proc_cancel_temporary_transformations (struct dataset *ds)
+{
+  if (proc_in_temporary_transformations (ds))
+    {
+      dict_destroy (ds->dict);
+      ds->dict = ds->permanent_dict;
+      ds->permanent_dict = NULL;
+
+      trns_chain_destroy (ds->temporary_trns_chain);
+      ds->temporary_trns_chain = NULL;
+      dataset_transformations_changed__ (
+        ds, !trns_chain_is_empty (ds->permanent_trns_chain));
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Cancels all transformations, if any.
+   Returns true if successful, false on I/O error. */
+bool
+proc_cancel_all_transformations (struct dataset *ds)
+{
+  bool ok;
+  assert (ds->proc_state == PROC_COMMITTED);
+  ok = trns_chain_destroy (ds->permanent_trns_chain);
+  ok = trns_chain_destroy (ds->temporary_trns_chain) && ok;
+  ds->permanent_trns_chain = ds->cur_trns_chain = trns_chain_create ();
+  ds->temporary_trns_chain = NULL;
+  dataset_transformations_changed__ (ds, false);
+
+  return ok;
+}
+\f
+/* Causes output from the next procedure to be discarded, instead
+   of being preserved for use as input for the next procedure. */
+void
+proc_discard_output (struct dataset *ds)
+{
+  ds->discard_output = true;
+}
+
+
+/* Checks whether DS has a corrupted active dataset.  If so,
+   discards it and returns false.  If not, returns true without
+   doing anything. */
+bool
+dataset_end_of_command (struct dataset *ds)
+{
+  if (ds->source != NULL)
+    {
+      if (casereader_error (ds->source))
+        {
+          dataset_clear (ds);
+          return false;
+        }
+      else
+        {
+          const struct taint *taint = casereader_get_taint (ds->source);
+          taint_reset_successor_taint (CONST_CAST (struct taint *, taint));
+          assert (!taint_has_tainted_successor (taint));
+        }
+    }
+  return true;
+}
+\f
+static trns_proc_func case_limit_trns_proc;
+static trns_free_func case_limit_trns_free;
+
+/* Adds a transformation that limits the number of cases that may
+   pass through, if DS->DICT has a case limit. */
+static void
+add_case_limit_trns (struct dataset *ds)
+{
+  casenumber case_limit = dict_get_case_limit (ds->dict);
+  if (case_limit != 0)
+    {
+      casenumber *cases_remaining = xmalloc (sizeof *cases_remaining);
+      *cases_remaining = case_limit;
+      add_transformation (ds, case_limit_trns_proc, case_limit_trns_free,
+                          cases_remaining);
+      dict_set_case_limit (ds->dict, 0);
+    }
+}
+
+/* Limits the maximum number of cases processed to
+   *CASES_REMAINING. */
+static int
+case_limit_trns_proc (void *cases_remaining_,
+                      struct ccase **c UNUSED, casenumber case_nr UNUSED)
+{
+  size_t *cases_remaining = cases_remaining_;
+  if (*cases_remaining > 0)
+    {
+      (*cases_remaining)--;
+      return TRNS_CONTINUE;
+    }
+  else
+    return TRNS_DROP_CASE;
+}
+
+/* Frees the data associated with a case limit transformation. */
+static bool
+case_limit_trns_free (void *cases_remaining_)
+{
+  size_t *cases_remaining = cases_remaining_;
+  free (cases_remaining);
+  return true;
+}
+\f
+static trns_proc_func filter_trns_proc;
+
+/* Adds a temporary transformation to filter data according to
+   the variable specified on FILTER, if any. */
+static void
+add_filter_trns (struct dataset *ds)
+{
+  struct variable *filter_var = dict_get_filter (ds->dict);
+  if (filter_var != NULL)
+    {
+      proc_start_temporary_transformations (ds);
+      add_transformation (ds, filter_trns_proc, NULL, filter_var);
+    }
+}
+
+/* FILTER transformation. */
+static int
+filter_trns_proc (void *filter_var_,
+                  struct ccase **c UNUSED, casenumber case_nr UNUSED)
+
+{
+  struct variable *filter_var = filter_var_;
+  double f = case_num (*c, filter_var);
+  return (f != 0.0 && !var_is_num_missing (filter_var, f, MV_ANY)
+          ? TRNS_CONTINUE : TRNS_DROP_CASE);
+}
+
+
+void
+dataset_need_lag (struct dataset *ds, int n_before)
+{
+  ds->n_lag = MAX (ds->n_lag, n_before);
+}
+\f
+static void
+dataset_changed__ (struct dataset *ds)
+{
+  if (ds->callbacks != NULL && ds->callbacks->changed != NULL)
+    ds->callbacks->changed (ds->cb_data);
+}
+
+static void
+dataset_transformations_changed__ (struct dataset *ds, bool non_empty)
+{
+  if (ds->callbacks != NULL && ds->callbacks->transformations_changed != NULL)
+    ds->callbacks->transformations_changed (non_empty, ds->cb_data);
+}
+\f
+/* Private interface for use by session code. */
+
+void
+dataset_set_session__ (struct dataset *ds, struct session *session)
+{
+  ds->session = session;
+}
diff --git a/src/data/dataset.h b/src/data/dataset.h
new file mode 100644 (file)
index 0000000..8445094
--- /dev/null
@@ -0,0 +1,118 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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 PROCEDURE_H
+#define PROCEDURE_H 1
+
+#include <time.h>
+#include <stdbool.h>
+
+#include "data/transformations.h"
+
+struct casereader;
+struct dataset;
+struct dictionary;
+struct session;
+\f
+struct dataset *dataset_create (struct session *, const char *);
+struct dataset *dataset_clone (struct dataset *, const char *);
+void dataset_destroy (struct dataset *);
+
+void dataset_clear (struct dataset *);
+
+const char *dataset_name (const struct dataset *);
+void dataset_set_name (struct dataset *, const char *);
+
+struct session *dataset_session (const struct dataset *);
+void dataset_set_session (struct dataset *, struct session *);
+
+struct dictionary *dataset_dict (const struct dataset *);
+void dataset_set_dict (struct dataset *, struct dictionary *);
+
+const struct casereader *dataset_source (const struct dataset *);
+bool dataset_has_source (const struct dataset *ds);
+bool dataset_set_source (struct dataset *, struct casereader *);
+struct casereader *dataset_steal_source (struct dataset *);
+
+unsigned int dataset_seqno (const struct dataset *);
+
+struct dataset_callbacks
+  {
+    /* Called whenever a procedure completes execution or whenever the
+       dictionary within the dataset is modified (though not when it is
+       replaced by a new dictionary). */
+    void (*changed) (void *aux);
+
+    /* Called whenever a transformation is added or removed.  NON_EMPTY is true
+       if after the change there is at least one transformation, false if there
+       are no transformations. */
+    void (*transformations_changed) (bool non_empty, void *aux);
+  };
+
+void dataset_set_callbacks (struct dataset *, const struct dataset_callbacks *,
+                            void *aux);
+
+/* Dataset GUI window display status. */
+enum dataset_display
+  {
+    DATASET_ASIS,               /* Current state unchanged. */
+    DATASET_FRONT,              /* Display and raise to top. */
+    DATASET_MINIMIZED,          /* Display as icon. */
+    DATASET_HIDDEN              /* Do not display. */
+  };
+enum dataset_display dataset_get_display (const struct dataset *);
+void dataset_set_display (struct dataset *, enum dataset_display);
+\f
+/* Transformations. */
+
+void add_transformation (struct dataset *ds,
+                        trns_proc_func *, trns_free_func *, void *);
+void add_transformation_with_finalizer (struct dataset *ds,
+                                       trns_finalize_func *,
+                                        trns_proc_func *,
+                                        trns_free_func *, void *);
+size_t next_transformation (const struct dataset *ds);
+
+bool proc_cancel_all_transformations (struct dataset *ds);
+struct trns_chain *proc_capture_transformations (struct dataset *ds);
+
+void proc_start_temporary_transformations (struct dataset *ds);
+bool proc_in_temporary_transformations (const struct dataset *ds);
+bool proc_make_temporary_transformations_permanent (struct dataset *ds);
+bool proc_cancel_temporary_transformations (struct dataset *ds);
+\f
+/* Procedures. */
+
+void proc_discard_output (struct dataset *ds);
+
+bool proc_execute (struct dataset *ds);
+time_t time_of_last_procedure (struct dataset *ds);
+
+struct casereader *proc_open_filtering (struct dataset *, bool filter);
+struct casereader *proc_open (struct dataset *);
+bool proc_is_open (const struct dataset *);
+bool proc_commit (struct dataset *);
+
+bool dataset_end_of_command (struct dataset *);
+\f
+const struct ccase *lagged_case (const struct dataset *ds, int n_before);
+void dataset_need_lag (struct dataset *ds, int n_before);
+\f
+/* Private interface for use by session code. */
+
+void dataset_set_session__(struct dataset *, struct session *);
+
+#endif /* dataset.h */
index 4abc526f0cb2a720cb8e3023eb7d732effdb5da4..ad8333256c0bd2732692d107910c85ae2ef8fb6d 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, 2011 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/datasheet.h>
+#include "data/datasheet.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <data/casereader-provider.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/lazy-casereader.h>
-#include <data/settings.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/misc.h>
-#include <libpspp/range-map.h>
-#include <libpspp/range-set.h>
-#include <libpspp/sparse-xarray.h>
-#include <libpspp/taint.h>
-#include <libpspp/tower.h>
-
-#include "minmax.h"
-#include "md4.h"
-#include "xalloc.h"
+#include "data/casereader-provider.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/lazy-casereader.h"
+#include "data/settings.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/misc.h"
+#include "libpspp/range-map.h"
+#include "libpspp/range-set.h"
+#include "libpspp/sparse-xarray.h"
+#include "libpspp/taint.h"
+#include "libpspp/tower.h"
+
+#include "gl/minmax.h"
+#include "gl/md4.h"
+#include "gl/xalloc.h"
 
 struct column;
 
@@ -360,6 +360,8 @@ datasheet_insert_column (struct datasheet *ds,
 {
   struct column *col;
 
+  assert (before <= ds->n_columns);
+
   ds->columns = xnrealloc (ds->columns,
                            ds->n_columns + 1, sizeof *ds->columns);
   insert_element (ds->columns, ds->n_columns, sizeof *ds->columns, before);
@@ -382,6 +384,8 @@ datasheet_insert_column (struct datasheet *ds,
 void
 datasheet_delete_columns (struct datasheet *ds, size_t start, size_t n)
 {
+  assert (start + n <= ds->n_columns);
+
   if (n > 0)
     {
       size_t i;
@@ -411,6 +415,9 @@ datasheet_move_columns (struct datasheet *ds,
                         size_t old_start, size_t new_start,
                         size_t n)
 {
+  assert (old_start + n <= ds->n_columns);
+  assert (new_start + n <= ds->n_columns);
+
   move_range (ds->columns, ds->n_columns, sizeof *ds->columns,
               old_start, new_start, n);
 
index 0508896ae9e30876be39c4e749aabe50d4e572ee..ab6c28d80af56697d18151ac7884106487b7ebfb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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,8 +17,8 @@
 #ifndef DATA_DATASHEET_H
 #define DATA_DATASHEET_H 1
 
-#include <data/case.h>
-#include <data/value.h>
+#include "data/case.h"
+#include "data/value.h"
 
 struct caseproto;
 struct casereader;
index c79b29a28fb387d0bea1ed6024240c7785abe4f1..5f0d036f1b0d5b8543eb86213c645135544655ad 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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
@@ -16,9 +16,9 @@
 
 #include <config.h>
 
-#include <data/dict-class.h>
+#include "data/dict-class.h"
 
-#include <libpspp/assertion.h>
+#include "libpspp/assertion.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 9222f7ec0ba85ab94bdc88952029f8e59fc4b3d5..2d99f6d72cfe2a7e6dc442102f16a4dc687cbe32 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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 <stdint.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <unistr.h>
 
 #include "data/attributes.h"
 #include "data/case.h"
 #include "libpspp/compiler.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "libpspp/pool.h"
 #include "libpspp/str.h"
+#include "libpspp/string-array.h"
 
 #include "gl/intprops.h"
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -63,7 +67,7 @@ struct dictionary
     struct variable *filter;    /* FILTER variable. */
     casenumber case_limit;      /* Current case limit (N command). */
     char *label;               /* File label. */
-    struct string documents;    /* Documents, as a string. */
+    struct string_array documents; /* Documents. */
     struct vector **vector;     /* Vectors of variables. */
     size_t vector_cnt;          /* Number of vectors. */
     struct attrset attributes;  /* Custom attributes. */
@@ -83,22 +87,23 @@ struct dictionary
 static void dict_unset_split_var (struct dictionary *, struct variable *);
 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
 
-void
-dict_set_encoding (struct dictionary *d, const char *enc)
-{
-  if (enc)
-    {
-      free (d->encoding);
-      d->encoding = xstrdup (enc);
-    }
-}
-
+/* Returns the encoding for data in dictionary D.  The return value is a
+   nonnull string that contains an IANA character set name. */
 const char *
 dict_get_encoding (const struct dictionary *d)
 {
   return d->encoding ;
 }
 
+/* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
+   encoding, false otherwise.  If ISSUE_ERROR is true, issues an explanatory
+   error message on failure. */
+bool
+dict_id_is_valid (const struct dictionary *dict, const char *id,
+                  bool issue_error)
+{
+  return id_is_valid (id, dict->encoding, issue_error);
+}
 
 void
 dict_set_change_callback (struct dictionary *d,
@@ -158,14 +163,16 @@ dict_copy_callbacks (struct dictionary *dest,
   dest->cb_data = src->cb_data;
 }
 
-/* Creates and returns a new dictionary. */
+/* Creates and returns a new dictionary with the specified ENCODING. */
 struct dictionary *
-dict_create (void)
+dict_create (const char *encoding)
 {
   struct dictionary *d = xzalloc (sizeof *d);
 
+  d->encoding = xstrdup (encoding);
   hmap_init (&d->name_map);
   attrset_init (&d->attributes);
+
   return d;
 }
 
@@ -176,14 +183,20 @@ dict_create (void)
    dictionary.  If the new dictionary won't be used to access
    cases produced with the old dictionary, then the new
    dictionary's case indexes should be compacted with
-   dict_compact_values to save space. */
+   dict_compact_values to save space.
+
+   Callbacks are not cloned. */
 struct dictionary *
 dict_clone (const struct dictionary *s)
 {
   struct dictionary *d;
   size_t i;
 
-  d = dict_create ();
+  d = dict_create (s->encoding);
+
+  /* Set the new dictionary's encoding early so that string length limitations
+     are interpreted correctly. */
+  d->encoding = xstrdup (s->encoding);
 
   for (i = 0; i < s->var_cnt; i++)
     {
@@ -222,9 +235,6 @@ dict_clone (const struct dictionary *s)
   for (i = 0; i < s->vector_cnt; i++)
     d->vector[i] = vector_clone (s->vector[i], s, d);
 
-  if ( s->encoding)
-    d->encoding = xstrdup (s->encoding);
-
   dict_set_attributes (d, dict_get_attributes (s));
 
   for (i = 0; i < s->n_mrsets; i++)
@@ -268,7 +278,7 @@ dict_clear (struct dictionary *d)
   d->case_limit = 0;
   free (d->label);
   d->label = NULL;
-  ds_destroy (&d->documents);
+  string_array_clear (&d->documents);
   dict_clear_vectors (d);
   attrset_clear (&d->attributes);
 }
@@ -575,7 +585,7 @@ reindex_vars (struct dictionary *d, size_t from, size_t to)
 /* Deletes variable V from dictionary D and frees V.
 
    This is a very bad idea if there might be any pointers to V
-   from outside D.  In general, no variable in the active file's
+   from outside D.  In general, no variable in the active dataset's
    dictionary should be deleted when any transformations are
    active on the dictionary's dataset, because those
    transformations might reference the deleted variable.  The
@@ -842,63 +852,75 @@ var_name_is_insertable (const struct dictionary *dict, const char *name)
           && lex_id_to_token (ss_cstr (name)) == T_ID);
 }
 
-static bool
-make_hinted_name (const struct dictionary *dict, const char *hint,
-                  char name[VAR_NAME_LEN + 1])
+static char *
+make_hinted_name (const struct dictionary *dict, const char *hint)
 {
+  size_t hint_len = strlen (hint);
   bool dropped = false;
-  char *cp;
-
-  for (cp = name; *hint && cp < name + VAR_NAME_LEN; hint++)
+  char *root, *rp;
+  size_t ofs;
+  int mblen;
+
+  /* The allocation size here is OK: characters that are copied directly fit
+     OK, and characters that are not copied directly are replaced by a single
+     '_' byte.  If u8_mbtouc() replaces bad input by 0xfffd, then that will get
+     replaced by '_' too.  */
+  root = rp = xmalloc (hint_len + 1);
+  for (ofs = 0; ofs < hint_len; ofs += mblen)
     {
-      if (cp == name
-          ? lex_is_id1 (*hint) && *hint != '$'
-          : lex_is_idn (*hint))
+      ucs4_t uc;
+
+      mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
+                         hint_len - ofs);
+      if (rp == root
+          ? lex_uc_is_id1 (uc) && uc != '$'
+          : lex_uc_is_idn (uc))
         {
           if (dropped)
             {
-              *cp++ = '_';
+              *rp++ = '_';
               dropped = false;
             }
-          if (cp < name + VAR_NAME_LEN)
-            *cp++ = *hint;
+          rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
         }
-      else if (cp > name)
+      else if (rp != root)
         dropped = true;
     }
-  *cp = '\0';
+  *rp = '\0';
 
-  if (name[0] != '\0')
+  if (root[0] != '\0')
     {
-      size_t len = strlen (name);
       unsigned long int i;
 
-      if (var_name_is_insertable (dict, name))
-        return true;
+      if (var_name_is_insertable (dict, root))
+        return root;
 
       for (i = 0; i < ULONG_MAX; i++)
         {
           char suffix[INT_BUFSIZE_BOUND (i) + 1];
-          int ofs;
+          char *name;
 
           suffix[0] = '_';
           if (!str_format_26adic (i + 1, &suffix[1], sizeof suffix - 1))
             NOT_REACHED ();
 
-          ofs = MIN (VAR_NAME_LEN - strlen (suffix), len);
-          strcpy (&name[ofs], suffix);
-
+          name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
           if (var_name_is_insertable (dict, name))
-            return true;
+            {
+              free (root);
+              return name;
+            }
+          free (name);
         }
     }
 
-  return false;
+  free (root);
+
+  return NULL;
 }
 
-static bool
-make_numeric_name (const struct dictionary *dict, unsigned long int *num_start,
-                   char name[VAR_NAME_LEN + 1])
+static char *
+make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
 {
   unsigned long int number;
 
@@ -906,27 +928,24 @@ make_numeric_name (const struct dictionary *dict, unsigned long int *num_start,
        number < ULONG_MAX;
        number++)
     {
+      char name[3 + INT_STRLEN_BOUND (number) + 1];
+
       sprintf (name, "VAR%03lu", number);
       if (dict_lookup_var (dict, name) == NULL)
         {
           if (num_start != NULL)
             *num_start = number + 1;
-          return true;
+          return xstrdup (name);
         }
     }
 
-  if (num_start != NULL)
-    *num_start = ULONG_MAX;
-  return false;
+  NOT_REACHED ();
 }
 
 
-/* Attempts to devise a variable name unique within DICT.
-   Returns true if successful, in which case the new variable
-   name is stored into NAME.  Returns false if all names that can
-   be generated have already been taken.  (Returning false is
-   quite unlikely: at least ULONG_MAX unique names can be
-   generated.)
+/* Devises and returns a variable name unique within DICT.  The variable name
+   is owned by the caller, which must free it with free() when it is no longer
+   needed.
 
    HINT, if it is non-null, is used as a suggestion that will be
    modified for suitability as a variable name and for
@@ -937,14 +956,18 @@ make_numeric_name (const struct dictionary *dict, unsigned long int *num_start,
    value is used.  If NUM_START is non-null, then its value is
    used as the minimum numeric value to check, and it is updated
    to the next value to be checked.
-   */
-bool
+*/
+char *
 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
-                           unsigned long int *num_start,
-                           char name[VAR_NAME_LEN + 1])
+                           unsigned long int *num_start)
 {
-  return ((hint != NULL && make_hinted_name (dict, hint, name))
-          || make_numeric_name (dict, num_start, name));
+  if (hint != NULL)
+    {
+      char *hinted_name = make_hinted_name (dict, hint);
+      if (hinted_name != NULL)
+        return hinted_name;
+    }
+  return make_numeric_name (dict, num_start);
 }
 
 /* Returns the weighting variable in dictionary D, or a null
@@ -1228,82 +1251,104 @@ dict_get_label (const struct dictionary *d)
 }
 
 /* Sets D's file label to LABEL, truncating it to a maximum of 60
-   characters. */
+   characters.
+
+   Removes D's label if LABEL is null or the empty string. */
 void
 dict_set_label (struct dictionary *d, const char *label)
 {
   free (d->label);
-  d->label = label != NULL ? xstrndup (label, 60) : NULL;
+  d->label = label != NULL && label[0] != '\0' ? xstrndup (label, 60) : NULL;
 }
 
-/* Returns the documents for D, or a null pointer if D has no
-   documents.  If the return value is nonnull, then the string
-   will be an exact multiple of DOC_LINE_LENGTH bytes in length,
-   with each segment corresponding to one line. */
-const char *
+/* Returns the documents for D, as an UTF-8 encoded string_array.  The
+   return value is always nonnull; if there are no documents then the
+   string_arary is empty.*/
+const struct string_array *
 dict_get_documents (const struct dictionary *d)
 {
-  return ds_is_empty (&d->documents) ? NULL : ds_cstr (&d->documents);
+  return &d->documents;
 }
 
-/* Sets the documents for D to DOCUMENTS, or removes D's
-   documents if DOCUMENT is a null pointer.  If DOCUMENTS is
-   nonnull, then it should be an exact multiple of
-   DOC_LINE_LENGTH bytes in length, with each segment
-   corresponding to one line. */
+/* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
 void
-dict_set_documents (struct dictionary *d, const char *documents)
+dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
 {
-  size_t remainder;
+  size_t i;
+
+  dict_clear_documents (d);
+
+  for (i = 0; i < new_docs->n; i++)
+    dict_add_document_line (d, new_docs->strings[i], false);
+}
 
-  ds_assign_cstr (&d->documents, documents != NULL ? documents : "");
+/* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
+   into individual lines at new-line characters.  Each line is truncated to at
+   most DOC_LINE_LENGTH bytes in D's encoding. */
+void
+dict_set_documents_string (struct dictionary *d, const char *new_docs)
+{
+  const char *s;
 
-  /* In case the caller didn't get it quite right, pad out the
-     final line with spaces. */
-  remainder = ds_length (&d->documents) % DOC_LINE_LENGTH;
-  if (remainder != 0)
-    ds_put_char_multiple (&d->documents, ' ', DOC_LINE_LENGTH - remainder);
+  dict_clear_documents (d);
+  for (s = new_docs; *s != '\0'; )
+    {
+      size_t len = strcspn (s, "\n");
+      char *line = xmemdup0 (s, len);
+      dict_add_document_line (d, line, false);
+      free (line);
+
+      s += len;
+      if (*s == '\n')
+        s++;
+    }
 }
 
 /* Drops the documents from dictionary D. */
 void
 dict_clear_documents (struct dictionary *d)
 {
-  ds_clear (&d->documents);
+  string_array_clear (&d->documents);
 }
 
-/* Appends LINE to the documents in D.  LINE will be truncated or
-   padded on the right with spaces to make it exactly
-   DOC_LINE_LENGTH bytes long. */
-void
-dict_add_document_line (struct dictionary *d, const char *line)
+/* Appends the UTF-8 encoded LINE to the documents in D.  LINE will be
+   truncated so that it is no more than 80 bytes in the dictionary's
+   encoding.  If this causes some text to be lost, and ISSUE_WARNING is true,
+   then a warning will be issued. */
+bool
+dict_add_document_line (struct dictionary *d, const char *line,
+                        bool issue_warning)
 {
-  if (strlen (line) > DOC_LINE_LENGTH)
+  size_t trunc_len;
+  bool truncated;
+
+  trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
+  truncated = line[trunc_len] != '\0';
+  if (truncated && issue_warning)
     {
       /* Note to translators: "bytes" is correct, not characters */
       msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
     }
-  buf_copy_str_rpad (ds_put_uninit (&d->documents, DOC_LINE_LENGTH),
-                     DOC_LINE_LENGTH, line, ' ');
+
+  string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
+
+  return !truncated;
 }
 
 /* Returns the number of document lines in dictionary D. */
 size_t
 dict_get_document_line_cnt (const struct dictionary *d)
 {
-  return ds_length (&d->documents) / DOC_LINE_LENGTH;
+  return d->documents.n;
 }
 
-/* Copies document line number IDX from dictionary D into
-   LINE, trimming off any trailing white space. */
-void
-dict_get_document_line (const struct dictionary *d,
-                        size_t idx, struct string *line)
+/* Returns document line number IDX in dictionary D.  The caller must not
+   modify or free the returned string. */
+const char *
+dict_get_document_line (const struct dictionary *d, size_t idx)
 {
-  assert (idx < dict_get_document_line_cnt (d));
-  ds_assign_substring (line, ds_substr (&d->documents, idx * DOC_LINE_LENGTH,
-                                        DOC_LINE_LENGTH));
-  ds_rtrim (line, ss_cstr (CC_SPACES));
+  assert (idx < d->documents.n);
+  return d->documents.strings[idx];
 }
 
 /* Creates in D a vector named NAME that contains the CNT
@@ -1610,7 +1655,7 @@ struct variable *
 dict_create_internal_var (int case_idx, int width)
 {
   if (internal_dict == NULL)
-    internal_dict = dict_create ();
+    internal_dict = dict_create ("UTF-8");
 
   for (;;)
     {
index 96529a1bd3aaa075dff403ef4bd2c78d46c25ec4..2a196950a97a3d6bae5aa86bb3dab83733576df8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2009, 2010, 2011 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/case.h>
-#include <data/dict-class.h>
+#include "data/case.h"
+#include "data/dict-class.h"
 
 struct string;
 struct ccase;
 
 /* Creating dictionaries. */
-struct dictionary *dict_create (void);
+struct dictionary *dict_create (const char *encoding);
 struct dictionary *dict_clone (const struct dictionary *);
 
 
@@ -84,9 +84,8 @@ void dict_rename_var (struct dictionary *, struct variable *, const char *);
 bool dict_rename_vars (struct dictionary *,
                        struct variable **, char **new_names,
                        size_t count, char **err_name);
-bool dict_make_unique_var_name (const struct dictionary *, const char *hint,
-                                unsigned long int *num_start,
-                                char name[]);
+char *dict_make_unique_var_name (const struct dictionary *, const char *hint,
+                                 unsigned long int *num_start);
 
 /* Weight variable. */
 double dict_get_case_weight (const struct dictionary *,
@@ -128,14 +127,15 @@ void dict_set_label (struct dictionary *, const char *);
 /* Documents. */
 #define DOC_LINE_LENGTH 80 /* Fixed length of document lines. */
 
-const char *dict_get_documents (const struct dictionary *);
-void dict_set_documents (struct dictionary *, const char *);
+const struct string_array *dict_get_documents (const struct dictionary *);
+void dict_set_documents (struct dictionary *, const struct string_array *);
+void dict_set_documents_string (struct dictionary *, const char *);
 void dict_clear_documents (struct dictionary *);
 
-void dict_add_document_line (struct dictionary *, const char *);
+bool dict_add_document_line (struct dictionary *, const char *,
+                             bool issue_warning);
 size_t dict_get_document_line_cnt (const struct dictionary *);
-void dict_get_document_line (const struct dictionary *,
-                             size_t, struct string *);
+const char *dict_get_document_line (const struct dictionary *, size_t);
 
 /* Vectors. */
 bool dict_create_vector (struct dictionary *, const char *name,
@@ -164,9 +164,11 @@ void dict_set_attributes (struct dictionary *, const struct attrset *);
 bool dict_has_attributes (const struct dictionary *);
 
 /* Data encoding. */
-void dict_set_encoding (struct dictionary *d, const char *enc);
 const char *dict_get_encoding (const struct dictionary *d);
 
+bool dict_id_is_valid (const struct dictionary *, const char *id,
+                       bool issue_error);
+
 /* Internal variables. */
 struct variable *dict_create_internal_var (int case_idx, int width);
 void dict_destroy_internal_var (struct variable *);
index d025ff6a3a35b4a493b7f6b72f0d3ed61ff461e1..6ca6977c87733d792fce4c7f31d48f8afab97e80 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 "file-handle-def.h"
+#include "data/file-handle-def.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/compiler.h>
-#include <libpspp/hmap.h>
-#include <libpspp/ll.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/hash-functions.h>
-#include <data/file-name.h>
-#include <data/variable.h>
-#include <data/scratch-handle.h>
+#include "data/dataset.h"
+#include "data/file-name.h"
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "libpspp/hash-functions.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -41,7 +41,7 @@
 /* File handle. */
 struct file_handle
   {
-    struct ll ll;               /* Element in global list. */
+    struct hmap_node name_node; /* Element in named_handles hmap. */
     size_t ref_cnt;             /* Number of references. */
     char *id;                   /* Identifier token, NULL if none. */
     char *name;                 /* User-friendly identifying name. */
@@ -56,18 +56,12 @@ struct file_handle
     size_t record_width;        /* Length of fixed-format records. */
     size_t tab_width;           /* Tab width, 0=do not expand tabs. */
 
-    /* FH_REF_SCRATCH only. */
-    struct scratch_handle *sh;  /* Scratch file data. */
+    /* FH_REF_DATASET only. */
+    struct dataset *ds;         /* Dataset. */
   };
 
-static struct file_handle *
-file_handle_from_ll (struct ll *ll)
-{
-  return ll_data (ll, struct file_handle, ll);
-}
-
-/* List of all named handles. */
-static struct ll_list named_handles;
+/* All "struct file_handle"s with nonnull 'id' member. */
+static struct hmap named_handles = HMAP_INITIALIZER (named_handles);
 
 /* Default file handle for DATA LIST, REREAD, REPEATING DATA
    commands. */
@@ -88,7 +82,6 @@ static struct hmap locks = HMAP_INITIALIZER (locks);
 void
 fh_init (void)
 {
-  ll_init (&named_handles);
   inline_file = create_handle ("INLINE", xstrdup ("INLINE"), FH_REF_INLINE);
   inline_file->record_width = 80;
   inline_file->tab_width = 8;
@@ -98,8 +91,11 @@ fh_init (void)
 void
 fh_done (void)
 {
-  while (!ll_is_empty (&named_handles))
-    unname_handle (file_handle_from_ll (ll_head (&named_handles)));
+  struct file_handle *handle, *next;
+
+  HMAP_FOR_EACH_SAFE (handle, next,
+                      struct file_handle, name_node, &named_handles)
+    unname_handle (handle);
 }
 
 /* Free HANDLE and remove it from the global list. */
@@ -108,13 +104,12 @@ free_handle (struct file_handle *handle)
 {
   /* Remove handle from global list. */
   if (handle->id != NULL)
-    ll_remove (&handle->ll);
+    hmap_delete (&named_handles, &handle->name_node);
 
   /* Free data. */
   free (handle->id);
   free (handle->name);
   free (handle->file_name);
-  scratch_handle_destroy (handle->sh);
   free (handle);
 }
 
@@ -127,7 +122,7 @@ unname_handle (struct file_handle *handle)
   assert (handle->id != NULL);
   free (handle->id);
   handle->id = NULL;
-  ll_remove (&handle->ll);
+  hmap_delete (&named_handles, &handle->name_node);
 
   /* Drop the reference held by the named_handles table. */
   fh_unref (handle);
@@ -176,7 +171,8 @@ fh_from_id (const char *id)
 {
   struct file_handle *handle;
 
-  ll_for_each (handle, struct file_handle, ll, &named_handles)
+  HMAP_FOR_EACH_WITH_HASH (handle, struct file_handle, name_node,
+                           hash_case_string (id, 0), &named_handles)
     if (!strcasecmp (id, handle->id))
       {
         handle->ref_cnt++;
@@ -205,7 +201,8 @@ create_handle (const char *id, char *handle_name, enum fh_referent referent)
   if (id != NULL)
     {
       assert (fh_from_id (id) == NULL);
-      ll_push_tail (&named_handles, &handle->ll);
+      hmap_insert (&named_handles, &handle->name_node,
+                   hash_case_string (handle->id, 0));
       handle->ref_cnt++;
     }
 
@@ -222,10 +219,10 @@ fh_inline_file (void)
   return inline_file;
 }
 
-/* Creates and returns a new file handle with the given ID, which
-   may be null.  If it is non-null, it must be unique among
-   existing file identifiers.  The new handle is associated with
-   file FILE_NAME and the given PROPERTIES. */
+/* Creates and returns a new file handle with the given ID, which may be null.
+   If it is non-null, it must be a UTF-8 encoded string that is unique among
+   existing file identifiers.  The new handle is associated with file FILE_NAME
+   and the given PROPERTIES. */
 struct file_handle *
 fh_create_file (const char *id, const char *file_name,
                 const struct fh_properties *properties)
@@ -245,13 +242,19 @@ fh_create_file (const char *id, const char *file_name,
 
 /* Creates a new file handle with the given ID, which must be
    unique among existing file identifiers.  The new handle is
-   associated with a scratch file (initially empty). */
+   associated with a dataset file (initially empty). */
 struct file_handle *
-fh_create_scratch (const char *id)
+fh_create_dataset (struct dataset *ds)
 {
+  const char *name;
   struct file_handle *handle;
-  handle = create_handle (id, xstrdup (id), FH_REF_SCRATCH);
-  handle->sh = NULL;
+
+  name = dataset_name (ds);
+  if (name[0] == '\0')
+    name = _("active dataset");
+
+  handle = create_handle (NULL, xstrdup (name), FH_REF_DATASET);
+  handle->ds = ds;
   return handle;
 }
 
@@ -260,7 +263,7 @@ const struct fh_properties *
 fh_default_properties (void)
 {
   static const struct fh_properties default_properties
-    = {FH_MODE_TEXT, 1024, 4, LEGACY_NATIVE};
+    = {FH_MODE_TEXT, 1024, 4, C_ENCODING};
   return &default_properties;
 }
 
@@ -333,25 +336,16 @@ const char *
 fh_get_legacy_encoding (const struct file_handle *handle)
 {
   assert (handle->referent & (FH_REF_FILE | FH_REF_INLINE));
-  return (handle->referent == FH_REF_FILE ? handle->encoding : LEGACY_NATIVE);
+  return (handle->referent == FH_REF_FILE ? handle->encoding : C_ENCODING);
 }
 
-/* Returns the scratch file handle associated with HANDLE.
-   Applicable to only FH_REF_SCRATCH files. */
-struct scratch_handle *
-fh_get_scratch_handle (const struct file_handle *handle)
+/* Returns the dataset handle associated with HANDLE.
+   Applicable to only FH_REF_DATASET files. */
+struct dataset *
+fh_get_dataset (const struct file_handle *handle)
 {
-  assert (handle->referent == FH_REF_SCRATCH);
-  return handle->sh;
-}
-
-/* Sets SH to be the scratch file handle associated with HANDLE.
-   Applicable to only FH_REF_SCRATCH files. */
-void
-fh_set_scratch_handle (struct file_handle *handle, struct scratch_handle *sh)
-{
-  assert (handle->referent == FH_REF_SCRATCH);
-  handle->sh = sh;
+  assert (handle->referent == FH_REF_DATASET);
+  return handle->ds;
 }
 
 /* Returns the current default handle. */
@@ -384,7 +378,7 @@ struct fh_lock
     union
       {
         struct file_identity *file; /* FH_REF_FILE only. */
-        unsigned int unique_id;    /* FH_REF_SCRATCH only. */
+        unsigned int unique_id;    /* FH_REF_DATASET only. */
       }
     u;
     enum fh_access access;      /* Type of file access. */
@@ -592,11 +586,8 @@ make_key (struct fh_lock *lock, const struct file_handle *h,
   lock->access = access;
   if (lock->referent == FH_REF_FILE)
     lock->u.file = fn_get_identity (fh_get_file_name (h));
-  else if (lock->referent == FH_REF_SCRATCH)
-    {
-      struct scratch_handle *sh = fh_get_scratch_handle (h);
-      lock->u.unique_id = sh != NULL ? sh->unique_id : 0;
-    }
+  else if (lock->referent == FH_REF_DATASET)
+    lock->u.unique_id = dataset_seqno (fh_get_dataset (h));
 }
 
 /* Frees the key fields in LOCK. */
@@ -618,7 +609,7 @@ compare_fh_locks (const struct fh_lock *a, const struct fh_lock *b)
     return a->access < b->access ? -1 : 1;
   else if (a->referent == FH_REF_FILE)
     return fn_compare_file_identities (a->u.file, b->u.file);
-  else if (a->referent == FH_REF_SCRATCH)
+  else if (a->referent == FH_REF_DATASET)
     return (a->u.unique_id < b->u.unique_id ? -1
             : a->u.unique_id > b->u.unique_id);
   else
@@ -632,7 +623,7 @@ hash_fh_lock (const struct fh_lock *lock)
   unsigned int basis;
   if (lock->referent == FH_REF_FILE)
     basis = fn_hash_identity (lock->u.file);
-  else if (lock->referent == FH_REF_SCRATCH)
+  else if (lock->referent == FH_REF_DATASET)
     basis = lock->u.unique_id;
   else
     basis = 0;
index b4a6d6100e8ed291ed8705a659d381beb8ec26a6..11898ef578eca45d437c86c41dfe71bd09d29ffc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2005, 2006, 2010, 2011 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,7 +19,8 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/legacy-encoding.h>
+
+struct dataset;
 
 /* What a file handle refers to.
    (Ordinarily only a single value is allowed, but fh_open()
@@ -28,7 +29,7 @@ enum fh_referent
   {
     FH_REF_FILE = 001,          /* Ordinary file (the most common case). */
     FH_REF_INLINE = 002,        /* The inline file. */
-    FH_REF_SCRATCH = 004        /* Temporary dataset. */
+    FH_REF_DATASET = 004        /* Dataset. */
   };
 
 /* File modes. */
@@ -64,7 +65,7 @@ void fh_done (void);
 struct file_handle *fh_create_file (const char *handle_name,
                                     const char *file_name,
                                     const struct fh_properties *);
-struct file_handle *fh_create_scratch (const char *handle_name);
+struct file_handle *fh_create_dataset (struct dataset *);
 const struct fh_properties *fh_default_properties (void);
 
 /* Reference management. */
@@ -91,9 +92,8 @@ size_t fh_get_record_width (const struct file_handle *);
 size_t fh_get_tab_width (const struct file_handle *);
 const char *fh_get_legacy_encoding (const struct file_handle *);
 
-/* Properties of FH_REF_SCRATCH file handles. */
-struct scratch_handle *fh_get_scratch_handle (const struct file_handle *);
-void fh_set_scratch_handle (struct file_handle *, struct scratch_handle *);
+/* Properties of FH_REF_DATASET file handles. */
+struct dataset *fh_get_dataset (const struct file_handle *);
 
 /* Mutual exclusion for access . */
 struct fh_lock *fh_lock (struct file_handle *, enum fh_referent mask,
index 1b31048e211b75dd301fc87d5c928cfe0bc764f6..2988d50295b073482b3bee10f274834a56bec6d0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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
@@ -221,14 +221,7 @@ fn_open (const char *fn, const char *mode)
     }
   else
 #endif
-    {
-      FILE *f = fopen (fn, mode);
-
-      if (f && mode[0] != 'r')
-       setvbuf (f, NULL, _IOLBF, 0);
-
-      return f;
-    }
+    return fopen (fn, mode);
 }
 
 /* Counterpart to fn_open that closes file F with name FN; returns 0
index 26c917b824ce77733409ecb27885fd7d7d0e55eb..17c5da90ceb8b2f74012889a3bcd036a798ef799 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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 "format-guesser.h"
+#include "data/format-guesser.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include "c-ctype.h"
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
 
-#include <data/format.h>
-#include <data/settings.h>
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+#include "gl/c-ctype.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 /* A token in which potential date or time fields are broken.
 
@@ -304,12 +304,12 @@ add_numeric (struct fmt_guesser *g, struct substring s)
   int c;
 
   /* Skip leading "$" and optional following white space. */
-  has_dollar = ss_match_char (&s, '$');
+  has_dollar = ss_match_byte (&s, '$');
   if (has_dollar)
     ss_ltrim (&s, ss_cstr (CC_SPACES));
 
   /* Skip optional sign. */
-  ss_match_char_in (&s, ss_cstr ("+-"));
+  ss_match_byte_in (&s, ss_cstr ("+-"));
 
   /* Skip digits punctuated by commas and dots.  We don't know
      whether the decimal point is a comma or a dot, so for now we
@@ -348,10 +348,10 @@ add_numeric (struct fmt_guesser *g, struct substring s)
     }
 
   /* Skip the optional exponent. */
-  has_exp = ss_match_char_in (&s, ss_cstr ("eEdD")) != EOF;
-  has_exp_sign = ss_match_char_in (&s, ss_cstr ("-+")) != EOF;
+  has_exp = ss_match_byte_in (&s, ss_cstr ("eEdD")) != EOF;
+  has_exp_sign = ss_match_byte_in (&s, ss_cstr ("-+")) != EOF;
   if (has_exp_sign)
-    ss_match_char (&s, ' ');
+    ss_match_byte (&s, ' ');
   exp_digits = ss_ltrim (&s, ss_cstr (CC_DIGITS));
   if ((has_exp || has_exp_sign) && !exp_digits)
     {
@@ -361,7 +361,7 @@ add_numeric (struct fmt_guesser *g, struct substring s)
     }
 
   /* Skip optional '%'. */
-  has_percent = ss_match_char (&s, '%');
+  has_percent = ss_match_byte (&s, '%');
   if (has_dollar && has_percent)
     {
       /* A valid number cannot have both '$' and '%'. */
@@ -635,7 +635,7 @@ parse_date_token (struct substring *s, enum date_token tokens_seen,
         ss_advance (s, 1);
         token = recognize_identifier_token (s);
         if (token)
-          ss_match_char_in (s, ss_cstr (CC_SPACES));
+          ss_match_byte_in (s, ss_cstr (CC_SPACES));
         else
           token = DT_DELIM | DT_SPACE;
         return token;
@@ -666,7 +666,7 @@ parse_date_number (struct substring *s, enum date_token tokens_seen,
   size_t digit_cnt = ss_get_long (s, &value);
   enum date_token token = 0;
 
-  if (ss_match_char (s, settings_get_decimal_char (FMT_F))
+  if (ss_match_byte (s, settings_get_decimal_char (FMT_F))
       && tokens_seen & DT_COLON
       && value <= 59)
     {
index 23249f6a85c10f261e04a6efd20551c926357e9d..395da5771e82ce086af5b14f63437aabe8b44fe6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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,7 +17,8 @@
 #ifndef FORMAT_GUESSER_H
 #define FORMAT_GUESSER_H 1
 
-#include <libpspp/str.h>
+#include "libpspp/str.h"
+
 struct fmt_spec;
 
 struct fmt_guesser *fmt_guesser_create (void);
index a78ea91c57fe38df914b608ee28e67c6aafa5a67..e15931ad1a2b4764547747945e9399305f2b8946 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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 <ctype.h>
 #include <stdlib.h>
-
-#include <data/identifier.h>
-#include <data/settings.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include <uniwidth.h>
+
+#include "data/identifier.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -48,6 +50,9 @@ static bool valid_width (enum fmt_type, int width, bool for_input);
 
 static int max_digits_for_bytes (int bytes);
 
+static void fmt_affix_set (struct fmt_affix *, const char *);
+static void fmt_affix_free (struct fmt_affix *);
+
 static void fmt_number_style_init (struct fmt_number_style *);
 static void fmt_number_style_clone (struct fmt_number_style *,
                                     const struct fmt_number_style *);
@@ -107,52 +112,53 @@ fmt_settings_get_style (const struct fmt_settings *settings,
   return &settings->styles[type];
 }
 
+/* Sets the number style for TYPE to have the given DECIMAL and GROUPING
+   characters, negative prefix NEG_PREFIX, prefix PREFIX, suffix SUFFIX, and
+   negative suffix NEG_SUFFIX.  All of the strings are UTF-8 encoded. */
 void
 fmt_settings_set_style (struct fmt_settings *settings, enum fmt_type type,
-                        const struct fmt_number_style *style)
-{
-  fmt_check_style (style);
-  fmt_number_style_destroy (&settings->styles[type]);
-  fmt_number_style_clone (&settings->styles[type], style);
-}
-
-/* Sets the number style for TYPE to have the given standard
-   PREFIX and SUFFIX, "-" as prefix suffix, an empty negative
-   suffix, DECIMAL as the decimal point character, and GROUPING
-   as the grouping character. */
-static void
-set_style (struct fmt_settings *settings, enum fmt_type type,
-           const char *prefix, const char *suffix,
-           char decimal, char grouping)
+                        char decimal, char grouping,
+                        const char *neg_prefix, const char *prefix,
+                        const char *suffix, const char *neg_suffix)
 {
-  struct fmt_number_style *style;
-
-  assert (is_fmt_type (type));
+  struct fmt_number_style *style = &settings->styles[type];
+  int total_bytes, total_width;
 
-  style = &settings->styles[type];
+  assert (grouping == '.' || grouping == ',' || grouping == 0);
+  assert (decimal == '.' || decimal == ',');
+  assert (decimal != grouping);
 
   fmt_number_style_destroy (style);
 
-  ss_alloc_substring (&style->neg_prefix, ss_cstr ("-"));
-  ss_alloc_substring (&style->prefix, ss_cstr (prefix));
-  ss_alloc_substring (&style->suffix, ss_cstr (suffix));
+  fmt_affix_set (&style->neg_prefix, neg_prefix);
+  fmt_affix_set (&style->prefix, prefix);
+  fmt_affix_set (&style->suffix, suffix);
+  fmt_affix_set (&style->neg_suffix, neg_suffix);
   style->decimal = decimal;
   style->grouping = grouping;
+
+  total_bytes = (strlen (neg_prefix) + strlen (prefix)
+                 + strlen (suffix) + strlen (neg_suffix));
+  total_width = (style->neg_prefix.width + style->prefix.width
+                 + style->suffix.width + style->neg_suffix.width);
+  style->extra_bytes = MAX (0, total_bytes - total_width);
 }
 
-/* Sets the decimal point character for SETTINGS to DECIMAL. */
+/* Sets the decimal point character for the settings in S to DECIMAL.
+
+   This has no effect on custom currency formats. */
 void
-fmt_settings_set_decimal (struct fmt_settings *settings, char decimal)
+fmt_settings_set_decimal (struct fmt_settings *s, char decimal)
 {
   int grouping = decimal == '.' ? ',' : '.';
   assert (decimal == '.' || decimal == ',');
 
-  set_style (settings, FMT_F, "", "", decimal, 0);
-  set_style (settings, FMT_E, "", "", decimal, 0);
-  set_style (settings, FMT_COMMA, "", "", decimal, grouping);
-  set_style (settings, FMT_DOT, "", "", grouping, decimal);
-  set_style (settings, FMT_DOLLAR, "$", "", decimal, grouping);
-  set_style (settings, FMT_PCT, "", "%", decimal, 0);
+  fmt_settings_set_style (s, FMT_F,      decimal,        0, "-",  "",  "", "");
+  fmt_settings_set_style (s, FMT_E,      decimal,        0, "-",  "",  "", "");
+  fmt_settings_set_style (s, FMT_COMMA,  decimal, grouping, "-",  "",  "", "");
+  fmt_settings_set_style (s, FMT_DOT,   grouping,  decimal, "-",  "",  "", "");
+  fmt_settings_set_style (s, FMT_DOLLAR, decimal, grouping, "-", "$",  "", "");
+  fmt_settings_set_style (s, FMT_PCT,    decimal,        0, "-",  "", "%", "");
 }
 
 /* Returns an input format specification with type TYPE, width W,
@@ -906,6 +912,56 @@ fmt_date_template (enum fmt_type type)
     }
 }
 
+/* Returns a string representing the format TYPE for use in a GUI dialog. */
+const char *
+fmt_gui_name (enum fmt_type type)
+{
+  switch (type)
+    {
+    case FMT_F:
+      return _("Numeric");
+
+    case FMT_COMMA:
+      return _("Comma");
+
+    case FMT_DOT:
+      return _("Dot");
+
+    case FMT_E:
+      return _("Scientific");
+
+    case FMT_DATE:
+    case FMT_EDATE:
+    case FMT_SDATE:
+    case FMT_ADATE:
+    case FMT_JDATE:
+    case FMT_QYR:
+    case FMT_MOYR:
+    case FMT_WKYR:
+    case FMT_DATETIME:
+    case FMT_TIME:
+    case FMT_DTIME:
+    case FMT_WKDAY:
+    case FMT_MONTH:
+      return _("Date");
+
+    case FMT_DOLLAR:
+      return _("Dollar");
+
+    case FMT_CCA:
+    case FMT_CCB:
+    case FMT_CCC:
+    case FMT_CCD:
+    case FMT_CCE:
+      return _("Custom");
+
+    case FMT_A:
+      return _("String");
+
+    default:
+      return fmt_name (type);
+    }
+}
 \f
 /* Returns true if TYPE is a valid format type,
    false otherwise. */
@@ -936,13 +992,29 @@ max_digits_for_bytes (int bytes)
   return map[bytes - 1];
 }
 \f
+/* Sets AFFIX's string value to S, a UTF-8 encoded string. */
+static void
+fmt_affix_set (struct fmt_affix *affix, const char *s)
+{
+  affix->s = s[0] == '\0' ? CONST_CAST (char *, "") : xstrdup (s);
+  affix->width = u8_strwidth (CHAR_CAST (const uint8_t *, s), "UTF-8");
+}
+
+/* Frees data in AFFIX. */
+static void
+fmt_affix_free (struct fmt_affix *affix)
+{
+  if (affix->s[0])
+    free (affix->s);
+}
+
 static void
 fmt_number_style_init (struct fmt_number_style *style)
 {
-  style->neg_prefix = ss_empty ();
-  style->prefix = ss_empty ();
-  style->suffix = ss_empty ();
-  style->neg_suffix = ss_empty ();
+  fmt_affix_set (&style->neg_prefix, "");
+  fmt_affix_set (&style->prefix, "");
+  fmt_affix_set (&style->suffix, "");
+  fmt_affix_set (&style->neg_suffix, "");
   style->decimal = '.';
   style->grouping = 0;
 }
@@ -951,12 +1023,13 @@ static void
 fmt_number_style_clone (struct fmt_number_style *new,
                         const struct fmt_number_style *old)
 {
-  ss_alloc_substring (&new->neg_prefix, old->neg_prefix);
-  ss_alloc_substring (&new->prefix, old->prefix);
-  ss_alloc_substring (&new->suffix, old->suffix);
-  ss_alloc_substring (&new->neg_suffix, old->neg_suffix);
+  fmt_affix_set (&new->neg_prefix, old->neg_prefix.s);
+  fmt_affix_set (&new->prefix, old->prefix.s);
+  fmt_affix_set (&new->suffix, old->suffix.s);
+  fmt_affix_set (&new->neg_suffix, old->neg_suffix.s);
   new->decimal = old->decimal;
   new->grouping = old->grouping;
+  new->extra_bytes = old->extra_bytes;
 }
 
 /* Destroys a struct fmt_number_style. */
@@ -965,42 +1038,27 @@ fmt_number_style_destroy (struct fmt_number_style *style)
 {
   if (style != NULL)
     {
-      ss_dealloc (&style->neg_prefix);
-      ss_dealloc (&style->prefix);
-      ss_dealloc (&style->suffix);
-      ss_dealloc (&style->neg_suffix);
+      fmt_affix_free (&style->neg_prefix);
+      fmt_affix_free (&style->prefix);
+      fmt_affix_free (&style->suffix);
+      fmt_affix_free (&style->neg_suffix);
     }
 }
 
-/* Checks that style is STYLE sane */
-void
-fmt_check_style (const struct fmt_number_style *style)
-{
-  assert (ss_length (style->neg_prefix) <= FMT_STYLE_AFFIX_MAX);
-  assert (ss_length (style->prefix) <= FMT_STYLE_AFFIX_MAX);
-  assert (ss_length (style->suffix) <= FMT_STYLE_AFFIX_MAX);
-  assert (ss_length (style->neg_suffix) <= FMT_STYLE_AFFIX_MAX);
-  assert (style->decimal == '.' || style->decimal == ',');
-  assert (style->grouping == '.' || style->grouping == ','
-          || style->grouping == 0);
-  assert (style->grouping != style->decimal);
-}
-
-
-/* Returns the total width of the standard prefix and suffix for
-   STYLE. */
+/* Returns the total width of the standard prefix and suffix for STYLE, in
+   display columns (e.g. as returned by u8_strwidth()). */
 int
 fmt_affix_width (const struct fmt_number_style *style)
 {
-  return ss_length (style->prefix) + ss_length (style->suffix);
+  return style->prefix.width + style->suffix.width;
 }
 
-/* Returns the total width of the negative prefix and suffix for
-   STYLE. */
+/* Returns the total width of the negative prefix and suffix for STYLE, in
+   display columns (e.g. as returned by u8_strwidth()). */
 int
 fmt_neg_affix_width (const struct fmt_number_style *style)
 {
-  return ss_length (style->neg_prefix) + ss_length (style->neg_suffix);
+  return style->neg_prefix.width + style->neg_suffix.width;
 }
 
 /* Returns the struct fmt_desc for the given format TYPE. */
index 36726542de9e40f5a65dbd131afb2187f527d0a8..88a82ee970c11647cee853579ed8edd566c4d673 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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,8 +20,8 @@
 /* Display format types. */
 
 #include <stdbool.h>
-#include <libpspp/str.h>
-#include <data/val-type.h>
+#include "data/val-type.h"
+#include "libpspp/str.h"
 
 /* Format type categories.
 
@@ -125,6 +125,7 @@ int fmt_to_io (enum fmt_type) PURE_FUNCTION;
 bool fmt_from_io (int io, enum fmt_type *);
 
 const char *fmt_date_template (enum fmt_type) PURE_FUNCTION;
+const char *fmt_gui_name (enum fmt_type);
 \f
 /* Format settings.
 
@@ -139,29 +140,40 @@ void fmt_settings_set_decimal (struct fmt_settings *, char);
 const struct fmt_number_style *fmt_settings_get_style (
   const struct fmt_settings *, enum fmt_type);
 void fmt_settings_set_style (struct fmt_settings *, enum fmt_type,
-                             const struct fmt_number_style *);
+                             char decimal, char grouping,
+                             const char *neg_prefix, const char *prefix,
+                             const char *suffix, const char *neg_suffix);
 \f
+/* A prefix or suffix for a numeric output format. */
+struct fmt_affix
+  {
+    char *s;                    /* String contents of affix, in UTF-8. */
+    int width;                  /* Display width in columns (see wcwidth()). */
+  };
+
 /* A numeric output style. */
 struct fmt_number_style
   {
-    struct substring neg_prefix;      /* Negative prefix. */
-    struct substring prefix;          /* Prefix. */
-    struct substring suffix;          /* Suffix. */
-    struct substring neg_suffix;      /* Negative suffix. */
-    char decimal;                     /* Decimal point: '.' or ','. */
-    char grouping;                    /* Grouping character: ',', '.', or 0. */
+    struct fmt_affix neg_prefix; /* Negative prefix. */
+    struct fmt_affix prefix;     /* Prefix. */
+    struct fmt_affix suffix;     /* Suffix. */
+    struct fmt_affix neg_suffix; /* Negative suffix. */
+    char decimal;                /* Decimal point: '.' or ','. */
+    char grouping;               /* Grouping character: ',', '.', or 0. */
+
+    /* A fmt_affix may require more bytes than its display width; for example,
+       U+00A5 (¥) is 3 bytes in UTF-8 but occupies only one display column.
+       This member is the sum of the number of bytes required by all of the
+       fmt_affix members in this struct, minus their display widths.  Thus, it
+       can be used to size memory allocations: for example, the formatted
+       result of CCA20.5 requires no more than (20 + extra_bytes) bytes in
+       UTF-8. */
+    int extra_bytes;
   };
 
-/* Maximum length of prefix or suffix string in
-   struct fmt_number_style. */
-#define FMT_STYLE_AFFIX_MAX 16
-
 int fmt_affix_width (const struct fmt_number_style *);
 int fmt_neg_affix_width (const struct fmt_number_style *);
 
-void fmt_check_style (const struct fmt_number_style *style);
-
-
 extern const struct fmt_spec F_8_0 ;
 
 #endif /* data/format.h */
index 26b90ee8916377d500512b1145422bff1fd9a1d1..61fbab899b8bd44eff63633bdb0f90a57a2553d4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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 <libpspp/message.h>
-#include <libpspp/misc.h>
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
 
-#include "minmax.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -40,25 +40,24 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 
 #else
 
-#include <data/casereader-provider.h>
-#include <errno.h>
-#include <libpspp/str.h>
-#include <libpspp/i18n.h>
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <xalloc.h>
+#include "data/gnumeric-reader.h"
 
+#include <assert.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <libxml/xmlreader.h>
 #include <zlib.h>
-#include <stdbool.h>
 
-#include <data/case.h>
-#include <data/value.h>
+#include "data/case.h"
+#include "data/casereader-provider.h"
+#include "data/dictionary.h"
+#include "data/identifier.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/i18n.h"
+#include "libpspp/str.h"
 
-#include "gnumeric-reader.h"
-#include <data/identifier.h>
-#include <assert.h>
+#include "gl/xalloc.h"
 
 /* Default width of string variables. */
 #define GNUMERIC_DEFAULT_WIDTH 8
@@ -497,27 +496,21 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 
 
   /* Create the dictionary and populate it */
-  *dict = r->dict = dict_create ();
-
-  dict_set_encoding (r->dict, CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
+  *dict = r->dict = dict_create (
+    CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
 
   for (i = 0 ; i < n_var_specs ; ++i )
     {
-      char name[VAR_NAME_LEN + 1];
+      char *name;
 
       /* Probably no data exists for this variable, so allocate a
         default width */
       if ( var_spec[i].width == -1 )
        var_spec[i].width = GNUMERIC_DEFAULT_WIDTH;
 
-      if  ( ! dict_make_unique_var_name (r->dict, var_spec[i].name,
-                                        &vstart, name))
-       {
-         msg (ME, _("Cannot create variable name from %s"), var_spec[i].name);
-         goto error;
-       }
-
+      name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart);
       dict_create_var (r->dict, name, var_spec[i].width);
+      free (name);
     }
 
   /* Create the first case, and cache it */
index 6bb5a6b7d9324c97ba2f4e6ff86bc67b8b7aece1..b313fc78768cf446975156c6d68647f277a72d4b 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
@@ -24,9 +24,9 @@ struct casereader;
 
 struct gnumeric_read_info
 {
-  char *sheet_name ;
-  char *file_name ;
-  char *cell_range ;
+  char *sheet_name ;            /* In UTF-8. */
+  char *file_name ;             /* In filename encoding. */
+  char *cell_range ;            /* In UTF-8. */
   int sheet_index ;
   bool read_names ;
   int asw ;
index 7bd2261e60f15ac8f162996b7ee346c1b0eb5468..f1c22ef1b567223579586ca8ac6f24fd3f4e3722 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2005, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2005, 2009, 2010, 2011 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 "identifier.h"
 
+#include "data/identifier.h"
 
-#include <assert.h>
 #include <string.h>
-#include <libpspp/assertion.h>
+#include <unictype.h>
+
+#include "libpspp/assertion.h"
+
+#include "gl/c-ctype.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Tokens. */
+
+/* Returns TYPE as a string, e.g. "ID" for T_ID. */
+const char *
+token_type_to_name (enum token_type type)
+{
+  switch (type)
+    {
+#define TOKEN_TYPE(TYPE) case T_##TYPE: return #TYPE;
+      TOKEN_TYPES
+#undef TOKEN_TYPE
+    case TOKEN_N_TYPES:
+    default:
+      return "unknown token type";
+    }
+}
+
+/* Returns an ASCII string that yields TOKEN if it appeared in a syntax file,
+   as a statically allocated constant string.  This function returns NULL for
+   tokens that don't have any fixed string representation, such as identifier
+   and number tokens. */
+const char *
+token_type_to_string (enum token_type token)
+{
+  switch (token)
+    {
+    case T_ID:
+    case T_POS_NUM:
+    case T_NEG_NUM:
+    case T_STRING:
+    case T_STOP:
+      return NULL;
+
+    case T_ENDCMD:
+      return ".";
+
+    case T_PLUS:
+      return "+";
+
+    case T_DASH:
+      return "-";
+
+    case T_ASTERISK:
+      return "*";
+
+    case T_SLASH:
+      return "/";
+
+    case T_EQUALS:
+      return "=";
+
+    case T_LPAREN:
+      return "(";
+
+    case T_RPAREN:
+      return ")";
+
+    case T_LBRACK:
+      return "[";
+
+    case T_RBRACK:
+      return "]";
+
+    case T_COMMA:
+      return ",";
+
+    case T_AND:
+      return "AND";
+
+    case T_OR:
+      return "OR";
+
+    case T_NOT:
+      return "NOT";
+
+    case T_EQ:
+      return "EQ";
+
+    case T_GE:
+      return ">=";
+
+    case T_GT:
+      return ">";
+
+    case T_LE:
+      return "<=";
+
+    case T_LT:
+      return "<";
+
+    case T_NE:
+      return "~=";
+
+    case T_ALL:
+      return "ALL";
+
+    case T_BY:
+      return "BY";
+
+    case T_TO:
+      return "TO";
+
+    case T_WITH:
+      return "WITH";
+
+    case T_EXP:
+      return "**";
+
+    case TOKEN_N_TYPES:
+      NOT_REACHED ();
+    }
+
+  NOT_REACHED ();
+}
 
 /* Recognizing identifiers. */
 
-/* Returns true if C may be the first character in an
+static bool
+is_ascii_id1 (unsigned char c)
+{
+  return c_isalpha (c) || c == '@' || c == '#' || c == '$';
+}
+
+static bool
+is_ascii_idn (unsigned char c)
+{
+  return is_ascii_id1 (c) || isdigit (c) || c == '.' || c == '_';
+}
+
+/* Returns true if C may be the first byte in an identifier in the current
+   locale.
+
+   (PSPP is transitioning to using Unicode internally for syntax, so please
+   use lex_uc_is_id1() instead, if possible.) */
+bool
+lex_is_id1 (char c)
+{
+  return is_ascii_id1 (c) || (unsigned char) c >= 128;
+}
+
+/* Returns true if C may be a byte in an identifier other than the first.
+
+   (PSPP is transitioning to using Unicode internally for syntax, so please
+   use lex_uc_is_idn() instead, if possible.) */
+bool
+lex_is_idn (char c)
+{
+  return is_ascii_idn (c) || (unsigned char) c >= 128;
+}
+
+/* Returns true if Unicode code point UC may be the first character in an
    identifier in the current locale. */
 bool
-lex_is_id1 (char c_)
+lex_uc_is_id1 (ucs4_t uc)
 {
-  unsigned char c = c_;
-  return isalpha (c) || c == '@' || c == '#' || c == '$' || c >= 128;
+  return is_ascii_id1 (uc) || (uc >= 0x80 && uc_is_property_id_start (uc));
 }
 
+/* Returns true if Unicode code point UC may be a character in an identifier
+   other than the first. */
+bool
+lex_uc_is_idn (ucs4_t uc)
+{
+  return (is_ascii_id1 (uc) || isdigit (uc) || uc == '.' || uc == '_'
+          || (uc >= 0x80 && uc_is_property_id_continue (uc)));
+}
 
-/* Returns true if C may be a character in an identifier other
-   than the first. */
+/* Returns true if Unicode code point UC is a space that separates tokens. */
 bool
-lex_is_idn (char c_)
+lex_uc_is_space (ucs4_t uc)
 {
-  unsigned char c = c_;
-  return lex_is_id1 (c) || isdigit (c) || c == '.' || c == '_';
+  /* These are all of the Unicode characters in category Zs, Zl, or Zp.  */
+  return (uc == ' ' || (uc <= 0x000d && uc >= 0x0009)
+          || (uc >= 0x80
+              && (uc == 0xa0 || uc == 0x85 || uc == 0x1680 || uc == 0x180e
+                  || (uc >= 0x2000 && uc <= 0x200a)
+                  || uc == 0x2028 || uc == 0x2029 || uc == 0x202f
+                  || uc == 0x205f || uc == 0x3000)));
 }
 
+
 /* Returns the length of the longest prefix of STRING that forms
    a valid identifier.  Returns zero if STRING does not begin
    with a valid identifier.  */
@@ -71,7 +237,10 @@ lex_id_get_length (struct substring string)
 
    Keywords match if one of the following is true: KEYWORD and
    TOKEN are identical, or TOKEN is at least 3 characters long
-   and those characters are identical to KEYWORD. */
+   and those characters are identical to KEYWORD.  (Letters that
+   differ only in case are considered identical.)
+
+   KEYWORD must be ASCII, but TOKEN may be ASCII or UTF-8. */
 bool
 lex_id_match (struct substring keyword, struct substring token)
 {
@@ -79,7 +248,9 @@ lex_id_match (struct substring keyword, struct substring token)
 }
 
 /* Returns true if TOKEN is a case-insensitive match for at least
-   the first N characters of KEYWORD. */
+   the first N characters of KEYWORD.
+
+   KEYWORD must be ASCII, but TOKEN may be ASCII or UTF-8. */
 bool
 lex_id_match_n (struct substring keyword, struct substring token, size_t n)
 {
@@ -119,7 +290,7 @@ static const size_t keyword_cnt = sizeof keywords / sizeof *keywords;
 
 /* Returns true if TOKEN is representable as a keyword. */
 bool
-lex_is_keyword (int token)
+lex_is_keyword (enum token_type token)
 {
   const struct keyword *kw;
   for (kw = keywords; kw < &keywords[keyword_cnt]; kw++)
@@ -143,20 +314,3 @@ lex_id_to_token (struct substring id)
 
   return T_ID;
 }
-
-/* Returns the name for the given keyword token type. */
-const char *
-lex_id_name (int token)
-{
-  const struct keyword *kw;
-
-  for (kw = keywords; kw < &keywords[keyword_cnt]; kw++)
-    if (kw->token == token)
-      {
-        /* A "struct substring" is not guaranteed to be
-           null-terminated, as our caller expects, but in this
-           case it always will be. */
-        return ss_data (kw->identifier);
-      }
-  NOT_REACHED ();
-}
index 352ef2eafc1b3b381a82d7ee55e96b4dc344623e..7f2f904239167f1c5c4200a570621dd7d83cf66a 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, 2011 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 <ctype.h>
 #include <stdbool.h>
-#include <sys/types.h>
-#include <libpspp/str.h>
+#include <unitypes.h>
+#include "libpspp/str.h"
+
+#define TOKEN_TYPES                                                     \
+    TOKEN_TYPE(ID)                         /* Identifier. */            \
+    TOKEN_TYPE(POS_NUM)                    /* Positive number. */       \
+    TOKEN_TYPE(NEG_NUM)                    /* Negative number. */       \
+    TOKEN_TYPE(STRING)                     /* Quoted string. */         \
+    TOKEN_TYPE(STOP)                       /* End of input. */          \
+                                                                        \
+    TOKEN_TYPE(ENDCMD)                     /* . */                      \
+    TOKEN_TYPE(PLUS)                       /* + */                      \
+    TOKEN_TYPE(DASH)                       /* - */                      \
+    TOKEN_TYPE(ASTERISK)                   /* * */                      \
+    TOKEN_TYPE(SLASH)                      /* / */                      \
+    TOKEN_TYPE(EQUALS)                     /* = */                      \
+    TOKEN_TYPE(LPAREN)                     /* ( */                      \
+    TOKEN_TYPE(RPAREN)                     /* ) */                      \
+    TOKEN_TYPE(LBRACK)                     /* [ */                      \
+    TOKEN_TYPE(RBRACK)                     /* ] */                      \
+    TOKEN_TYPE(COMMA)                      /* , */                      \
+                                                                        \
+    TOKEN_TYPE(AND)                        /* AND */                    \
+    TOKEN_TYPE(OR)                         /* OR */                     \
+    TOKEN_TYPE(NOT)                        /* NOT */                    \
+                                                                        \
+    TOKEN_TYPE(EQ)                         /* EQ */                     \
+    TOKEN_TYPE(GE)                         /* GE or >= */               \
+    TOKEN_TYPE(GT)                         /* GT or > */                \
+    TOKEN_TYPE(LE)                         /* LE or <= */               \
+    TOKEN_TYPE(LT)                         /* LT or < */                \
+    TOKEN_TYPE(NE)                         /* NE or ~= */               \
+                                                                        \
+    TOKEN_TYPE(ALL)                        /* ALL */                    \
+    TOKEN_TYPE(BY)                         /* BY */                     \
+    TOKEN_TYPE(TO)                         /* TO */                     \
+    TOKEN_TYPE(WITH)                       /* WITH */                   \
+                                                                        \
+    TOKEN_TYPE(EXP)                        /* ** */
 
 /* Token types. */
-enum
+enum token_type
   {
-    T_ID = 256, /* Identifier. */
-    T_POS_NUM, /* Positive number. */
-    T_NEG_NUM, /* Negative number. */
-    T_STRING,  /* Quoted string. */
-    T_STOP,    /* End of input. */
+#define TOKEN_TYPE(TYPE) T_##TYPE,
+    TOKEN_TYPES
+    TOKEN_N_TYPES
+#undef TOKEN_TYPE
+  };
 
-    T_AND,     /* AND */
-    T_OR,      /* OR */
-    T_NOT,     /* NOT */
+const char *token_type_to_name (enum token_type);
+const char *token_type_to_string (enum token_type);
 
-    T_EQ,      /* EQ */
-    T_GE,      /* GE or >= */
-    T_GT,      /* GT or > */
-    T_LE,      /* LE or <= */
-    T_LT,      /* LT or < */
-    T_NE,      /* NE or ~= */
+/* Tokens. */
+bool lex_is_keyword (enum token_type);
 
-    T_ALL,     /* ALL */
-    T_BY,      /* BY */
-    T_TO,      /* TO */
-    T_WITH,    /* WITH */
+/* Validating identifiers. */
+#define ID_MAX_LEN 64          /* Maximum length of identifier, in bytes. */
 
-    T_EXP,     /* ** */
-  };
-
-/* Tokens. */
-bool lex_is_keyword (int token);
+bool id_is_valid (const char *id, const char *dict_encoding, bool issue_error);
+bool id_is_plausible (const char *id, bool issue_error);
 
 /* Recognizing identifiers. */
 bool lex_is_id1 (char);
 bool lex_is_idn (char);
+bool lex_uc_is_id1 (ucs4_t);
+bool lex_uc_is_idn (ucs4_t);
+bool lex_uc_is_space (ucs4_t);
 size_t lex_id_get_length (struct substring);
 
 /* Comparing identifiers. */
@@ -64,7 +94,4 @@ bool lex_id_match_n (struct substring keyword, struct substring token,
                      size_t n);
 int lex_id_to_token (struct substring);
 
-/* Identifier names. */
-const char *lex_id_name (int);
-
 #endif /* !data/identifier.h */
diff --git a/src/data/identifier2.c b/src/data/identifier2.c
new file mode 100644 (file)
index 0000000..3b6458f
--- /dev/null
@@ -0,0 +1,133 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2005, 2009, 2010, 2011 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 file implements parts of identifier.h that call the msg() function.
+   This allows test programs that do not use those functions to avoid linking
+   additional object files. */
+
+#include <config.h>
+
+#include "data/identifier.h"
+
+#include <string.h>
+#include <unistr.h>
+
+#include "libpspp/cast.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+
+#include "gl/c-ctype.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Returns true if UTF-8 string ID is an acceptable identifier in encoding
+   DICT_ENCODING (UTF-8 if null), false otherwise.  If ISSUE_ERROR is true,
+   issues an explanatory error message on failure. */
+bool
+id_is_valid (const char *id, const char *dict_encoding, bool issue_error)
+{
+  size_t dict_len;
+
+  if (!id_is_plausible (id, issue_error))
+    return false;
+
+  if (dict_encoding != NULL)
+    {
+      /* XXX need to reject recoded strings that contain the fallback
+         character. */
+      dict_len = recode_string_len (dict_encoding, "UTF-8", id, -1);
+    }
+  else
+    dict_len = strlen (id);
+
+  if (dict_len > ID_MAX_LEN)
+    {
+      if (issue_error)
+        msg (SE, _("Identifier `%s' exceeds %d-byte limit."),
+             id, ID_MAX_LEN);
+      return false;
+    }
+
+  return true;
+}
+
+/* Returns true if UTF-8 string ID is an plausible identifier, false
+   otherwise.  If ISSUE_ERROR is true, issues an explanatory error message on
+   failure.  */
+bool
+id_is_plausible (const char *id, bool issue_error)
+{
+  const uint8_t *bad_unit;
+  const uint8_t *s;
+  char ucname[16];
+  int mblen;
+  ucs4_t uc;
+
+  /* ID cannot be the empty string. */
+  if (id[0] == '\0')
+    {
+      if (issue_error)
+        msg (SE, _("Identifier cannot be empty string."));
+      return false;
+    }
+
+  /* ID cannot be a reserved word. */
+  if (lex_id_to_token (ss_cstr (id)) != T_ID)
+    {
+      if (issue_error)
+        msg (SE, _("`%s' may not be used as an identifier because it "
+                   "is a reserved word."), id);
+      return false;
+    }
+
+  bad_unit = u8_check (CHAR_CAST (const uint8_t *, id), strlen (id));
+  if (bad_unit != NULL)
+    {
+      /* If this message ever appears, it probably indicates a PSPP bug since
+         it shouldn't be possible to get invalid UTF-8 this far. */
+      if (issue_error)
+        msg (SE, _("`%s' may not be used as an identifier because it "
+                   "contains ill-formed UTF-8 at byte offset %tu."),
+             id, CHAR_CAST (const char *, bad_unit) - id);
+      return false;
+    }
+
+  /* Check that it is a valid identifier. */
+  mblen = u8_strmbtouc (&uc, CHAR_CAST (uint8_t *, id));
+  if (!lex_uc_is_id1 (uc))
+    {
+      if (issue_error)
+        msg (SE, _("Character %s (in `%s') may not appear "
+                   "as the first character in a identifier."),
+             uc_name (uc, ucname), id);
+      return false;
+    }
+
+  for (s = CHAR_CAST (uint8_t *, id + mblen);
+       (mblen = u8_strmbtouc (&uc, s)) != 0;
+        s += mblen)
+    if (!lex_uc_is_idn (uc))
+      {
+        if (issue_error)
+          msg (SE, _("Character %s (in `%s') may not appear in an "
+                     "identifier."),
+               uc_name (uc, ucname), id);
+        return false;
+      }
+
+  return true;
+}
index 44897d165a3537fa69d9cdaf7c3418e24031bfab..bc68b938d5b0169ad0278a8ca760060c5e2c931a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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/lazy-casereader.h>
+#include "data/lazy-casereader.h"
 
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casereader-provider.h>
-#include <libpspp/assertion.h>
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casereader-provider.h"
+#include "libpspp/assertion.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A lazy casereader's auxiliary data. */
 struct lazy_casereader
index 561d98eb943e0ff50fca1600957eb2a646bc5045..ed0e37b4f92e5c4ea673329cca7535a8081f7df5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 @@
 #define DATA_LAZY_CASEREADER_H 1
 
 #include <stdbool.h>
-#include <data/case.h>
+#include "data/case.h"
 
 struct casereader *lazy_casereader_create (const struct caseproto *,
                                            casenumber case_cnt,
index 61bb9bcb13c4968a4500fc4fc98ee13e2f631c1b..0fc9d01af01ae5a7842aebf3a8285217485de3ca 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009, 2011 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/missing-values.h>
+
+#include "data/missing-values.h"
+
 #include <assert.h>
 #include <stdlib.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
 
 /* Types of user-missing values.
    Invisible--use access functions defined below instead. */
index d1807b96f301000f807ccc87fb696d735562530e..38b0ab2d5266e88192342166df828cd7a98e2bd9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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 <stdlib.h>
 
 #include "data/dictionary.h"
+#include "data/identifier.h"
 #include "data/val-type.h"
 #include "data/variable.h"
+#include "libpspp/message.h"
 
 #include "gl/xalloc.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 /* Creates and returns a clone of OLD.  The caller is responsible for freeing
    the new multiple response set (using mrset_destroy()). */
 struct mrset *
@@ -62,9 +67,31 @@ mrset_destroy (struct mrset *mrset)
     }
 }
 
+/* Returns true if the UTF-8 encoded NAME is a valid name for a multiple
+   response set in a dictionary encoded in DICT_ENCODING, false otherwise.  If
+   ISSUE_ERROR is true, issues an explanatory error message on failure. */
+bool
+mrset_is_valid_name (const char *name, const char *dict_encoding,
+                     bool issue_error)
+{
+  if (!id_is_valid (name, dict_encoding, issue_error))
+    return false;
+
+  if (name[0] != '$')
+    {
+      if (issue_error)
+        msg (SE, _("%s is not a valid name for a multiple response "
+                   "set.  Multiple response set names must begin with "
+                   "`$'."), name);
+      return false;
+    }
+
+  return true;
+}
+
 /* Checks various constraints on MRSET:
 
-   - MRSET has a valid name for a multiple response set (beginning with '$').
+   - MRSET's name begins with '$' and is valid as an identifier in DICT.
 
    - MRSET has a valid type.
 
@@ -85,7 +112,7 @@ mrset_ok (const struct mrset *mrset, const struct dictionary *dict)
   size_t i;
 
   if (mrset->name == NULL
-      || mrset->name[0] != '$'
+      || !mrset_is_valid_name (mrset->name, dict_get_encoding (dict), false)
       || (mrset->type != MRSET_MD && mrset->type != MRSET_MC)
       || mrset->vars == NULL
       || mrset->n_vars < 2)
index c531db7a016791227c6bafba44e99e1ba9240a25..9971924e0d39d2d9c1adb044e2c033d39b9ab77f 100644 (file)
@@ -61,8 +61,8 @@ enum mrset_md_cat_source
 /* A multiple response set. */
 struct mrset
   {
-    char *name;                 /* Name for syntax.  Always begins with "$". */
-    char *label;                /* Human-readable label for group. */
+    char *name;                 /* UTF-8 encoded name beginning with "$". */
+    char *label;                /* Human-readable UTF-8 label for group. */
     enum mrset_type type;       /* Group type. */
     struct variable **vars;     /* Constituent variables. */
     size_t n_vars;              /* Number of constituent variables. */
@@ -77,6 +77,9 @@ struct mrset
 struct mrset *mrset_clone (const struct mrset *);
 void mrset_destroy (struct mrset *);
 
+bool mrset_is_valid_name (const char *name, const char *dict_encoding,
+                          bool issue_error);
+
 bool mrset_ok (const struct mrset *, const struct dictionary *);
 
 #endif /* data/mrset.h */
index adf177bee71c7db83104a6789ee1b0f5053a0cba..58d4d03985688b5a39e03872811b0f2038907c6b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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,7 +15,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "por-file-reader.h"
+
+#include "data/por-file-reader.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <data/casereader-provider.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/file-name.h>
-#include <data/format.h>
-#include <data/missing-values.h>
-#include <data/short-names.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/casereader-provider.h"
+#include "data/casereader.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/short-names.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -103,10 +106,11 @@ error (struct pfm_reader *r, const char *msg, ...)
 
   m.category = MSG_C_GENERAL;
   m.severity = MSG_S_ERROR;
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = 0;
-  m.where.last_column = 0;
+  m.file_name = NULL;
+  m.first_line = 0;
+  m.last_line = 0;
+  m.first_column = 0;
+  m.last_column = 0;
   m.text = ds_cstr (&text);
 
   msg_emit (&m);
@@ -134,10 +138,11 @@ warning (struct pfm_reader *r, const char *msg, ...)
 
   m.category = MSG_C_GENERAL;
   m.severity = MSG_S_WARNING;
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = 0;
-  m.where.last_column = 0;
+  m.file_name = NULL;
+  m.first_line = 0;
+  m.last_line = 0;
+  m.first_column = 0;
+  m.last_column = 0;
   m.text = ds_cstr (&text);
 
   msg_emit (&m);
@@ -246,7 +251,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
   struct pool *volatile pool = NULL;
   struct pfm_reader *volatile r = NULL;
 
-  *dict = dict_create ();
+  *dict = dict_create (get_default_encoding ());
 
   /* Create and initialize reader. */
   pool = pool_create ();
@@ -680,7 +685,8 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       for (j = 0; j < 6; j++)
         fmt[j] = read_int (r);
 
-      if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
+      if (!dict_id_is_valid (dict, name, false)
+          || *name == '#' || *name == '$')
         error (r, _("Invalid variable name `%s' in position %d."), name, i);
       str_uppercase (name);
 
@@ -690,17 +696,15 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       v = dict_create_var (dict, name, width);
       if (v == NULL)
         {
-          int i;
-          for (i = 1; i < 100000; i++)
+          unsigned long int i;
+          for (i = 1; ; i++)
             {
-              char try_name[VAR_NAME_LEN + 1];
-              sprintf (try_name, "%.*s_%d", VAR_NAME_LEN - 6, name, i);
+              char try_name[8 + 1 + INT_STRLEN_BOUND (i) + 1];
+              sprintf (try_name, "%s_%lu", name, i);
               v = dict_create_var (dict, try_name, width);
               if (v != NULL)
                 break;
             }
-          if (v == NULL)
-            error (r, _("Duplicate variable name %s in position %d."), name, i);
           warning (r, _("Duplicate variable name %s in position %d renamed "
                         "to %s."), name, i, var_get_name (v));
         }
@@ -742,7 +746,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
         {
           char label[256];
           read_string (r, label);
-          var_set_label (v, label);
+          var_set_label (v, label, false); /* XXX */
         }
     }
 
@@ -832,7 +836,7 @@ read_documents (struct pfm_reader *r, struct dictionary *dict)
     {
       char line[256];
       read_string (r, line);
-      dict_add_document_line (dict, line);
+      dict_add_document_line (dict, line, false);
     }
 }
 
index c5f758a1e5db1a1a16545fdd7cd35cf86e2f322c..3c475d30b58d83b9e0217e88d8d22d05afe4383b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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,7 +15,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "por-file-writer.h"
+
+#include "data/por-file-writer.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <sys/stat.h>
 #include <time.h>
 
-#include <data/case.h>
-#include <data/casewriter-provider.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/file-name.h>
-#include <data/format.h>
-#include <data/make-file.h>
-#include <data/missing-values.h>
-#include <data/short-names.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <libpspp/version.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casewriter-provider.h"
+#include "data/casewriter.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/format.h"
+#include "data/make-file.h"
+#include "data/missing-values.h"
+#include "data/short-names.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -419,7 +419,7 @@ write_value_labels (struct pfm_writer *w, const struct dictionary *dict)
         {
           const struct val_lab *vl = labels[i];
           write_value (w, val_lab_get_value (vl), var_get_width (v));
-          write_string (w, val_lab_get_label (vl));
+          write_string (w, val_lab_get_escaped_label (vl));
         }
       free (labels);
     }
@@ -436,10 +436,7 @@ write_documents (struct pfm_writer *w, const struct dictionary *dict)
   buf_write (w, "E", 1);
   write_int (w, line_cnt);
   for (i = 0; i < line_cnt; i++)
-    {
-      dict_get_document_line (dict, i, &line);
-      write_string (w, ds_cstr (&line));
-    }
+    write_string (w, dict_get_document_line (dict, i));
   ds_destroy (&line);
 }
 
diff --git a/src/data/procedure.c b/src/data/procedure.c
deleted file mode 100644 (file)
index fa52806..0000000
+++ /dev/null
@@ -1,816 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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/procedure.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "data/case.h"
-#include "data/case-map.h"
-#include "data/caseinit.h"
-#include "data/casereader.h"
-#include "data/casereader-provider.h"
-#include "data/casereader-shim.h"
-#include "data/casewriter.h"
-#include "data/dictionary.h"
-#include "data/file-handle-def.h"
-#include "data/transformations.h"
-#include "data/variable.h"
-#include "libpspp/deque.h"
-#include "libpspp/misc.h"
-#include "libpspp/str.h"
-#include "libpspp/taint.h"
-#include "libpspp/i18n.h"
-
-#include "gl/minmax.h"
-#include "gl/xalloc.h"
-
-struct dataset {
-  /* Cases are read from source,
-     their transformation variables are initialized,
-     pass through permanent_trns_chain (which transforms them into
-     the format described by permanent_dict),
-     are written to sink,
-     pass through temporary_trns_chain (which transforms them into
-     the format described by dict),
-     and are finally passed to the procedure. */
-  struct casereader *source;
-  struct caseinit *caseinit;
-  struct trns_chain *permanent_trns_chain;
-  struct dictionary *permanent_dict;
-  struct casewriter *sink;
-  struct trns_chain *temporary_trns_chain;
-  struct dictionary *dict;
-
-  /* Callback which occurs whenever the transformation chain(s) have
-     been modified */
-  transformation_change_callback_func *xform_callback;
-  void *xform_callback_aux;
-
-  /* If true, cases are discarded instead of being written to
-     sink. */
-  bool discard_output;
-
-  /* The transformation chain that the next transformation will be
-     added to. */
-  struct trns_chain *cur_trns_chain;
-
-  /* The case map used to compact a case, if necessary;
-     otherwise a null pointer. */
-  struct case_map *compactor;
-
-  /* Time at which proc was last invoked. */
-  time_t last_proc_invocation;
-
-  /* Cases just before ("lagging") the current one. */
-  int n_lag;                   /* Number of cases to lag. */
-  struct deque lag;             /* Deque of lagged cases. */
-  struct ccase **lag_cases;     /* Lagged cases managed by deque. */
-
-  /* Procedure data. */
-  enum
-    {
-      PROC_COMMITTED,           /* No procedure in progress. */
-      PROC_OPEN,                /* proc_open called, casereader still open. */
-      PROC_CLOSED               /* casereader from proc_open destroyed,
-                                   but proc_commit not yet called. */
-    }
-  proc_state;
-  casenumber cases_written;     /* Cases output so far. */
-  bool ok;                      /* Error status. */
-  struct casereader_shim *shim; /* Shim on proc_open() casereader. */
-
-  void (*callback) (void *); /* Callback for when the dataset changes */
-  void *cb_data;
-
-}; /* struct dataset */
-
-
-static void add_case_limit_trns (struct dataset *ds);
-static void add_filter_trns (struct dataset *ds);
-
-static void update_last_proc_invocation (struct dataset *ds);
-
-static void
-dataset_set_unsaved (const struct dataset *ds)
-{
-  if (ds->callback) ds->callback (ds->cb_data);
-}
-
-\f
-/* Public functions. */
-
-void
-dataset_set_callback (struct dataset *ds, void (*cb) (void *), void *cb_data)
-{
-  ds->callback = cb;
-  ds->cb_data = cb_data;
-}
-
-
-/* Returns the last time the data was read. */
-time_t
-time_of_last_procedure (struct dataset *ds)
-{
-  if (ds->last_proc_invocation == 0)
-    update_last_proc_invocation (ds);
-  return ds->last_proc_invocation;
-}
-\f
-/* Regular procedure. */
-
-/* Executes any pending transformations, if necessary.
-   This is not identical to the EXECUTE command in that it won't
-   always read the source data.  This can be important when the
-   source data is given inline within BEGIN DATA...END FILE. */
-bool
-proc_execute (struct dataset *ds)
-{
-  bool ok;
-
-  if ((ds->temporary_trns_chain == NULL
-       || trns_chain_is_empty (ds->temporary_trns_chain))
-      && trns_chain_is_empty (ds->permanent_trns_chain))
-    {
-      ds->n_lag = 0;
-      ds->discard_output = false;
-      dict_set_case_limit (ds->dict, 0);
-      dict_clear_vectors (ds->dict);
-      return true;
-    }
-
-  ok = casereader_destroy (proc_open (ds));
-  return proc_commit (ds) && ok;
-}
-
-static const struct casereader_class proc_casereader_class;
-
-/* Opens dataset DS for reading cases with proc_read.  If FILTER is true, then
-   cases filtered out with FILTER BY will not be included in the casereader
-   (which is usually desirable).  If FILTER is false, all cases will be
-   included regardless of FILTER BY settings.
-
-   proc_commit must be called when done. */
-struct casereader *
-proc_open_filtering (struct dataset *ds, bool filter)
-{
-  struct casereader *reader;
-
-  assert (ds->source != NULL);
-  assert (ds->proc_state == PROC_COMMITTED);
-
-  update_last_proc_invocation (ds);
-
-  caseinit_mark_for_init (ds->caseinit, ds->dict);
-
-  /* Finish up the collection of transformations. */
-  add_case_limit_trns (ds);
-  if (filter)
-    add_filter_trns (ds);
-  trns_chain_finalize (ds->cur_trns_chain);
-
-  /* Make permanent_dict refer to the dictionary right before
-     data reaches the sink. */
-  if (ds->permanent_dict == NULL)
-    ds->permanent_dict = ds->dict;
-
-  /* Prepare sink. */
-  if (!ds->discard_output)
-    {
-      struct dictionary *pd = ds->permanent_dict;
-      size_t compacted_value_cnt = dict_count_values (pd, 1u << DC_SCRATCH);
-      if (compacted_value_cnt < dict_get_next_value_idx (pd))
-        {
-          struct caseproto *compacted_proto;
-          compacted_proto = dict_get_compacted_proto (pd, 1u << DC_SCRATCH);
-          ds->compactor = case_map_to_compact_dict (pd, 1u << DC_SCRATCH);
-          ds->sink = autopaging_writer_create (compacted_proto);
-          caseproto_unref (compacted_proto);
-        }
-      else
-        {
-          ds->compactor = NULL;
-          ds->sink = autopaging_writer_create (dict_get_proto (pd));
-        }
-    }
-  else
-    {
-      ds->compactor = NULL;
-      ds->sink = NULL;
-    }
-
-  /* Allocate memory for lagged cases. */
-  ds->lag_cases = deque_init (&ds->lag, ds->n_lag, sizeof *ds->lag_cases);
-
-  ds->proc_state = PROC_OPEN;
-  ds->cases_written = 0;
-  ds->ok = true;
-
-  /* FIXME: use taint in dataset in place of `ok'? */
-  /* FIXME: for trivial cases we can just return a clone of
-     ds->source? */
-
-  /* Create casereader and insert a shim on top.  The shim allows us to
-     arbitrarily extend the casereader's lifetime, by slurping the cases into
-     the shim's buffer in proc_commit().  That is especially useful when output
-     table_items are generated directly from the procedure casereader (e.g. by
-     the LIST procedure) when we are using an output driver that keeps a
-     reference to the output items passed to it (e.g. the GUI output driver in
-     PSPPIRE). */
-  reader = casereader_create_sequential (NULL, dict_get_proto (ds->dict),
-                                         CASENUMBER_MAX,
-                                         &proc_casereader_class, ds);
-  ds->shim = casereader_shim_insert (reader);
-  return reader;
-}
-
-/* Opens dataset DS for reading cases with proc_read.
-   proc_commit must be called when done. */
-struct casereader *
-proc_open (struct dataset *ds)
-{
-  return proc_open_filtering (ds, true);
-}
-
-/* Returns true if a procedure is in progress, that is, if
-   proc_open has been called but proc_commit has not. */
-bool
-proc_is_open (const struct dataset *ds)
-{
-  return ds->proc_state != PROC_COMMITTED;
-}
-
-/* "read" function for procedure casereader. */
-static struct ccase *
-proc_casereader_read (struct casereader *reader UNUSED, void *ds_)
-{
-  struct dataset *ds = ds_;
-  enum trns_result retval = TRNS_DROP_CASE;
-  struct ccase *c;
-
-  assert (ds->proc_state == PROC_OPEN);
-  for (; ; case_unref (c))
-    {
-      casenumber case_nr;
-
-      assert (retval == TRNS_DROP_CASE || retval == TRNS_ERROR);
-      if (retval == TRNS_ERROR)
-        ds->ok = false;
-      if (!ds->ok)
-        return NULL;
-
-      /* Read a case from source. */
-      c = casereader_read (ds->source);
-      if (c == NULL)
-        return NULL;
-      c = case_unshare_and_resize (c, dict_get_proto (ds->dict));
-      caseinit_init_vars (ds->caseinit, c);
-
-      /* Execute permanent transformations.  */
-      case_nr = ds->cases_written + 1;
-      retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE,
-                                   &c, case_nr);
-      caseinit_update_left_vars (ds->caseinit, c);
-      if (retval != TRNS_CONTINUE)
-        continue;
-
-      /* Write case to collection of lagged cases. */
-      if (ds->n_lag > 0)
-        {
-          while (deque_count (&ds->lag) >= ds->n_lag)
-            case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
-          ds->lag_cases[deque_push_front (&ds->lag)] = case_ref (c);
-        }
-
-      /* Write case to replacement active file. */
-      ds->cases_written++;
-      if (ds->sink != NULL)
-        casewriter_write (ds->sink,
-                          case_map_execute (ds->compactor, case_ref (c)));
-
-      /* Execute temporary transformations. */
-      if (ds->temporary_trns_chain != NULL)
-        {
-          retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE,
-                                       &c, ds->cases_written);
-          if (retval != TRNS_CONTINUE)
-            continue;
-        }
-
-      return c;
-    }
-}
-
-/* "destroy" function for procedure casereader. */
-static void
-proc_casereader_destroy (struct casereader *reader, void *ds_)
-{
-  struct dataset *ds = ds_;
-  struct ccase *c;
-
-  /* We are always the subreader for a casereader_buffer, so if we're being
-     destroyed then it's because the casereader_buffer has read all the cases
-     that it ever will. */
-  ds->shim = NULL;
-
-  /* Make sure transformations happen for every input case, in
-     case they have side effects, and ensure that the replacement
-     active file gets all the cases it should. */
-  while ((c = casereader_read (reader)) != NULL)
-    case_unref (c);
-
-  ds->proc_state = PROC_CLOSED;
-  ds->ok = casereader_destroy (ds->source) && ds->ok;
-  ds->source = NULL;
-  proc_set_active_file_data (ds, NULL);
-}
-
-/* Must return false if the source casereader, a transformation,
-   or the sink casewriter signaled an error.  (If a temporary
-   transformation signals an error, then the return value is
-   false, but the replacement active file may still be
-   untainted.) */
-bool
-proc_commit (struct dataset *ds)
-{
-  if (ds->shim != NULL)
-    casereader_shim_slurp (ds->shim);
-
-  assert (ds->proc_state == PROC_CLOSED);
-  ds->proc_state = PROC_COMMITTED;
-
-  dataset_set_unsaved (ds);
-
-  /* Free memory for lagged cases. */
-  while (!deque_is_empty (&ds->lag))
-    case_unref (ds->lag_cases[deque_pop_back (&ds->lag)]);
-  free (ds->lag_cases);
-
-  /* Dictionary from before TEMPORARY becomes permanent. */
-  proc_cancel_temporary_transformations (ds);
-
-  if (!ds->discard_output)
-    {
-      /* Finish compacting. */
-      if (ds->compactor != NULL)
-        {
-          case_map_destroy (ds->compactor);
-          ds->compactor = NULL;
-
-          dict_delete_scratch_vars (ds->dict);
-          dict_compact_values (ds->dict);
-        }
-
-      /* Old data sink becomes new data source. */
-      if (ds->sink != NULL)
-        ds->source = casewriter_make_reader (ds->sink);
-    }
-  else
-    {
-      ds->source = NULL;
-      ds->discard_output = false;
-    }
-  ds->sink = NULL;
-
-  caseinit_clear (ds->caseinit);
-  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
-
-  dict_clear_vectors (ds->dict);
-  ds->permanent_dict = NULL;
-  return proc_cancel_all_transformations (ds) && ds->ok;
-}
-
-/* Casereader class for procedure execution. */
-static const struct casereader_class proc_casereader_class =
-  {
-    proc_casereader_read,
-    proc_casereader_destroy,
-    NULL,
-    NULL,
-  };
-
-/* Updates last_proc_invocation. */
-static void
-update_last_proc_invocation (struct dataset *ds)
-{
-  ds->last_proc_invocation = time (NULL);
-}
-\f
-/* Returns a pointer to the lagged case from N_BEFORE cases before the
-   current one, or NULL if there haven't been that many cases yet. */
-const struct ccase *
-lagged_case (const struct dataset *ds, int n_before)
-{
-  assert (n_before >= 1);
-  assert (n_before <= ds->n_lag);
-
-  if (n_before <= deque_count (&ds->lag))
-    return ds->lag_cases[deque_front (&ds->lag, n_before - 1)];
-  else
-    return NULL;
-}
-\f
-/* Returns the current set of permanent transformations,
-   and clears the permanent transformations.
-   For use by INPUT PROGRAM. */
-struct trns_chain *
-proc_capture_transformations (struct dataset *ds)
-{
-  struct trns_chain *chain;
-
-  assert (ds->temporary_trns_chain == NULL);
-  chain = ds->permanent_trns_chain;
-  ds->cur_trns_chain = ds->permanent_trns_chain = trns_chain_create ();
-
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
-
-  return chain;
-}
-
-/* Adds a transformation that processes a case with PROC and
-   frees itself with FREE to the current set of transformations.
-   The functions are passed AUX as auxiliary data. */
-void
-add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *free, void *aux)
-{
-  trns_chain_append (ds->cur_trns_chain, NULL, proc, free, aux);
-  if ( ds->xform_callback)
-    ds->xform_callback (true, ds->xform_callback_aux);
-}
-
-/* Adds a transformation that processes a case with PROC and
-   frees itself with FREE to the current set of transformations.
-   When parsing of the block of transformations is complete,
-   FINALIZE will be called.
-   The functions are passed AUX as auxiliary data. */
-void
-add_transformation_with_finalizer (struct dataset *ds,
-                                  trns_finalize_func *finalize,
-                                   trns_proc_func *proc,
-                                   trns_free_func *free, void *aux)
-{
-  trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux);
-
-  if ( ds->xform_callback)
-    ds->xform_callback (true, ds->xform_callback_aux);
-}
-
-/* Returns the index of the next transformation.
-   This value can be returned by a transformation procedure
-   function to indicate a "jump" to that transformation. */
-size_t
-next_transformation (const struct dataset *ds)
-{
-  return trns_chain_next (ds->cur_trns_chain);
-}
-
-/* Returns true if the next call to add_transformation() will add
-   a temporary transformation, false if it will add a permanent
-   transformation. */
-bool
-proc_in_temporary_transformations (const struct dataset *ds)
-{
-  return ds->temporary_trns_chain != NULL;
-}
-
-/* Marks the start of temporary transformations.
-   Further calls to add_transformation() will add temporary
-   transformations. */
-void
-proc_start_temporary_transformations (struct dataset *ds)
-{
-  if (!proc_in_temporary_transformations (ds))
-    {
-      add_case_limit_trns (ds);
-
-      ds->permanent_dict = dict_clone (ds->dict);
-
-      trns_chain_finalize (ds->permanent_trns_chain);
-      ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create ();
-
-      if ( ds->xform_callback)
-       ds->xform_callback (true, ds->xform_callback_aux);
-    }
-}
-
-/* Converts all the temporary transformations, if any, to
-   permanent transformations.  Further transformations will be
-   permanent.
-   Returns true if anything changed, false otherwise. */
-bool
-proc_make_temporary_transformations_permanent (struct dataset *ds)
-{
-  if (proc_in_temporary_transformations (ds))
-    {
-      trns_chain_finalize (ds->temporary_trns_chain);
-      trns_chain_splice (ds->permanent_trns_chain, ds->temporary_trns_chain);
-      ds->temporary_trns_chain = NULL;
-
-      dict_destroy (ds->permanent_dict);
-      ds->permanent_dict = NULL;
-
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Cancels all temporary transformations, if any.  Further
-   transformations will be permanent.
-   Returns true if anything changed, false otherwise. */
-bool
-proc_cancel_temporary_transformations (struct dataset *ds)
-{
-  if (proc_in_temporary_transformations (ds))
-    {
-      dict_destroy (ds->dict);
-      ds->dict = ds->permanent_dict;
-      ds->permanent_dict = NULL;
-
-      trns_chain_destroy (ds->temporary_trns_chain);
-      ds->temporary_trns_chain = NULL;
-
-      if ( ds->xform_callback)
-       ds->xform_callback (!trns_chain_is_empty (ds->permanent_trns_chain),
-                           ds->xform_callback_aux);
-
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Cancels all transformations, if any.
-   Returns true if successful, false on I/O error. */
-bool
-proc_cancel_all_transformations (struct dataset *ds)
-{
-  bool ok;
-  assert (ds->proc_state == PROC_COMMITTED);
-  ok = trns_chain_destroy (ds->permanent_trns_chain);
-  ok = trns_chain_destroy (ds->temporary_trns_chain) && ok;
-  ds->permanent_trns_chain = ds->cur_trns_chain = trns_chain_create ();
-  ds->temporary_trns_chain = NULL;
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
-
-  return ok;
-}
-\f
-
-static void
-dict_callback (struct dictionary *d UNUSED, void *ds_)
-{
-  struct dataset *ds = ds_;
-  dataset_set_unsaved (ds);
-}
-
-/* Initializes procedure handling. */
-struct dataset *
-create_dataset (void)
-{
-  struct dataset *ds = xzalloc (sizeof(*ds));
-  ds->dict = dict_create ();
-
-  dict_set_change_callback (ds->dict, dict_callback, ds);
-
-  dict_set_encoding (ds->dict, get_default_encoding ());
-
-  ds->caseinit = caseinit_create ();
-  proc_cancel_all_transformations (ds);
-  return ds;
-}
-
-
-void
-dataset_add_transform_change_callback (struct dataset *ds,
-                                      transformation_change_callback_func *cb,
-                                      void *aux)
-{
-  ds->xform_callback = cb;
-  ds->xform_callback_aux = aux;
-}
-
-/* Finishes up procedure handling. */
-void
-destroy_dataset (struct dataset *ds)
-{
-  proc_discard_active_file (ds);
-  dict_destroy (ds->dict);
-  caseinit_destroy (ds->caseinit);
-  trns_chain_destroy (ds->permanent_trns_chain);
-
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
-  free (ds);
-}
-
-/* Causes output from the next procedure to be discarded, instead
-   of being preserved for use as input for the next procedure. */
-void
-proc_discard_output (struct dataset *ds)
-{
-  ds->discard_output = true;
-}
-
-/* Discards the active file dictionary, data, and
-   transformations. */
-void
-proc_discard_active_file (struct dataset *ds)
-{
-  assert (ds->proc_state == PROC_COMMITTED);
-
-  dict_clear (ds->dict);
-  fh_set_default_handle (NULL);
-
-  ds->n_lag = 0;
-
-  casereader_destroy (ds->source);
-  ds->source = NULL;
-
-  proc_cancel_all_transformations (ds);
-}
-
-/* Sets SOURCE as the source for procedure input for the next
-   procedure. */
-void
-proc_set_active_file (struct dataset *ds,
-                      struct casereader *source,
-                      struct dictionary *dict)
-{
-  assert (ds->proc_state == PROC_COMMITTED);
-  assert (ds->dict != dict);
-
-  proc_discard_active_file (ds);
-
-  dict_destroy (ds->dict);
-  ds->dict = dict;
-  dict_set_change_callback (ds->dict, dict_callback, ds);
-
-  proc_set_active_file_data (ds, source);
-}
-
-/* Replaces the active file's data by READER without replacing
-   the associated dictionary. */
-bool
-proc_set_active_file_data (struct dataset *ds, struct casereader *reader)
-{
-  casereader_destroy (ds->source);
-  ds->source = reader;
-
-  caseinit_clear (ds->caseinit);
-  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
-
-  return reader == NULL || !casereader_error (reader);
-}
-
-/* Returns true if an active file data source is available, false
-   otherwise. */
-bool
-proc_has_active_file (const struct dataset *ds)
-{
-  return ds->source != NULL;
-}
-
-/* Returns the active file data source from DS, or a null pointer
-   if DS has no data source, and removes it from DS. */
-struct casereader *
-proc_extract_active_file_data (struct dataset *ds)
-{
-  struct casereader *reader = ds->source;
-  ds->source = NULL;
-
-  return reader;
-}
-
-/* Checks whether DS has a corrupted active file.  If so,
-   discards it and returns false.  If not, returns true without
-   doing anything. */
-bool
-dataset_end_of_command (struct dataset *ds)
-{
-  if (ds->source != NULL)
-    {
-      if (casereader_error (ds->source))
-        {
-          proc_discard_active_file (ds);
-          return false;
-        }
-      else
-        {
-          const struct taint *taint = casereader_get_taint (ds->source);
-          taint_reset_successor_taint (CONST_CAST (struct taint *, taint));
-          assert (!taint_has_tainted_successor (taint));
-        }
-    }
-  return true;
-}
-\f
-static trns_proc_func case_limit_trns_proc;
-static trns_free_func case_limit_trns_free;
-
-/* Adds a transformation that limits the number of cases that may
-   pass through, if DS->DICT has a case limit. */
-static void
-add_case_limit_trns (struct dataset *ds)
-{
-  casenumber case_limit = dict_get_case_limit (ds->dict);
-  if (case_limit != 0)
-    {
-      casenumber *cases_remaining = xmalloc (sizeof *cases_remaining);
-      *cases_remaining = case_limit;
-      add_transformation (ds, case_limit_trns_proc, case_limit_trns_free,
-                          cases_remaining);
-      dict_set_case_limit (ds->dict, 0);
-    }
-}
-
-/* Limits the maximum number of cases processed to
-   *CASES_REMAINING. */
-static int
-case_limit_trns_proc (void *cases_remaining_,
-                      struct ccase **c UNUSED, casenumber case_nr UNUSED)
-{
-  size_t *cases_remaining = cases_remaining_;
-  if (*cases_remaining > 0)
-    {
-      (*cases_remaining)--;
-      return TRNS_CONTINUE;
-    }
-  else
-    return TRNS_DROP_CASE;
-}
-
-/* Frees the data associated with a case limit transformation. */
-static bool
-case_limit_trns_free (void *cases_remaining_)
-{
-  size_t *cases_remaining = cases_remaining_;
-  free (cases_remaining);
-  return true;
-}
-\f
-static trns_proc_func filter_trns_proc;
-
-/* Adds a temporary transformation to filter data according to
-   the variable specified on FILTER, if any. */
-static void
-add_filter_trns (struct dataset *ds)
-{
-  struct variable *filter_var = dict_get_filter (ds->dict);
-  if (filter_var != NULL)
-    {
-      proc_start_temporary_transformations (ds);
-      add_transformation (ds, filter_trns_proc, NULL, filter_var);
-    }
-}
-
-/* FILTER transformation. */
-static int
-filter_trns_proc (void *filter_var_,
-                  struct ccase **c UNUSED, casenumber case_nr UNUSED)
-
-{
-  struct variable *filter_var = filter_var_;
-  double f = case_num (*c, filter_var);
-  return (f != 0.0 && !var_is_num_missing (filter_var, f, MV_ANY)
-          ? TRNS_CONTINUE : TRNS_DROP_CASE);
-}
-
-
-struct dictionary *
-dataset_dict (const struct dataset *ds)
-{
-  return ds->dict;
-}
-
-const struct casereader *
-dataset_source (const struct dataset *ds)
-{
-  return ds->source;
-}
-
-void
-dataset_need_lag (struct dataset *ds, int n_before)
-{
-  ds->n_lag = MAX (ds->n_lag, n_before);
-}
diff --git a/src/data/procedure.h b/src/data/procedure.h
deleted file mode 100644 (file)
index bb4dad2..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 PROCEDURE_H
-#define PROCEDURE_H 1
-
-#include <time.h>
-#include <stdbool.h>
-
-#include <data/transformations.h>
-#include <libpspp/compiler.h>
-
-struct casereader;
-struct dataset;
-struct dictionary;
-\f
-/* Transformations. */
-
-void add_transformation (struct dataset *ds,
-                        trns_proc_func *, trns_free_func *, void *);
-void add_transformation_with_finalizer (struct dataset *ds,
-                                       trns_finalize_func *,
-                                        trns_proc_func *,
-                                        trns_free_func *, void *);
-size_t next_transformation (const struct dataset *ds);
-
-bool proc_cancel_all_transformations (struct dataset *ds);
-struct trns_chain *proc_capture_transformations (struct dataset *ds);
-
-void proc_start_temporary_transformations (struct dataset *ds);
-bool proc_in_temporary_transformations (const struct dataset *ds);
-bool proc_make_temporary_transformations_permanent (struct dataset *ds);
-bool proc_cancel_temporary_transformations (struct dataset *ds);
-\f
-/* Procedures. */
-
-struct dictionary ;
-typedef void  replace_source_callback (struct casereader *);
-typedef void  replace_dictionary_callback (struct dictionary *);
-
-typedef void transformation_change_callback_func (bool non_empty, void *aux);
-
-struct dataset * create_dataset (void);
-
-void destroy_dataset (struct dataset *);
-
-void dataset_add_transform_change_callback (struct dataset *,
-                                           transformation_change_callback_func *, void *);
-
-void proc_discard_active_file (struct dataset *);
-void proc_set_active_file (struct dataset *,
-                           struct casereader *, struct dictionary *);
-bool proc_set_active_file_data (struct dataset *, struct casereader *);
-bool proc_has_active_file (const struct dataset *ds);
-struct casereader *proc_extract_active_file_data (struct dataset *);
-
-void proc_discard_output (struct dataset *ds);
-
-bool proc_execute (struct dataset *ds);
-time_t time_of_last_procedure (struct dataset *ds);
-
-struct casereader *proc_open_filtering (struct dataset *, bool filter);
-struct casereader *proc_open (struct dataset *);
-bool proc_is_open (const struct dataset *);
-bool proc_commit (struct dataset *);
-
-bool dataset_end_of_command (struct dataset *);
-\f
-struct dictionary *dataset_dict (const struct dataset *ds);
-const struct casereader *dataset_source (const struct dataset *ds);
-
-
-const struct ccase *lagged_case (const struct dataset *ds, int n_before);
-void dataset_need_lag (struct dataset *ds, int n_before);
-
-void dataset_set_callback (struct dataset *ds, void (*cb) (void *), void *);
-
-#endif /* procedure.h */
index 76b4674dc9d914cabaadce71aef6512be050e683..4cbd8409eae549cf6cd1118a001c698e46a88125 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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/casereader-provider.h>
-#include <libpspp/message.h>
-#include <gl/xalloc.h>
-#include <data/dictionary.h>
+#include "data/psql-reader.h"
+
+#include <inttypes.h>
 #include <math.h>
 #include <stdlib.h>
 
-#include "psql-reader.h"
-#include "variable.h"
-#include "format.h"
-#include "calendar.h"
-
-#include <inttypes.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
+#include "data/calendar.h"
+#include "data/casereader-provider.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
 
-#include "minmax.h"
+#include "gl/xalloc.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -180,15 +181,12 @@ create_var (struct psql_reader *r, const struct fmt_spec *fmt,
 {
   unsigned long int vx = 0;
   struct variable *var;
-  char name[VAR_NAME_LEN + 1];
-
-  if ( ! dict_make_unique_var_name (r->dict, suggested_name, &vx, name))
-    {
-      msg (ME, _("Cannot create variable name from %s"), suggested_name);
-      return NULL;
-    }
+  char *name;
 
+  name = dict_make_unique_var_name (r->dict, suggested_name, &vx);
   var = dict_create_var (r->dict, name, width);
+  free (name);
+
   var_set_both_formats (var, fmt);
 
   if ( col != -1)
@@ -232,6 +230,7 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
   int n_fields, n_tuples;
   PGresult *qres = NULL;
   casenumber n_cases = CASENUMBER_MAX;
+  const char *encoding;
 
   struct psql_reader *r = xzalloc (sizeof *r);
   struct string query ;
@@ -288,21 +287,19 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
 
   r->postgres_epoch = calendar_gregorian_to_offset (2000, 1, 1, NULL);
 
-
-  /* Create the dictionary and populate it */
-  *dict = r->dict = dict_create ();
-
   {
     const int enc = PQclientEncoding (r->conn);
 
     /* According to section 22.2 of the Postgresql manual
        a value of zero (SQL_ASCII) indicates
        "a declaration of ignorance about the encoding".
-       Accordingly, we don't set the dictionary's encoding
+       Accordingly, we use the default encoding
        if we find this value.
     */
-    if ( enc != 0 )
-      dict_set_encoding (r->dict, pg_encoding_to_char (enc));
+    encoding = enc ? pg_encoding_to_char (enc) : get_default_encoding ();
+
+    /* Create the dictionary and populate it */
+    *dict = r->dict = dict_create (encoding);
   }
 
   /*
index 2811daa5f7bcacab52e7520a7fb8901b3eb66253..8fd584c60cdb7cbf7ad1695bf3d6de5e21b1fc6e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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
@@ -18,7 +18,7 @@
 #define PSQL_READER_H 1
 
 #include <stdbool.h>
-#include <libpspp/str.h>
+#include "libpspp/str.h"
 
 struct casereader;
 
diff --git a/src/data/scratch-handle.c b/src/data/scratch-handle.c
deleted file mode 100644 (file)
index 6681936..0000000
+++ /dev/null
@@ -1,33 +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 <stdlib.h>
-#include <data/casereader.h>
-#include <data/scratch-handle.h>
-#include <data/dictionary.h>
-
-/* Destroys HANDLE. */
-void
-scratch_handle_destroy (struct scratch_handle *handle)
-{
-  if (handle != NULL)
-    {
-      dict_destroy (handle->dictionary);
-      casereader_destroy (handle->casereader);
-      free (handle);
-    }
-}
diff --git a/src/data/scratch-handle.h b/src/data/scratch-handle.h
deleted file mode 100644 (file)
index c7775f4..0000000
+++ /dev/null
@@ -1,32 +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 SCRATCH_HANDLE_H
-#define SCRATCH_HANDLE_H 1
-
-#include <stdbool.h>
-
-/* A scratch file. */
-struct scratch_handle
-  {
-    unsigned int unique_id;             /* Identifies this scratch file. */
-    struct dictionary *dictionary;      /* Dictionary. */
-    struct casereader *casereader;      /* Cases. */
-  };
-
-void scratch_handle_destroy (struct scratch_handle *);
-
-#endif /* scratch-handle.h */
diff --git a/src/data/scratch-reader.c b/src/data/scratch-reader.c
deleted file mode 100644 (file)
index 3aa1768..0000000
+++ /dev/null
@@ -1,63 +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 <data/scratch-reader.h>
-
-#include <stdlib.h>
-
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/scratch-handle.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* Opens FH, which must have referent type FH_REF_SCRATCH, and
-   returns a scratch_reader for it, or a null pointer on
-   failure.  Stores the dictionary for the scratch file into
-   *DICT. */
-struct casereader *
-scratch_reader_open (struct file_handle *fh, struct dictionary **dict)
-{
-  struct scratch_handle *sh;
-
-  /* We don't bother doing fh_lock or fh_ref on the file handle,
-     as there's no advantage in this case, and doing these would
-     require us to keep track of the "struct file_handle" and
-     "struct fh_lock" and undo our work later. */
-  assert (fh_get_referent (fh) == FH_REF_SCRATCH);
-
-  sh = fh_get_scratch_handle (fh);
-  if (sh == NULL || sh->casereader == NULL)
-    {
-      msg (SE, _("Scratch file handle %s has not yet been written, "
-                 "using SAVE or another procedure, so it cannot yet "
-                 "be used for reading."),
-           fh_get_name (fh));
-      return NULL;
-    }
-
-  *dict = dict_clone (sh->dictionary);
-  return casereader_clone (sh->casereader);
-}
diff --git a/src/data/scratch-reader.h b/src/data/scratch-reader.h
deleted file mode 100644 (file)
index a5ee005..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 SCRATCH_READER_H
-#define SCRATCH_READER_H 1
-
-#include <stdbool.h>
-
-struct dictionary;
-struct file_handle;
-struct casereader *scratch_reader_open (struct file_handle *,
-                                        struct dictionary **);
-
-#endif /* scratch-reader.h */
diff --git a/src/data/scratch-writer.c b/src/data/scratch-writer.c
deleted file mode 100644 (file)
index 631305f..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 "scratch-writer.h"
-
-#include <stdlib.h>
-
-#include <data/case.h>
-#include <data/case-map.h>
-#include <data/casereader.h>
-#include <data/casewriter-provider.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/scratch-handle.h>
-#include <data/variable.h>
-#include <libpspp/compiler.h>
-#include <libpspp/taint.h>
-
-#include "xalloc.h"
-
-#define N_(msgid) (msgid)
-
-/* A scratch file writer. */
-struct scratch_writer
-  {
-    struct file_handle *fh;             /* Underlying file handle. */
-    struct fh_lock *lock;               /* Exclusive access to file handle. */
-    struct dictionary *dict;            /* Dictionary for subwriter. */
-    struct case_map *compactor;         /* Compacts into dictionary. */
-    struct casewriter *subwriter;       /* Data output. */
-  };
-
-static const struct casewriter_class scratch_writer_casewriter_class;
-
-/* Opens FH, which must have referent type FH_REF_SCRATCH, and
-   returns a scratch_writer for it, or a null pointer on
-   failure.  Cases stored in the scratch_writer will be expected
-   to be drawn from DICTIONARY. */
-struct casewriter *
-scratch_writer_open (struct file_handle *fh,
-                     const struct dictionary *dictionary)
-{
-  struct scratch_writer *writer;
-  struct casewriter *casewriter;
-  struct fh_lock *lock;
-
-  /* Get exclusive write access to handle. */
-  /* TRANSLATORS: this fragment will be interpolated into
-     messages in fh_lock() that identify types of files. */
-  lock = fh_lock (fh, FH_REF_SCRATCH, N_("scratch file"), FH_ACC_WRITE, true);
-  if (lock == NULL)
-    return NULL;
-
-  /* Create writer. */
-  writer = xmalloc (sizeof *writer);
-  writer->lock = lock;
-  writer->fh = fh_ref (fh);
-
-  writer->dict = dict_clone (dictionary);
-  dict_delete_scratch_vars (writer->dict);
-  if (dict_count_values (writer->dict, 0)
-      < dict_get_next_value_idx (writer->dict))
-    {
-      writer->compactor = case_map_to_compact_dict (writer->dict, 0);
-      dict_compact_values (writer->dict);
-    }
-  else
-    writer->compactor = NULL;
-  writer->subwriter = autopaging_writer_create (dict_get_proto (writer->dict));
-
-  casewriter = casewriter_create (dict_get_proto (writer->dict),
-                                  &scratch_writer_casewriter_class, writer);
-  taint_propagate (casewriter_get_taint (writer->subwriter),
-                   casewriter_get_taint (casewriter));
-  return casewriter;
-}
-
-/* Writes case C to WRITER. */
-static void
-scratch_writer_casewriter_write (struct casewriter *w UNUSED, void *writer_,
-                                 struct ccase *c)
-{
-  struct scratch_writer *writer = writer_;
-  casewriter_write (writer->subwriter,
-                    case_map_execute (writer->compactor, c));
-}
-
-/* Closes WRITER. */
-static void
-scratch_writer_casewriter_destroy (struct casewriter *w UNUSED, void *writer_)
-{
-  static unsigned int next_unique_id = 0x12345678;
-
-  struct scratch_writer *writer = writer_;
-  struct casereader *reader = casewriter_make_reader (writer->subwriter);
-  if (!casereader_error (reader))
-    {
-      /* Destroy previous contents of handle. */
-      struct scratch_handle *sh = fh_get_scratch_handle (writer->fh);
-      if (sh != NULL)
-        scratch_handle_destroy (sh);
-
-      /* Create new contents. */
-      sh = xmalloc (sizeof *sh);
-      sh->unique_id = ++next_unique_id;
-      sh->dictionary = writer->dict;
-      sh->casereader = reader;
-      fh_set_scratch_handle (writer->fh, sh);
-    }
-  else
-    {
-      casereader_destroy (reader);
-      dict_destroy (writer->dict);
-    }
-
-  fh_unlock (writer->lock);
-  fh_unref (writer->fh);
-  free (writer);
-}
-
-static const struct casewriter_class scratch_writer_casewriter_class =
-  {
-    scratch_writer_casewriter_write,
-    scratch_writer_casewriter_destroy,
-    NULL,
-  };
diff --git a/src/data/scratch-writer.h b/src/data/scratch-writer.h
deleted file mode 100644 (file)
index a9c7a4d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 SCRATCH_WRITER_H
-#define SCRATCH_WRITER_H 1
-
-#include <stdbool.h>
-
-struct dictionary;
-struct file_handle;
-struct casewriter *scratch_writer_open (struct file_handle *,
-                                        const struct dictionary *);
-
-#endif /* scratch-writer.h */
diff --git a/src/data/session.c b/src/data/session.c
new file mode 100644 (file)
index 0000000..24c22b2
--- /dev/null
@@ -0,0 +1,180 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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/session.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "data/dataset.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/str.h"
+#include "libpspp/hmapx.h"
+
+#include "gl/xalloc.h"
+
+struct session
+  {
+    struct hmapx datasets;
+    struct dataset *active;
+    char *syntax_encoding;      /* Default encoding for syntax files. */
+  };
+
+static struct hmapx_node *session_lookup_dataset__ (const struct session *,
+                                                    const char *name);
+
+struct session *
+session_create (void)
+{
+  struct session *s;
+
+  s = xmalloc (sizeof *s);
+  hmapx_init (&s->datasets);
+  s->active = NULL;
+  s->syntax_encoding = xstrdup ("Auto");
+  return s;
+}
+
+void
+session_destroy (struct session *s)
+{
+  if (s != NULL)
+    {
+      struct hmapx_node *node, *next;
+      struct dataset *ds;
+
+      s->active = NULL;
+      HMAPX_FOR_EACH_SAFE (ds, node, next, &s->datasets)
+        dataset_destroy (ds);
+      free (s->syntax_encoding);
+      free (s);
+    }
+}
+
+struct dataset *
+session_active_dataset (struct session *s)
+{
+  return s->active;
+}
+
+void
+session_set_active_dataset (struct session *s, struct dataset *ds)
+{
+  assert (ds == NULL || dataset_session (ds) == s);
+  s->active = ds;
+}
+
+void
+session_add_dataset (struct session *s, struct dataset *ds)
+{
+  struct dataset *old;
+
+  old = session_lookup_dataset (s, dataset_name (ds));
+  if (old == s->active)
+    s->active = ds;
+  if (old != NULL)
+    session_remove_dataset (s, old);
+
+  hmapx_insert (&s->datasets, ds, hash_case_string (dataset_name (ds), 0));
+  if (s->active == NULL)
+    s->active = ds;
+
+  dataset_set_session__ (ds, s);
+}
+
+void
+session_remove_dataset (struct session *s, struct dataset *ds)
+{
+  assert (ds != s->active);
+  hmapx_delete (&s->datasets, session_lookup_dataset__ (s, dataset_name (ds)));
+  dataset_set_session__ (ds, NULL);
+}
+
+struct dataset *
+session_lookup_dataset (const struct session *s, const char *name)
+{
+  struct hmapx_node *node = session_lookup_dataset__ (s, name);
+  return node != NULL ? node->data : NULL;
+}
+
+struct dataset *
+session_lookup_dataset_assert (const struct session *s, const char *name)
+{
+  struct dataset *ds = session_lookup_dataset (s, name);
+  assert (ds != NULL);
+  return ds;
+}
+
+void
+session_set_default_syntax_encoding (struct session *s, const char *encoding)
+{
+  free (s->syntax_encoding);
+  s->syntax_encoding = xstrdup (encoding);
+}
+
+const char *
+session_get_default_syntax_encoding (const struct session *s)
+{
+  return s->syntax_encoding;
+}
+
+size_t
+session_n_datasets (const struct session *s)
+{
+  return hmapx_count (&s->datasets);
+}
+
+void
+session_for_each_dataset (const struct session *s,
+                          void (*cb) (struct dataset *, void *aux),
+                          void *aux)
+{
+  struct hmapx_node *node, *next;
+  struct dataset *ds;
+
+  HMAPX_FOR_EACH_SAFE (ds, node, next, &s->datasets)
+    cb (ds, aux);
+}
+
+struct dataset *
+session_get_dataset_by_seqno (const struct session *s, unsigned int seqno)
+{
+  struct hmapx_node *node;
+  struct dataset *ds;
+
+  HMAPX_FOR_EACH (ds, node, &s->datasets)
+    if (dataset_seqno (ds) == seqno)
+      return ds;
+  return NULL;
+}
+\f
+static struct hmapx_node *
+session_lookup_dataset__ (const struct session *s_, const char *name)
+{
+  struct session *s = CONST_CAST (struct session *, s_);
+  struct hmapx_node *node;
+  struct dataset *ds;
+
+  HMAPX_FOR_EACH_WITH_HASH (ds, node, hash_case_string (name, 0), &s->datasets)
+    if (!strcasecmp (dataset_name (ds), name))
+      return node;
+
+  return NULL;
+}
diff --git a/src/data/session.h b/src/data/session.h
new file mode 100644 (file)
index 0000000..f45cceb
--- /dev/null
@@ -0,0 +1,47 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 SESSION_H
+#define SESSION_H 1
+
+#include <stddef.h>
+
+struct dataset;
+
+struct session *session_create (void);
+void session_destroy (struct session *);
+
+struct dataset *session_active_dataset (struct session *);
+void session_set_active_dataset (struct session *, struct dataset *);
+
+void session_add_dataset (struct session *, struct dataset *);
+void session_remove_dataset (struct session *, struct dataset *);
+struct dataset *session_lookup_dataset (const struct session *, const char *);
+struct dataset *session_lookup_dataset_assert (const struct session *,
+                                               const char *);
+
+void session_set_default_syntax_encoding (struct session *, const char *);
+const char *session_get_default_syntax_encoding (const struct session *);
+
+size_t session_n_datasets (const struct session *);
+void session_for_each_dataset (const struct session *,
+                               void (*cb) (struct dataset *, void *aux),
+                               void *aux);
+
+struct dataset *session_get_dataset_by_seqno (const struct session *,
+                                              unsigned int seqno);
+
+#endif /* session.h */
index 13512cc03242f7b7d7d78e6ebf2d0369bb9f13c3..71d4261de8d7afa442ad14eec28509877315c938 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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
@@ -64,8 +64,6 @@ struct settings
   bool printback;
   bool mprint;
   int mxloops;
-  bool nulline;
-  char endcmd;
   size_t workspace;
   struct fmt_spec default_format;
   bool testing_mode;
@@ -105,8 +103,6 @@ static struct settings the_settings = {
   true,                         /* printback */
   true,                         /* mprint */
   1,                            /* mxloops */
-  true,                         /* nulline */
-  '.',                          /* endcmd */
   64L * 1024 * 1024,            /* workspace */
   {FMT_F, 8, 2},                /* default_format */
   false,                        /* testing_mode */
@@ -429,34 +425,6 @@ settings_set_mxloops ( int mxloops)
   the_settings.mxloops = mxloops;
 }
 
-/* Whether a blank line is a command terminator. */
-bool
-settings_get_nulline (void)
-{
-  return the_settings.nulline;
-}
-
-/* Set whether a blank line is a command terminator. */
-void
-settings_set_nulline ( bool nulline)
-{
-  the_settings.nulline = nulline;
-}
-
-/* The character used to terminate commands. */
-char
-settings_get_endcmd (void)
-{
-  return the_settings.endcmd;
-}
-
-/* Set the character used to terminate commands. */
-void
-settings_set_endcmd ( char endcmd)
-{
-  the_settings.endcmd = endcmd;
-}
-
 /* Approximate maximum amount of memory to use for cases, in
    bytes. */
 size_t
@@ -558,11 +526,10 @@ settings_set_syntax ( enum behavior_mode mode)
 
 \f
 
-/* Find the grouping characters in CC_STRING and set CC's
-   grouping and decimal members appropriately.  Returns true if
-   successful, false otherwise. */
+/* Find the grouping characters in CC_STRING and sets *GROUPING and *DECIMAL
+   appropriately.  Returns true if successful, false otherwise. */
 static bool
-find_cc_separators (const char *cc_string, struct fmt_number_style *cc)
+find_cc_separators (const char *cc_string, char *decimal, char *grouping)
 {
   const char *sp;
   int comma_cnt, dot_cnt;
@@ -584,36 +551,32 @@ find_cc_separators (const char *cc_string, struct fmt_number_style *cc)
 
   if (comma_cnt == 3)
     {
-      cc->decimal = '.';
-      cc->grouping = ',';
+      *decimal = '.';
+      *grouping = ',';
     }
   else
     {
-      cc->decimal = ',';
-      cc->grouping = '.';
+      *decimal = ',';
+      *grouping = '.';
     }
   return true;
 }
 
-/* Extracts a token from IN into AFFIX, using BUFFER for storage.  BUFFER must
-   have at least FMT_STYLE_AFFIX_MAX + 1 bytes of space.  Tokens are delimited
-   by GROUPING.  The token is truncated to at most FMT_STYLE_AFFIX_MAX bytes,
-   followed by a null terminator.  Returns the first character following the
-   token. */
+/* Extracts a token from IN into a newly allocated string AFFIXP.  Tokens are
+   delimited by GROUPING.  Returns the first character following the token. */
 static const char *
-extract_cc_token (const char *in, int grouping, struct substring *affix,
-                  char buffer[FMT_STYLE_AFFIX_MAX + 1])
+extract_cc_token (const char *in, int grouping, char **affixp)
 {
-  size_t ofs = 0;
+  char *out;
 
+  out = *affixp = xmalloc (strlen (in) + 1);
   for (; *in != '\0' && *in != grouping; in++)
     {
       if (*in == '\'' && in[1] == grouping)
         in++;
-      if (ofs < FMT_STYLE_AFFIX_MAX)
-        buffer[ofs++] = *in;
+      *out++ = *in;
     }
-  *affix = ss_buffer (buffer, ofs);
+  *out = '\0';
 
   if (*in == grouping)
     in++;
@@ -625,16 +588,13 @@ extract_cc_token (const char *in, int grouping, struct substring *affix,
 bool
 settings_set_cc (const char *cc_string, enum fmt_type type)
 {
-  char a[FMT_STYLE_AFFIX_MAX + 1];
-  char b[FMT_STYLE_AFFIX_MAX + 1];
-  char c[FMT_STYLE_AFFIX_MAX + 1];
-  char d[FMT_STYLE_AFFIX_MAX + 1];
-  struct fmt_number_style cc;
+  char *neg_prefix, *prefix, *suffix, *neg_suffix;
+  char decimal, grouping;
 
   assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
 
   /* Determine separators. */
-  if (!find_cc_separators (cc_string, &cc))
+  if (!find_cc_separators (cc_string, &decimal, &grouping))
     {
       msg (SE, _("%s: Custom currency string `%s' does not contain "
                  "exactly three periods or commas (or it contains both)."),
@@ -642,12 +602,18 @@ settings_set_cc (const char *cc_string, enum fmt_type type)
       return false;
     }
 
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.neg_prefix, a);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.prefix, b);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.suffix, c);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.neg_suffix, d);
+  cc_string = extract_cc_token (cc_string, grouping, &neg_prefix);
+  cc_string = extract_cc_token (cc_string, grouping, &prefix);
+  cc_string = extract_cc_token (cc_string, grouping, &suffix);
+  cc_string = extract_cc_token (cc_string, grouping, &neg_suffix);
+
+  fmt_settings_set_style (the_settings.styles, type, decimal, grouping,
+                          neg_prefix, prefix, suffix, neg_suffix);
 
-  fmt_settings_set_style (the_settings.styles, type, &cc);
+  free (neg_suffix);
+  free (suffix);
+  free (prefix);
+  free (neg_prefix);
 
   return true;
 }
@@ -688,20 +654,20 @@ settings_dollar_template (const struct fmt_spec *fmt)
 
   fns = fmt_settings_get_style (the_settings.styles, fmt->type);
 
-  ds_put_char (&str, '$');
+  ds_put_byte (&str, '$');
   for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0; )
     {
-      ds_put_char (&str, '#');
+      ds_put_byte (&str, '#');
       if (--c % 4 == 0 && c > 0)
         {
-          ds_put_char (&str, fns->grouping);
+          ds_put_byte (&str, fns->grouping);
           --c;
         }
     }
   if (fmt->d > 0)
     {
-      ds_put_char (&str, fns->decimal);
-      ds_put_char_multiple (&str, '#', fmt->d);
+      ds_put_byte (&str, fns->decimal);
+      ds_put_byte_multiple (&str, '#', fmt->d);
     }
 
   return ds_cstr (&str);
index e68325f7f2bca21aed2ef100420a170b15c2522a..963458d82610a3c782d43dd15081f53c45fe8b2a 100644 (file)
@@ -92,12 +92,6 @@ void settings_set_mprint (bool);
 int settings_get_mxloops (void);
 void settings_set_mxloops ( int);
 
-bool settings_get_nulline (void);
-void settings_set_nulline (bool);
-
-char settings_get_endcmd (void);
-void settings_set_endcmd (char);
-
 size_t settings_get_workspace (void);
 size_t settings_get_workspace_cases (const struct caseproto *);
 void settings_set_workspace (size_t);
index d1e37f5be06e079c846383dbbd16e70bb360e39f..aa157bae1b13c105f4685fb120e7c92980f13938 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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
@@ -23,6 +23,7 @@
 #include "data/variable.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 #include "libpspp/stringi-set.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Sets V's short name to BASE, followed by a suffix of the form
-   _A, _B, _C, ..., _AA, _AB, etc. according to the value of
-   SUFFIX_NUMBER.  Truncates BASE as necessary to fit. */
-static void
-set_var_short_name_suffix (struct variable *v, size_t i,
-                           const char *base, int suffix_number)
-{
-  char suffix[SHORT_NAME_LEN + 1];
-  char short_name[SHORT_NAME_LEN + 1];
-  int len, ofs;
-
-  assert (suffix_number >= 0);
-
-  /* Set base name. */
-  var_set_short_name (v, i, base);
-
-  /* Compose suffix. */
-  suffix[0] = '_';
-  if (!str_format_26adic (suffix_number, &suffix[1], sizeof suffix - 1))
-    msg (SE, _("Variable suffix too large."));
-  len = strlen (suffix);
-
-  /* Append suffix to V's short name. */
-  str_copy_trunc (short_name, sizeof short_name, base);
-  if (strlen (short_name) + len > SHORT_NAME_LEN)
-    ofs = SHORT_NAME_LEN - len;
-  else
-    ofs = strlen (short_name);
-  strcpy (short_name + ofs, suffix);
-
-  /* Set name. */
-  var_set_short_name (v, i, short_name);
-}
-
 static void
 claim_short_name (struct variable *v, size_t i,
                   struct stringi_set *short_names)
@@ -86,13 +53,28 @@ assign_short_name (struct variable *v, size_t i,
 
   for (trial = 0; ; trial++)
     {
+      char suffix[SHORT_NAME_LEN + 1];
+      char *short_name;
+
+      /* Compose suffix. */
       if (trial == 0)
-        var_set_short_name (v, i, var_get_name (v));
+        suffix[0] = '\0';
       else
-        set_var_short_name_suffix (v, i, var_get_name (v), trial);
+        {
+          suffix[0] = '_';
+          str_format_26adic (trial, &suffix[1], sizeof suffix - 1);
+        }
 
-      if (stringi_set_insert (short_names, var_get_short_name (v, i)))
-        break;
+      /* Set name. */
+      short_name = utf8_encoding_concat (var_get_name (v), suffix,
+                                         var_get_encoding (v), SHORT_NAME_LEN);
+      if (stringi_set_insert (short_names, short_name))
+        {
+          var_set_short_name (v, i, short_name);
+          free (short_name);
+          return;
+        }
+      free (short_name);
     }
 }
 
@@ -136,7 +118,8 @@ short_names_assign (struct dictionary *d)
     {
       struct variable *v = dict_get_var (d, i);
       const char *name = var_get_name (v);
-      if (strlen (name) <= SHORT_NAME_LEN)
+      int len = recode_string_len (var_get_encoding (v), "UTF-8", name, -1);
+      if (len <= SHORT_NAME_LEN)
         var_set_short_name (v, 0, name);
     }
 
index 32056215e4ace37d4fcd9b544c3e48c493d82dec..f87093cd18413cbf97351ffdac019e807db33191 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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/subcase.h>
+
+#include "data/subcase.h"
+
 #include <stdlib.h>
-#include <data/case.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
 
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+
+#include "gl/xalloc.h"
 
 static void invalidate_proto (struct subcase *sc);
 
diff --git a/src/data/sys-file-encoding.c b/src/data/sys-file-encoding.c
new file mode 100644 (file)
index 0000000..5138e84
--- /dev/null
@@ -0,0 +1,1690 @@
+/* -*- mode: c; buffer-read-only: t -*-
+
+   Generated by sys-file-encoding.pl.  Do not modify!
+*/
+
+#include <config.h>
+
+#include "data/sys-file-private.h"
+
+struct sys_encoding sys_codepage_number_to_name[] = {
+  { 37, "IBM037" },
+  { 256, "ibm-256" },
+  { 259, "IBM-Symbols" },
+  { 273, "IBM273" },
+  { 274, "IBM274" },
+  { 275, "IBM275" },
+  { 277, "IBM277" },
+  { 278, "IBM278" },
+  { 280, "IBM280" },
+  { 284, "IBM284" },
+  { 285, "IBM285" },
+  { 286, "EBCDIC-AT-DE-A" },
+  { 290, "IBM290" },
+  { 293, "ibm-293" },
+  { 297, "IBM297" },
+  { 300, "ibm-300" },
+  { 301, "ibm-301" },
+  { 367, "ANSI_X3.4-1968" },
+  { 420, "IBM420" },
+  { 424, "IBM424" },
+  { 425, "ibm-425" },
+  { 437, "IBM437" },
+  { 500, "IBM500" },
+  { 720, "windows-720" },
+  { 737, "windows-737" },
+  { 775, "IBM775" },
+  { 803, "ibm-803" },
+  { 806, "ibm-806" },
+  { 808, "ibm-808" },
+  { 813, "ISO-8859-7" },
+  { 819, "ISO_8859-1:1987" },
+  { 833, "ibm-833" },
+  { 834, "ibm-834" },
+  { 835, "ibm-835" },
+  { 836, "ibm-836" },
+  { 837, "ibm-837" },
+  { 838, "IBM-Thai" },
+  { 848, "ibm-848" },
+  { 849, "ibm-849" },
+  { 850, "IBM850" },
+  { 851, "IBM851" },
+  { 852, "IBM852" },
+  { 855, "IBM855" },
+  { 856, "cp856" },
+  { 857, "IBM857" },
+  { 858, "IBM00858" },
+  { 859, "ibm-859" },
+  { 860, "IBM860" },
+  { 861, "IBM861" },
+  { 862, "IBM862" },
+  { 863, "IBM863" },
+  { 864, "IBM864" },
+  { 865, "IBM865" },
+  { 866, "IBM866" },
+  { 867, "ibm-867" },
+  { 868, "IBM868" },
+  { 869, "IBM869" },
+  { 870, "IBM870" },
+  { 871, "IBM871" },
+  { 872, "ibm-872" },
+  { 874, "windows-874" },
+  { 875, "cp875" },
+  { 878, "KOI8-R" },
+  { 880, "IBM880" },
+  { 896, "ibm-896" },
+  { 897, "JIS_X0201" },
+  { 901, "ibm-901" },
+  { 902, "ibm-902" },
+  { 905, "IBM905" },
+  { 912, "ISO_8859-2:1987" },
+  { 913, "ISO_8859-3:1988" },
+  { 914, "ISO_8859-4:1988" },
+  { 915, "ISO_8859-5:1988" },
+  { 916, "ibm-916" },
+  { 918, "IBM918" },
+  { 920, "ISO_8859-9:1989" },
+  { 921, "ISO-8859-13" },
+  { 922, "cp922" },
+  { 923, "ISO-8859-15" },
+  { 924, "IBM00924" },
+  { 926, "ibm-926" },
+  { 927, "ibm-927" },
+  { 928, "ibm-928" },
+  { 930, "cp930" },
+  { 932, "Shift_JIS" },
+  { 933, "cp933" },
+  { 935, "cp935" },
+  { 936, "GBK" },
+  { 937, "cp937" },
+  { 939, "cp939" },
+  { 941, "ibm-941" },
+  { 943, "cp943" },
+  { 944, "ibm-944" },
+  { 946, "ibm-946" },
+  { 947, "ibm-947" },
+  { 948, "ibm-948" },
+  { 949, "windows-949" },
+  { 950, "Big5" },
+  { 951, "ibm-951" },
+  { 952, "ibm-952" },
+  { 953, "JIS_X0212-1990" },
+  { 954, "EUC-JP" },
+  { 955, "ibm-955" },
+  { 964, "cp964" },
+  { 970, "EUC-KR" },
+  { 971, "ibm-971" },
+  { 1004, "ibm-1004" },
+  { 1006, "cp1006" },
+  { 1008, "ibm-1008" },
+  { 1009, "ibm-1009" },
+  { 1010, "NF_Z_62-010" },
+  { 1011, "DIN_66003" },
+  { 1012, "IT" },
+  { 1013, "BS_4730" },
+  { 1014, "ES2" },
+  { 1015, "PT2" },
+  { 1016, "NS_4551-1" },
+  { 1017, "ibm-1017" },
+  { 1018, "SEN_850200_B" },
+  { 1019, "ibm-1019" },
+  { 1020, "CSA_Z243.4-1985-1" },
+  { 1021, "ibm-1021" },
+  { 1023, "ES" },
+  { 1025, "cp1025" },
+  { 1026, "IBM1026" },
+  { 1027, "ibm-1027" },
+  { 1041, "ibm-1041" },
+  { 1043, "ibm-1043" },
+  { 1046, "ibm-1046" },
+  { 1047, "IBM1047" },
+  { 1051, "hp-roman8" },
+  { 1088, "ibm-1088" },
+  { 1089, "ISO_8859-6:1987" },
+  { 1097, "cp1097" },
+  { 1098, "cp1098" },
+  { 1100, "DEC-MCS" },
+  { 1101, "ibm-1101" },
+  { 1102, "ibm-1102" },
+  { 1103, "ibm-1103" },
+  { 1104, "iso-ir-25" },
+  { 1105, "ibm-1105" },
+  { 1106, "ibm-1106" },
+  { 1107, "DS_2089" },
+  { 1112, "cp1112" },
+  { 1114, "ibm-1114" },
+  { 1115, "ibm-1115" },
+  { 1122, "cp1122" },
+  { 1123, "cp1123" },
+  { 1124, "cp1124" },
+  { 1125, "ibm-1125" },
+  { 1127, "ibm-1127" },
+  { 1129, "ibm-1129" },
+  { 1130, "ibm-1130" },
+  { 1131, "ibm-1131" },
+  { 1132, "ibm-1132" },
+  { 1133, "ibm-1133" },
+  { 1137, "ibm-1137" },
+  { 1140, "IBM01140" },
+  { 1141, "IBM01141" },
+  { 1142, "IBM01142" },
+  { 1143, "IBM01143" },
+  { 1144, "IBM01144" },
+  { 1145, "IBM01145" },
+  { 1146, "IBM01146" },
+  { 1147, "IBM01147" },
+  { 1148, "IBM01148" },
+  { 1149, "IBM01149" },
+  { 1153, "ibm-1153" },
+  { 1154, "ibm-1154" },
+  { 1155, "ibm-1155" },
+  { 1156, "ibm-1156" },
+  { 1157, "ibm-1157" },
+  { 1158, "ibm-1158" },
+  { 1160, "ibm-1160" },
+  { 1161, "ibm-1161" },
+  { 1162, "ibm-1162" },
+  { 1163, "ibm-1163" },
+  { 1164, "ibm-1164" },
+  { 1165, "ibm-1165" },
+  { 1166, "ibm-1166" },
+  { 1167, "ibm-1167" },
+  { 1168, "KOI8-U" },
+  { 1174, "KZ-1048" },
+  { 1200, "UTF-16LE" },
+  { 1201, "UTF-16BE" },
+  { 1205, "UTF-16" },
+  { 1213, "SCSU" },
+  { 1215, "BOCU-1" },
+  { 1235, "UTF-32LE" },
+  { 1237, "UTF-32" },
+  { 1250, "windows-1250" },
+  { 1251, "windows-1251" },
+  { 1252, "windows-1252" },
+  { 1253, "windows-1253" },
+  { 1254, "windows-1254" },
+  { 1255, "windows-1255" },
+  { 1256, "windows-1256" },
+  { 1257, "windows-1257" },
+  { 1258, "windows-1258" },
+  { 1276, "Adobe-Standard-Encoding" },
+  { 1277, "ibm-1277" },
+  { 1350, "ibm-1350" },
+  { 1351, "ibm-1351" },
+  { 1362, "ibm-1362" },
+  { 1363, "ibm-1363" },
+  { 1364, "ibm-1364" },
+  { 1370, "ibm-1370" },
+  { 1371, "ibm-1371" },
+  { 1373, "ibm-1373" },
+  { 1375, "Big5-HKSCS" },
+  { 1380, "ibm-1380" },
+  { 1381, "cp1381" },
+  { 1382, "ibm-1382" },
+  { 1383, "GB2312" },
+  { 1385, "ibm-9577" },
+  { 1386, "ibm-1386" },
+  { 1390, "ibm-1390" },
+  { 1392, "gb18030" },
+  { 1399, "ibm-1399" },
+  { 4517, "ibm-4517" },
+  { 4899, "ibm-4899" },
+  { 4902, "ibm-4902" },
+  { 4909, "ibm-4909" },
+  { 4930, "ibm-4930" },
+  { 4933, "ibm-4933" },
+  { 4948, "ibm-4948" },
+  { 4951, "ibm-4951" },
+  { 4952, "ibm-4952" },
+  { 4960, "ibm-4960" },
+  { 4971, "ibm-4971" },
+  { 5012, "ISO_8859-8:1988" },
+  { 5026, "cp930" },
+  { 5035, "cp939" },
+  { 5039, "ibm-5039" },
+  { 5048, "ibm-5048" },
+  { 5049, "ibm-5049" },
+  { 5050, "cp33722" },
+  { 5054, "JIS_Encoding" },
+  { 5067, "ibm-5067" },
+  { 5104, "ibm-5104" },
+  { 5123, "ibm-5123" },
+  { 5346, "windows-1250" },
+  { 5347, "windows-1251" },
+  { 5348, "windows-1252" },
+  { 5349, "windows-1253" },
+  { 5350, "windows-1254" },
+  { 5351, "ibm-5351" },
+  { 5352, "ibm-5352" },
+  { 5353, "ibm-5353" },
+  { 5354, "windows-1258" },
+  { 5471, "MS950_HKSCS" },
+  { 5478, "GB_2312-80" },
+  { 8482, "ibm-8482" },
+  { 8612, "ibm-8612" },
+  { 9005, "ISO_8859-7:1987" },
+  { 9027, "ibm-9027" },
+  { 9030, "IBM-Thai" },
+  { 9048, "ibm-9048" },
+  { 9056, "ibm-9056" },
+  { 9061, "ibm-9061" },
+  { 9066, "TIS-620" },
+  { 9067, "ibm-9067" },
+  { 9145, "ibm-9145" },
+  { 9238, "ibm-9238" },
+  { 9400, "CESU-8" },
+  { 9424, "UTF-32BE" },
+  { 9447, "windows-1255" },
+  { 9448, "windows-1256" },
+  { 9449, "windows-1257" },
+  { 9580, "ibm-1388" },
+  { 10000, "macintosh" },
+  { 10006, "windows-10006" },
+  { 10007, "windows-10007" },
+  { 10029, "windows-10029" },
+  { 10081, "windows-10081" },
+  { 12712, "ibm-12712" },
+  { 13125, "ibm-13125" },
+  { 13140, "ibm-13140" },
+  { 13218, "ibm-13218" },
+  { 13676, "ibm-13676" },
+  { 16804, "ibm-16804" },
+  { 17221, "ibm-17221" },
+  { 17248, "ibm-17248" },
+  { 17593, "UTF-8" },
+  { 20127, "ANSI_X3.4-1968" },
+  { 20780, "ibm-16684" },
+  { 20866, "KOI8-R" },
+  { 20880, "IBM880" },
+  { 20905, "IBM905" },
+  { 21344, "ibm-21344" },
+  { 21427, "ibm-21427" },
+  { 21866, "KOI8-U" },
+  { 25546, "ibm-25546" },
+  { 28592, "ISO_8859-2:1987" },
+  { 28593, "ISO_8859-3:1988" },
+  { 28594, "ISO_8859-4:1988" },
+  { 28595, "ISO_8859-5:1988" },
+  { 28596, "ISO_8859-6:1987" },
+  { 28597, "ISO_8859-7:1987" },
+  { 28598, "ISO_8859-8:1988" },
+  { 28599, "ISO_8859-9:1989" },
+  { 28603, "ISO-8859-13" },
+  { 28605, "ISO-8859-15" },
+  { 29875, "UTF-16LE" },
+  { 33058, "ibm-33058" },
+  { 33722, "cp33722" },
+  { 51932, "Extended_UNIX_Code_Packed_Format_for_Japanese" },
+  { 51949, "EUC-KR" },
+  { 54936, "gb18030" },
+  { 57002, "ibm-4902" },
+  { 57004, "windows-57004" },
+  { 57005, "windows-57005" },
+  { 57006, "windows-57003" },
+  { 57007, "windows-57007" },
+  { 57008, "windows-57008" },
+  { 57009, "windows-57009" },
+  { 57010, "windows-57010" },
+  { 57011, "windows-57011" },
+  { 61956, "UTF-16BE" },
+  { 65000, "UTF-7" },
+  { 65001, "UTF-8" },
+  { 65025, "ibm-65025" },
+  { 0, NULL }
+};
+
+struct sys_encoding sys_codepage_name_to_number[] = {
+  { 37, "037" },
+  { 1006, "1006" },
+  { 1025, "1025" },
+  { 1026, "1026" },
+  { 1047, "1047" },
+  { 28596, "1089" },
+  { 1097, "1097" },
+  { 1098, "1098" },
+  { 1112, "1112" },
+  { 1122, "1122" },
+  { 1123, "1123" },
+  { 1124, "1124" },
+  { 1381, "1381" },
+  { 1383, "1383" },
+  { 273, "273" },
+  { 277, "277" },
+  { 278, "278" },
+  { 280, "280" },
+  { 284, "284" },
+  { 285, "285" },
+  { 297, "297" },
+  { 5050, "33722" },
+  { 420, "420" },
+  { 424, "424" },
+  { 437, "437" },
+  { 51949, "5601" },
+  { 20127, "646" },
+  { 737, "737" },
+  { 775, "775" },
+  { 813, "813" },
+  { 819, "819" },
+  { 9030, "838" },
+  { 850, "850" },
+  { 851, "851" },
+  { 852, "852" },
+  { 855, "855" },
+  { 856, "856" },
+  { 857, "857" },
+  { 860, "860" },
+  { 861, "861" },
+  { 862, "862" },
+  { 863, "863" },
+  { 865, "865" },
+  { 866, "866" },
+  { 868, "868" },
+  { 869, "869" },
+  { 871, "871" },
+  { 875, "875" },
+  { 819, "8859_1" },
+  { 28603, "8859_13" },
+  { 28605, "8859_15" },
+  { 28592, "8859_2" },
+  { 28593, "8859_3" },
+  { 28594, "8859_4" },
+  { 28595, "8859_5" },
+  { 28596, "8859_6" },
+  { 813, "8859_7" },
+  { 28598, "8859_8" },
+  { 28599, "8859_9" },
+  { 28592, "912" },
+  { 28593, "913" },
+  { 28594, "914" },
+  { 28595, "915" },
+  { 916, "916" },
+  { 28599, "920" },
+  { 922, "922" },
+  { 28605, "923" },
+  { 5026, "930" },
+  { 933, "933" },
+  { 935, "935" },
+  { 937, "937" },
+  { 5035, "939" },
+  { 943, "943" },
+  { 949, "949" },
+  { 950, "950" },
+  { 964, "964" },
+  { 51949, "970" },
+  { 20127, "ANSI_X3.4-1968" },
+  { 20127, "ANSI_X3.4-1986" },
+  { 20127, "ASCII" },
+  { 28596, "ASMO-708" },
+  { 1276, "Adobe-Standard-Encoding" },
+  { 1215, "BOCU-1" },
+  { 1013, "BS_4730" },
+  { 950, "Big5" },
+  { 1375, "Big5-HKSCS" },
+  { 858, "CCSID00858" },
+  { 924, "CCSID00924" },
+  { 1140, "CCSID01140" },
+  { 1141, "CCSID01141" },
+  { 1142, "CCSID01142" },
+  { 1143, "CCSID01143" },
+  { 1144, "CCSID01144" },
+  { 1145, "CCSID01145" },
+  { 1146, "CCSID01146" },
+  { 1147, "CCSID01147" },
+  { 1148, "CCSID01148" },
+  { 1149, "CCSID01149" },
+  { 9400, "CESU-8" },
+  { 858, "CP00858" },
+  { 924, "CP00924" },
+  { 1140, "CP01140" },
+  { 1141, "CP01141" },
+  { 1142, "CP01142" },
+  { 1143, "CP01143" },
+  { 1144, "CP01144" },
+  { 1145, "CP01145" },
+  { 1146, "CP01146" },
+  { 1147, "CP01147" },
+  { 1148, "CP01148" },
+  { 1149, "CP01149" },
+  { 1026, "CP1026" },
+  { 273, "CP273" },
+  { 274, "CP274" },
+  { 280, "CP280" },
+  { 284, "CP284" },
+  { 285, "CP285" },
+  { 500, "CP500" },
+  { 868, "CP868" },
+  { 870, "CP870" },
+  { 871, "CP871" },
+  { 20905, "CP905" },
+  { 918, "CP918" },
+  { 936, "CP936" },
+  { 1020, "CSA_Z243.4-1985-1" },
+  { 1100, "DEC-MCS" },
+  { 1011, "DIN_66003" },
+  { 720, "DOS-720" },
+  { 862, "DOS-862" },
+  { 1107, "DS_2089" },
+  { 286, "EBCDIC-AT-DE-A" },
+  { 274, "EBCDIC-BE" },
+  { 275, "EBCDIC-BR" },
+  { 277, "EBCDIC-CP-DK" },
+  { 277, "EBCDIC-CP-NO" },
+  { 20880, "EBCDIC-Cyrillic" },
+  { 290, "EBCDIC-JP-kana" },
+  { 28596, "ECMA-114" },
+  { 28597, "ECMA-118" },
+  { 28597, "ELOT_928" },
+  { 1023, "ES" },
+  { 1014, "ES2" },
+  { 51932, "EUC-JP" },
+  { 51949, "EUC-KR" },
+  { 51932, "Extended_UNIX_Code_Packed_Format_for_Japanese" },
+  { 1018, "FI" },
+  { 54936, "GB18030" },
+  { 1383, "GB2312" },
+  { 936, "GBK" },
+  { 5478, "GB_2312-80" },
+  { 259, "IBM-Symbols" },
+  { 9030, "IBM-Thai" },
+  { 858, "IBM00858" },
+  { 924, "IBM00924" },
+  { 1140, "IBM01140" },
+  { 1141, "IBM01141" },
+  { 1142, "IBM01142" },
+  { 1143, "IBM01143" },
+  { 1144, "IBM01144" },
+  { 1145, "IBM01145" },
+  { 1146, "IBM01146" },
+  { 1147, "IBM01147" },
+  { 1148, "IBM01148" },
+  { 1149, "IBM01149" },
+  { 37, "IBM037" },
+  { 1006, "IBM1006" },
+  { 1026, "IBM1026" },
+  { 1047, "IBM1047" },
+  { 1098, "IBM1098" },
+  { 1153, "IBM1153" },
+  { 273, "IBM273" },
+  { 274, "IBM274" },
+  { 275, "IBM275" },
+  { 277, "IBM277" },
+  { 278, "IBM278" },
+  { 280, "IBM280" },
+  { 284, "IBM284" },
+  { 285, "IBM285" },
+  { 290, "IBM290" },
+  { 297, "IBM297" },
+  { 20127, "IBM367" },
+  { 420, "IBM420" },
+  { 424, "IBM424" },
+  { 437, "IBM437" },
+  { 500, "IBM500" },
+  { 737, "IBM737" },
+  { 775, "IBM775" },
+  { 819, "IBM819" },
+  { 9030, "IBM838" },
+  { 850, "IBM850" },
+  { 851, "IBM851" },
+  { 852, "IBM852" },
+  { 855, "IBM855" },
+  { 856, "IBM856" },
+  { 857, "IBM857" },
+  { 860, "IBM860" },
+  { 861, "IBM861" },
+  { 862, "IBM862" },
+  { 863, "IBM863" },
+  { 864, "IBM864" },
+  { 865, "IBM865" },
+  { 866, "IBM866" },
+  { 868, "IBM868" },
+  { 869, "IBM869" },
+  { 870, "IBM870" },
+  { 871, "IBM871" },
+  { 875, "IBM875" },
+  { 20880, "IBM880" },
+  { 20905, "IBM905" },
+  { 918, "IBM918" },
+  { 922, "IBM922" },
+  { 5026, "IBM930" },
+  { 5035, "IBM939" },
+  { 1205, "ISO-10646-UCS-2" },
+  { 1237, "ISO-10646-UCS-4" },
+  { 5054, "ISO-2022-JP-1" },
+  { 819, "ISO-8859-1" },
+  { 28603, "ISO-8859-13" },
+  { 28605, "ISO-8859-15" },
+  { 28592, "ISO-8859-2" },
+  { 28593, "ISO-8859-3" },
+  { 28594, "ISO-8859-4" },
+  { 28595, "ISO-8859-5" },
+  { 28596, "ISO-8859-6" },
+  { 28596, "ISO-8859-6-E" },
+  { 28596, "ISO-8859-6-I" },
+  { 28597, "ISO-8859-7" },
+  { 28598, "ISO-8859-8" },
+  { 28598, "ISO-8859-8-E" },
+  { 28598, "ISO-8859-8-I" },
+  { 28599, "ISO-8859-9" },
+  { 1020, "ISO646-CA" },
+  { 1011, "ISO646-DE" },
+  { 1107, "ISO646-DK" },
+  { 1023, "ISO646-ES" },
+  { 1014, "ISO646-ES2" },
+  { 1018, "ISO646-FI" },
+  { 1010, "ISO646-FR" },
+  { 1104, "ISO646-FR1" },
+  { 1013, "ISO646-GB" },
+  { 1012, "ISO646-IT" },
+  { 1016, "ISO646-NO" },
+  { 1015, "ISO646-PT2" },
+  { 1018, "ISO646-SE" },
+  { 20127, "ISO646-US" },
+  { 20127, "ISO_646.irv:1991" },
+  { 819, "ISO_8859-1:1987" },
+  { 28592, "ISO_8859-2:1987" },
+  { 28593, "ISO_8859-3:1988" },
+  { 28594, "ISO_8859-4:1988" },
+  { 28595, "ISO_8859-5:1988" },
+  { 28596, "ISO_8859-6:1987" },
+  { 28597, "ISO_8859-7:1987" },
+  { 28598, "ISO_8859-8:1988" },
+  { 28599, "ISO_8859-9:1989" },
+  { 1012, "IT" },
+  { 5054, "JIS_Encoding" },
+  { 897, "JIS_X0201" },
+  { 953, "JIS_X0212-1990" },
+  { 20866, "KOI8-R" },
+  { 21866, "KOI8-U" },
+  /* KSC_5601 has multiple numbers for windows: 949 51949 */
+  { 949, "KSC_5601" },
+  /* KS_C_5601-1987 has multiple numbers for windows: 949 51949 */
+  { 949, "KS_C_5601-1987" },
+  { 949, "KS_C_5601-1989" },
+  { 1174, "KZ-1048" },
+  { 28605, "Latin-9" },
+  { 874, "MS874" },
+  { 936, "MS936" },
+  { 5471, "MS950_HKSCS" },
+  { 932, "MS_Kanji" },
+  { 1010, "NF_Z_62-010" },
+  { 1016, "NS_4551-1" },
+  { 858, "PC-Multilingual-850+euro" },
+  { 1015, "PT2" },
+  { 1174, "RK1048" },
+  { 1213, "SCSU" },
+  { 1018, "SEN_850200_B" },
+  { 1174, "STRK1048-2002" },
+  { 932, "Shift_JIS" },
+  { 874, "TIS-620" },
+  { 20127, "US-ASCII" },
+  { 1205, "UTF-16" },
+  { 1201, "UTF-16BE" },
+  { 1200, "UTF-16LE" },
+  { 1237, "UTF-32" },
+  { 9424, "UTF-32BE" },
+  { 1235, "UTF-32LE" },
+  { 65000, "UTF-7" },
+  { 65001, "UTF-8" },
+  { 1201, "UnicodeBigUnmarked" },
+  { 1200, "UnicodeLittleUnmarked" },
+  { 51932, "X-EUC-JP" },
+  { 897, "X0201" },
+  { 28596, "arabic" },
+  { 20127, "ascii7" },
+  { 1375, "big5hk" },
+  { 1020, "ca" },
+  { 5478, "chinese" },
+  { 868, "cp-ar" },
+  { 869, "cp-gr" },
+  { 861, "cp-is" },
+  { 37, "cp037" },
+  { 1006, "cp1006" },
+  { 1025, "cp1025" },
+  { 1047, "cp1047" },
+  { 28596, "cp1089" },
+  { 1097, "cp1097" },
+  { 1098, "cp1098" },
+  { 1112, "cp1112" },
+  { 1122, "cp1122" },
+  { 1123, "cp1123" },
+  { 1124, "cp1124" },
+  { 1140, "cp1140" },
+  { 1141, "cp1141" },
+  { 1142, "cp1142" },
+  { 1143, "cp1143" },
+  { 1144, "cp1144" },
+  { 1145, "cp1145" },
+  { 1146, "cp1146" },
+  { 1147, "cp1147" },
+  { 1148, "cp1148" },
+  { 1149, "cp1149" },
+  { 1250, "cp1250" },
+  { 1251, "cp1251" },
+  { 1252, "cp1252" },
+  { 1253, "cp1253" },
+  { 1254, "cp1254" },
+  { 1255, "cp1255" },
+  { 1256, "cp1256" },
+  { 1257, "cp1257" },
+  { 1258, "cp1258" },
+  { 1363, "cp1363" },
+  { 1381, "cp1381" },
+  { 1383, "cp1383" },
+  { 275, "cp275" },
+  { 277, "cp277" },
+  { 278, "cp278" },
+  { 290, "cp290" },
+  { 297, "cp297" },
+  { 5050, "cp33722" },
+  { 20127, "cp367" },
+  { 420, "cp420" },
+  { 424, "cp424" },
+  { 437, "cp437" },
+  { 737, "cp737" },
+  { 775, "cp775" },
+  { 813, "cp813" },
+  { 819, "cp819" },
+  { 9030, "cp838" },
+  { 850, "cp850" },
+  { 851, "cp851" },
+  { 852, "cp852" },
+  { 855, "cp855" },
+  { 856, "cp856" },
+  { 857, "cp857" },
+  { 858, "cp858" },
+  { 860, "cp860" },
+  { 861, "cp861" },
+  { 862, "cp862" },
+  { 863, "cp863" },
+  { 864, "cp864" },
+  { 865, "cp865" },
+  { 866, "cp866" },
+  { 869, "cp869" },
+  { 9066, "cp874" },
+  { 875, "cp875" },
+  { 20880, "cp880" },
+  { 28592, "cp912" },
+  { 28593, "cp913" },
+  { 28594, "cp914" },
+  { 28595, "cp915" },
+  { 916, "cp916" },
+  { 28599, "cp920" },
+  { 922, "cp922" },
+  { 28605, "cp923" },
+  { 5026, "cp930" },
+  { 932, "cp932" },
+  { 933, "cp933" },
+  { 935, "cp935" },
+  { 937, "cp937" },
+  { 5035, "cp939" },
+  { 943, "cp943" },
+  { 932, "cp943c" },
+  { 949, "cp949" },
+  { 950, "cp950" },
+  { 964, "cp964" },
+  { 51949, "cp970" },
+  { 284, "cpibm284" },
+  { 285, "cpibm285" },
+  { 297, "cpibm297" },
+  { 37, "cpibm37" },
+  { 20127, "csASCII" },
+  { 1276, "csAdobeStandardEncoding" },
+  { 1215, "csBOCU-1" },
+  { 950, "csBig5" },
+  { 1100, "csDECMCS" },
+  { 286, "csEBCDICATDEA" },
+  { 51949, "csEUCKR" },
+  { 51932, "csEUCPkdFmtJapanese" },
+  { 1383, "csGB2312" },
+  { 1051, "csHPRoman8" },
+  { 897, "csHalfWidthKatakana" },
+  { 37, "csIBM037" },
+  { 1026, "csIBM1026" },
+  { 273, "csIBM273" },
+  { 274, "csIBM274" },
+  { 275, "csIBM275" },
+  { 277, "csIBM277" },
+  { 278, "csIBM278" },
+  { 280, "csIBM280" },
+  { 284, "csIBM284" },
+  { 285, "csIBM285" },
+  { 290, "csIBM290" },
+  { 297, "csIBM297" },
+  { 420, "csIBM420" },
+  { 424, "csIBM424" },
+  { 500, "csIBM500" },
+  { 855, "csIBM855" },
+  { 857, "csIBM857" },
+  { 860, "csIBM860" },
+  { 861, "csIBM861" },
+  { 863, "csIBM863" },
+  { 864, "csIBM864" },
+  { 865, "csIBM865" },
+  { 866, "csIBM866" },
+  { 868, "csIBM868" },
+  { 869, "csIBM869" },
+  { 870, "csIBM870" },
+  { 871, "csIBM871" },
+  { 20880, "csIBM880" },
+  { 20905, "csIBM905" },
+  { 918, "csIBM918" },
+  { 259, "csIBMSymbols" },
+  { 9030, "csIBMThai" },
+  { 1018, "csISO10Swedish" },
+  { 1020, "csISO121Canadian1" },
+  { 1012, "csISO15Italian" },
+  { 1023, "csISO17Spanish" },
+  { 1011, "csISO21German" },
+  { 1104, "csISO25French" },
+  { 1013, "csISO4UnitedKingdom" },
+  { 5478, "csISO58GB231280" },
+  { 1016, "csISO60DanishNorwegian" },
+  { 1016, "csISO60Norwegian1" },
+  { 1107, "csISO646Danish" },
+  { 1010, "csISO69French" },
+  { 1015, "csISO84Portuguese2" },
+  { 1014, "csISO85Spanish2" },
+  { 819, "csISOLatin1" },
+  { 28592, "csISOLatin2" },
+  { 28593, "csISOLatin3" },
+  { 28594, "csISOLatin4" },
+  { 28599, "csISOLatin5" },
+  { 28596, "csISOLatinArabic" },
+  { 28595, "csISOLatinCyrillic" },
+  { 28597, "csISOLatinGreek" },
+  { 28598, "csISOLatinHebrew" },
+  { 5054, "csJISEncoding" },
+  { 20866, "csKOI8R" },
+  { 949, "csKSC56011987" },
+  { 1174, "csKZ1048" },
+  { 10000, "csMacintosh" },
+  { 775, "csPC775Baltic" },
+  { 850, "csPC850Multilingual" },
+  { 851, "csPC851" },
+  { 862, "csPC862LatinHebrew" },
+  { 437, "csPC8CodePage437" },
+  { 852, "csPCp852" },
+  { 855, "csPCp855" },
+  { 932, "csShiftJIS" },
+  { 932, "csWindows31J" },
+  { 1020, "csa7-1" },
+  { 28605, "csisolatin0" },
+  { 28605, "csisolatin9" },
+  { 28595, "cyrillic" },
+  { 1011, "de" },
+  { 1100, "dec" },
+  { 1107, "dk" },
+  { 924, "ebcdic-Latin9--euro" },
+  { 420, "ebcdic-cp-ar1" },
+  { 918, "ebcdic-cp-ar2" },
+  { 500, "ebcdic-cp-be" },
+  { 37, "ebcdic-cp-ca" },
+  { 500, "ebcdic-cp-ch" },
+  { 284, "ebcdic-cp-es" },
+  { 278, "ebcdic-cp-fi" },
+  { 297, "ebcdic-cp-fr" },
+  { 285, "ebcdic-cp-gb" },
+  { 424, "ebcdic-cp-he" },
+  { 871, "ebcdic-cp-is" },
+  { 280, "ebcdic-cp-it" },
+  { 37, "ebcdic-cp-nl" },
+  { 870, "ebcdic-cp-roece" },
+  { 278, "ebcdic-cp-se" },
+  { 20905, "ebcdic-cp-tr" },
+  { 37, "ebcdic-cp-us" },
+  { 37, "ebcdic-cp-wt" },
+  { 870, "ebcdic-cp-yu" },
+  { 1141, "ebcdic-de-273+euro" },
+  { 1142, "ebcdic-dk-277+euro" },
+  { 1145, "ebcdic-es-284+euro" },
+  { 1143, "ebcdic-fi-278+euro" },
+  { 1147, "ebcdic-fr-297+euro" },
+  { 285, "ebcdic-gb" },
+  { 1146, "ebcdic-gb-285+euro" },
+  { 1148, "ebcdic-international-500+euro" },
+  { 871, "ebcdic-is" },
+  { 1149, "ebcdic-is-871+euro" },
+  { 1144, "ebcdic-it-280+euro" },
+  { 1142, "ebcdic-no-277+euro" },
+  { 1143, "ebcdic-se-278+euro" },
+  { 278, "ebcdic-sv" },
+  { 1140, "ebcdic-us-37+euro" },
+  { 1350, "eucJP-Open" },
+  { 954, "eucjis" },
+  { 1010, "fr" },
+  { 1013, "gb" },
+  { 54936, "gb18030" },
+  { 28597, "greek" },
+  { 28597, "greek8" },
+  { 28598, "hebrew" },
+  { 1051, "hp-roman8" },
+  { 1004, "ibm-1004" },
+  { 1004, "ibm-1004_P100-1995" },
+  { 1006, "ibm-1006" },
+  { 1006, "ibm-1006_P100-1995" },
+  { 1008, "ibm-1008" },
+  { 1008, "ibm-1008_P100-1995" },
+  { 1009, "ibm-1009" },
+  { 1009, "ibm-1009_P100-1995" },
+  { 1010, "ibm-1010" },
+  { 1010, "ibm-1010_P100-1995" },
+  { 1011, "ibm-1011" },
+  { 1011, "ibm-1011_P100-1995" },
+  { 1012, "ibm-1012" },
+  { 1012, "ibm-1012_P100-1995" },
+  { 1013, "ibm-1013" },
+  { 1013, "ibm-1013_P100-1995" },
+  { 1014, "ibm-1014" },
+  { 1014, "ibm-1014_P100-1995" },
+  { 1015, "ibm-1015" },
+  { 1015, "ibm-1015_P100-1995" },
+  { 1016, "ibm-1016" },
+  { 1016, "ibm-1016_P100-1995" },
+  { 1017, "ibm-1017" },
+  { 1017, "ibm-1017_P100-1995" },
+  { 1018, "ibm-1018" },
+  { 1018, "ibm-1018_P100-1995" },
+  { 1019, "ibm-1019" },
+  { 1019, "ibm-1019_P100-1995" },
+  { 1020, "ibm-1020" },
+  { 1020, "ibm-1020_P100-2003" },
+  { 1021, "ibm-1021" },
+  { 1021, "ibm-1021_P100-2003" },
+  { 1023, "ibm-1023" },
+  { 1023, "ibm-1023_P100-2003" },
+  { 1025, "ibm-1025" },
+  { 1025, "ibm-1025_P100-1995" },
+  { 1026, "ibm-1026" },
+  { 1026, "ibm-1026_P100-1995" },
+  { 1027, "ibm-1027" },
+  { 1027, "ibm-1027_P100-1995" },
+  { 1041, "ibm-1041" },
+  { 1041, "ibm-1041_P100-1995" },
+  { 1043, "ibm-1043" },
+  { 1043, "ibm-1043_P100-1995" },
+  { 1046, "ibm-1046" },
+  { 1046, "ibm-1046_X110-1999" },
+  { 1047, "ibm-1047" },
+  { 1047, "ibm-1047_P100-1995" },
+  { 1051, "ibm-1051" },
+  { 1051, "ibm-1051_P100-1995" },
+  { 1088, "ibm-1088" },
+  { 1088, "ibm-1088_P100-1995" },
+  { 28596, "ibm-1089" },
+  { 28596, "ibm-1089_P100-1995" },
+  { 1097, "ibm-1097" },
+  { 1097, "ibm-1097_P100-1995" },
+  { 1098, "ibm-1098" },
+  { 1098, "ibm-1098_P100-1995" },
+  { 1100, "ibm-1100" },
+  { 1100, "ibm-1100_P100-2003" },
+  { 1101, "ibm-1101" },
+  { 1101, "ibm-1101_P100-2003" },
+  { 1102, "ibm-1102" },
+  { 1102, "ibm-1102_P100-2003" },
+  { 1103, "ibm-1103" },
+  { 1103, "ibm-1103_P100-2003" },
+  { 1104, "ibm-1104" },
+  { 1104, "ibm-1104_P100-2003" },
+  { 1105, "ibm-1105" },
+  { 1105, "ibm-1105_P100-2003" },
+  { 1106, "ibm-1106" },
+  { 1106, "ibm-1106_P100-2003" },
+  { 1107, "ibm-1107" },
+  { 1107, "ibm-1107_P100-2003" },
+  { 1112, "ibm-1112" },
+  { 1112, "ibm-1112_P100-1995" },
+  { 1114, "ibm-1114" },
+  { 1114, "ibm-1114_P100-2001" },
+  { 1115, "ibm-1115" },
+  { 1115, "ibm-1115_P100-1995" },
+  { 1122, "ibm-1122" },
+  { 1122, "ibm-1122_P100-1999" },
+  { 1123, "ibm-1123" },
+  { 1123, "ibm-1123_P100-1995" },
+  { 1124, "ibm-1124" },
+  { 1124, "ibm-1124_P100-1996" },
+  { 1125, "ibm-1125" },
+  { 1125, "ibm-1125_P100-1997" },
+  { 1127, "ibm-1127" },
+  { 1127, "ibm-1127_P100-2004" },
+  { 1129, "ibm-1129" },
+  { 1129, "ibm-1129_P100-1997" },
+  { 1130, "ibm-1130" },
+  { 1130, "ibm-1130_P100-1997" },
+  { 1131, "ibm-1131" },
+  { 1131, "ibm-1131_P100-1997" },
+  { 1132, "ibm-1132" },
+  { 1132, "ibm-1132_P100-1998" },
+  { 1133, "ibm-1133" },
+  { 1133, "ibm-1133_P100-1997" },
+  { 1137, "ibm-1137" },
+  { 1137, "ibm-1137_P100-1999" },
+  { 1140, "ibm-1140" },
+  { 1140, "ibm-1140_P100-1997" },
+  { 1141, "ibm-1141" },
+  { 1141, "ibm-1141_P100-1997" },
+  { 1142, "ibm-1142" },
+  { 1142, "ibm-1142_P100-1997" },
+  { 1143, "ibm-1143" },
+  { 1143, "ibm-1143_P100-1997" },
+  { 1144, "ibm-1144" },
+  { 1144, "ibm-1144_P100-1997" },
+  { 1145, "ibm-1145" },
+  { 1145, "ibm-1145_P100-1997" },
+  { 1146, "ibm-1146" },
+  { 1146, "ibm-1146_P100-1997" },
+  { 1147, "ibm-1147" },
+  { 1147, "ibm-1147_P100-1997" },
+  { 1148, "ibm-1148" },
+  { 1148, "ibm-1148_P100-1997" },
+  { 1149, "ibm-1149" },
+  { 1149, "ibm-1149_P100-1997" },
+  { 1153, "ibm-1153" },
+  { 1153, "ibm-1153_P100-1999" },
+  { 1154, "ibm-1154" },
+  { 1154, "ibm-1154_P100-1999" },
+  { 1155, "ibm-1155" },
+  { 1155, "ibm-1155_P100-1999" },
+  { 1156, "ibm-1156" },
+  { 1156, "ibm-1156_P100-1999" },
+  { 1157, "ibm-1157" },
+  { 1157, "ibm-1157_P100-1999" },
+  { 1158, "ibm-1158" },
+  { 1158, "ibm-1158_P100-1999" },
+  { 1160, "ibm-1160" },
+  { 1160, "ibm-1160_P100-1999" },
+  { 1161, "ibm-1161" },
+  { 1161, "ibm-1161_P100-1999" },
+  { 1162, "ibm-1162" },
+  { 1162, "ibm-1162_P100-1999" },
+  { 1163, "ibm-1163" },
+  { 1163, "ibm-1163_P100-1999" },
+  { 1164, "ibm-1164" },
+  { 1164, "ibm-1164_P100-1999" },
+  { 1165, "ibm-1165" },
+  { 1165, "ibm-1165_P101-2000" },
+  { 1166, "ibm-1166" },
+  { 1166, "ibm-1166_P100-2002" },
+  { 1167, "ibm-1167" },
+  { 1167, "ibm-1167_P100-2002" },
+  { 21866, "ibm-1168" },
+  { 21866, "ibm-1168_P100-2002" },
+  { 1174, "ibm-1174" },
+  { 1174, "ibm-1174_X100-2007" },
+  { 1201, "ibm-1200" },
+  { 1201, "ibm-1201" },
+  { 1200, "ibm-1202" },
+  { 1200, "ibm-1203" },
+  { 1205, "ibm-1204" },
+  { 1205, "ibm-1205" },
+  { 65001, "ibm-1208" },
+  { 65001, "ibm-1209" },
+  { 1213, "ibm-1212" },
+  { 1213, "ibm-1213" },
+  { 1215, "ibm-1214" },
+  { 1215, "ibm-1215" },
+  { 9424, "ibm-1232" },
+  { 9424, "ibm-1233" },
+  { 1235, "ibm-1234" },
+  { 1235, "ibm-1235" },
+  { 1237, "ibm-1236" },
+  { 1237, "ibm-1237" },
+  { 1250, "ibm-1250" },
+  { 1250, "ibm-1250_P100-1995" },
+  { 1251, "ibm-1251" },
+  { 1251, "ibm-1251_P100-1995" },
+  { 1252, "ibm-1252" },
+  { 1252, "ibm-1252_P100-2000" },
+  { 1253, "ibm-1253" },
+  { 1253, "ibm-1253_P100-1995" },
+  { 1254, "ibm-1254" },
+  { 1254, "ibm-1254_P100-1995" },
+  { 1255, "ibm-1255" },
+  { 1255, "ibm-1255_P100-1995" },
+  { 1256, "ibm-1256" },
+  { 1256, "ibm-1256_P110-1997" },
+  { 1257, "ibm-1257" },
+  { 1257, "ibm-1257_P100-1995" },
+  { 1258, "ibm-1258" },
+  { 1258, "ibm-1258_P100-1997" },
+  { 12712, "ibm-12712" },
+  { 12712, "ibm-12712_P100-1998" },
+  { 1276, "ibm-1276" },
+  { 1276, "ibm-1276_P100-1995" },
+  { 1277, "ibm-1277" },
+  { 1277, "ibm-1277_P100-1995" },
+  { 13125, "ibm-13125" },
+  { 13125, "ibm-13125_P100-1997" },
+  { 13140, "ibm-13140" },
+  { 13140, "ibm-13140_P101-2000" },
+  { 13218, "ibm-13218" },
+  { 13218, "ibm-13218_P100-1996" },
+  { 1201, "ibm-13488" },
+  { 1201, "ibm-13489" },
+  { 1200, "ibm-13490" },
+  { 1200, "ibm-13491" },
+  { 65001, "ibm-13496" },
+  { 65001, "ibm-13497" },
+  { 1350, "ibm-1350" },
+  { 1350, "ibm-1350_P110-1997" },
+  { 1351, "ibm-1351" },
+  { 1351, "ibm-1351_P110-1997" },
+  { 1362, "ibm-1362" },
+  { 1362, "ibm-1362_P110-1999" },
+  { 1363, "ibm-1363" },
+  { 1363, "ibm-1363_P110-1997" },
+  { 1363, "ibm-1363_P11B-1998" },
+  { 1364, "ibm-1364" },
+  { 1364, "ibm-1364_P110-2007" },
+  { 13676, "ibm-13676" },
+  { 13676, "ibm-13676_P102-2001" },
+  { 1370, "ibm-1370" },
+  { 1370, "ibm-1370_P100-1999" },
+  { 1371, "ibm-1371" },
+  { 1371, "ibm-1371_P100-1999" },
+  { 1373, "ibm-1373" },
+  { 1373, "ibm-1373_P100-2002" },
+  { 1375, "ibm-1375" },
+  { 1375, "ibm-1375_P100-2007" },
+  { 1380, "ibm-1380" },
+  { 1380, "ibm-1380_P100-1995" },
+  { 1381, "ibm-1381" },
+  { 1381, "ibm-1381_P110-1999" },
+  { 1382, "ibm-1382" },
+  { 1382, "ibm-1382_P100-1995" },
+  { 1383, "ibm-1383" },
+  { 1383, "ibm-1383_P110-1999" },
+  { 1385, "ibm-1385" },
+  { 1386, "ibm-1386" },
+  { 1386, "ibm-1386_P100-2001" },
+  { 9580, "ibm-1388" },
+  { 9580, "ibm-1388_P103-2001" },
+  { 1390, "ibm-1390" },
+  { 1390, "ibm-1390_P110-2003" },
+  { 54936, "ibm-1392" },
+  { 1399, "ibm-1399" },
+  { 1399, "ibm-1399_P110-2003" },
+  { 20780, "ibm-16684" },
+  { 20780, "ibm-16684_P110-2003" },
+  { 16804, "ibm-16804" },
+  { 16804, "ibm-16804_X110-1999" },
+  { 17221, "ibm-17221" },
+  { 17221, "ibm-17221_P100-2001" },
+  { 17248, "ibm-17248" },
+  { 17248, "ibm-17248_X110-1999" },
+  { 1201, "ibm-17584" },
+  { 1201, "ibm-17585" },
+  { 1200, "ibm-17586" },
+  { 1200, "ibm-17587" },
+  { 65001, "ibm-17592" },
+  { 65001, "ibm-17593" },
+  { 20780, "ibm-20780" },
+  { 21344, "ibm-21344" },
+  { 21344, "ibm-21344_P101-2000" },
+  { 21427, "ibm-21427" },
+  { 21427, "ibm-21427_P100-1999" },
+  { 1201, "ibm-21680" },
+  { 1201, "ibm-21681" },
+  { 1200, "ibm-21682" },
+  { 1200, "ibm-21683" },
+  { 25546, "ibm-25546" },
+  { 256, "ibm-256" },
+  { 256, "ibm-256_P100-1995" },
+  { 1201, "ibm-25776" },
+  { 1201, "ibm-25777" },
+  { 1200, "ibm-25778" },
+  { 1200, "ibm-25779" },
+  { 259, "ibm-259" },
+  { 259, "ibm-259_P100-1995" },
+  { 273, "ibm-273" },
+  { 273, "ibm-273_P100-1995" },
+  { 274, "ibm-274" },
+  { 274, "ibm-274_P100-2000" },
+  { 275, "ibm-275" },
+  { 275, "ibm-275_P100-1995" },
+  { 277, "ibm-277" },
+  { 277, "ibm-277_P100-1995" },
+  { 278, "ibm-278" },
+  { 278, "ibm-278_P100-1995" },
+  { 280, "ibm-280" },
+  { 280, "ibm-280_P100-1995" },
+  { 284, "ibm-284" },
+  { 284, "ibm-284_P100-1995" },
+  { 285, "ibm-285" },
+  { 285, "ibm-285_P100-1995" },
+  { 286, "ibm-286" },
+  { 286, "ibm-286_P100-2003" },
+  { 290, "ibm-290" },
+  { 290, "ibm-290_P100-1995" },
+  { 293, "ibm-293" },
+  { 293, "ibm-293_P100-1995" },
+  { 297, "ibm-297" },
+  { 297, "ibm-297_P100-1995" },
+  { 1201, "ibm-29872" },
+  { 1201, "ibm-29873" },
+  { 1200, "ibm-29874" },
+  { 1200, "ibm-29875" },
+  { 300, "ibm-300" },
+  { 300, "ibm-300_P120-2006" },
+  { 301, "ibm-301" },
+  { 301, "ibm-301_P110-1997" },
+  { 33058, "ibm-33058" },
+  { 33058, "ibm-33058_P100-2000" },
+  { 5050, "ibm-33722" },
+  { 5050, "ibm-33722_P120-1999" },
+  { 51932, "ibm-33722_P12A_P12A-2004_U2" },
+  { 20127, "ibm-367" },
+  { 37, "ibm-37" },
+  { 37, "ibm-37_P100-1995" },
+  { 420, "ibm-420" },
+  { 420, "ibm-420_X120-1999" },
+  { 424, "ibm-424" },
+  { 424, "ibm-424_P100-1995" },
+  { 425, "ibm-425" },
+  { 425, "ibm-425_P101-2000" },
+  { 437, "ibm-437" },
+  { 437, "ibm-437_P100-1995" },
+  { 4517, "ibm-4517" },
+  { 4517, "ibm-4517_P100-2005" },
+  { 4899, "ibm-4899" },
+  { 4899, "ibm-4899_P100-1998" },
+  { 57002, "ibm-4902" },
+  { 4909, "ibm-4909" },
+  { 4909, "ibm-4909_P100-1999" },
+  { 4930, "ibm-4930" },
+  { 4930, "ibm-4930_P110-1999" },
+  { 4933, "ibm-4933" },
+  { 4933, "ibm-4933_P100-2002" },
+  { 4948, "ibm-4948" },
+  { 4948, "ibm-4948_P100-1995" },
+  { 4951, "ibm-4951" },
+  { 4951, "ibm-4951_P100-1995" },
+  { 4952, "ibm-4952" },
+  { 4952, "ibm-4952_P100-1995" },
+  { 4960, "ibm-4960" },
+  { 4960, "ibm-4960_P100-1995" },
+  { 4971, "ibm-4971" },
+  { 4971, "ibm-4971_P100-1999" },
+  { 500, "ibm-500" },
+  { 500, "ibm-500_P100-1995" },
+  { 28598, "ibm-5012" },
+  { 28598, "ibm-5012_P100-1999" },
+  { 5026, "ibm-5026" },
+  { 5035, "ibm-5035" },
+  { 5039, "ibm-5039" },
+  { 5039, "ibm-5039_P11A-1998" },
+  { 5048, "ibm-5048" },
+  { 5048, "ibm-5048_P100-1995" },
+  { 5049, "ibm-5049" },
+  { 5049, "ibm-5049_P100-1995" },
+  { 5050, "ibm-5050" },
+  { 5054, "ibm-5054" },
+  { 5067, "ibm-5067" },
+  { 5067, "ibm-5067_P100-1995" },
+  { 5104, "ibm-5104" },
+  { 5104, "ibm-5104_X110-1999" },
+  { 5123, "ibm-5123" },
+  { 5123, "ibm-5123_P100-1999" },
+  { 65001, "ibm-5304" },
+  { 65001, "ibm-5305" },
+  { 1250, "ibm-5346" },
+  { 1250, "ibm-5346_P100-1998" },
+  { 1251, "ibm-5347" },
+  { 1251, "ibm-5347_P100-1998" },
+  { 1252, "ibm-5348" },
+  { 1252, "ibm-5348_P100-1997" },
+  { 1253, "ibm-5349" },
+  { 1253, "ibm-5349_P100-1998" },
+  { 1254, "ibm-5350" },
+  { 1254, "ibm-5350_P100-1998" },
+  { 5351, "ibm-5351" },
+  { 5351, "ibm-5351_P100-1998" },
+  { 5352, "ibm-5352" },
+  { 5352, "ibm-5352_P100-1998" },
+  { 5353, "ibm-5353" },
+  { 5353, "ibm-5353_P100-1998" },
+  { 1258, "ibm-5354" },
+  { 1258, "ibm-5354_P100-1998" },
+  { 5471, "ibm-5471" },
+  { 5471, "ibm-5471_P100-2006" },
+  { 5478, "ibm-5478" },
+  { 5478, "ibm-5478_P100-1995" },
+  { 1201, "ibm-61955" },
+  { 1201, "ibm-61956" },
+  { 65025, "ibm-65025" },
+  { 720, "ibm-720" },
+  { 720, "ibm-720_P100-1997" },
+  { 737, "ibm-737" },
+  { 737, "ibm-737_P100-1997" },
+  { 775, "ibm-775" },
+  { 775, "ibm-775_P100-1996" },
+  { 803, "ibm-803" },
+  { 803, "ibm-803_P100-1999" },
+  { 806, "ibm-806" },
+  { 806, "ibm-806_P100-1998" },
+  { 808, "ibm-808" },
+  { 808, "ibm-808_P100-1999" },
+  { 813, "ibm-813" },
+  { 813, "ibm-813_P100-1995" },
+  { 819, "ibm-819" },
+  { 833, "ibm-833" },
+  { 833, "ibm-833_P100-1995" },
+  { 834, "ibm-834" },
+  { 834, "ibm-834_P100-1995" },
+  { 835, "ibm-835" },
+  { 835, "ibm-835_P100-1995" },
+  { 836, "ibm-836" },
+  { 836, "ibm-836_P100-1995" },
+  { 837, "ibm-837" },
+  { 837, "ibm-837_P100-1995" },
+  { 9030, "ibm-838" },
+  { 9030, "ibm-838_P100-1995" },
+  { 848, "ibm-848" },
+  { 8482, "ibm-8482" },
+  { 8482, "ibm-8482_P100-1999" },
+  { 848, "ibm-848_P100-1999" },
+  { 849, "ibm-849" },
+  { 849, "ibm-849_P100-1999" },
+  { 850, "ibm-850" },
+  { 850, "ibm-850_P100-1995" },
+  { 851, "ibm-851" },
+  { 851, "ibm-851_P100-1995" },
+  { 852, "ibm-852" },
+  { 852, "ibm-852_P100-1995" },
+  { 855, "ibm-855" },
+  { 855, "ibm-855_P100-1995" },
+  { 856, "ibm-856" },
+  { 856, "ibm-856_P100-1995" },
+  { 857, "ibm-857" },
+  { 857, "ibm-857_P100-1995" },
+  { 858, "ibm-858" },
+  { 858, "ibm-858_P100-1997" },
+  { 859, "ibm-859" },
+  { 859, "ibm-859_P100-1999" },
+  { 860, "ibm-860" },
+  { 860, "ibm-860_P100-1995" },
+  { 861, "ibm-861" },
+  { 8612, "ibm-8612" },
+  { 8612, "ibm-8612_P100-1995" },
+  { 861, "ibm-861_P100-1995" },
+  { 862, "ibm-862" },
+  { 862, "ibm-862_P100-1995" },
+  { 863, "ibm-863" },
+  { 863, "ibm-863_P100-1995" },
+  { 864, "ibm-864" },
+  { 864, "ibm-864_X110-1999" },
+  { 865, "ibm-865" },
+  { 865, "ibm-865_P100-1995" },
+  { 866, "ibm-866" },
+  { 866, "ibm-866_P100-1995" },
+  { 867, "ibm-867" },
+  { 867, "ibm-867_P100-1998" },
+  { 868, "ibm-868" },
+  { 868, "ibm-868_P100-1995" },
+  { 869, "ibm-869" },
+  { 869, "ibm-869_P100-1995" },
+  { 870, "ibm-870" },
+  { 870, "ibm-870_P100-1995" },
+  { 871, "ibm-871" },
+  { 871, "ibm-871_P100-1995" },
+  { 872, "ibm-872" },
+  { 872, "ibm-872_P100-1999" },
+  { 9066, "ibm-874" },
+  { 9066, "ibm-874_P100-1995" },
+  { 875, "ibm-875" },
+  { 875, "ibm-875_P100-1995" },
+  { 20866, "ibm-878" },
+  { 20866, "ibm-878_P100-1996" },
+  { 20880, "ibm-880" },
+  { 20880, "ibm-880_P100-1995" },
+  { 896, "ibm-896" },
+  { 896, "ibm-896_P100-1995" },
+  { 897, "ibm-897" },
+  { 897, "ibm-897_P100-1995" },
+  { 28597, "ibm-9005" },
+  { 28597, "ibm-9005_X110-2007" },
+  { 901, "ibm-901" },
+  { 901, "ibm-901_P100-1999" },
+  { 902, "ibm-902" },
+  { 9027, "ibm-9027" },
+  { 9027, "ibm-9027_P100-1999" },
+  { 902, "ibm-902_P100-1999" },
+  { 9030, "ibm-9030" },
+  { 9048, "ibm-9048" },
+  { 9048, "ibm-9048_P100-1998" },
+  { 20905, "ibm-905" },
+  { 9056, "ibm-9056" },
+  { 9056, "ibm-9056_P100-1995" },
+  { 20905, "ibm-905_P100-1995" },
+  { 9061, "ibm-9061" },
+  { 9061, "ibm-9061_P100-1999" },
+  { 9066, "ibm-9066" },
+  { 9067, "ibm-9067" },
+  { 9067, "ibm-9067_X100-2005" },
+  { 28592, "ibm-912" },
+  { 28592, "ibm-912_P100-1995" },
+  { 28593, "ibm-913" },
+  { 28593, "ibm-913_P100-2000" },
+  { 28594, "ibm-914" },
+  { 9145, "ibm-9145" },
+  { 9145, "ibm-9145_P110-1997" },
+  { 28594, "ibm-914_P100-1995" },
+  { 28595, "ibm-915" },
+  { 28595, "ibm-915_P100-1995" },
+  { 916, "ibm-916" },
+  { 916, "ibm-916_P100-1995" },
+  { 918, "ibm-918" },
+  { 918, "ibm-918_P100-1995" },
+  { 28599, "ibm-920" },
+  { 28599, "ibm-920_P100-1995" },
+  { 28603, "ibm-921" },
+  { 28603, "ibm-921_P100-1995" },
+  { 922, "ibm-922" },
+  { 922, "ibm-922_P100-1999" },
+  { 28605, "ibm-923" },
+  { 9238, "ibm-9238" },
+  { 9238, "ibm-9238_X110-1999" },
+  { 28605, "ibm-923_P100-1998" },
+  { 924, "ibm-924" },
+  { 924, "ibm-924_P100-1998" },
+  { 926, "ibm-926" },
+  { 926, "ibm-926_P100-2000" },
+  { 927, "ibm-927" },
+  { 927, "ibm-927_P100-1995" },
+  { 928, "ibm-928" },
+  { 928, "ibm-928_P100-1995" },
+  { 5026, "ibm-930" },
+  { 5026, "ibm-930_P120-1999" },
+  { 5035, "ibm-931" },
+  { 932, "ibm-932" },
+  { 933, "ibm-933" },
+  { 933, "ibm-933_P110-1995" },
+  { 935, "ibm-935" },
+  { 935, "ibm-935_P110-1999" },
+  { 937, "ibm-937" },
+  { 937, "ibm-937_P110-1999" },
+  { 5035, "ibm-939" },
+  { 5035, "ibm-939_P120-1999" },
+  { 9400, "ibm-9400" },
+  { 941, "ibm-941" },
+  { 941, "ibm-941_P13A-2001" },
+  { 932, "ibm-942" },
+  { 9424, "ibm-9424" },
+  { 932, "ibm-942_P12A-1999" },
+  { 943, "ibm-943" },
+  { 943, "ibm-943_P130-1999" },
+  { 932, "ibm-943_P15A-2003" },
+  { 944, "ibm-944" },
+  { 1255, "ibm-9447" },
+  { 1255, "ibm-9447_P100-2002" },
+  { 1256, "ibm-9448" },
+  { 1256, "ibm-9448_X100-2005" },
+  { 1257, "ibm-9449" },
+  { 1257, "ibm-9449_P100-2002" },
+  { 944, "ibm-944_P100-1995" },
+  { 946, "ibm-946" },
+  { 946, "ibm-946_P100-1995" },
+  { 947, "ibm-947" },
+  { 947, "ibm-947_P100-1995" },
+  { 948, "ibm-948" },
+  { 948, "ibm-948_P110-1999" },
+  { 949, "ibm-949" },
+  { 949, "ibm-949_P110-1999" },
+  { 950, "ibm-950" },
+  { 950, "ibm-950_P110-1999" },
+  { 951, "ibm-951" },
+  { 951, "ibm-951_P100-1995" },
+  { 952, "ibm-952" },
+  { 952, "ibm-952_P110-1997" },
+  { 953, "ibm-953" },
+  { 953, "ibm-953_P100-2000" },
+  { 954, "ibm-954" },
+  { 954, "ibm-954_P101-2007" },
+  { 955, "ibm-955" },
+  { 955, "ibm-955_P110-1997" },
+  { 1385, "ibm-9577" },
+  { 1385, "ibm-9577_P100-2001" },
+  { 9580, "ibm-9580" },
+  { 964, "ibm-964" },
+  { 964, "ibm-964_P110-1999" },
+  { 51949, "ibm-970" },
+  { 51949, "ibm-970_P110_P110-2006_U2" },
+  { 971, "ibm-971" },
+  { 51949, "ibm-eucKR" },
+  { 1018, "iso-ir-10" },
+  { 819, "iso-ir-100" },
+  { 28592, "iso-ir-101" },
+  { 28593, "iso-ir-109" },
+  { 28594, "iso-ir-110" },
+  { 1020, "iso-ir-121" },
+  { 28597, "iso-ir-126" },
+  { 28596, "iso-ir-127" },
+  { 28598, "iso-ir-138" },
+  { 28595, "iso-ir-144" },
+  { 28599, "iso-ir-148" },
+  { 949, "iso-ir-149" },
+  { 1012, "iso-ir-15" },
+  { 1023, "iso-ir-17" },
+  { 1011, "iso-ir-21" },
+  { 1104, "iso-ir-25" },
+  { 1013, "iso-ir-4" },
+  { 5478, "iso-ir-58" },
+  { 20127, "iso-ir-6" },
+  { 1016, "iso-ir-60" },
+  { 1010, "iso-ir-69" },
+  { 1015, "iso-ir-84" },
+  { 1014, "iso-ir-85" },
+  { 28605, "iso8859_15_fdis" },
+  { 20127, "iso_646.irv:1983" },
+  { 20866, "koi8" },
+  { 949, "korean" },
+  { 819, "l1" },
+  { 28592, "l2" },
+  { 28593, "l3" },
+  { 28594, "l4" },
+  { 28599, "l5" },
+  { 28605, "l9" },
+  { 28605, "latin0" },
+  { 819, "latin1" },
+  { 28592, "latin2" },
+  { 28593, "latin3" },
+  { 28594, "latin4" },
+  { 28599, "latin5" },
+  { 10000, "mac" },
+  { 10000, "macintosh" },
+  { 10000, "macos-0_2-10.2" },
+  { 10029, "macos-29-10.2" },
+  { 10081, "macos-35-10.2" },
+  { 10006, "macos-6_2-10.4" },
+  { 10007, "macos-7_3-10.2" },
+  { 10000, "macroman" },
+  { 949, "ms949" },
+  { 1016, "no" },
+  { 1051, "r8" },
+  { 1051, "roman8" },
+  { 1018, "se" },
+  { 9066, "tis620.2533" },
+  { 1013, "uk" },
+  { 20127, "us" },
+  { 10000, "windows-10000" },
+  { 10006, "windows-10006" },
+  { 10007, "windows-10007" },
+  { 10029, "windows-10029" },
+  { 10081, "windows-10081" },
+  { 1200, "windows-1200" },
+  { 1201, "windows-1201" },
+  { 1250, "windows-1250" },
+  { 1251, "windows-1251" },
+  { 1252, "windows-1252" },
+  { 1253, "windows-1253" },
+  { 1254, "windows-1254" },
+  { 1255, "windows-1255" },
+  { 1256, "windows-1256" },
+  { 1257, "windows-1257" },
+  { 1258, "windows-1258" },
+  { 20127, "windows-20127" },
+  { 20866, "windows-20866" },
+  { 20880, "windows-20880" },
+  { 20905, "windows-20905" },
+  { 21866, "windows-21866" },
+  { 28592, "windows-28592" },
+  { 28593, "windows-28593" },
+  { 28594, "windows-28594" },
+  { 28595, "windows-28595" },
+  { 28596, "windows-28596" },
+  { 28597, "windows-28597" },
+  { 28598, "windows-28598" },
+  { 28599, "windows-28599" },
+  { 28603, "windows-28603" },
+  { 28605, "windows-28605" },
+  { 932, "windows-31j" },
+  { 437, "windows-437" },
+  { 51932, "windows-51932" },
+  { 51949, "windows-51949" },
+  { 54936, "windows-54936" },
+  { 57002, "windows-57002" },
+  { 57006, "windows-57003" },
+  { 57004, "windows-57004" },
+  { 57005, "windows-57005" },
+  { 57006, "windows-57006" },
+  { 57007, "windows-57007" },
+  { 57008, "windows-57008" },
+  { 57009, "windows-57009" },
+  { 57010, "windows-57010" },
+  { 57011, "windows-57011" },
+  { 65000, "windows-65000" },
+  { 65001, "windows-65001" },
+  { 720, "windows-720" },
+  { 737, "windows-737" },
+  { 775, "windows-775" },
+  { 850, "windows-850" },
+  { 852, "windows-852" },
+  { 855, "windows-855" },
+  { 857, "windows-857" },
+  { 858, "windows-858" },
+  { 861, "windows-861" },
+  { 862, "windows-862" },
+  { 866, "windows-866" },
+  { 869, "windows-869" },
+  { 874, "windows-874" },
+  { 874, "windows-874-2000" },
+  { 932, "windows-932" },
+  { 936, "windows-936" },
+  { 936, "windows-936-2000" },
+  { 949, "windows-949" },
+  { 949, "windows-949-2000" },
+  { 950, "windows-950" },
+  { 950, "windows-950-2000" },
+  { 1006, "x-IBM1006" },
+  { 1025, "x-IBM1025" },
+  { 1027, "x-IBM1027" },
+  { 1041, "x-IBM1041" },
+  { 1043, "x-IBM1043" },
+  { 1046, "x-IBM1046" },
+  { 1046, "x-IBM1046S" },
+  { 1088, "x-IBM1088" },
+  { 1097, "x-IBM1097" },
+  { 1098, "x-IBM1098" },
+  { 1112, "x-IBM1112" },
+  { 1114, "x-IBM1114" },
+  { 1115, "x-IBM1115" },
+  { 1122, "x-IBM1122" },
+  { 1123, "x-IBM1123" },
+  { 1124, "x-IBM1124" },
+  { 1153, "x-IBM1153" },
+  { 1351, "x-IBM1351" },
+  { 1362, "x-IBM1362" },
+  { 1363, "x-IBM1363" },
+  { 1363, "x-IBM1363C" },
+  { 1364, "x-IBM1364" },
+  { 1370, "x-IBM1370" },
+  { 1371, "x-IBM1371" },
+  { 1380, "x-IBM1380" },
+  { 1381, "x-IBM1381" },
+  { 1382, "x-IBM1382" },
+  { 1385, "x-IBM1385" },
+  { 9580, "x-IBM1388" },
+  { 1390, "x-IBM1390" },
+  { 1399, "x-IBM1399" },
+  { 300, "x-IBM300" },
+  { 301, "x-IBM301" },
+  { 5050, "x-IBM33722" },
+  { 5050, "x-IBM33722A" },
+  { 5050, "x-IBM33722C" },
+  { 720, "x-IBM720" },
+  { 737, "x-IBM737" },
+  { 808, "x-IBM808" },
+  { 833, "x-IBM833" },
+  { 834, "x-IBM834" },
+  { 835, "x-IBM835" },
+  { 836, "x-IBM836" },
+  { 837, "x-IBM837" },
+  { 856, "x-IBM856" },
+  { 859, "x-IBM859" },
+  { 867, "x-IBM867" },
+  { 9066, "x-IBM874" },
+  { 875, "x-IBM875" },
+  { 897, "x-IBM897" },
+  { 28603, "x-IBM921" },
+  { 922, "x-IBM922" },
+  { 927, "x-IBM927" },
+  { 5026, "x-IBM930" },
+  { 5026, "x-IBM930A" },
+  { 933, "x-IBM933" },
+  { 935, "x-IBM935" },
+  { 937, "x-IBM937" },
+  { 5035, "x-IBM939" },
+  { 5035, "x-IBM939A" },
+  { 932, "x-IBM942" },
+  { 932, "x-IBM942C" },
+  { 943, "x-IBM943" },
+  { 947, "x-IBM947" },
+  { 948, "x-IBM948" },
+  { 949, "x-IBM949" },
+  { 950, "x-IBM950" },
+  { 951, "x-IBM951" },
+  { 954, "x-IBM954" },
+  { 954, "x-IBM954C" },
+  { 964, "x-IBM964" },
+  { 51949, "x-IBM970" },
+  { 971, "x-IBM971" },
+  { 57002, "x-ISCII91" },
+  { 28596, "x-ISO-8859-6S" },
+  { 932, "x-JISAutoDetect" },
+  { 1167, "x-KOI8_RU" },
+  { 949, "x-KSC5601" },
+  { 932, "x-MS932_0213" },
+  { 5471, "x-MS950-HKSCS" },
+  { 10029, "x-MacCentralEurope" },
+  { 10007, "x-MacCyrillic" },
+  { 10006, "x-MacGreek" },
+  { 10081, "x-MacTurkish" },
+  { 10007, "x-MacUkraine" },
+  { 1350, "x-eucJP-Open" },
+  { 57006, "x-iscii-as" },
+  { 57006, "x-iscii-be" },
+  { 57002, "x-iscii-de" },
+  { 57010, "x-iscii-gu" },
+  { 57008, "x-iscii-ka" },
+  { 57009, "x-iscii-ma" },
+  { 57007, "x-iscii-or" },
+  { 57011, "x-iscii-pa" },
+  { 57004, "x-iscii-ta" },
+  { 57005, "x-iscii-te" },
+  { 10029, "x-mac-ce" },
+  { 10029, "x-mac-centraleurroman" },
+  { 10007, "x-mac-cyrillic" },
+  { 10006, "x-mac-greek" },
+  { 10081, "x-mac-turkish" },
+  { 10000, "x-macroman" },
+  { 932, "x-ms-cp932" },
+  { 932, "x-sjis" },
+  { 1201, "x-utf-16be" },
+  { 1200, "x-utf-16le" },
+  { 1256, "x-windows-1256S" },
+  { 5054, "x-windows-50221" },
+  { 874, "x-windows-874" },
+  { 950, "x-windows-950" },
+  { 0, NULL }
+};
diff --git a/src/data/sys-file-encoding.pl b/src/data/sys-file-encoding.pl
new file mode 100755 (executable)
index 0000000..b49c654
--- /dev/null
@@ -0,0 +1,149 @@
+#! /usr/bin/perl
+
+use strict;
+use warnings;
+
+if (-t 0 || @ARGV) {
+    print <<EOF;
+$0: generate code page tables from ICU encoding list
+usage: $0 < convrtrs.txt > sys-file-encoding.c
+
+To regenerate the encoding data, get the latest ICU encoding data from:
+http://source.icu-project.org/repos/icu/icu/trunk/source/data/mappings/convrtrs.txt
+then convert it with this script using the command above.
+EOF
+    exit (@ARGV && $ARGV[0] eq '--help' ? 0 : 1);
+}
+
+open (CONVERTERS, '<', 'convrtrs.txt')
+  or die "convrtrs.txt: open failed ($!)\n";
+
+our $WINDOWS = 3;              # Windows code pages.
+our $IBM = 2;                  # IBM code pages.
+our $CP = 1;                   # Java (?) code pages.
+our %sources = ($WINDOWS => "windows", $IBM => "ibm", $CP => "cp");
+
+my $converter = "";
+while (<CONVERTERS>) {
+    chomp;
+    s/#.*//;
+    if (s/^\s+//) {
+       $converter .= " $_";
+    } else {
+       process_converter ($converter);
+       $converter = $_;
+    }
+}
+process_converter ($converter);
+close (CONVERTERS);
+
+our %codepages;
+
+print <<'EOF';
+/* -*- mode: c; buffer-read-only: t -*-
+
+   Generated by sys-file-encoding.pl.  Do not modify!
+*/
+
+#include <config.h>
+
+#include "data/sys-file-private.h"
+
+struct sys_encoding sys_codepage_number_to_name[] = {
+EOF
+for my $cpnumber (sort { $a <=> $b } (keys (%codepages))) {
+    my $source = max (keys (%{$codepages{$cpnumber}}));
+    my $name = ${$codepages{$cpnumber}{$source}}[0];
+    print "  { $cpnumber, \"$name\" },\n";
+}
+print "  { 0, NULL }\n";
+print "};\n\n";
+
+my %names;
+for my $cpnumber (sort { $a <=> $b } (keys (%codepages))) {
+    for my $source (keys (%{$codepages{$cpnumber}})) {
+       for my $name (@{$codepages{$cpnumber}{$source}}) {
+           push(@{$names{$name}{$source}}, $cpnumber);
+       }
+    }
+}
+print "struct sys_encoding sys_codepage_name_to_number[] = {\n";
+for my $name (sort (keys (%names))) {
+    for my $source (reverse (sort (keys (%sources)))) {
+       next if !exists ($names{$name}{$source});
+       my (@numbers) = @{$names{$name}{$source}};
+
+       # The only two encodings that currently print this are KSC_5601
+       # and KS_C_5601-1987, for code pages 949 and 51949.  It looks to
+       # me like the correct code page number is 949, which is the one
+       # chosen (because the numbers are in sorted order).
+       print "  /* $name has multiple numbers for $sources{$source}: @numbers */\n"
+         if @numbers > 1;
+
+       print "  { $numbers[0], \"$name\" },\n";
+       last;
+    }
+}
+print "  { 0, NULL }\n";
+print "};\n";
+
+sub process_converter {
+    my ($converter) = @_;
+    return if $converter =~ /^\s*$/;
+    return if $converter =~ /^\s*\{/;
+
+    my %cps;
+    my @iana;
+    my @other;
+
+    my @fields = split (' ', $converter);
+    while (@fields) {
+       my $name = shift (@fields);
+       if (@fields && $fields[0] eq '{') {
+           shift (@fields);
+
+           my (%standards);
+           for (;;) {
+               my $standard = shift (@fields);
+               last if $standard eq '}';
+               $standards{$standard} = 1;
+           }
+           if (exists $standards{'IANA*'}) {
+               unshift (@iana, $name);
+           } elsif (exists $standards{'IANA'}) {
+               push (@iana, $name);
+           } elsif (grep (/\*$/, keys %standards)) {
+               unshift (@other, $name);
+           } else {
+               push (@other, $name);
+           }
+       } else {
+           # Untagged names are completely nonstandard.
+           next;
+       }
+
+       my $number;
+       if (($number) = $name =~ /^cp([0-9]+)$/) {
+           $cps{$CP} = int ($number);
+       } elsif (($number) = $name =~ /^windows-([0-9]+)$/) {
+           $cps{$WINDOWS} = int ($number);
+       } elsif (($number) = $name =~ /^ibm-([0-9]+)$/) {
+           $cps{$IBM} = int ($number);
+       } else {
+           next;
+       }
+    }
+
+    # If there are no tagged names then this is completely nonstandard.
+    return if !@iana && !@other;
+
+    $codepages{$cps{$_}}{$_} = [@iana, @other] for keys (%cps);
+}
+
+sub max {
+    my ($best);
+    for my $x (@_) {
+       $best = $x if !defined ($best) || $x > $best;
+    }
+    return $best;
+}
index dd50ea8babefb434edece1080504bcc0f1e22e13..9114f54e2fda289a4c3a60a962434845c8aec48b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 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 <data/sys-file-private.h>
+#include "data/sys-file-private.h"
 
-#include <data/dictionary.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/misc.h>
+#include "data/dictionary.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/misc.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/c-strcase.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 /* Number of bytes really stored in each segment of a very long
    string variable. */
@@ -248,3 +249,34 @@ sfm_dictionary_to_sfm_vars (const struct dictionary *dict,
 
   return segment_cnt;
 }
+\f
+/* Given the name of an encoding, returns the codepage number to use in the
+   'character_code' member of the machine integer info record for writing a
+   system file. */
+int
+sys_get_codepage_from_encoding (const char *name)
+{
+  const struct sys_encoding *e;
+
+  for (e = sys_codepage_name_to_number; e->name != NULL; e++)
+    if (!c_strcasecmp (name, e->name))
+      return e->number;
+
+  return 0;
+}
+
+/* Given a codepage number from the 'character_code' member of the machine
+   integer info record in a system file, returns a corresponding encoding name.
+   Most encodings have multiple aliases; the one returned is the one that would
+   be used in the character encoding record. */
+const char *
+sys_get_encoding_from_codepage (int codepage)
+{
+  const struct sys_encoding *e;
+
+  for (e = sys_codepage_number_to_name; e->name != NULL; e++)
+    if (codepage == e->number)
+      return e->name;
+
+  return NULL;
+}
index e839cd6ac02008ab5fec2ee08feffcfbdcad003f..1eee77950fb7acd892f7f737c8e802f9367b27ef 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 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
@@ -60,4 +60,17 @@ int sfm_width_to_segments (int width);
 int sfm_segment_effective_offset (int width, int segment);
 int sfm_segment_alloc_width (int width, int segment);
 
+/* A mapping between an encoding name and a Windows codepage. */
+struct sys_encoding
+  {
+    int number;
+    const char *name;
+  };
+
+extern struct sys_encoding sys_codepage_number_to_name[];
+extern struct sys_encoding sys_codepage_name_to_number[];
+
+int sys_get_codepage_from_encoding (const char *);
+const char *sys_get_encoding_from_codepage (int);
+
 #endif /* data/sys-file-private.h */
index c9c843dfaf4dd83cee88f7dd510284fa37e516a7..9ec176f09f494f9562548918db80b61b31fa36f1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-2000, 2006-2007, 2009-2011 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,6 +33,7 @@
 #include "data/file-handle-def.h"
 #include "data/file-name.h"
 #include "data/format.h"
+#include "data/identifier.h"
 #include "data/missing-values.h"
 #include "data/mrset.h"
 #include "data/short-names.h"
@@ -51,6 +52,7 @@
 
 #include "gl/c-ctype.h"
 #include "gl/inttostr.h"
+#include "gl/localcharset.h"
 #include "gl/minmax.h"
 #include "gl/unlocked-io.h"
 #include "gl/xalloc.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) (msgid)
 
+enum
+  {
+    /* subtypes 0-2 unknown */
+    EXT_INTEGER       = 3,      /* Machine integer info. */
+    EXT_FLOAT         = 4,      /* Machine floating-point info. */
+    EXT_VAR_SETS      = 5,      /* Variable sets. */
+    EXT_DATE          = 6,      /* DATE. */
+    EXT_MRSETS        = 7,      /* Multiple response sets. */
+    EXT_DATA_ENTRY    = 8,      /* SPSS Data Entry. */
+    /* subtypes 9-10 unknown */
+    EXT_DISPLAY       = 11,     /* Variable display parameters. */
+    /* subtype 12 unknown */
+    EXT_LONG_NAMES    = 13,     /* Long variable names. */
+    EXT_LONG_STRINGS  = 14,     /* Long strings. */
+    /* subtype 15 unknown */
+    EXT_NCASES        = 16,     /* Extended number of cases. */
+    EXT_FILE_ATTRS    = 17,     /* Data file attributes. */
+    EXT_VAR_ATTRS     = 18,     /* Variable attributes. */
+    EXT_MRSETS2       = 19,     /* Multiple response sets (extended). */
+    EXT_ENCODING      = 20,     /* Character encoding. */
+    EXT_LONG_LABELS   = 21      /* Value labels for long strings. */
+  };
+
+struct sfm_var_record
+  {
+    off_t pos;
+    int width;
+    char name[8];
+    int print_format;
+    int write_format;
+    int missing_value_code;
+    uint8_t missing[24];
+    char *label;
+    struct variable *var;
+  };
+
+struct sfm_value_label
+  {
+    uint8_t value[8];
+    char *label;
+  };
+
+struct sfm_value_label_record
+  {
+    off_t pos;
+    struct sfm_value_label *labels;
+    size_t n_labels;
+
+    int *vars;
+    size_t n_vars;
+  };
+
+struct sfm_document_record
+  {
+    off_t pos;
+    char *documents;
+    size_t n_lines;
+  };
+
+struct sfm_extension_record
+  {
+    off_t pos;                  /* Starting offset in file. */
+    size_t size;                /* Size of data elements. */
+    size_t count;               /* Number of data elements. */
+    void *data;                 /* Contents. */
+  };
+
 /* System file reader. */
 struct sfm_reader
   {
@@ -71,17 +140,17 @@ struct sfm_reader
     struct file_handle *fh;     /* File handle. */
     struct fh_lock *lock;       /* Mutual exclusion for file handle. */
     FILE *file;                 /* File stream. */
+    off_t pos;                  /* Position in file. */
     bool error;                 /* I/O or corruption error? */
     struct caseproto *proto;    /* Format of output cases. */
 
     /* File format. */
     enum integer_format integer_format; /* On-disk integer format. */
     enum float_format float_format; /* On-disk floating point format. */
-    int oct_cnt;               /* Number of 8-byte units per case. */
     struct sfm_var *sfm_vars;   /* Variables. */
     size_t sfm_var_cnt;         /* Number of variables. */
     casenumber case_cnt;        /* Number of cases */
-    bool has_long_var_names;    /* File has a long variable name map */
+    const char *encoding;       /* String encoding. */
 
     /* Decompression. */
     bool compressed;           /* File is compressed? */
@@ -95,21 +164,17 @@ static const struct casereader_class sys_file_casereader_class;
 
 static bool close_reader (struct sfm_reader *);
 
-static struct variable **make_var_by_value_idx (struct sfm_reader *,
-                                                struct dictionary *);
-static struct variable *lookup_var_by_value_idx (struct sfm_reader *,
-                                                 struct variable **,
-                                                 int value_idx);
-static struct variable *lookup_var_by_short_name (struct dictionary *,
-                                                  const char *short_name);
+static struct variable *lookup_var_by_index (struct sfm_reader *, off_t,
+                                             const struct sfm_var_record *,
+                                             size_t n, int idx);
 
-static void sys_msg (struct sfm_reader *r, int class,
+static void sys_msg (struct sfm_reader *r, off_t, int class,
                      const char *format, va_list args)
-     PRINTF_FORMAT (3, 0);
-static void sys_warn (struct sfm_reader *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-static void sys_error (struct sfm_reader *, const char *, ...)
-     PRINTF_FORMAT (2, 3)
+     PRINTF_FORMAT (4, 0);
+static void sys_warn (struct sfm_reader *, off_t, const char *, ...)
+     PRINTF_FORMAT (3, 4);
+static void sys_error (struct sfm_reader *, off_t, const char *, ...)
+     PRINTF_FORMAT (3, 4)
      NO_RETURN;
 
 static void read_bytes (struct sfm_reader *, void *, size_t);
@@ -119,8 +184,28 @@ static double read_float (struct sfm_reader *);
 static void read_string (struct sfm_reader *, char *, size_t);
 static void skip_bytes (struct sfm_reader *, size_t);
 
-static struct text_record *open_text_record (struct sfm_reader *, size_t size);
-static void close_text_record (struct sfm_reader *r,
+static int parse_int (struct sfm_reader *, const void *data, size_t ofs);
+static double parse_float (struct sfm_reader *, const void *data, size_t ofs);
+
+static void read_variable_record (struct sfm_reader *,
+                                  struct sfm_var_record *);
+static void read_value_label_record (struct sfm_reader *,
+                                     struct sfm_value_label_record *,
+                                     size_t n_vars);
+static struct sfm_document_record *read_document_record (struct sfm_reader *);
+static struct sfm_extension_record *read_extension_record (
+  struct sfm_reader *, int subtype);
+static void skip_extension_record (struct sfm_reader *, int subtype);
+
+static const char *choose_encoding (
+  struct sfm_reader *,
+  const struct sfm_extension_record *ext_integer,
+  const struct sfm_extension_record *ext_encoding);
+
+static struct text_record *open_text_record (
+  struct sfm_reader *, const struct sfm_extension_record *,
+  bool recode_to_utf8);
+static void close_text_record (struct sfm_reader *,
                                struct text_record *);
 static bool read_variable_to_value_pair (struct sfm_reader *,
                                          struct dictionary *,
@@ -154,133 +239,83 @@ enum which_format
     WRITE_FORMAT
   };
 
-static void read_header (struct sfm_reader *, struct dictionary *,
-                         int *weight_idx, int *claimed_oct_cnt,
-                         struct sfm_read_info *);
-static void read_variable_record (struct sfm_reader *, struct dictionary *,
-                                  int *format_warning_cnt);
-static void parse_format_spec (struct sfm_reader *, unsigned int,
-                               enum which_format, struct variable *,
-                               int *format_warning_cnt);
-static void setup_weight (struct sfm_reader *, int weight_idx,
-                          struct variable **var_by_value_idx,
+static void read_header (struct sfm_reader *, int *weight_idx,
+                         int *claimed_oct_cnt, struct sfm_read_info *,
+                         char **file_labelp);
+static void parse_file_label (struct sfm_reader *, const char *file_label,
+                              struct dictionary *);
+static void parse_variable_records (struct sfm_reader *, struct dictionary *,
+                                    struct sfm_var_record *, size_t n);
+static void parse_format_spec (struct sfm_reader *, off_t pos,
+                               unsigned int format, enum which_format,
+                               struct variable *, int *format_warning_cnt);
+static void parse_document (struct dictionary *, struct sfm_document_record *);
+static void parse_display_parameters (struct sfm_reader *,
+                                      const struct sfm_extension_record *,
+                                      struct dictionary *);
+static void parse_machine_integer_info (struct sfm_reader *,
+                                        const struct sfm_extension_record *,
+                                        struct sfm_read_info *);
+static void parse_machine_float_info (struct sfm_reader *,
+                                      const struct sfm_extension_record *);
+static void parse_mrsets (struct sfm_reader *,
+                          const struct sfm_extension_record *,
                           struct dictionary *);
-static void read_documents (struct sfm_reader *, struct dictionary *);
-static void read_value_labels (struct sfm_reader *, struct dictionary *,
-                               struct variable **var_by_value_idx);
-
-static void read_extension_record (struct sfm_reader *, struct dictionary *,
-                                   struct sfm_read_info *);
-static void read_machine_integer_info (struct sfm_reader *,
-                                       size_t size, size_t count,
-                                       struct sfm_read_info *,
-                                      struct dictionary *
-                                      );
-static void read_machine_float_info (struct sfm_reader *,
-                                     size_t size, size_t count);
-static void read_mrsets (struct sfm_reader *, size_t size, size_t count,
-                         struct dictionary *);
-static void read_display_parameters (struct sfm_reader *,
-                                     size_t size, size_t count,
+static void parse_long_var_name_map (struct sfm_reader *,
+                                     const struct sfm_extension_record *,
                                      struct dictionary *);
-static void read_long_var_name_map (struct sfm_reader *,
-                                    size_t size, size_t count,
-                                    struct dictionary *);
-static void read_long_string_map (struct sfm_reader *,
-                                  size_t size, size_t count,
-                                  struct dictionary *);
-static void read_data_file_attributes (struct sfm_reader *,
-                                       size_t size, size_t count,
+static void parse_long_string_map (struct sfm_reader *,
+                                   const struct sfm_extension_record *,
+                                   struct dictionary *);
+static void parse_value_labels (struct sfm_reader *, struct dictionary *,
+                                const struct sfm_var_record *,
+                                size_t n_var_recs,
+                                const struct sfm_value_label_record *);
+static void parse_data_file_attributes (struct sfm_reader *,
+                                        const struct sfm_extension_record *,
+                                        struct dictionary *);
+static void parse_variable_attributes (struct sfm_reader *,
+                                       const struct sfm_extension_record *,
                                        struct dictionary *);
-static void read_variable_attributes (struct sfm_reader *,
-                                      size_t size, size_t count,
-                                      struct dictionary *);
-static void read_long_string_value_labels (struct sfm_reader *,
-                                          size_t size, size_t count,
-                                          struct dictionary *);
-
-/* Convert all the strings in DICT from the dict encoding to UTF8 */
-static void
-recode_strings (struct dictionary *dict)
-{
-  int i;
-
-  const char *enc = dict_get_encoding (dict);
-
-  if ( NULL == enc)
-    enc = get_default_encoding ();
-
-  for (i = 0 ; i < dict_get_var_cnt (dict); ++i)
-    {
-      /* Convert the long variable name */
-      struct variable *var = dict_get_var (dict, i);
-      const char *native_name = var_get_name (var);
-      char *utf8_name = recode_string (UTF8, enc, native_name, -1);
-      if ( 0 != strcmp (utf8_name, native_name))
-       {
-         if ( NULL == dict_lookup_var (dict, utf8_name))
-           dict_rename_var (dict, var, utf8_name);
-         else
-           msg (MW,
-            _("Recoded variable name duplicates an existing `%s' within system file."), utf8_name);
-    }
-
-      free (utf8_name);
-
-      /* Convert the variable label */
-      if (var_has_label (var))
-       {
-         char *utf8_label = recode_string (UTF8, enc, var_get_label (var), -1);
-         var_set_label (var, utf8_label);
-         free (utf8_label);
-       }
-
-      if (var_has_value_labels (var))
-       {
-         const struct val_lab *vl = NULL;
-         const struct val_labs *vlabs = var_get_value_labels (var);
-
-         for (vl = val_labs_first (vlabs); vl != NULL; vl = val_labs_next (vlabs, vl))
-           {
-             const union value *val = val_lab_get_value (vl);
-             const char *label = val_lab_get_label (vl);
-             char *new_label = NULL;
-
-             new_label = recode_string (UTF8, enc, label, -1);
-
-             var_replace_value_label (var, val, new_label);
-             free (new_label);
-           }
-       }
-    }
-}
+static void parse_long_string_value_labels (struct sfm_reader *,
+                                            const struct sfm_extension_record *,
+                                            struct dictionary *);
 
 /* Opens the system file designated by file handle FH for
    reading.  Reads the system file's dictionary into *DICT.
    If INFO is non-null, then it receives additional info about the
    system file. */
 struct casereader *
-sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
+sfm_open_reader (struct file_handle *fh, struct dictionary **dictp,
                  struct sfm_read_info *volatile info)
 {
   struct sfm_reader *volatile r = NULL;
-  struct variable **var_by_value_idx;
   struct sfm_read_info local_info;
-  int format_warning_cnt = 0;
+
+  struct sfm_var_record *vars;
+  size_t n_vars, allocated_vars;
+
+  struct sfm_value_label_record *labels;
+  size_t n_labels, allocated_labels;
+
+  struct sfm_document_record *document;
+
+  struct sfm_extension_record *extensions[32];
+
   int weight_idx;
   int claimed_oct_cnt;
-  int rec_type;
+  char *file_label;
 
-  *dict = dict_create ();
+  struct dictionary *dict = NULL;
+  size_t i;
 
   /* Create and initialize reader. */
   r = pool_create_container (struct sfm_reader, pool);
   r->fh = fh_ref (fh);
   r->lock = NULL;
   r->file = NULL;
+  r->pos = 0;
   r->error = false;
-  r->oct_cnt = 0;
-  r->has_long_var_names = false;
   r->opcode_idx = sizeof r->opcodes;
   r->corruption_warning = false;
 
@@ -306,97 +341,177 @@ sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
   if (setjmp (r->bail_out))
     goto error;
 
-
   /* Read header. */
-  read_header (r, *dict, &weight_idx, &claimed_oct_cnt, info);
+  read_header (r, &weight_idx, &claimed_oct_cnt, info, &file_label);
 
-  /* Read all the variable definition records. */
-  rec_type = read_int (r);
-  while (rec_type == 2)
-    {
-      read_variable_record (r, *dict, &format_warning_cnt);
-      rec_type = read_int (r);
-    }
+  vars = NULL;
+  n_vars = allocated_vars = 0;
+
+  labels = NULL;
+  n_labels = allocated_labels = 0;
+
+  document = NULL;
 
-  /* Figure out the case format. */
-  var_by_value_idx = make_var_by_value_idx (r, *dict);
-  setup_weight (r, weight_idx, var_by_value_idx, *dict);
+  memset (extensions, 0, sizeof extensions);
 
-  /* Read all the rest of the dictionary records. */
-  while (rec_type != 999)
+  for (;;)
     {
-      switch (rec_type)
+      int subtype;
+      int type;
+
+      type = read_int (r);
+      if (type == 999)
         {
+          read_int (r);         /* Skip filler. */
+          break;
+        }
+
+      switch (type)
+        {
+        case 2:
+          if (n_vars >= allocated_vars)
+            vars = pool_2nrealloc (r->pool, vars, &allocated_vars,
+                                   sizeof *vars);
+          read_variable_record (r, &vars[n_vars++]);
+          break;
+
         case 3:
-          read_value_labels (r, *dict, var_by_value_idx);
+          if (n_labels >= allocated_labels)
+            labels = pool_2nrealloc (r->pool, labels, &allocated_labels,
+                                     sizeof *labels);
+          read_value_label_record (r, &labels[n_labels++], n_vars);
           break;
 
         case 4:
-          sys_error (r, _("Misplaced type 4 record."));
+          /* A Type 4 record is always immediately after a type 3 record,
+             so the code for type 3 records reads the type 4 record too. */
+          sys_error (r, r->pos, _("Misplaced type 4 record."));
 
         case 6:
-          read_documents (r, *dict);
+          if (document != NULL)
+            sys_error (r, r->pos, _("Duplicate type 6 (document) record."));
+          document = read_document_record (r);
           break;
 
         case 7:
-          read_extension_record (r, *dict, info);
+          subtype = read_int (r);
+          if (subtype < 0 || subtype >= sizeof extensions / sizeof *extensions)
+            {
+              sys_warn (r, r->pos,
+                        _("Unrecognized record type 7, subtype %d.  Please "
+                          "send a copy of this file, and the syntax which "
+                          "created it to %s."),
+                        subtype, PACKAGE_BUGREPORT);
+              skip_extension_record (r, subtype);
+            }
+          else if (extensions[subtype] != NULL)
+            {
+              sys_warn (r, r->pos,
+                        _("Record type 7, subtype %d found here has the same "
+                          "type as the record found near offset 0x%llx.  "
+                          "Please send a copy of this file, and the syntax "
+                          "which created it to %s."),
+                        subtype, (long long int) extensions[subtype]->pos,
+                        PACKAGE_BUGREPORT);
+              skip_extension_record (r, subtype);
+            }
+          else
+            extensions[subtype] = read_extension_record (r, subtype);
           break;
 
         default:
-          sys_error (r, _("Unrecognized record type %d."), rec_type);
+          sys_error (r, r->pos, _("Unrecognized record type %d."), type);
+          goto error;
         }
-      rec_type = read_int (r);
     }
 
+  /* Now actually parse what we read.
 
-  if ( ! r->has_long_var_names )
-    {
-      int i;
-      for (i = 0; i < dict_get_var_cnt (*dict); i++)
-       {
-         struct variable *var = dict_get_var (*dict, i);
-         char short_name[SHORT_NAME_LEN + 1];
-         char long_name[SHORT_NAME_LEN + 1];
+     First, figure out the correct character encoding, because this determines
+     how the rest of the header data is to be interpreted. */
+  dict = dict_create (choose_encoding (r, extensions[EXT_INTEGER],
+                                       extensions[EXT_ENCODING]));
+  r->encoding = dict_get_encoding (dict);
 
-         strcpy (short_name, var_get_name (var));
+  /* These records don't use variables at all. */
+  if (document != NULL)
+    parse_document (dict, document);
 
-         strcpy (long_name, short_name);
-         str_lowercase (long_name);
+  if (extensions[EXT_INTEGER] != NULL)
+    parse_machine_integer_info (r, extensions[EXT_INTEGER], info);
 
-         /* Set long name.  Renaming a variable may clear the short
-            name, but we want to retain it, so re-set it
-            explicitly. */
-         dict_rename_var (*dict, var, long_name);
-         var_set_short_name (var, 0, short_name);
-       }
+  if (extensions[EXT_FLOAT] != NULL)
+    parse_machine_float_info (r, extensions[EXT_FLOAT]);
 
-      r->has_long_var_names = true;
+  if (extensions[EXT_FILE_ATTRS] != NULL)
+    parse_data_file_attributes (r, extensions[EXT_FILE_ATTRS], dict);
+
+  parse_file_label (r, file_label, dict);
+
+  /* Parse the variable records, the basis of almost everything else. */
+  parse_variable_records (r, dict, vars, n_vars);
+
+  /* Parse value labels and the weight variable immediately after the variable
+     records.  These records use indexes into var_recs[], so we must parse them
+     before those indexes become invalidated by very long string variables. */
+  for (i = 0; i < n_labels; i++)
+    parse_value_labels (r, dict, vars, n_vars, &labels[i]);
+  if (weight_idx != 0)
+    {
+      struct variable *weight_var;
+
+      weight_var = lookup_var_by_index (r, 76, vars, n_vars, weight_idx);
+      if (var_is_numeric (weight_var))
+        dict_set_weight (dict, weight_var);
+      else
+        sys_error (r, -1, _("Weighting variable must be numeric "
+                            "(not string variable `%s')."),
+                   var_get_name (weight_var));
     }
 
-  recode_strings (*dict);
+  if (extensions[EXT_DISPLAY] != NULL)
+    parse_display_parameters (r, extensions[EXT_DISPLAY], dict);
+
+  /* The following records use short names, so they need to be parsed before
+     parse_long_var_name_map() changes short names to long names. */
+  if (extensions[EXT_MRSETS] != NULL)
+    parse_mrsets (r, extensions[EXT_MRSETS], dict);
+
+  if (extensions[EXT_MRSETS2] != NULL)
+    parse_mrsets (r, extensions[EXT_MRSETS2], dict);
+
+  if (extensions[EXT_LONG_STRINGS] != NULL)
+    parse_long_string_map (r, extensions[EXT_LONG_STRINGS], dict);
+
+  /* Now rename variables to their long names. */
+  parse_long_var_name_map (r, extensions[EXT_LONG_NAMES], dict);
 
-  /* Read record 999 data, which is just filler. */
-  read_int (r);
+  /* The following records use long names, so they need to follow renaming. */
+  if (extensions[EXT_VAR_ATTRS] != NULL)
+    parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
+
+  if (extensions[EXT_LONG_LABELS] != NULL)
+    parse_long_string_value_labels (r, extensions[EXT_LONG_LABELS], dict);
 
   /* Warn if the actual amount of data per case differs from the
      amount that the header claims.  SPSS version 13 gets this
      wrong when very long strings are involved, so don't warn in
      that case. */
-  if (claimed_oct_cnt != -1 && claimed_oct_cnt != r->oct_cnt
+  if (claimed_oct_cnt != -1 && claimed_oct_cnt != n_vars
       && info->version_major != 13)
-    sys_warn (r, _("File header claims %d variable positions but "
-                   "%d were read from file."),
-              claimed_oct_cnt, r->oct_cnt);
+    sys_warn (r, -1, _("File header claims %d variable positions but "
+                       "%zu were read from file."),
+              claimed_oct_cnt, n_vars);
 
   /* Create an index of dictionary variable widths for
      sfm_read_case to use.  We cannot use the `struct variable's
      from the dictionary we created, because the caller owns the
      dictionary and may destroy or modify its variables. */
-  sfm_dictionary_to_sfm_vars (*dict, &r->sfm_vars, &r->sfm_var_cnt);
+  sfm_dictionary_to_sfm_vars (dict, &r->sfm_vars, &r->sfm_var_cnt);
   pool_register (r->pool, free, r->sfm_vars);
-  r->proto = caseproto_ref_pool (dict_get_proto (*dict), r->pool);
+  r->proto = caseproto_ref_pool (dict_get_proto (dict), r->pool);
 
-  pool_free (r->pool, var_by_value_idx);
+  *dictp = dict;
   return casereader_create_sequential
     (NULL, r->proto,
      r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
@@ -404,8 +519,8 @@ sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
 
 error:
   close_reader (r);
-  dict_destroy (*dict);
-  *dict = NULL;
+  dict_destroy (dict);
+  *dictp = NULL;
   return NULL;
 }
 
@@ -462,18 +577,16 @@ sfm_detect (FILE *file)
   return !strcmp ("$FL2", rec_type);
 }
 \f
-/* Reads the global header of the system file.
-   Sets DICT's file label to the system file's label.
-   Sets *WEIGHT_IDX to 0 if the system file is unweighted,
-   or to the value index of the weight variable otherwise.
-   Sets *CLAIMED_OCT_CNT to the number of "octs" (8-byte units)
-   per case that the file claims to have (although it is not
-   always correct).
-   Initializes INFO with header information. */
+/* Reads the global header of the system file.  Sets *WEIGHT_IDX to 0 if the
+   system file is unweighted, or to the value index of the weight variable
+   otherwise.  Sets *CLAIMED_OCT_CNT to the number of "octs" (8-byte units) per
+   case that the file claims to have (although it is not always correct).
+   Initializes INFO with header information.  Stores the file label as a string
+   in dictionary encoding into *FILE_LABELP. */
 static void
-read_header (struct sfm_reader *r, struct dictionary *dict,
-             int *weight_idx, int *claimed_oct_cnt,
-             struct sfm_read_info *info)
+read_header (struct sfm_reader *r, int *weight_idx,
+             int *claimed_oct_cnt, struct sfm_read_info *info,
+             char **file_labelp)
 {
   char rec_type[5];
   char eye_catcher[61];
@@ -482,14 +595,13 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
   char creation_date[10];
   char creation_time[9];
   char file_label[65];
-  struct substring file_label_ss;
   struct substring product;
 
   read_string (r, rec_type, sizeof rec_type);
   read_string (r, eye_catcher, sizeof eye_catcher);
 
   if (strcmp ("$FL2", rec_type) != 0)
-    sys_error (r, _("This is not an SPSS system file."));
+    sys_error (r, 0, _("This is not an SPSS system file."));
 
   /* Identify integer format. */
   read_bytes (r, raw_layout_code, sizeof raw_layout_code);
@@ -499,7 +611,7 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
                              &r->integer_format))
       || (r->integer_format != INTEGER_MSB_FIRST
           && r->integer_format != INTEGER_LSB_FIRST))
-    sys_error (r, _("This is not an SPSS system file."));
+    sys_error (r, 64, _("This is not an SPSS system file."));
 
   *claimed_oct_cnt = read_int (r);
   if (*claimed_oct_cnt < 0 || *claimed_oct_cnt > INT_MAX / 16)
@@ -513,7 +625,6 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
   if ( r->case_cnt > INT_MAX / 2)
     r->case_cnt = -1;
 
-
   /* Identify floating-point format and obtain compression bias. */
   read_bytes (r, raw_bias, sizeof raw_bias);
   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
@@ -521,9 +632,10 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
       uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
       if (memcmp (raw_bias, zero_bias, 8))
-        sys_warn (r, _("Compression bias is not the usual "
-                       "value of 100, or system file uses unrecognized "
-                       "floating-point format."));
+        sys_warn (r, r->pos - 8,
+                  _("Compression bias is not the usual "
+                    "value of 100, or system file uses unrecognized "
+                    "floating-point format."));
       else
         {
           /* Some software is known to write all-zeros to this
@@ -545,14 +657,6 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
   read_string (r, file_label, sizeof file_label);
   skip_bytes (r, 3);
 
-  file_label_ss = ss_cstr (file_label);
-  ss_trim (&file_label_ss, ss_cstr (" "));
-  if (!ss_is_empty (file_label_ss))
-    {
-      ss_data (file_label_ss)[ss_length (file_label_ss)] = '\0';
-      dict_set_label (dict, ss_data (file_label_ss));
-    }
-
   strcpy (info->creation_date, creation_date);
   strcpy (info->creation_time, creation_time);
   info->integer_format = r->integer_format;
@@ -565,67 +669,37 @@ read_header (struct sfm_reader *r, struct dictionary *dict,
   ss_trim (&product, ss_cstr (" "));
   str_copy_buf_trunc (info->product, sizeof info->product,
                       ss_data (product), ss_length (product));
+
+  *file_labelp = pool_strdup0 (r->pool, file_label, sizeof file_label - 1);
 }
 
-/* Reads a variable (type 2) record from R and adds the
-   corresponding variable to DICT.
-   Also skips past additional variable records for long string
-   variables. */
+/* Reads a variable (type 2) record from R into RECORD. */
 static void
-read_variable_record (struct sfm_reader *r, struct dictionary *dict,
-                      int *format_warning_cnt)
+read_variable_record (struct sfm_reader *r, struct sfm_var_record *record)
 {
-  int width;
   int has_variable_label;
-  int missing_value_code;
-  int print_format;
-  int write_format;
-  char name[9];
 
-  struct variable *var;
-  int nv;
+  memset (record, 0, sizeof *record);
 
-  width = read_int (r);
+  record->pos = r->pos;
+  record->width = read_int (r);
   has_variable_label = read_int (r);
-  missing_value_code = read_int (r);
-  print_format = read_int (r);
-  write_format = read_int (r);
-  read_string (r, name, sizeof name);
-  name[strcspn (name, " ")] = '\0';
-
-  /* Check variable name. */
-  if (name[0] == '$' || name[0] == '#')
-    sys_error (r, _("Variable name begins with invalid character `%c'."),
-               name[0]);
-  if (!var_is_plausible_name (name, false))
-    sys_error (r, _("Invalid variable name `%s'."), name);
-
-  /* Create variable. */
-  if (width < 0 || width > 255)
-    sys_error (r, _("Bad width %d for variable %s."), width, name);
-  var = dict_create_var (dict, name, width);
-  if (var == NULL)
-    sys_error (r,
-               _("Duplicate variable name `%s' within system file."),
-               name);
-
-  /* Set the short name the same as the long name. */
-  var_set_short_name (var, 0, var_get_name (var));
-
-  /* Get variable label, if any. */
-  if (has_variable_label != 0 && has_variable_label != 1)
-    sys_error (r, _("Variable label indicator field is not 0 or 1."));
+  record->missing_value_code = read_int (r);
+  record->print_format = read_int (r);
+  record->write_format = read_int (r);
+  read_bytes (r, record->name, sizeof record->name);
+
   if (has_variable_label == 1)
     {
+      enum { MAX_LABEL_LEN = 255 };
       size_t len, read_len;
-      char label[255 + 1];
 
       len = read_int (r);
 
-      /* Read up to 255 bytes of label. */
-      read_len = MIN (sizeof label - 1, len);
-      read_string (r, label, read_len + 1);
-      var_set_label (var, label);
+      /* Read up to MAX_LABEL_LEN bytes of label. */
+      read_len = MIN (MAX_LABEL_LEN, len);
+      record->label = xmalloc (read_len + 1);
+      read_string (r, record->label, read_len + 1);
 
       /* Skip unread label bytes. */
       skip_bytes (r, len - read_len);
@@ -633,108 +707,360 @@ read_variable_record (struct sfm_reader *r, struct dictionary *dict,
       /* Skip label padding up to multiple of 4 bytes. */
       skip_bytes (r, ROUND_UP (len, 4) - len);
     }
+  else if (has_variable_label != 0)
+    sys_error (r, record->pos,
+               _("Variable label indicator field is not 0 or 1."));
 
   /* Set missing values. */
-  if (missing_value_code != 0)
+  if (record->missing_value_code != 0)
     {
-      struct missing_values mv;
-      int i;
-
-      mv_init_pool (r->pool, &mv, var_get_width (var));
-      if (var_is_numeric (var))
+      int code = record->missing_value_code;
+      if (record->width == 0)
         {
-          if (missing_value_code < -3 || missing_value_code > 3
-              || missing_value_code == -1)
-            sys_error (r, _("Numeric missing value indicator field is not "
-                            "-3, -2, 0, 1, 2, or 3."));
-          if (missing_value_code < 0)
-            {
-              double low = read_float (r);
-              double high = read_float (r);
-              mv_add_range (&mv, low, high);
-              missing_value_code = -missing_value_code - 2;
-            }
-          for (i = 0; i < missing_value_code; i++)
-            mv_add_num (&mv, read_float (r));
+          if (code < -3 || code > 3 || code == -1)
+            sys_error (r, record->pos,
+                       _("Numeric missing value indicator field is not "
+                         "-3, -2, 0, 1, 2, or 3."));
         }
       else
         {
-          int mv_width = MAX (width, 8);
-          union value value;
+          if (code < 1 || code > 3)
+            sys_error (r, record->pos,
+                       _("String missing value indicator field is not "
+                         "0, 1, 2, or 3."));
+        }
 
-          if (missing_value_code < 1 || missing_value_code > 3)
-            sys_error (r, _("String missing value indicator field is not "
-                            "0, 1, 2, or 3."));
+      read_bytes (r, record->missing, 8 * abs (code));
+    }
+}
 
-          value_init (&value, mv_width);
-          value_set_missing (&value, mv_width);
-          for (i = 0; i < missing_value_code; i++)
-            {
-              uint8_t *s = value_str_rw (&value, mv_width);
-              read_bytes (r, s, 8);
-              mv_add_str (&mv, s);
-            }
-          value_destroy (&value, mv_width);
-        }
-      var_set_missing_values (var, &mv);
+/* Reads value labels from R into RECORD. */
+static void
+read_value_label_record (struct sfm_reader *r,
+                         struct sfm_value_label_record *record,
+                         size_t n_vars)
+{
+  size_t i;
+
+  /* Read type 3 record. */
+  record->pos = r->pos;
+  record->n_labels = read_int (r);
+  if (record->n_labels > SIZE_MAX / sizeof *record->labels)
+    sys_error (r, r->pos - 4, _("Invalid number of labels %zu."),
+               record->n_labels);
+  record->labels = pool_nmalloc (r->pool, record->n_labels,
+                                 sizeof *record->labels);
+  for (i = 0; i < record->n_labels; i++)
+    {
+      struct sfm_value_label *label = &record->labels[i];
+      unsigned char label_len;
+      size_t padded_len;
+
+      read_bytes (r, label->value, sizeof label->value);
+
+      /* Read label length. */
+      read_bytes (r, &label_len, sizeof label_len);
+      padded_len = ROUND_UP (label_len + 1, 8);
+
+      /* Read label, padding. */
+      label->label = pool_malloc (r->pool, padded_len + 1);
+      read_bytes (r, label->label, padded_len - 1);
+      label->label[label_len] = '\0';
     }
 
-  /* Set formats. */
-  parse_format_spec (r, print_format, PRINT_FORMAT, var, format_warning_cnt);
-  parse_format_spec (r, write_format, WRITE_FORMAT, var, format_warning_cnt);
+  /* Read record type of type 4 record. */
+  if (read_int (r) != 4)
+    sys_error (r, r->pos - 4,
+               _("Variable index record (type 4) does not immediately "
+                 "follow value label record (type 3) as it should."));
 
-  /* Account for values.
-     Skip long string continuation records, if any. */
-  nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
-  r->oct_cnt += nv;
-  if (width > 8)
+  /* Read number of variables associated with value label from type 4
+     record. */
+  record->n_vars = read_int (r);
+  if (record->n_vars < 1 || record->n_vars > n_vars)
+    sys_error (r, r->pos - 4,
+               _("Number of variables associated with a value label (%zu) "
+                 "is not between 1 and the number of variables (%zu)."),
+               record->n_vars, n_vars);
+  record->vars = pool_nmalloc (r->pool, record->n_vars, sizeof *record->vars);
+  for (i = 0; i < record->n_vars; i++)
+    record->vars[i] = read_int (r);
+}
+
+/* Reads a document record from R and returns it. */
+static struct sfm_document_record *
+read_document_record (struct sfm_reader *r)
+{
+  struct sfm_document_record *record;
+  int n_lines;
+
+  record = pool_malloc (r->pool, sizeof *record);
+  record->pos = r->pos;
+
+  n_lines = read_int (r);
+  if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH)
+    sys_error (r, record->pos,
+               _("Number of document lines (%d) "
+                 "must be greater than 0 and less than %d."),
+               n_lines, INT_MAX / DOC_LINE_LENGTH);
+
+  record->n_lines = n_lines;
+  record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines);
+  read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines);
+
+  return record;
+}
+
+static void
+read_extension_record_header (struct sfm_reader *r, int subtype,
+                              struct sfm_extension_record *record)
+{
+  record->pos = r->pos;
+  record->size = read_int (r);
+  record->count = read_int (r);
+
+  /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
+     allows an extra byte for a null terminator, used by some
+     extension processing routines. */
+  if (record->size != 0
+      && size_overflow_p (xsum (1, xtimes (record->count, record->size))))
+    sys_error (r, record->pos, "Record type 7 subtype %d too large.", subtype);
+}
+
+/* Reads an extension record from R into RECORD. */
+static struct sfm_extension_record *
+read_extension_record (struct sfm_reader *r, int subtype)
+{
+  struct extension_record_type
     {
-      int i;
+      int subtype;
+      int size;
+      int count;
+    };
+
+  static const struct extension_record_type types[] =
+    {
+      /* Implemented record types. */
+      { EXT_INTEGER,      4, 8 },
+      { EXT_FLOAT,        8, 3 },
+      { EXT_MRSETS,       1, 0 },
+      { EXT_DISPLAY,      4, 0 },
+      { EXT_LONG_NAMES,   1, 0 },
+      { EXT_LONG_STRINGS, 1, 0 },
+      { EXT_NCASES,       8, 2 },
+      { EXT_FILE_ATTRS,   1, 0 },
+      { EXT_VAR_ATTRS,    1, 0 },
+      { EXT_MRSETS2,      1, 0 },
+      { EXT_ENCODING,     1, 0 },
+      { EXT_LONG_LABELS,  1, 0 },
+
+      /* Ignored record types. */
+      { EXT_VAR_SETS,     0, 0 },
+      { EXT_DATE,         0, 0 },
+      { EXT_DATA_ENTRY,   0, 0 },
+    };
+
+  const struct extension_record_type *type;
+  struct sfm_extension_record *record;
+  size_t n_bytes;
+
+  record = pool_malloc (r->pool, sizeof *record);
+  read_extension_record_header (r, subtype, record);
+  n_bytes = record->count * record->size;
+
+  for (type = types; type < &types[sizeof types / sizeof *types]; type++)
+    if (subtype == type->subtype)
+      {
+        if (type->size > 0 && record->size != type->size)
+          sys_warn (r, record->pos,
+                    _("Record type 7, subtype %d has bad size %zu "
+                      "(expected %d)."), subtype, record->size, type->size);
+        else if (type->count > 0 && record->count != type->count)
+          sys_warn (r, record->pos,
+                    _("Record type 7, subtype %d has bad count %zu "
+                      "(expected %d)."), subtype, record->count, type->count);
+        else if (type->count == 0 && type->size == 0)
+          {
+            /* Ignore this record. */
+          }
+        else
+          {
+            char *data = pool_malloc (r->pool, n_bytes + 1);
+            data[n_bytes] = '\0';
+
+            record->data = data;
+            read_bytes (r, record->data, n_bytes);
+            return record;
+          }
+
+        goto skip;
+      }
+
+  sys_warn (r, record->pos,
+            _("Unrecognized record type 7, subtype %d.  Please send a "
+              "copy of this file, and the syntax which created it to %s."),
+            subtype, PACKAGE_BUGREPORT);
+
+skip:
+  skip_bytes (r, n_bytes);
+  return NULL;
+}
+
+static void
+skip_extension_record (struct sfm_reader *r, int subtype)
+{
+  struct sfm_extension_record record;
+
+  read_extension_record_header (r, subtype, &record);
+  skip_bytes (r, record.count * record.size);
+}
 
-      for (i = 1; i < nv; i++)
+static void
+parse_file_label (struct sfm_reader *r, const char *file_label,
+                  struct dictionary *dict)
+{
+  char *utf8_file_label;
+  size_t file_label_len;
+
+  utf8_file_label = recode_string_pool ("UTF-8", dict_get_encoding (dict),
+                                        file_label, -1, r->pool);
+  file_label_len = strlen (utf8_file_label);
+  while (file_label_len > 0 && utf8_file_label[file_label_len - 1] == ' ')
+    file_label_len--;
+  utf8_file_label[file_label_len] = '\0';
+  dict_set_label (dict, utf8_file_label);
+}
+
+/* Reads a variable (type 2) record from R and adds the
+   corresponding variable to DICT.
+   Also skips past additional variable records for long string
+   variables. */
+static void
+parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
+                        struct sfm_var_record *var_recs, size_t n_var_recs)
+{
+  const char *dict_encoding = dict_get_encoding (dict);
+  struct sfm_var_record *rec;
+  int n_warnings = 0;
+
+  for (rec = var_recs; rec < &var_recs[n_var_recs]; )
+    {
+      struct variable *var;
+      size_t n_values;
+      char *name;
+      size_t i;
+
+      name = recode_string_pool ("UTF-8", dict_encoding,
+                                 rec->name, 8, r->pool);
+      name[strcspn (name, " ")] = '\0';
+
+      if (!dict_id_is_valid (dict, name, false)
+          || name[0] == '$' || name[0] == '#')
+        sys_error (r, rec->pos, _("Invalid variable name `%s'."), name);
+
+      if (rec->width < 0 || rec->width > 255)
+        sys_error (r, rec->pos,
+                   _("Bad width %d for variable %s."), rec->width, name);
+
+      var = rec->var = dict_create_var (dict, name, rec->width);
+      if (var == NULL)
+        sys_error (r, rec->pos, _("Duplicate variable name `%s'."), name);
+
+      /* Set the short name the same as the long name. */
+      var_set_short_name (var, 0, name);
+
+      /* Get variable label, if any. */
+      if (rec->label)
+        {
+          char *utf8_label;
+
+          utf8_label = recode_string_pool ("UTF-8", dict_encoding,
+                                           rec->label, -1, r->pool);
+          var_set_label (var, utf8_label, false);
+        }
+
+      /* Set missing values. */
+      if (rec->missing_value_code != 0)
         {
-          /* Check for record type 2 and width -1. */
-          if (read_int (r) != 2 || read_int (r) != -1)
-            sys_error (r, _("Missing string continuation record."));
-
-          /* Skip and ignore remaining continuation data. */
-          has_variable_label = read_int (r);
-          missing_value_code = read_int (r);
-          print_format = read_int (r);
-          write_format = read_int (r);
-          read_string (r, name, sizeof name);
-
-          /* Variable label fields on continuation records have
-             been spotted in system files created by "SPSS Power
-             Macintosh Release 6.1". */
-          if (has_variable_label)
-            skip_bytes (r, ROUND_UP (read_int (r), 4));
+          int width = var_get_width (var);
+          struct missing_values mv;
+
+          mv_init_pool (r->pool, &mv, width);
+          if (var_is_numeric (var))
+            {
+              bool has_range = rec->missing_value_code < 0;
+              int n_discrete = (has_range
+                                ? rec->missing_value_code == -3
+                                : rec->missing_value_code);
+              int ofs = 0;
+
+              if (has_range)
+                {
+                  double low = parse_float (r, rec->missing, 0);
+                  double high = parse_float (r, rec->missing, 8);
+                  mv_add_range (&mv, low, high);
+                  ofs += 16;
+                }
+
+              for (i = 0; i < n_discrete; i++)
+                {
+                  mv_add_num (&mv, parse_float (r, rec->missing, ofs));
+                  ofs += 8;
+                }
+            }
+          else
+            {
+              union value value;
+
+              value_init_pool (r->pool, &value, width);
+              value_set_missing (&value, width);
+              for (i = 0; i < rec->missing_value_code; i++)
+                {
+                  uint8_t *s = value_str_rw (&value, width);
+                  memcpy (s, rec->missing + 8 * i, MIN (width, 8));
+                  mv_add_str (&mv, s);
+                }
+            }
+          var_set_missing_values (var, &mv);
         }
+
+      /* Set formats. */
+      parse_format_spec (r, rec->pos + 12, rec->print_format,
+                         PRINT_FORMAT, var, &n_warnings);
+      parse_format_spec (r, rec->pos + 16, rec->write_format,
+                         WRITE_FORMAT, var, &n_warnings);
+
+      /* Account for values.
+         Skip long string continuation records, if any. */
+      n_values = rec->width == 0 ? 1 : DIV_RND_UP (rec->width, 8);
+      for (i = 1; i < n_values; i++)
+        if (i + (rec - var_recs) >= n_var_recs || rec[i].width != -1)
+          sys_error (r, rec->pos, _("Missing string continuation record."));
+      rec += n_values;
     }
 }
 
 /* Translates the format spec from sysfile format to internal
    format. */
 static void
-parse_format_spec (struct sfm_reader *r, unsigned int s,
+parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
                    enum which_format which, struct variable *v,
-                   int *format_warning_cnt)
+                   int *n_warnings)
 {
-  const int max_format_warnings = 8;
+  const int max_warnings = 8;
+  uint8_t raw_type = format >> 16;
+  uint8_t w = format >> 8;
+  uint8_t d = format;
   struct fmt_spec f;
-  uint8_t raw_type = s >> 16;
-  uint8_t w = s >> 8;
-  uint8_t d = s;
-
   bool ok;
 
-  if (!fmt_from_io (raw_type, &f.type))
-    sys_error (r, _("Unknown variable format %"PRIu8"."), raw_type);
   f.w = w;
   f.d = d;
 
   msg_disable ();
-  ok = fmt_check_output (&f) && fmt_check_width_compat (&f, var_get_width (v));
+  ok = (fmt_from_io (raw_type, &f.type)
+        && fmt_check_output (&f)
+        && fmt_check_width_compat (&f, var_get_width (v)));
   msg_enable ();
 
   if (ok)
@@ -744,188 +1070,64 @@ parse_format_spec (struct sfm_reader *r, unsigned int s,
       else
         var_set_write_format (v, &f);
     }
-  else if (*++format_warning_cnt <= max_format_warnings)
+  else if (format == 0)
     {
-      char fmt_string[FMT_STRING_LEN_MAX + 1];
-      sys_warn (r, _("%s variable %s has invalid %s format %s."),
-                var_is_numeric (v) ? _("Numeric") : _("String"),
-                var_get_name (v),
-                which == PRINT_FORMAT ? _("print") : _("write"),
-                fmt_to_string (&f, fmt_string));
-
-      if (*format_warning_cnt == max_format_warnings)
-        sys_warn (r, _("Suppressing further invalid format warnings."));
+      /* Actually observed in the wild.  No point in warning about it. */
     }
-}
-
-/* Sets the weighting variable in DICT to the variable
-   corresponding to the given 1-based VALUE_IDX, if VALUE_IDX is
-   nonzero. */
-static void
-setup_weight (struct sfm_reader *r, int weight_idx,
-              struct variable **var_by_value_idx, struct dictionary *dict)
-{
-  if (weight_idx != 0)
+  else if (++*n_warnings <= max_warnings)
     {
-      struct variable *weight_var
-        = lookup_var_by_value_idx (r, var_by_value_idx, weight_idx);
-      if (var_is_numeric (weight_var))
-        dict_set_weight (dict, weight_var);
+      if (which == PRINT_FORMAT)
+        sys_warn (r, pos, _("Variable %s with width %d has invalid print "
+                            "format 0x%x."),
+                  var_get_name (v), var_get_width (v), format);
       else
-        sys_error (r, _("Weighting variable must be numeric."));
-    }
-}
+        sys_warn (r, pos, _("Variable %s with width %d has invalid write "
+                            "format 0x%x."),
+                  var_get_name (v), var_get_width (v), format);
 
-/* Reads a document record, type 6, from system file R, and sets up
-   the documents and n_documents fields in the associated
-   dictionary. */
-static void
-read_documents (struct sfm_reader *r, struct dictionary *dict)
-{
-  int line_cnt;
-  char *documents;
-
-  if (dict_get_documents (dict) != NULL)
-    sys_error (r, _("Multiple type 6 (document) records."));
-
-  line_cnt = read_int (r);
-  if (line_cnt <= 0)
-    sys_error (r, _("Number of document lines (%d) "
-                    "must be greater than 0."), line_cnt);
-
-  documents = pool_nmalloc (r->pool, line_cnt + 1, DOC_LINE_LENGTH);
-  read_string (r, documents, DOC_LINE_LENGTH * line_cnt + 1);
-  if (strlen (documents) == DOC_LINE_LENGTH * line_cnt)
-    dict_set_documents (dict, documents);
-  else
-    sys_error (r, _("Document line contains null byte."));
-  pool_free (r->pool, documents);
+      if (*n_warnings == max_warnings)
+        sys_warn (r, -1, _("Suppressing further invalid format warnings."));
+    }
 }
 
-/* Read a type 7 extension record. */
 static void
-read_extension_record (struct sfm_reader *r, struct dictionary *dict,
-                       struct sfm_read_info *info)
+parse_document (struct dictionary *dict, struct sfm_document_record *record)
 {
-  int subtype = read_int (r);
-  size_t size = read_int (r);
-  size_t count = read_int (r);
-  size_t bytes = size * count;
+  const char *p;
 
-  /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
-     allows an extra byte for a null terminator, used by some
-     extension processing routines. */
-  if (size != 0 && size_overflow_p (xsum (1, xtimes (count, size))))
-    sys_error (r, "Record type 7 subtype %d too large.", subtype);
-
-  switch (subtype)
+  for (p = record->documents;
+       p < record->documents + DOC_LINE_LENGTH * record->n_lines;
+       p += DOC_LINE_LENGTH)
     {
-    case 3:
-      read_machine_integer_info (r, size, count, info, dict);
-      return;
-
-    case 4:
-      read_machine_float_info (r, size, count);
-      return;
+      struct substring line;
 
-    case 5:
-      /* Variable sets information.  We don't use these yet.
-         They only apply to GUIs; see VARSETS on the APPLY
-         DICTIONARY command in SPSS documentation. */
-      break;
-
-    case 6:
-      /* DATE variable information.  We don't use it yet, but we
-         should. */
-      break;
-
-    case 7:
-    case 19:
-      read_mrsets (r, size, count, dict);
-      return;
-
-    case 8:
-      /* Used by the SPSS Data Entry software. */
-      break;
+      line = recode_substring_pool ("UTF-8", dict_get_encoding (dict),
+                                    ss_buffer (p, DOC_LINE_LENGTH), NULL);
+      ss_rtrim (&line, ss_cstr (" "));
+      line.string[line.length] = '\0';
 
-    case 11:
-      read_display_parameters (r, size, count, dict);
-      return;
+      dict_add_document_line (dict, line.string, false);
 
-    case 13:
-      read_long_var_name_map (r, size, count, dict);
-      return;
-
-    case 14:
-      read_long_string_map (r, size, count, dict);
-      return;
-
-    case 16:
-      /* Extended number of cases.  Not important. */
-      break;
-
-    case 17:
-      read_data_file_attributes (r, size, count, dict);
-      return;
-
-    case 18:
-      read_variable_attributes (r, size, count, dict);
-      return;
-
-    case 20:
-      /* New in SPSS 16.  Contains a single string that describes
-         the character encoding, e.g. "windows-1252". */
-      {
-       char *encoding = pool_calloc (r->pool, size, count + 1);
-       read_string (r, encoding, count + 1);
-       dict_set_encoding (dict, encoding);
-       return;
-      }
-
-    case 21:
-      /* New in SPSS 16.  Encodes value labels for long string
-         variables. */
-      read_long_string_value_labels (r, size, count, dict);
-      return;
-
-    default:
-      sys_warn (r, _("Unrecognized record type 7, subtype %d.  Please send a copy of this file, and the syntax which created it to %s"),
-               subtype, PACKAGE_BUGREPORT);
-      break;
+      ss_dealloc (&line);
     }
-
-  skip_bytes (r, bytes);
 }
 
-/* Read record type 7, subtype 3. */
+/* Parses record type 7, subtype 3. */
 static void
-read_machine_integer_info (struct sfm_reader *r, size_t size, size_t count,
-                           struct sfm_read_info *info,
-                          struct dictionary *dict)
+parse_machine_integer_info (struct sfm_reader *r,
+                            const struct sfm_extension_record *record,
+                            struct sfm_read_info *info)
 {
-  int version_major = read_int (r);
-  int version_minor = read_int (r);
-  int version_revision = read_int (r);
-  int machine_code UNUSED = read_int (r);
-  int float_representation = read_int (r);
-  int compression_code UNUSED = read_int (r);
-  int integer_representation = read_int (r);
-  int character_code = read_int (r);
-
-  int expected_float_format;
-  int expected_integer_format;
-
-  if (size != 4 || count != 8)
-    sys_error (r, _("Bad size (%zu) or count (%zu) field on record type 7, "
-                    "subtype 3."),
-                size, count);
+  int float_representation, expected_float_format;
+  int integer_representation, expected_integer_format;
 
   /* Save version info. */
-  info->version_major = version_major;
-  info->version_minor = version_minor;
-  info->version_revision = version_revision;
+  info->version_major = parse_int (r, record->data, 0);
+  info->version_minor = parse_int (r, record->data, 4);
+  info->version_revision = parse_int (r, record->data, 8);
 
   /* Check floating point format. */
+  float_representation = parse_int (r, record->data, 16);
   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
     expected_float_format = 1;
@@ -936,11 +1138,12 @@ read_machine_integer_info (struct sfm_reader *r, size_t size, size_t count,
   else
     NOT_REACHED ();
   if (float_representation != expected_float_format)
-    sys_error (r, _("Floating-point representation indicated by "
-                    "system file (%d) differs from expected (%d)."),
-               r->float_format, expected_float_format);
+    sys_error (r, record->pos, _("Floating-point representation indicated by "
+                 "system file (%d) differs from expected (%d)."),
+               float_representation, expected_float_format);
 
   /* Check integer format. */
+  integer_representation = parse_int (r, record->data, 24);
   if (r->integer_format == INTEGER_MSB_FIRST)
     expected_integer_format = 1;
   else if (r->integer_format == INTEGER_LSB_FIRST)
@@ -948,93 +1151,92 @@ read_machine_integer_info (struct sfm_reader *r, size_t size, size_t count,
   else
     NOT_REACHED ();
   if (integer_representation != expected_integer_format)
-    {
-      static const char *const endian[] = {N_("Little Endian"), N_("Big Endian")};
-      sys_warn (r, _("Integer format indicated by system file (%s) "
-                     "differs from expected (%s)."),
-                gettext (endian[integer_representation == 1]),
-                gettext (endian[expected_integer_format == 1]));
-    }
+    sys_warn (r, record->pos,
+              _("Integer format indicated by system file (%d) "
+                "differs from expected (%d)."),
+              integer_representation, expected_integer_format);
 
+}
 
-  /*
-    Record 7 (20) provides a much more reliable way of
-    setting the encoding.
-    The character_code is used as a fallback only.
-  */
-  if ( NULL == dict_get_encoding (dict))
+static const char *
+choose_encoding (struct sfm_reader *r,
+                 const struct sfm_extension_record *ext_integer,
+                 const struct sfm_extension_record *ext_encoding)
+{
+  /* The EXT_ENCODING record is a more reliable way to determine dictionary
+     encoding. */
+  if (ext_encoding)
+    return ext_encoding->data;
+
+  /* But EXT_INTEGER is better than nothing as a fallback. */
+  if (ext_integer)
     {
-      switch (character_code)
-       {
-       case 1:
-         dict_set_encoding (dict, "EBCDIC-US");
-         break;
-       case 2:
-       case 3:
-         /* These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
-            respectively.   However, there are known to be many files
-            in the wild with character code 2, yet have data which are
-            clearly not ascii.
-            Therefore we ignore these values.
-         */
-         return;
-       case 4:
-         dict_set_encoding (dict, "MS_KANJI");
-         break;
-       case 65000:
-         dict_set_encoding (dict, "UTF-7");
-         break;
-       case 65001:
-         dict_set_encoding (dict, "UTF-8");
-         break;
-       default:
-         {
-           char enc[100];
-           snprintf (enc, 100, "CP%d", character_code);
-           dict_set_encoding (dict, enc);
-         }
-         break;
-       };
+      int codepage = parse_int (r, ext_integer->data, 7 * 4);
+      const char *encoding;
+
+      switch (codepage)
+        {
+        case 1:
+          return "EBCDIC-US";
+
+        case 2:
+        case 3:
+          /* These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
+             respectively.  However, there are known to be many files in the wild
+             with character code 2, yet have data which are clearly not ASCII.
+             Therefore we ignore these values. */
+          break;
+
+        case 4:
+          return "MS_KANJI";
+
+        default:
+          encoding = sys_get_encoding_from_codepage (codepage);
+          if (encoding != NULL)
+            return encoding;
+          break;
+        }
     }
+
+  return locale_charset ();
 }
 
-/* Read record type 7, subtype 4. */
+/* Parses record type 7, subtype 4. */
 static void
-read_machine_float_info (struct sfm_reader *r, size_t size, size_t count)
+parse_machine_float_info (struct sfm_reader *r,
+                          const struct sfm_extension_record *record)
 {
-  double sysmis = read_float (r);
-  double highest = read_float (r);
-  double lowest = read_float (r);
-
-  if (size != 8 || count != 3)
-    sys_error (r, _("Bad size (%zu) or count (%zu) on extension 4."),
-               size, count);
+  double sysmis = parse_float (r, record->data, 0);
+  double highest = parse_float (r, record->data, 8);
+  double lowest = parse_float (r, record->data, 16);
 
   if (sysmis != SYSMIS)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
+    sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
               sysmis, "SYSMIS");
 
   if (highest != HIGHEST)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
+    sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
               highest, "HIGHEST");
 
   if (lowest != LOWEST)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
+    sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
               lowest, "LOWEST");
 }
 
-/* Read record type 7, subtype 7 or 19. */
+/* Parses record type 7, subtype 7 or 19. */
 static void
-read_mrsets (struct sfm_reader *r, size_t size, size_t count,
-             struct dictionary *dict)
+parse_mrsets (struct sfm_reader *r, const struct sfm_extension_record *record,
+              struct dictionary *dict)
 {
   struct text_record *text;
   struct mrset *mrset;
 
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, record, false);
   for (;;)
     {
-      const char *name, *label, *counted;
+      const char *counted = NULL;
+      const char *name;
+      const char *label;
       struct stringi_set var_names;
       size_t allocated_vars;
       char delimiter;
@@ -1045,15 +1247,24 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
       name = text_get_token (text, ss_cstr ("="), NULL);
       if (name == NULL)
         break;
-      mrset->name = xstrdup (name);
+      mrset->name = recode_string ("UTF-8", r->encoding, name, -1);
+
+      if (mrset->name[0] != '$')
+        {
+          sys_warn (r, record->pos,
+                    _("`%s' does not begin with `$' at offset %zu "
+                      "in MRSETS record."), mrset->name, text_pos (text));
+          break;
+        }
 
       if (text_match (text, 'C'))
         {
           mrset->type = MRSET_MC;
           if (!text_match (text, ' '))
             {
-              sys_warn (r, _("Missing space following `%c' at offset %zu "
-                             "in MRSETS record"), 'C', text_pos (text));
+              sys_warn (r, record->pos,
+                        _("Missing space following `%c' at offset %zu "
+                          "in MRSETS record."), 'C', text_pos (text));
               break;
             }
         }
@@ -1070,8 +1281,9 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
           mrset->cat_source = MRSET_COUNTEDVALUES;
           if (!text_match (text, ' '))
             {
-              sys_warn (r, _("Missing space following `%c' at offset %zu "
-                             "in MRSETS record"), 'E',  text_pos (text));
+              sys_warn (r, record->pos,
+                        _("Missing space following `%c' at offset %zu "
+                          "in MRSETS record."), 'E',  text_pos (text));
               break;
             }
 
@@ -1079,14 +1291,16 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
           if (!strcmp (number, "11"))
             mrset->label_from_var_label = true;
           else if (strcmp (number, "1"))
-            sys_warn (r, _("Unexpected label source value `%s' "
-                           "following `E' at offset %zu in MRSETS record"),
+            sys_warn (r, record->pos,
+                      _("Unexpected label source value `%s' following `E' "
+                        "at offset %zu in MRSETS record."),
                       number, text_pos (text));
         }
       else
         {
-          sys_warn (r, _("Missing `C', `D', or `E' at offset %zu "
-                         "in MRSETS record."),
+          sys_warn (r, record->pos,
+                    _("Missing `C', `D', or `E' at offset %zu "
+                      "in MRSETS record."),
                     text_pos (text));
           break;
         }
@@ -1101,35 +1315,45 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
       label = text_parse_counted_string (r, text);
       if (label == NULL)
         break;
-      mrset->label = label[0] != '\0' ? xstrdup (label) : NULL;
+      if (label[0] != '\0')
+        mrset->label = recode_string ("UTF-8", r->encoding, label, -1);
 
       stringi_set_init (&var_names);
       allocated_vars = 0;
       width = INT_MAX;
       do
         {
+          const char *raw_var_name;
           struct variable *var;
-          const char *var_name;
+          char *var_name;
 
-          var_name = text_get_token (text, ss_cstr (" \n"), &delimiter);
-          if (var_name == NULL)
+          raw_var_name = text_get_token (text, ss_cstr (" \n"), &delimiter);
+          if (raw_var_name == NULL)
             {
-              sys_warn (r, _("Missing new-line parsing variable names "
-                             "at offset %zu in MRSETS record."),
+              sys_warn (r, record->pos,
+                        _("Missing new-line parsing variable names "
+                          "at offset %zu in MRSETS record."),
                         text_pos (text));
               break;
             }
+          var_name = recode_string ("UTF-8", r->encoding, raw_var_name, -1);
 
-          var = lookup_var_by_short_name (dict, var_name);
+          var = dict_lookup_var (dict, var_name);
           if (var == NULL)
-            continue;
+            {
+              free (var_name);
+              continue;
+            }
           if (!stringi_set_insert (&var_names, var_name))
             {
-              sys_warn (r, _("Duplicate variable name %s "
-                             "at offset %zu in MRSETS record."),
+              sys_warn (r, record->pos,
+                        _("Duplicate variable name %s "
+                          "at offset %zu in MRSETS record."),
                         var_name, text_pos (text));
+              free (var_name);
               continue;
             }
+          free (var_name);
 
           if (mrset->label == NULL && mrset->label_from_var_label
               && var_has_label (var))
@@ -1138,8 +1362,9 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
           if (mrset->n_vars
               && var_get_type (var) != var_get_type (mrset->vars[0]))
             {
-              sys_warn (r, _("MRSET %s contains both string and "
-                             "numeric variables."), name);
+              sys_warn (r, record->pos,
+                        _("MRSET %s contains both string and "
+                          "numeric variables."), name);
               continue;
             }
           width = MIN (width, var_get_width (var));
@@ -1153,7 +1378,8 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
 
       if (mrset->n_vars < 2)
         {
-          sys_warn (r, _("MRSET %s has only %zu variables."), mrset->name,
+          sys_warn (r, record->pos,
+                    _("MRSET %s has only %zu variables."), mrset->name,
                     mrset->n_vars);
           mrset_destroy (mrset);
           continue;
@@ -1181,40 +1407,48 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count,
 /* Read record type 7, subtype 11, which specifies how variables
    should be displayed in GUI environments. */
 static void
-read_display_parameters (struct sfm_reader *r, size_t size, size_t count,
+parse_display_parameters (struct sfm_reader *r,
+                         const struct sfm_extension_record *record,
                          struct dictionary *dict)
 {
-  size_t n_vars;
   bool includes_width;
   bool warned = false;
+  size_t n_vars;
+  size_t ofs;
   size_t i;
 
-  if (size != 4)
-    {
-      sys_warn (r, _("Bad size %zu on extension 11."), size);
-      skip_bytes (r, size * count);
-      return;
-    }
-
   n_vars = dict_get_var_cnt (dict);
-  if (count == 3 * n_vars)
+  if (record->count == 3 * n_vars)
     includes_width = true;
-  else if (count == 2 * n_vars)
+  else if (record->count == 2 * n_vars)
     includes_width = false;
   else
     {
-      sys_warn (r, _("Extension 11 has bad count %zu (for %zu variables)."),
-                count, n_vars);
-      skip_bytes (r, size * count);
+      sys_warn (r, record->pos,
+                _("Extension 11 has bad count %zu (for %zu variables)."),
+                record->count, n_vars);
       return;
     }
 
+  ofs = 0;
   for (i = 0; i < n_vars; ++i)
     {
       struct variable *v = dict_get_var (dict, i);
-      int measure = read_int (r);
-      int width = includes_width ? read_int (r) : 0;
-      int align = read_int (r);
+      int measure, width, align;
+
+      measure = parse_int (r, record->data, ofs);
+      ofs += 4;
+
+      if (includes_width)
+        {
+          width = parse_int (r, record->data, ofs);
+          ofs += 4;
+        }
+      else
+        width = 0;
+
+      align = parse_int (r, record->data, ofs);
+      ofs += 4;
 
       /* SPSS 14 sometimes seems to set string variables' measure
          to zero. */
@@ -1224,9 +1458,9 @@ read_display_parameters (struct sfm_reader *r, size_t size, size_t count,
       if (measure < 1 || measure > 3 || align < 0 || align > 2)
         {
           if (!warned)
-            sys_warn (r, _("Invalid variable display parameters "
-                           "for variable %zu (%s).  "
-                           "Default parameters substituted."),
+            sys_warn (r, record->pos,
+                      _("Invalid variable display parameters for variable "
+                        "%zu (%s).  Default parameters substituted."),
                       i, var_get_name (v));
           warned = true;
           continue;
@@ -1247,29 +1481,83 @@ read_display_parameters (struct sfm_reader *r, size_t size, size_t count,
     }
 }
 
-/* Reads record type 7, subtype 13, which gives the long name
-   that corresponds to each short name.  Modifies variable names
-   in DICT accordingly.  */
 static void
-read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count,
-                        struct dictionary *dict)
+rename_var_and_save_short_names (struct dictionary *dict, struct variable *var,
+                                 const char *new_name)
+{
+  size_t n_short_names;
+  char **short_names;
+  size_t i;
+
+  /* Renaming a variable may clear its short names, but we
+     want to retain them, so we save them and re-set them
+     afterward. */
+  n_short_names = var_get_short_name_cnt (var);
+  short_names = xnmalloc (n_short_names, sizeof *short_names);
+  for (i = 0; i < n_short_names; i++)
+    {
+      const char *s = var_get_short_name (var, i);
+      short_names[i] = s != NULL ? xstrdup (s) : NULL;
+    }
+
+  /* Set long name. */
+  dict_rename_var (dict, var, new_name);
+
+  /* Restore short names. */
+  for (i = 0; i < n_short_names; i++)
+    {
+      var_set_short_name (var, i, short_names[i]);
+      free (short_names[i]);
+    }
+  free (short_names);
+}
+
+/* Parses record type 7, subtype 13, which gives the long name that corresponds
+   to each short name.  Modifies variable names in DICT accordingly.  */
+static void
+parse_long_var_name_map (struct sfm_reader *r,
+                         const struct sfm_extension_record *record,
+                         struct dictionary *dict)
 {
   struct text_record *text;
   struct variable *var;
   char *long_name;
 
-  text = open_text_record (r, size * count);
-  while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
+  if (record == NULL)
     {
-      char **short_names;
-      size_t short_name_cnt;
+      /* Convert variable names to lowercase. */
       size_t i;
 
+      for (i = 0; i < dict_get_var_cnt (dict); i++)
+       {
+         struct variable *var = dict_get_var (dict, i);
+          char *new_name;
+
+          new_name = xstrdup (var_get_name (var));
+         str_lowercase (new_name);
+
+          rename_var_and_save_short_names (dict, var, new_name);
+
+          free (new_name);
+       }
+
+      return;
+    }
+
+  /* Rename each of the variables, one by one.  (In a correctly constructed
+     system file, this cannot create any intermediate duplicate variable names,
+     because all of the new variable names are longer than any of the old
+     variable names and thus there cannot be any overlaps.) */
+  text = open_text_record (r, record, true);
+  while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
+    {
       /* Validate long name. */
-      if (!var_is_valid_name (long_name, false))
+      /* XXX need to reencode name to UTF-8 */
+      if (!dict_id_is_valid (dict, long_name, false))
         {
-          sys_warn (r, _("Long variable mapping from %s to invalid "
-                         "variable name `%s'."),
+          sys_warn (r, record->pos,
+                    _("Long variable mapping from %s to invalid "
+                      "variable name `%s'."),
                     var_get_name (var), long_name);
           continue;
         }
@@ -1278,48 +1566,28 @@ read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count,
       if (strcasecmp (var_get_short_name (var, 0), long_name)
           && dict_lookup_var (dict, long_name) != NULL)
         {
-          sys_warn (r, _("Duplicate long variable name `%s' "
-                         "within system file."), long_name);
+          sys_warn (r, record->pos,
+                    _("Duplicate long variable name `%s'."), long_name);
           continue;
         }
 
-      /* Renaming a variable may clear its short names, but we
-         want to retain them, so we save them and re-set them
-         afterward. */
-      short_name_cnt = var_get_short_name_cnt (var);
-      short_names = xnmalloc (short_name_cnt, sizeof *short_names);
-      for (i = 0; i < short_name_cnt; i++)
-        {
-          const char *s = var_get_short_name (var, i);
-          short_names[i] = s != NULL ? xstrdup (s) : NULL;
-        }
-
-      /* Set long name. */
-      dict_rename_var (dict, var, long_name);
-
-      /* Restore short names. */
-      for (i = 0; i < short_name_cnt; i++)
-        {
-          var_set_short_name (var, i, short_names[i]);
-          free (short_names[i]);
-        }
-      free (short_names);
+      rename_var_and_save_short_names (dict, var, long_name);
     }
   close_text_record (r, text);
-  r->has_long_var_names = true;
 }
 
 /* Reads record type 7, subtype 14, which gives the real length
    of each very long string.  Rearranges DICT accordingly. */
 static void
-read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
-                      struct dictionary *dict)
+parse_long_string_map (struct sfm_reader *r,
+                       const struct sfm_extension_record *record,
+                       struct dictionary *dict)
 {
   struct text_record *text;
   struct variable *var;
   char *length_s;
 
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, record, true);
   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
     {
       size_t idx = var_get_dict_index (var);
@@ -1331,8 +1599,9 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
       length = strtol (length_s, NULL, 10);
       if (length < 1 || length > MAX_STRING)
         {
-          sys_warn (r, _("%s listed as string of invalid length %s "
-                         "in very length string record."),
+          sys_warn (r, record->pos,
+                    _("%s listed as string of invalid length %s "
+                      "in very long string record."),
                     var_get_name (var), length_s);
           continue;
         }
@@ -1341,13 +1610,15 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
       segment_cnt = sfm_width_to_segments (length);
       if (segment_cnt == 1)
         {
-          sys_warn (r, _("%s listed in very long string record with width %s, "
-                         "which requires only one segment."),
+          sys_warn (r, record->pos,
+                    _("%s listed in very long string record with width %s, "
+                      "which requires only one segment."),
                     var_get_name (var), length_s);
           continue;
         }
       if (idx + segment_cnt > dict_get_var_cnt (dict))
-        sys_error (r, _("Very long string %s overflows dictionary."),
+        sys_error (r, record->pos,
+                   _("Very long string %s overflows dictionary."),
                    var_get_name (var));
 
       /* Get the short names from the segments and check their
@@ -1361,8 +1632,9 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
           if (i > 0)
             var_set_short_name (var, i, var_get_short_name (seg, 0));
           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
-            sys_error (r, _("Very long string with width %ld has segment %d "
-                            "of width %d (expected %d)"),
+            sys_error (r, record->pos,
+                       _("Very long string with width %ld has segment %d "
+                         "of width %d (expected %d)."),
                        length, i, width, alloc_width);
         }
       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
@@ -1372,152 +1644,117 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
   dict_compact_values (dict);
 }
 
-/* Reads value labels from sysfile H and inserts them into the
-   associated dictionary. */
 static void
-read_value_labels (struct sfm_reader *r,
-                   struct dictionary *dict, struct variable **var_by_value_idx)
+parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
+                    const struct sfm_var_record *var_recs, size_t n_var_recs,
+                    const struct sfm_value_label_record *record)
 {
-  struct pool *subpool;
+  struct variable **vars;
+  char **utf8_labels;
+  size_t i;
 
-  struct label
+  utf8_labels = pool_nmalloc (r->pool, sizeof *utf8_labels, record->n_labels);
+  for (i = 0; i < record->n_labels; i++)
+    utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
+                                         record->labels[i].label, -1,
+                                         r->pool);
+
+  vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
+  for (i = 0; i < record->n_vars; i++)
+    vars[i] = lookup_var_by_index (r, record->pos,
+                                   var_recs, n_var_recs, record->vars[i]);
+
+  for (i = 1; i < record->n_vars; i++)
+    if (var_get_type (vars[i]) != var_get_type (vars[0]))
+      sys_error (r, record->pos,
+                 _("Variables associated with value label are not all of "
+                   "identical type.  Variable %s is %s, but variable "
+                   "%s is %s."),
+                 var_get_name (vars[0]),
+                 var_is_numeric (vars[0]) ? _("numeric") : _("string"),
+                 var_get_name (vars[i]),
+                 var_is_numeric (vars[i]) ? _("numeric") : _("string"));
+
+  for (i = 0; i < record->n_vars; i++)
     {
-      uint8_t raw_value[8];        /* Value as uninterpreted bytes. */
-      union value value;        /* Value. */
-      char *label;              /* Null-terminated label string. */
-    };
-
-  struct label *labels = NULL;
-  int label_cnt;               /* Number of labels. */
-
-  struct variable **var = NULL;        /* Associated variables. */
-  int var_cnt;                 /* Number of associated variables. */
-  int max_width;                /* Maximum width of string variables. */
-
-  int i;
-
-  subpool = pool_create_subpool (r->pool);
-
-  /* Read the type 3 record and record its contents.  We can't do
-     much with the data yet because we don't know whether it is
-     of numeric or string type. */
-
-  /* Read number of labels. */
-  label_cnt = read_int (r);
+      struct variable *var = vars[i];
+      int width;
+      size_t j;
 
-  if (size_overflow_p (xtimes (label_cnt, sizeof *labels)))
-    {
-      sys_warn (r, _("Invalid number of labels: %d.  Ignoring labels."),
-                label_cnt);
-      label_cnt = 0;
-    }
+      width = var_get_width (var);
+      if (width > 8)
+        sys_error (r, record->pos,
+                   _("Value labels may not be added to long string "
+                     "variables (e.g. %s) using records types 3 and 4."),
+                   var_get_name (var));
 
-  /* Read each value/label tuple into labels[]. */
-  labels = pool_nalloc (subpool, label_cnt, sizeof *labels);
-  for (i = 0; i < label_cnt; i++)
-    {
-      struct label *label = labels + i;
-      unsigned char label_len;
-      size_t padded_len;
+      for (j = 0; j < record->n_labels; j++)
+        {
+          struct sfm_value_label *label = &record->labels[j];
+          union value value;
 
-      /* Read value. */
-      read_bytes (r, label->raw_value, sizeof label->raw_value);
+          value_init (&value, width);
+          if (width == 0)
+            value.f = parse_float (r, label->value, 0);
+          else
+            memcpy (value_str_rw (&value, width), label->value, width);
 
-      /* Read label length. */
-      read_bytes (r, &label_len, sizeof label_len);
-      padded_len = ROUND_UP (label_len + 1, 8);
+          if (!var_add_value_label (var, &value, utf8_labels[j]))
+            {
+              if (var_is_numeric (var))
+                sys_warn (r, record->pos,
+                          _("Duplicate value label for %g on %s."),
+                          value.f, var_get_name (var));
+              else
+                sys_warn (r, record->pos,
+                          _("Duplicate value label for `%.*s' on %s."),
+                          width, value_str (&value, width),
+                          var_get_name (var));
+            }
 
-      /* Read label, padding. */
-      label->label = pool_alloc (subpool, padded_len + 1);
-      read_bytes (r, label->label, padded_len - 1);
-      label->label[label_len] = 0;
+          value_destroy (&value, width);
+        }
     }
 
-  /* Now, read the type 4 record that has the list of variables
-     to which the value labels are to be applied. */
-
-  /* Read record type of type 4 record. */
-  if (read_int (r) != 4)
-    sys_error (r, _("Variable index record (type 4) does not immediately "
-                    "follow value label record (type 3) as it should."));
+  pool_free (r->pool, vars);
+  for (i = 0; i < record->n_labels; i++)
+    pool_free (r->pool, utf8_labels[i]);
+  pool_free (r->pool, utf8_labels);
+}
 
-  /* Read number of variables associated with value label from type 4
-     record. */
-  var_cnt = read_int (r);
-  if (var_cnt < 1 || var_cnt > dict_get_var_cnt (dict))
-    sys_error (r, _("Number of variables associated with a value label (%d) "
-                    "is not between 1 and the number of variables (%zu)."),
-               var_cnt, dict_get_var_cnt (dict));
-
-  /* Read the list of variables. */
-  var = pool_nalloc (subpool, var_cnt, sizeof *var);
-  max_width = 0;
-  for (i = 0; i < var_cnt; i++)
-    {
-      var[i] = lookup_var_by_value_idx (r, var_by_value_idx, read_int (r));
-      if (var_get_width (var[i]) > 8)
-        sys_error (r, _("Value labels may not be added to long string "
-                        "variables (e.g. %s) using records types 3 and 4."),
-                   var_get_name (var[i]));
-      max_width = MAX (max_width, var_get_width (var[i]));
-    }
+static struct variable *
+lookup_var_by_index (struct sfm_reader *r, off_t offset,
+                     const struct sfm_var_record *var_recs, size_t n_var_recs,
+                     int idx)
+{
+  const struct sfm_var_record *rec;
 
-  /* Type check the variables. */
-  for (i = 1; i < var_cnt; i++)
-    if (var_get_type (var[i]) != var_get_type (var[0]))
-      sys_error (r, _("Variables associated with value label are not all of "
-                      "identical type.  Variable %s is %s, but variable "
-                      "%s is %s."),
-                 var_get_name (var[0]),
-                 var_is_numeric (var[0]) ? _("numeric") : _("string"),
-                 var_get_name (var[i]),
-                 var_is_numeric (var[i]) ? _("numeric") : _("string"));
-
-  /* Fill in labels[].value, now that we know the desired type. */
-  for (i = 0; i < label_cnt; i++)
+  if (idx < 1 || idx > n_var_recs)
     {
-      struct label *label = labels + i;
-
-      value_init_pool (subpool, &label->value, max_width);
-      if (var_is_alpha (var[0]))
-        u8_buf_copy_rpad (value_str_rw (&label->value, max_width), max_width,
-                       label->raw_value, sizeof label->raw_value, ' ');
-      else
-        label->value.f = float_get_double (r->float_format, label->raw_value);
+      sys_error (r, offset,
+                 _("Variable index %d not in valid range 1...%zu."),
+                 idx, n_var_recs);
+      return NULL;
     }
 
-  /* Assign the `value_label's to each variable. */
-  for (i = 0; i < var_cnt; i++)
+  rec = &var_recs[idx - 1];
+  if (rec->var == NULL)
     {
-      struct variable *v = var[i];
-      int j;
-
-      /* Add each label to the variable. */
-      for (j = 0; j < label_cnt; j++)
-       {
-          struct label *label = &labels[j];
-          if (!var_add_value_label (v, &label->value, label->label))
-            {
-              if (var_is_numeric (var[0]))
-                sys_warn (r, _("Duplicate value label for %g on %s."),
-                          label->value.f, var_get_name (v));
-              else
-                sys_warn (r, _("Duplicate value label for `%.*s' on %s."),
-                          max_width, value_str (&label->value, max_width),
-                          var_get_name (v));
-            }
-       }
+      sys_error (r, offset,
+                 _("Variable index %d refers to long string continuation."),
+                 idx);
+      return NULL;
     }
 
-  pool_destroy (subpool);
+  return rec->var;
 }
 
-/* Reads a set of custom attributes from TEXT into ATTRS.
+/* Parses a set of custom attributes from TEXT into ATTRS.
    ATTRS may be a null pointer, in which case the attributes are
    read but discarded. */
 static void
-read_attributes (struct sfm_reader *r, struct text_record *text,
-                 struct attrset *attrs)
+parse_attributes (struct sfm_reader *r, struct text_record *text,
+                  struct attrset *attrs)
 {
   do
     {
@@ -1540,7 +1777,7 @@ read_attributes (struct sfm_reader *r, struct text_record *text,
           value = text_get_token (text, ss_cstr ("\n"), NULL);
           if (value == NULL)
             {
-              text_warn (r, text, _("Error parsing attribute value %s[%d]"),
+              text_warn (r, text, _("Error parsing attribute value %s[%d]."),
                          key, index);
               break;
             }              
@@ -1554,7 +1791,7 @@ read_attributes (struct sfm_reader *r, struct text_record *text,
           else 
             {
               text_warn (r, text,
-                         _("Attribute value %s[%d] is not quoted: %s"),
+                         _("Attribute value %s[%d] is not quoted: %s."),
                          key, index, value);
               attribute_add_value (attr, value); 
             }
@@ -1574,140 +1811,153 @@ read_attributes (struct sfm_reader *r, struct text_record *text,
 /* Reads record type 7, subtype 17, which lists custom
    attributes on the data file.  */
 static void
-read_data_file_attributes (struct sfm_reader *r,
-                           size_t size, size_t count,
-                           struct dictionary *dict)
+parse_data_file_attributes (struct sfm_reader *r,
+                            const struct sfm_extension_record *record,
+                            struct dictionary *dict)
 {
-  struct text_record *text = open_text_record (r, size * count);
-  read_attributes (r, text, dict_get_attributes (dict));
+  struct text_record *text = open_text_record (r, record, true);
+  parse_attributes (r, text, dict_get_attributes (dict));
   close_text_record (r, text);
 }
 
+/* Parses record type 7, subtype 18, which lists custom
+   attributes on individual variables.  */
 static void
-skip_long_string_value_labels (struct sfm_reader *r, size_t n_labels)
+parse_variable_attributes (struct sfm_reader *r,
+                           const struct sfm_extension_record *record,
+                           struct dictionary *dict)
 {
-  size_t i;
+  struct text_record *text;
+  struct variable *var;
 
-  for (i = 0; i < n_labels; i++)
-    {
-      size_t value_length, label_length;
+  text = open_text_record (r, record, true);
+  while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
+    parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
+  close_text_record (r, text);
+}
 
-      value_length = read_int (r);
-      skip_bytes (r, value_length);
-      label_length = read_int (r);
-      skip_bytes (r, label_length);
-    }
+static void
+check_overflow (struct sfm_reader *r,
+                const struct sfm_extension_record *record,
+                size_t ofs, size_t length)
+{
+  size_t end = record->size * record->count;
+  if (length >= end || ofs + length > end)
+    sys_error (r, record->pos + end,
+               _("Long string value label record ends unexpectedly."));
 }
 
 static void
-read_long_string_value_labels (struct sfm_reader *r,
-                              size_t size, size_t count,
-                              struct dictionary *d)
+parse_long_string_value_labels (struct sfm_reader *r,
+                                const struct sfm_extension_record *record,
+                                struct dictionary *dict)
 {
-  const off_t start = ftello (r->file);
-  while (ftello (r->file) - start < size * count)
+  const char *dict_encoding = dict_get_encoding (dict);
+  size_t end = record->size * record->count;
+  size_t ofs = 0;
+
+  while (ofs < end)
     {
-      char var_name[VAR_NAME_LEN + 1];
+      char *var_name;
       size_t n_labels, i;
-      struct variable *v;
+      struct variable *var;
       union value value;
       int var_name_len;
       int width;
 
-      /* Read header. */
-      var_name_len = read_int (r);
-      if (var_name_len > VAR_NAME_LEN)
-        sys_error (r, _("Variable name length in long string value label "
-                        "record (%d) exceeds %d-byte limit."),
-                   var_name_len, VAR_NAME_LEN);
-      read_string (r, var_name, var_name_len + 1);
-      width = read_int (r);
-      n_labels = read_int (r);
-
-      v = dict_lookup_var (d, var_name);
-      if (v == NULL)
-        {
-          sys_warn (r, _("Ignoring long string value record for "
-                         "unknown variable %s."), var_name);
-          skip_long_string_value_labels (r, n_labels);
-          continue;
-        }
-      if (var_is_numeric (v))
+      /* Parse variable name length. */
+      check_overflow (r, record, ofs, 4);
+      var_name_len = parse_int (r, record->data, ofs);
+      ofs += 4;
+
+      /* Parse variable name, width, and number of labels. */
+      check_overflow (r, record, ofs, var_name_len + 8);
+      var_name = recode_string_pool ("UTF-8", dict_encoding,
+                                     (const char *) record->data + ofs,
+                                     var_name_len, r->pool);
+      width = parse_int (r, record->data, ofs + var_name_len);
+      n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
+      ofs += var_name_len + 8;
+
+      /* Look up 'var' and validate. */
+      var = dict_lookup_var (dict, var_name);
+      if (var == NULL)
+        sys_warn (r, record->pos + ofs,
+                  _("Ignoring long string value record for "
+                    "unknown variable %s."), var_name);
+      else if (var_is_numeric (var))
         {
-          sys_warn (r, _("Ignoring long string value record for "
-                         "numeric variable %s."), var_name);
-          skip_long_string_value_labels (r, n_labels);
-          continue;
+          sys_warn (r, record->pos + ofs,
+                    _("Ignoring long string value record for "
+                      "numeric variable %s."), var_name);
+          var = NULL;
         }
-      if (width != var_get_width (v))
+      else if (width != var_get_width (var))
         {
-          sys_warn (r, _("Ignoring long string value record for variable %s "
-                         "because the record's width (%d) does not match the "
-                         "variable's width (%d)"),
-                    var_name, width, var_get_width (v));
-          skip_long_string_value_labels (r, n_labels);
-          continue;
+          sys_warn (r, record->pos + ofs,
+                    _("Ignoring long string value record for variable %s "
+                      "because the record's width (%d) does not match the "
+                      "variable's width (%d)."),
+                    var_name, width, var_get_width (var));
+          var = NULL;
         }
 
-      /* Read values. */
+      /* Parse values. */
       value_init_pool (r->pool, &value, width);
       for (i = 0; i < n_labels; i++)
        {
           size_t value_length, label_length;
-          char label[256];
-          bool skip = false;
+          bool skip = var == NULL;
 
-          /* Read value. */
-          value_length = read_int (r);
-          if (value_length == width)
-            read_bytes (r, value_str_rw (&value, width), width);
-          else
+          /* Parse value length. */
+          check_overflow (r, record, ofs, 4);
+          value_length = parse_int (r, record->data, ofs);
+          ofs += 4;
+
+          /* Parse value. */
+          check_overflow (r, record, ofs, value_length);
+          if (!skip)
             {
-              sys_warn (r, _("Ignoring long string value %zu for variable %s, "
-                             "with width %d, that has bad value width %zu."),
-                        i, var_get_name (v), width, value_length);
-              skip_bytes (r, value_length);
-              skip = true;
+              if (value_length == width)
+                memcpy (value_str_rw (&value, width),
+                        (const uint8_t *) record->data + ofs, width);
+              else
+                {
+                  sys_warn (r, record->pos + ofs,
+                            _("Ignoring long string value %zu for variable "
+                              "%s, with width %d, that has bad value "
+                              "width %zu."),
+                            i, var_get_name (var), width, value_length);
+                  skip = true;
+                }
             }
+          ofs += value_length;
+
+          /* Parse label length. */
+          check_overflow (r, record, ofs, 4);
+          label_length = parse_int (r, record->data, ofs);
+          ofs += 4;
 
-          /* Read label. */
-          label_length = read_int (r);
-          read_string (r, label, MIN (sizeof label, label_length + 1));
-          if (label_length >= sizeof label)
+          /* Parse label. */
+          check_overflow (r, record, ofs, label_length);
+          if (!skip)
             {
-              /* Skip and silently ignore label text after the
-                 first 255 bytes.  The maximum documented length
-                 of a label is 120 bytes so this is more than
-                 generous. */
-              skip_bytes (r, (label_length + 1) - sizeof label);
+              char *label;
+
+              label = recode_string_pool ("UTF-8", dict_encoding,
+                                          (const char *) record->data + ofs,
+                                          label_length, r->pool);
+              if (!var_add_value_label (var, &value, label))
+                sys_warn (r, record->pos + ofs,
+                          _("Duplicate value label for `%.*s' on %s."),
+                          width, value_str (&value, width),
+                          var_get_name (var));
+              pool_free (r->pool, label);
             }
-
-          if (!skip && !var_add_value_label (v, &value, label))
-            sys_warn (r, _("Duplicate value label for `%.*s' on %s."),
-                      width, value_str (&value, width), var_get_name (v));
+          ofs += label_length;
         }
     }
 }
-
-
-/* Reads record type 7, subtype 18, which lists custom
-   attributes on individual variables.  */
-static void
-read_variable_attributes (struct sfm_reader *r,
-                          size_t size, size_t count,
-                          struct dictionary *dict)
-{
-  struct text_record *text = open_text_record (r, size * count);
-  for (;;) 
-    {
-      struct variable *var;
-      if (!text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
-        break;
-      read_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
-    }
-  close_text_record (r, text);
-}
-
 \f
 /* Case reader. */
 
@@ -1766,11 +2016,11 @@ sys_file_casereader_read (struct casereader *reader, void *r_)
   return c;
 
 eof:
-  case_unref (c);
   if (i != 0)
     partial_record (r);
   if (r->case_cnt != -1)
     read_error (reader, r);
+  case_unref (c);
   return NULL;
 }
 
@@ -1778,7 +2028,7 @@ eof:
 static void
 partial_record (struct sfm_reader *r)
 {
-  sys_error (r, _("File ends in partial case."));
+  sys_error (r, r->pos, _("File ends in partial case."));
 }
 
 /* Issues an error that an unspecified error occurred SFM, and
@@ -1887,8 +2137,9 @@ read_compressed_number (struct sfm_reader *r, double *d)
       if (!r->corruption_warning)
         {
           r->corruption_warning = true;
-          sys_warn (r, _("Possible compressed data corruption: "
-                         "compressed spaces appear in numeric field."));
+          sys_warn (r, r->pos,
+                    _("Possible compressed data corruption: "
+                      "compressed spaces appear in numeric field."));
         }
       break;
 
@@ -1940,8 +2191,9 @@ read_compressed_string (struct sfm_reader *r, uint8_t *dst)
         else if (!r->corruption_warning)
           {
             r->corruption_warning = true;
-            sys_warn (r, _("Possible compressed data corruption: "
-                           "string contains compressed integer (opcode %d)"),
+            sys_warn (r, r->pos,
+                      _("Possible compressed data corruption: "
+                        "string contains compressed integer (opcode %d)."),
                       opcode);
           }
       }
@@ -1990,86 +2242,6 @@ skip_whole_strings (struct sfm_reader *r, size_t length)
   return read_whole_strings (r, buffer, length);
 }
 \f
-/* Creates and returns a table that can be used for translating a value
-   index into a case to a "struct variable *" for DICT.  Multiple
-   system file fields reference variables this way.
-
-   This table must be created before processing the very long
-   string extension record, because that record causes some
-   values to be deleted from the case and the dictionary to be
-   compacted. */
-static struct variable **
-make_var_by_value_idx (struct sfm_reader *r, struct dictionary *dict)
-{
-  struct variable **var_by_value_idx;
-  int value_idx = 0;
-  int i;
-
-  var_by_value_idx = pool_nmalloc (r->pool,
-                                   r->oct_cnt, sizeof *var_by_value_idx);
-  for (i = 0; i < dict_get_var_cnt (dict); i++)
-    {
-      struct variable *v = dict_get_var (dict, i);
-      int nv = var_is_numeric (v) ? 1 : DIV_RND_UP (var_get_width (v), 8);
-      int j;
-
-      var_by_value_idx[value_idx++] = v;
-      for (j = 1; j < nv; j++)
-        var_by_value_idx[value_idx++] = NULL;
-    }
-  assert (value_idx == r->oct_cnt);
-
-  return var_by_value_idx;
-}
-
-/* Returns the "struct variable" corresponding to the given
-   1-basd VALUE_IDX in VAR_BY_VALUE_IDX.  Verifies that the index
-   is valid. */
-static struct variable *
-lookup_var_by_value_idx (struct sfm_reader *r,
-                         struct variable **var_by_value_idx, int value_idx)
-{
-  struct variable *var;
-
-  if (value_idx < 1 || value_idx > r->oct_cnt)
-    sys_error (r, _("Variable index %d not in valid range 1...%d."),
-               value_idx, r->oct_cnt);
-
-  var = var_by_value_idx[value_idx - 1];
-  if (var == NULL)
-    sys_error (r, _("Variable index %d refers to long string "
-                    "continuation."),
-               value_idx);
-
-  return var;
-}
-
-/* Returns the variable in D with the given SHORT_NAME,
-   or a null pointer if there is none. */
-static struct variable *
-lookup_var_by_short_name (struct dictionary *d, const char *short_name)
-{
-  struct variable *var;
-  size_t var_cnt;
-  size_t i;
-
-  /* First try looking up by full name.  This often succeeds. */
-  var = dict_lookup_var (d, short_name);
-  if (var != NULL && !strcasecmp (var_get_short_name (var, 0), short_name))
-    return var;
-
-  /* Iterate through the whole dictionary as a fallback. */
-  var_cnt = dict_get_var_cnt (d);
-  for (i = 0; i < var_cnt; i++)
-    {
-      var = dict_get_var (d, i);
-      if (!strcasecmp (var_get_short_name (var, 0), short_name))
-        return var;
-    }
-
-  return NULL;
-}
-\f
 /* Helpers for reading records that contain structured text
    strings. */
 
@@ -2081,21 +2253,30 @@ lookup_var_by_short_name (struct dictionary *d, const char *short_name)
 struct text_record
   {
     struct substring buffer;    /* Record contents. */
+    off_t start;                /* Starting offset in file. */
     size_t pos;                 /* Current position in buffer. */
     int n_warnings;             /* Number of warnings issued or suppressed. */
+    bool recoded;               /* Recoded into UTF-8? */
   };
 
-/* Reads SIZE bytes into a text record for R,
-   and returns the new text record. */
 static struct text_record *
-open_text_record (struct sfm_reader *r, size_t size)
+open_text_record (struct sfm_reader *r,
+                  const struct sfm_extension_record *record,
+                  bool recode_to_utf8)
 {
-  struct text_record *text = pool_alloc (r->pool, sizeof *text);
-  char *buffer = pool_malloc (r->pool, size + 1);
-  read_bytes (r, buffer, size);
-  text->buffer = ss_buffer (buffer, size);
+  struct text_record *text;
+  struct substring raw;
+
+  text = pool_alloc (r->pool, sizeof *text);
+  raw = ss_buffer (record->data, record->size * record->count);
+  text->start = record->pos;
+  text->buffer = (recode_to_utf8
+                  ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
+                  : raw);
   text->pos = 0;
   text->n_warnings = 0;
+  text->recoded = recode_to_utf8;
+
   return text;
 }
 
@@ -2105,9 +2286,10 @@ static void
 close_text_record (struct sfm_reader *r, struct text_record *text)
 {
   if (text->n_warnings > MAX_TEXT_WARNINGS)
-    sys_warn (r, _("Suppressed %d additional related warnings."),
+    sys_warn (r, -1, _("Suppressed %d additional related warnings."),
               text->n_warnings - MAX_TEXT_WARNINGS);
-  pool_free (r->pool, ss_data (text->buffer));
+  if (text->recoded)
+    pool_free (r->pool, ss_data (text->buffer));
 }
 
 /* Reads a variable=value pair from TEXT.
@@ -2165,7 +2347,7 @@ text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
   if (short_name == NULL)
     return false;
 
-  *var = lookup_var_by_short_name (dict, short_name);
+  *var = dict_lookup_var (dict, short_name);
   if (*var == NULL)
     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
                short_name);
@@ -2183,7 +2365,7 @@ text_warn (struct sfm_reader *r, struct text_record *text,
       va_list args;
 
       va_start (args, format);
-      sys_msg (r, MW, format, args);
+      sys_msg (r, text->start + text->pos, MW, format, args);
       va_end (args);
     }
 }
@@ -2228,22 +2410,25 @@ text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
     }
   if (start == text->pos)
     {
-      sys_warn (r, _("Expecting digit at offset %zu in MRSETS record."),
-                 text->pos);
+      sys_warn (r, text->start,
+                _("Expecting digit at offset %zu in MRSETS record."),
+                text->pos);
       return NULL;
     }
 
   if (!text_match (text, ' '))
     {
-      sys_warn (r, _("Expecting space at offset %zu in MRSETS record."),
+      sys_warn (r, text->start,
+                _("Expecting space at offset %zu in MRSETS record."),
                 text->pos);
       return NULL;
     }
 
   if (text->pos + n > text->buffer.length)
     {
-      sys_warn (r, _("%zu-byte string starting at offset %zu "
-                     "exceeds record length %zu."),
+      sys_warn (r, text->start,
+                _("%zu-byte string starting at offset %zu "
+                  "exceeds record length %zu."),
                 n, text->pos, text->buffer.length);
       return NULL;
     }
@@ -2251,7 +2436,7 @@ text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
   s = &text->buffer.string[text->pos];
   if (s[n] != ' ')
     {
-      sys_warn (r,
+      sys_warn (r, text->start,
                 _("Expecting space at offset %zu following %zu-byte string."),
                 text->pos + n, n);
       return NULL;
@@ -2273,7 +2458,8 @@ text_match (struct text_record *text, char c)
     return false;
 }
 
-/* Returns the current byte offset inside the TEXT's string. */
+/* Returns the current byte offset (as converted to UTF-8, if it was converted)
+   inside the TEXT's string. */
 static size_t
 text_pos (const struct text_record *text)
 {
@@ -2284,35 +2470,40 @@ text_pos (const struct text_record *text)
 
 /* Displays a corruption message. */
 static void
-sys_msg (struct sfm_reader *r, int class, const char *format, va_list args)
+sys_msg (struct sfm_reader *r, off_t offset,
+         int class, const char *format, va_list args)
 {
   struct msg m;
   struct string text;
 
   ds_init_empty (&text);
-  ds_put_format (&text, "`%s' near offset 0x%llx: ",
-                 fh_get_file_name (r->fh), (long long int) ftello (r->file));
+  if (offset >= 0)
+    ds_put_format (&text, _("`%s' near offset 0x%llx: "),
+                   fh_get_file_name (r->fh), (long long int) offset);
+  else
+    ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
   ds_put_vformat (&text, format, args);
 
   m.category = msg_class_to_category (class);
   m.severity = msg_class_to_severity (class);
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = 0;
-  m.where.last_column = 0;
+  m.file_name = NULL;
+  m.first_line = 0;
+  m.last_line = 0;
+  m.first_column = 0;
+  m.last_column = 0;
   m.text = ds_cstr (&text);
 
   msg_emit (&m);
 }
 
-/* Displays a warning for the current file position. */
+/* Displays a warning for offset OFFSET in the file. */
 static void
-sys_warn (struct sfm_reader *r, const char *format, ...)
+sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
 {
   va_list args;
 
   va_start (args, format);
-  sys_msg (r, MW, format, args);
+  sys_msg (r, offset, MW, format, args);
   va_end (args);
 }
 
@@ -2320,12 +2511,12 @@ sys_warn (struct sfm_reader *r, const char *format, ...)
    marks it as in an error state,
    and aborts reading it using longjmp. */
 static void
-sys_error (struct sfm_reader *r, const char *format, ...)
+sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
 {
   va_list args;
 
   va_start (args, format);
-  sys_msg (r, ME, format, args);
+  sys_msg (r, offset, ME, format, args);
   va_end (args);
 
   r->error = true;
@@ -2343,12 +2534,13 @@ read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
                    void *buf, size_t byte_cnt)
 {
   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
+  r->pos += bytes_read;
   if (bytes_read == byte_cnt)
     return true;
   else if (ferror (r->file))
-    sys_error (r, _("System error: %s."), strerror (errno));
+    sys_error (r, r->pos, _("System error: %s."), strerror (errno));
   else if (!eof_is_ok || bytes_read != 0)
-    sys_error (r, _("Unexpected end of file."));
+    sys_error (r, r->pos, _("Unexpected end of file."));
   else
     return false;
 }
@@ -2391,6 +2583,18 @@ read_float (struct sfm_reader *r)
   return float_get_double (r->float_format, number);
 }
 
+static int
+parse_int (struct sfm_reader *r, const void *data, size_t ofs)
+{
+  return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
+}
+
+static double
+parse_float (struct sfm_reader *r, const void *data, size_t ofs)
+{
+  return float_get_double (r->float_format, (const uint8_t *) data + ofs);
+}
+
 /* Reads exactly SIZE - 1 bytes into BUFFER
    and stores a null byte into BUFFER[SIZE - 1]. */
 static void
index 242857494ee365af5238936bdd8c7e2027c30c0a..24c3f8467f642575d9bd0b854e65570f91b45b5d 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, 2011 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,9 +20,9 @@
 #include <stdbool.h>
 #include <stdio.h>
 
-#include <data/case.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
+#include "data/case.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
 
 /* Reading system files. */
 
@@ -35,7 +35,7 @@ struct sfm_read_info
     enum float_format float_format;
     bool compressed;           /* 0=no, 1=yes. */
     casenumber case_cnt;        /* -1 if unknown. */
-    char product[61];          /* Product name plus a null. */
+    char product[61];          /* Product name, as ASCII string. */
 
     /* Writer's version number in X.Y.Z format.
        The version number is not always present; if not, then
index f31bd99a883e395304f1819f61e388871105f63f..9586cbc2e38e503c75ede6be7ea754bd93d80a11 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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
@@ -47,6 +47,7 @@
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "libpspp/str.h"
+#include "libpspp/string-array.h"
 #include "libpspp/version.h"
 
 #include "gl/xmemdup0.h"
@@ -97,9 +98,10 @@ static const struct casewriter_class sys_file_casewriter_class;
 
 static void write_header (struct sfm_writer *, const struct dictionary *);
 static void write_variable (struct sfm_writer *, const struct variable *);
-static void write_value_labels (struct sfm_writer *, struct variable *,
-                                int idx);
-static void write_integer_info_record (struct sfm_writer *);
+static void write_value_labels (struct sfm_writer *,
+                                const struct dictionary *);
+static void write_integer_info_record (struct sfm_writer *,
+                                       const struct dictionary *);
 static void write_float_info_record (struct sfm_writer *);
 
 static void write_longvar_table (struct sfm_writer *w,
@@ -131,6 +133,12 @@ static void write_int (struct sfm_writer *, int32_t);
 static inline void convert_double_to_output_format (double, uint8_t[8]);
 static void write_float (struct sfm_writer *, double);
 static void write_string (struct sfm_writer *, const char *, size_t);
+static void write_utf8_string (struct sfm_writer *, const char *encoding,
+                               const char *string, size_t width);
+static void write_utf8_record (struct sfm_writer *, const char *encoding,
+                               const struct string *content, int subtype);
+static void write_string_record (struct sfm_writer *,
+                                 const struct substring content, int subtype);
 static void write_bytes (struct sfm_writer *, const void *, size_t);
 static void write_zeros (struct sfm_writer *, size_t);
 static void write_spaces (struct sfm_writer *, size_t);
@@ -170,7 +178,6 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
 {
   struct sfm_writer *w;
   mode_t mode;
-  int idx;
   int i;
 
   /* Check version. */
@@ -228,20 +235,12 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
   for (i = 0; i < dict_get_var_cnt (d); i++)
     write_variable (w, dict_get_var (d, i));
 
-  /* Write out value labels. */
-  idx = 0;
-  for (i = 0; i < dict_get_var_cnt (d); i++)
-    {
-      struct variable *v = dict_get_var (d, i);
-
-      write_value_labels (w, v, idx);
-      idx += sfm_width_to_octs (var_get_width (v));
-    }
+  write_value_labels (w, d);
 
-  if (dict_get_documents (d) != NULL)
+  if (dict_get_document_line_cnt (d) > 0)
     write_documents (w, d);
 
-  write_integer_info_record (w);
+  write_integer_info_record (w, d);
   write_float_info_record (w);
 
   write_mrsets (w, d, true);
@@ -382,7 +381,7 @@ write_header (struct sfm_writer *w, const struct dictionary *d)
   file_label = dict_get_label (d);
   if (file_label == NULL)
     file_label = "";
-  write_string (w, file_label, 64);
+  write_utf8_string (w, dict_get_encoding (d), file_label, 64);
 
   /* Padding. */
   write_zeros (w, 3);
@@ -430,6 +429,7 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   int width = var_get_width (v);
   int segment_cnt = sfm_width_to_segments (width);
   int seg0_width = sfm_segment_alloc_width (width, 0);
+  const char *encoding = var_get_encoding (v);
   struct missing_values mv;
   int i;
 
@@ -460,12 +460,12 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   /* Short name.
      The full name is in a translation table written
      separately. */
-  write_string (w, var_get_short_name (v, 0), 8);
+  write_utf8_string (w, encoding, var_get_short_name (v, 0), 8);
 
   /* Value label. */
   if (var_has_label (v))
     {
-      char *label = recode_string (var_get_encoding (v), UTF8, var_get_label (v), -1);
+      char *label = recode_string (encoding, UTF8, var_get_label (v), -1);
       size_t label_len = MIN (strlen (label), 255);
       size_t padded_len = ROUND_UP (label_len, 4);
       write_int (w, label_len);
@@ -498,7 +498,7 @@ write_variable (struct sfm_writer *w, const struct variable *v)
       write_int (w, 0);           /* No missing values. */
       write_format (w, fmt, seg_width); /* Print format. */
       write_format (w, fmt, seg_width); /* Write format. */
-      write_string (w, var_get_short_name (v, i), 8);
+      write_utf8_string (w, encoding, var_get_short_name (v, i), 8);
 
       write_variable_continuation_records (w, seg_width);
     }
@@ -506,57 +506,139 @@ write_variable (struct sfm_writer *w, const struct variable *v)
   mv_destroy (&mv);
 }
 
-/* Writes the value labels for variable V having system file
-   variable index IDX to system file W.
+/* Writes the value labels to system file W.
 
    Value labels for long string variables are written separately,
    by write_long_string_value_labels. */
 static void
-write_value_labels (struct sfm_writer *w, struct variable *v, int idx)
+write_value_labels (struct sfm_writer *w, const struct dictionary *d)
 {
-  const struct val_labs *val_labs;
-  const struct val_lab **labels;
-  size_t n_labels;
+  struct label_set
+    {
+      struct hmap_node hmap_node;
+      const struct val_labs *val_labs;
+      int *indexes;
+      size_t n_indexes, allocated_indexes;
+    };
+
+  size_t n_sets, allocated_sets;
+  struct label_set **sets;
+  struct hmap same_sets;
   size_t i;
+  int idx;
 
-  val_labs = var_get_value_labels (v);
-  n_labels = val_labs_count (val_labs);
-  if (n_labels == 0 || var_get_width (v) > 8)
-    return;
+  n_sets = allocated_sets = 0;
+  sets = NULL;
+  hmap_init (&same_sets);
 
-  /* Value label record. */
-  write_int (w, 3);             /* Record type. */
-  write_int (w, val_labs_count (val_labs));
-  labels = val_labs_sorted (val_labs);
-  for (i = 0; i < n_labels; i++)
+  idx = 0;
+  for (i = 0; i < dict_get_var_cnt (d); i++)
     {
-      const struct val_lab *vl = labels[i];
-      char *label = recode_string (var_get_encoding (v), UTF8, val_lab_get_label (vl), -1);
-      uint8_t len = MIN (strlen (label), 255);
-
-      write_value (w, val_lab_get_value (vl), var_get_width (v));
-      write_bytes (w, &len, 1);
-      write_bytes (w, label, len);
-      write_zeros (w, REM_RND_UP (len + 1, 8));
-      free (label);
+      struct variable *v = dict_get_var (d, i);
+
+      if (var_has_value_labels (v) && var_get_width (v) <= 8)
+        {
+          const struct val_labs *val_labs = var_get_value_labels (v);
+          unsigned int hash = val_labs_hash (val_labs, 0);
+          struct label_set *set;
+
+          HMAP_FOR_EACH_WITH_HASH (set, struct label_set, hmap_node,
+                                   hash, &same_sets)
+            {
+              if (val_labs_equal (set->val_labs, val_labs))
+                {
+                  if (set->n_indexes >= set->allocated_indexes)
+                    set->indexes = x2nrealloc (set->indexes,
+                                               &set->allocated_indexes,
+                                               sizeof *set->indexes);
+                  set->indexes[set->n_indexes++] = idx;
+                  goto next_var;
+                }
+            }
+
+          set = xmalloc (sizeof *set);
+          set->val_labs = val_labs;
+          set->indexes = xmalloc (sizeof *set->indexes);
+          set->indexes[0] = idx;
+          set->n_indexes = 1;
+          set->allocated_indexes = 1;
+          hmap_insert (&same_sets, &set->hmap_node, hash);
+
+          if (n_sets >= allocated_sets)
+            sets = x2nrealloc (sets, &allocated_sets, sizeof *sets);
+          sets[n_sets++] = set;
+        }
+
+    next_var:
+      idx += sfm_width_to_octs (var_get_width (v));
+    }
+
+  for (i = 0; i < n_sets; i++)
+    {
+      const struct label_set *set = sets[i];
+      const struct val_labs *val_labs = set->val_labs;
+      size_t n_labels = val_labs_count (val_labs);
+      int width = val_labs_get_width (val_labs);
+      const struct val_lab **labels;
+      size_t j;
+
+      /* Value label record. */
+      write_int (w, 3);             /* Record type. */
+      write_int (w, n_labels);
+      labels = val_labs_sorted (val_labs);
+      for (j = 0; j < n_labels; j++)
+        {
+          const struct val_lab *vl = labels[j];
+          char *label = recode_string (dict_get_encoding (d), UTF8,
+                                       val_lab_get_escaped_label (vl), -1);
+          uint8_t len = MIN (strlen (label), 255);
+
+          write_value (w, val_lab_get_value (vl), width);
+          write_bytes (w, &len, 1);
+          write_bytes (w, label, len);
+          write_zeros (w, REM_RND_UP (len + 1, 8));
+          free (label);
+        }
+      free (labels);
+
+      /* Value label variable record. */
+      write_int (w, 4);              /* Record type. */
+      write_int (w, set->n_indexes);
+      for (j = 0; j < set->n_indexes; j++)
+        write_int (w, set->indexes[j] + 1);
     }
-  free (labels);
 
-  /* Value label variable record. */
-  write_int (w, 4);             /* Record type. */
-  write_int (w, 1);             /* Number of variables. */
-  write_int (w, idx + 1);       /* Variable's dictionary index. */
+  for (i = 0; i < n_sets; i++)
+    {
+      struct label_set *set = sets[i];
+
+      free (set->indexes);
+      free (set);
+    }
+  free (sets);
+  hmap_destroy (&same_sets);
 }
 
 /* Writes record type 6, document record. */
 static void
 write_documents (struct sfm_writer *w, const struct dictionary *d)
 {
-  size_t line_cnt = dict_get_document_line_cnt (d);
+  const struct string_array *docs = dict_get_documents (d);
+  const char *enc = dict_get_encoding (d);
+  size_t i;
 
   write_int (w, 6);             /* Record type. */
-  write_int (w, line_cnt);
-  write_bytes (w, dict_get_documents (d), line_cnt * DOC_LINE_LENGTH);
+  write_int (w, docs->n);
+  for (i = 0; i < docs->n; i++)
+    {
+      char *s = recode_string (enc, "UTF-8", docs->strings[i], -1);
+      size_t s_len = strlen (s);
+      size_t write_len = MIN (s_len, DOC_LINE_LENGTH);
+
+      write_bytes (w, s, write_len);
+      write_spaces (w, DOC_LINE_LENGTH - write_len);
+      free (s);
+    }
 }
 
 static void
@@ -572,31 +654,20 @@ put_attrset (struct string *string, const struct attrset *attrs)
       size_t j;
 
       ds_put_cstr (string, attribute_get_name (attr));
-      ds_put_char (string, '(');
+      ds_put_byte (string, '(');
       for (j = 0; j < n_values; j++) 
         ds_put_format (string, "'%s'\n", attribute_get_value (attr, j));
-      ds_put_char (string, ')');
+      ds_put_byte (string, ')');
     }
 }
 
-static void
-write_attribute_record (struct sfm_writer *w, const struct string *content,
-                        int subtype) 
-{
-  write_int (w, 7);
-  write_int (w, subtype);
-  write_int (w, 1);
-  write_int (w, ds_length (content));
-  write_bytes (w, ds_data (content), ds_length (content));
-}
-
 static void
 write_data_file_attributes (struct sfm_writer *w,
                             const struct dictionary *d)
 {
   struct string s = DS_EMPTY_INITIALIZER;
   put_attrset (&s, dict_get_attributes (d));
-  write_attribute_record (w, &s, 17);
+  write_utf8_record (w, dict_get_encoding (d), &s, 17);
   ds_destroy (&s);
 }
 
@@ -615,13 +686,13 @@ write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
       if (attrset_count (attrs)) 
         {
           if (n_attrsets++)
-            ds_put_char (&s, '/');
-          ds_put_format (&s, "%s:", var_get_short_name (v, 0));
+            ds_put_byte (&s, '/');
+          ds_put_format (&s, "%s:", var_get_name (v));
           put_attrset (&s, attrs);
         }
     }
-  if (n_attrsets) 
-    write_attribute_record (w, &s, 18);
+  if (n_attrsets)
+    write_utf8_record (w, dict_get_encoding (d), &s, 18);
   ds_destroy (&s);
 }
 
@@ -632,6 +703,7 @@ static void
 write_mrsets (struct sfm_writer *w, const struct dictionary *dict,
               bool pre_v14)
 {
+  const char *encoding = dict_get_encoding (dict);
   struct string s = DS_EMPTY_INITIALIZER;
   size_t n_mrsets;
   size_t i;
@@ -643,14 +715,17 @@ write_mrsets (struct sfm_writer *w, const struct dictionary *dict,
   for (i = 0; i < n_mrsets; i++)
     {
       const struct mrset *mrset = dict_get_mrset (dict, i);
-      const char *label;
+      char *name;
       size_t j;
 
       if ((mrset->type != MRSET_MD || mrset->cat_source != MRSET_COUNTEDVALUES)
           != pre_v14)
         continue;
 
-      ds_put_format (&s, "%s=", mrset->name);
+      name = recode_string (encoding, "UTF-8", mrset->name, -1);
+      ds_put_format (&s, "%s=", name);
+      free (name);
+
       if (mrset->type == MRSET_MD)
         {
           char *counted;
@@ -658,7 +733,7 @@ write_mrsets (struct sfm_writer *w, const struct dictionary *dict,
           if (mrset->cat_source == MRSET_COUNTEDVALUES)
             ds_put_format (&s, "E %d ", mrset->label_from_var_label ? 11 : 1);
           else
-            ds_put_char (&s, 'D');
+            ds_put_byte (&s, 'D');
 
           if (mrset->width == 0)
             counted = xasprintf ("%.0f", mrset->counted.f);
@@ -669,17 +744,32 @@ write_mrsets (struct sfm_writer *w, const struct dictionary *dict,
           free (counted);
         }
       else
-        ds_put_char (&s, 'C');
-      ds_put_char (&s, ' ');
+        ds_put_byte (&s, 'C');
+      ds_put_byte (&s, ' ');
 
-      label = mrset->label && !mrset->label_from_var_label ? mrset->label : "";
-      ds_put_format (&s, "%zu %s", strlen (label), label);
+      if (mrset->label && !mrset->label_from_var_label)
+        {
+          char *label = recode_string (encoding, "UTF-8", mrset->label, -1);
+          ds_put_format (&s, "%zu %s", strlen (label), label);
+          free (label);
+        }
+      else
+        ds_put_cstr (&s, "0 ");
 
       for (j = 0; j < mrset->n_vars; j++)
-        ds_put_format (&s, " %s", var_get_short_name (mrset->vars[j], 0));
-      ds_put_char (&s, '\n');
+        {
+          const char *short_name_utf8 = var_get_short_name (mrset->vars[j], 0);
+          char *short_name = recode_string (encoding, "UTF-8",
+                                            short_name_utf8, -1);
+          str_lowercase (short_name);
+          ds_put_format (&s, " %s", short_name);
+          free (short_name);
+        }
+      ds_put_byte (&s, '\n');
     }
-  write_attribute_record (w, &s, 7);
+
+  if (!ds_is_empty (&s))
+    write_string_record (w, ds_ss (&s), pre_v14 ? 7 : 19);
   ds_destroy (&s);
 }
 
@@ -736,13 +826,7 @@ write_vls_length_table (struct sfm_writer *w,
                        var_get_short_name (v, 0), var_get_width (v), 0);
     }
   if (!ds_is_empty (&map))
-    {
-      write_int (w, 7);         /* Record type. */
-      write_int (w, 14);        /* Record subtype. */
-      write_int (w, 1);         /* Data item (char) size. */
-      write_int (w, ds_length (&map)); /* Number of data items. */
-      write_bytes (w, ds_data (&map), ds_length (&map));
-    }
+    write_utf8_record (w, dict_get_encoding (dict), &map, 14);
   ds_destroy (&map);
 }
 
@@ -761,16 +845,22 @@ write_long_string_value_labels (struct sfm_writer *w,
     {
       struct variable *var = dict_get_var (dict, i);
       const struct val_labs *val_labs = var_get_value_labels (var);
+      const char *encoding = var_get_encoding (var);
       int width = var_get_width (var);
       const struct val_lab *val_lab;
 
       if (val_labs_count (val_labs) == 0 || width < 9)
         continue;
 
-      size += 12 + strlen (var_get_name (var));
+      size += 12;
+      size += recode_string_len (encoding, "UTF-8", var_get_name (var), -1);
       for (val_lab = val_labs_first (val_labs); val_lab != NULL;
            val_lab = val_labs_next (val_labs, val_lab))
-        size += 8 + width + strlen (val_lab_get_label (val_lab));
+        {
+          size += 8 + width;
+          size += recode_string_len (encoding, "UTF-8",
+                                     val_lab_get_escaped_label (val_lab), -1);
+        }
     }
   if (size == 0)
     return;
@@ -785,28 +875,37 @@ write_long_string_value_labels (struct sfm_writer *w,
     {
       struct variable *var = dict_get_var (dict, i);
       const struct val_labs *val_labs = var_get_value_labels (var);
-      const char *var_name = var_get_name (var);
+      const char *encoding = var_get_encoding (var);
       int width = var_get_width (var);
       const struct val_lab *val_lab;
+      char *var_name;
 
       if (val_labs_count (val_labs) == 0 || width < 9)
         continue;
 
+      var_name = recode_string (encoding, "UTF-8", var_get_name (var), -1);
       write_int (w, strlen (var_name));
       write_bytes (w, var_name, strlen (var_name));
+      free (var_name);
+
       write_int (w, width);
       write_int (w, val_labs_count (val_labs));
       for (val_lab = val_labs_first (val_labs); val_lab != NULL;
            val_lab = val_labs_next (val_labs, val_lab))
         {
-          const char *label = val_lab_get_label (val_lab);
-          size_t label_length = strlen (label);
+          char *label;
+          size_t len;
 
           write_int (w, width);
           write_bytes (w, value_str (val_lab_get_value (val_lab), width),
                        width);
-          write_int (w, label_length);
-          write_bytes (w, label, label_length);
+
+          label = recode_string (var_get_encoding (var), "UTF-8",
+                                 val_lab_get_escaped_label (val_lab), -1);
+          len = strlen (label);
+          write_int (w, len);
+          write_bytes (w, label, len);
+          free (label);
         }
     }
   assert (ftello (w->file) == start + size);
@@ -816,19 +915,18 @@ static void
 write_encoding_record (struct sfm_writer *w,
                       const struct dictionary *d)
 {
-  const char *enc = dict_get_encoding (d);
-
-  if ( NULL == enc)
-    return;
-
-  write_int (w, 7);             /* Record type. */
-  write_int (w, 20);            /* Record subtype. */
-  write_int (w, 1);             /* Data item (char) size. */
-  write_int (w, strlen (enc));  /* Number of data items. */
-  write_string (w, enc, strlen (enc));
+  /* IANA says "...character set names may be up to 40 characters taken
+     from the printable characters of US-ASCII," so character set names
+     don't need to be recoded to be in UTF-8.
+
+     We convert encoding names to uppercase because SPSS writes encoding
+     names in uppercase. */
+  char *encoding = xstrdup (dict_get_encoding (d));
+  str_uppercase (encoding);
+  write_string_record (w, ss_cstr (encoding), 20);
+  free (encoding);
 }
 
-
 /* Writes the long variable name table. */
 static void
 write_longvar_table (struct sfm_writer *w, const struct dictionary *dict)
@@ -840,30 +938,23 @@ write_longvar_table (struct sfm_writer *w, const struct dictionary *dict)
   for (i = 0; i < dict_get_var_cnt (dict); i++)
     {
       struct variable *v = dict_get_var (dict, i);
-      char *longname = recode_string (dict_get_encoding (dict), UTF8, var_get_name (v), -1);
-
       if (i)
-        ds_put_char (&map, '\t');
+        ds_put_byte (&map, '\t');
       ds_put_format (&map, "%s=%s",
-                     var_get_short_name (v, 0), longname);
-      free (longname);
+                     var_get_short_name (v, 0), var_get_name (v));
     }
-
-  write_int (w, 7);             /* Record type. */
-  write_int (w, 13);            /* Record subtype. */
-  write_int (w, 1);             /* Data item (char) size. */
-  write_int (w, ds_length (&map)); /* Number of data items. */
-  write_bytes (w, ds_data (&map), ds_length (&map));
-
+  write_utf8_record (w, dict_get_encoding (dict), &map, 13);
   ds_destroy (&map);
 }
 
 /* Write integer information record. */
 static void
-write_integer_info_record (struct sfm_writer *w)
+write_integer_info_record (struct sfm_writer *w,
+                           const struct dictionary *d)
 {
   int version_component[3];
   int float_format;
+  int codepage;
 
   /* Parse the version string. */
   memset (version_component, 0, sizeof version_component);
@@ -881,6 +972,16 @@ write_integer_info_record (struct sfm_writer *w)
   else
     abort ();
 
+  /* Choose codepage. */
+  codepage = sys_get_codepage_from_encoding (dict_get_encoding (d));
+  if (codepage == 0)
+    {
+      /* Default to "7-bit ASCII" if the codepage number is unknown, because
+         many files use this codepage number regardless of their actual
+         encoding. */
+      codepage = 2;
+    }
+
   /* Write record. */
   write_int (w, 7);             /* Record type. */
   write_int (w, 3);             /* Record subtype. */
@@ -893,7 +994,7 @@ write_integer_info_record (struct sfm_writer *w)
   write_int (w, float_format);
   write_int (w, 1);           /* Compression code. */
   write_int (w, INTEGER_NATIVE == INTEGER_MSB_FIRST ? 1 : 2);
-  write_int (w, 2);           /* 7-bit ASCII. */
+  write_int (w, codepage);
 }
 
 /* Write floating-point information record. */
@@ -1189,9 +1290,9 @@ write_value (struct sfm_writer *w, const union value *value, int width)
     }
 }
 
-/* Writes null-terminated STRING in a field of the given WIDTH to
-   W.  If STRING is longer than WIDTH, it is truncated; if WIDTH
-   is narrowed, it is padded on the right with spaces. */
+/* Writes null-terminated STRING in a field of the given WIDTH to W.  If STRING
+   is longer than WIDTH, it is truncated; if STRING is shorter than WIDTH, it
+   is padded on the right with spaces. */
 static void
 write_string (struct sfm_writer *w, const char *string, size_t width)
 {
@@ -1202,6 +1303,44 @@ write_string (struct sfm_writer *w, const char *string, size_t width)
     putc (' ', w->file);
 }
 
+/* Recodes null-terminated UTF-8 encoded STRING into ENCODING, and writes the
+   recoded version in a field of the given WIDTH to W.  The string is truncated
+   or padded on the right with spaces to exactly WIDTH bytes. */
+static void
+write_utf8_string (struct sfm_writer *w, const char *encoding,
+                   const char *string, size_t width)
+{
+  char *s = recode_string (encoding, "UTF-8", string, -1);
+  write_string (w, s, width);
+  free (s);
+}
+
+/* Writes a record with type 7, subtype SUBTYPE that contains CONTENT recoded
+   from UTF-8 encoded into ENCODING. */
+static void
+write_utf8_record (struct sfm_writer *w, const char *encoding,
+                   const struct string *content, int subtype)
+{
+  struct substring s;
+
+  s = recode_substring_pool (encoding, "UTF-8", ds_ss (content), NULL);
+  write_string_record (w, s, subtype);
+  ss_dealloc (&s);
+}
+
+/* Writes a record with type 7, subtype SUBTYPE that contains the string
+   CONTENT. */
+static void
+write_string_record (struct sfm_writer *w,
+                     const struct substring content, int subtype)
+{
+  write_int (w, 7);
+  write_int (w, subtype);
+  write_int (w, 1);
+  write_int (w, ss_length (content));
+  write_bytes (w, ss_data (content), ss_length (content));
+}
+
 /* Writes SIZE bytes of DATA to W's output file. */
 static void
 write_bytes (struct sfm_writer *w, const void *data, size_t size)
index 2a73cade41bbcf6e4c55622c5d00b9d8b18505b6..8321cf5d4eba5ef2e9674bb6cd9ada6977311141 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, 2011 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/transformations.h>
+#include "data/transformations.h"
 
 #include <assert.h>
 #include <stdlib.h>
 
-#include <libpspp/str.h>
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A single transformation. */
 struct transformation
index 59001f1139da18a544775337b9921baa435b7e6c..013bcaa731e8e29adedaad8eb04d75b46e3e37e4 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, 2011 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,7 +19,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <data/case.h>
+#include "data/case.h"
 
 /* trns_proc_func return values. */
 enum trns_result
index 27139af9a88feed090bf58440f3d520d28e00703..8aaa06a0d92e95fc90acbafe0dc140122c281a4c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - computes sample statistics.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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
@@ -21,7 +21,7 @@
 
 #include <float.h>
 #include <stdbool.h>
-#include <libpspp/float-format.h>
+#include "libpspp/float-format.h"
 
 /* Special numeric values. */
 #define SYSMIS (-DBL_MAX)               /* System-missing value. */
index b1c0dc7ae2682c9fec73dd2d322fea651e251002..746e20908f8f8bdafa7fa8a6529e7d8450be333c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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 "value-labels.h"
+#include "data/value-labels.h"
 
 #include <stdlib.h>
 
-#include <data/data-out.h>
-#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 "data/data-out.h"
+#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"
+#include "gl/xalloc.h"
 
 /* Creates and returns a new, empty set of value labels with the
    given WIDTH. */
@@ -58,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, label->label);
+    val_labs_add (copy, &label->value, label->escaped_label);
   return copy;
 }
 
@@ -114,6 +114,7 @@ val_labs_clear (struct val_labs *vls)
       hmap_delete (&vls->labels, &label->node);
       value_destroy (&label->value, vls->width);
       intern_unref (label->label);
+      intern_unref (label->escaped_label);
       free (label);
     }
 }
@@ -133,18 +134,48 @@ val_labs_count (const struct val_labs *vls)
   return vls == NULL ? 0 : hmap_count (&vls->labels);
 }
 \f
+static void
+set_label (struct val_lab *lab, const char *escaped_label)
+{
+  lab->escaped_label = intern_new (escaped_label);
+  if (strstr (escaped_label, "\\n") == NULL)
+    lab->label = intern_ref (lab->escaped_label);
+  else
+    {
+      struct string s;
+      const char *p;
+
+      ds_init_empty (&s);
+      ds_extend (&s, intern_strlen (lab->escaped_label));
+      for (p = escaped_label; *p != '\0'; p++)
+        {
+          char c = *p;
+          if (c == '\\' && p[1] == 'n')
+            {
+              c = '\n';
+              p++;
+            }
+          ds_put_byte (&s, c);
+        }
+      lab->label = intern_new (ds_cstr (&s));
+      ds_destroy (&s);
+    }
+}
+
 static void
 do_add_val_lab (struct val_labs *vls, const union value *value,
-                const char *label)
+                const char *escaped_label)
 {
   struct val_lab *lab = xmalloc (sizeof *lab);
   value_clone (&lab->value, value, vls->width);
-  lab->label = intern_new (label);
+  set_label (lab, escaped_label);
   hmap_insert (&vls->labels, &lab->node, value_hash (value, vls->width, 0));
 }
 
-/* If VLS does not already contain a value label for VALUE, adds
-   LABEL for it and returns true.  Otherwise, returns false. */
+/* If VLS does not already contain a value label for VALUE, adds the UTF-8
+   encoded LABEL for it and returns true.  Otherwise, returns false.
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 bool
 val_labs_add (struct val_labs *vls, const union value *value,
               const char *label)
@@ -160,7 +191,9 @@ val_labs_add (struct val_labs *vls, const union value *value,
 }
 
 /* Sets LABEL as the value label for VALUE in VLS, replacing any
-   existing label for VALUE. */
+   existing label for VALUE.
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 void
 val_labs_replace (struct val_labs *vls, const union value *value,
                   const char *label)
@@ -169,7 +202,8 @@ val_labs_replace (struct val_labs *vls, const union value *value,
   if (vl != NULL)
     {
       intern_unref (vl->label);
-      vl->label = intern_new (label);
+      intern_unref (vl->escaped_label);
+      set_label (vl, label);
     }
   else
     do_add_val_lab (vls, value, label);
@@ -182,12 +216,14 @@ val_labs_remove (struct val_labs *vls, struct val_lab *label)
   hmap_delete (&vls->labels, &label->node);
   value_destroy (&label->value, vls->width);
   intern_unref (label->label);
+  intern_unref (label->escaped_label);
   free (label);
 }
 
-/* Searches VLS for a value label for VALUE.  If successful,
-   returns the string used as the label; otherwise, returns a
-   null pointer.  Returns a null pointer if VLS is null. */
+/* Searches VLS for a value label for VALUE.  If successful, returns the string
+   used as the label, as a UTF-8 encoded string in a format suitable for
+   output.  Otherwise, returns a null pointer.  Returns a null pointer if VLS
+   is null. */
 const char *
 val_labs_find (const struct val_labs *vls, const union value *value)
 {
@@ -195,21 +231,30 @@ val_labs_find (const struct val_labs *vls, const union value *value)
   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. */
+static struct val_lab *
+val_labs_lookup__ (const struct val_labs *vls, const union value *value,
+                   unsigned int hash)
+{
+  struct val_lab *label;
+
+  HMAP_FOR_EACH_WITH_HASH (label, struct val_lab, node, hash, &vls->labels)
+    if (value_equal (&label->value, value, vls->width))
+      return label;
+
+  return 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. */
 struct val_lab *
 val_labs_lookup (const struct val_labs *vls, const union value *value)
 {
-  if (vls != NULL)
-    {
-      struct val_lab *label;
-      HMAP_FOR_EACH_WITH_HASH (label, struct val_lab, node,
-                               value_hash (value, vls->width, 0), &vls->labels)
-        if (value_equal (&label->value, value, vls->width))
-          return label;
-    }
-  return NULL;
+  return (vls == NULL ? NULL
+          : val_labs_lookup__ (vls, value, value_hash (value, vls->width, 0)));
 }
 \f
 /* Returns the first value label in VLS, in arbitrary order, or a
@@ -265,3 +310,39 @@ val_labs_sorted (const struct val_labs *vls)
   else
     return NULL;
 }
+
+/* Returns a hash value that represents all of the labels in VLS, starting from
+   BASIS. */
+unsigned int
+val_labs_hash (const struct val_labs *vls, unsigned int basis)
+{
+  const struct val_lab *label;
+  unsigned int hash;
+
+  hash = hash_int (val_labs_count (vls), basis);
+  HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
+    hash ^= value_hash (&label->value, vls->width,
+                        hash_string (label->label, basis));
+  return hash;
+}
+
+/* Returns true if A and B contain the same values with the same labels,
+   false if they differ in some way. */
+bool
+val_labs_equal (const struct val_labs *a, const struct val_labs *b)
+{
+  const struct val_lab *label;
+
+  if (val_labs_count (a) != val_labs_count (b) || a->width != b->width)
+    return false;
+
+  HMAP_FOR_EACH (label, struct val_lab, node, &a->labels)
+    {
+      struct val_lab *label2 = val_labs_lookup__ (b, &label->value,
+                                                  label->node.hash);
+      if (!label2 || label->label != label2->label)
+        return false;
+    }
+
+  return true;
+}
index d6f65d43c334d3b8657993af922cc26673cfe4a6..f0f7ce01264c392552f7b96d130be6577ddb50a9 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, 2011 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,8 +27,8 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <data/value.h>
-#include <libpspp/hmap.h>
+#include "data/value.h"
+#include "libpspp/hmap.h"
 
 /* One value label.
 
@@ -39,6 +39,7 @@ struct val_lab
     struct hmap_node node;      /* Node in hash map. */
     union value value;          /* The value being labeled. */
     const char *label;          /* An interned string. */
+    const char *escaped_label;  /* An interned string. */
   };
 
 /* Returns the value in VL.  The caller must not modify or free
@@ -52,19 +53,33 @@ static inline const union value *val_lab_get_value (const struct val_lab *vl)
   return &vl->value;
 }
 
-/* Returns the label in VL.  The caller must not modify or free the returned
-   value. */
+/* Returns the label in VL as a UTF-8 encoded interned string, in a format
+   appropriate for use in output.  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;
 }
+
+/* Returns the label in VL as a UTF-8 encoded interned string.  Any new-line
+   characters in the label's usual output form are represented in the returned
+   string as the two-byte sequence "\\n".  This form is used on the VALUE
+   LABELS command, in system and portable files, and passed to val_labs_add()
+   and val_labs_replace().
+
+   The caller must not modify or free the returned value. */
+static inline const char *
+val_lab_get_escaped_label (const struct val_lab *vl)
+{
+  return vl->escaped_label;
+}
 \f
 /* A set of value labels. */
 struct val_labs
   {
     int width;                  /* 0=numeric, otherwise string width. */
-    struct hmap labels;         /* Hash table of `struct int_val_lab's. */
+    struct hmap labels;         /* Hash table of `struct val_lab's. */
   };
 
 /* Creating and destroying sets of value labels. */
@@ -77,7 +92,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 *);
 struct val_lab *val_labs_lookup (const struct val_labs *,
-                                       const union value *);
+                                 const union value *);
 
 /* Basic properties. */
 size_t val_labs_count (const struct val_labs *);
@@ -96,4 +111,8 @@ const struct val_lab *val_labs_next (const struct val_labs *,
                                      const struct val_lab *);
 const struct val_lab **val_labs_sorted (const struct val_labs *);
 
+/* Properties of entire sets. */
+unsigned int val_labs_hash (const struct val_labs *, unsigned int basis);
+bool val_labs_equal (const struct val_labs *, const struct val_labs *);
+
 #endif /* data/value-labels.h */
index 65b250e085f40c1a791735bbb6273c2df7f664ff..144f39b5241d1fb7b8b36021e57c23cea65a22ae 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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/value.h>
 
-#include <data/val-type.h>
-#include <data/variable.h>
-#include <libpspp/hash-functions.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <gl/unistr.h>
+#include "data/value.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+#include "gl/unistr.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 /* Copies the contents of string value SRC with width SRC_WIDTH
    to string value DST with width DST_WIDTH.  If SRC_WIDTH is
index 707b2813eccb172bdbee017ff92f2bea009ac8f2..41f9221d436c66201393d7bf4efe2b705bce840d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 "variable.h"
+
+#include "data/variable.h"
 
 #include <stdlib.h>
 
-#include <data/attributes.h>
-#include <data/data-out.h>
-#include <data/format.h>
-#include <data/dictionary.h>
-#include <data/identifier.h>
-#include <data/missing-values.h>
-#include <data/value-labels.h>
-#include <data/vardict.h>
-
-#include <libpspp/misc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash-functions.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/attributes.h"
+#include "data/data-out.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/identifier.h"
+#include "data/missing-values.h"
+#include "data/value-labels.h"
+#include "data/vardict.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -45,7 +46,7 @@
 struct variable
   {
     /* Dictionary information. */
-    char name[VAR_NAME_LEN + 1]; /* Variable name.  Mixed case. */
+    char *name;                 /* Variable name.  Mixed case. */
     int width;                 /* 0 for numeric, otherwise string width. */
     struct missing_values miss; /* Missing values. */
     struct fmt_spec print;     /* Default format for PRINT. */
@@ -91,6 +92,7 @@ var_create (const char *name, int width)
 
   v = xmalloc (sizeof *v);
   v->vardict = NULL;
+  v->name = NULL;
   var_set_name (v, name);
   v->width = width;
   mv_init (&v->miss, width);
@@ -131,7 +133,7 @@ var_clone (const struct variable *old_var)
   var_set_print_format (new_var, var_get_print_format (old_var));
   var_set_write_format (new_var, var_get_write_format (old_var));
   var_set_value_labels (new_var, var_get_value_labels (old_var));
-  var_set_label (new_var, var_get_label (old_var));
+  var_set_label (new_var, var_get_label (old_var), false);
   var_set_measure (new_var, var_get_measure (old_var));
   var_set_display_width (new_var, var_get_display_width (old_var));
   var_set_alignment (new_var, var_get_alignment (old_var));
@@ -155,114 +157,34 @@ var_destroy (struct variable *v)
       var_clear_aux (v);
       val_labs_destroy (v->val_labs);
       var_clear_label (v);
+      free (v->name);
       free (v);
     }
 }
 \f
 /* Variable names. */
 
-/* Return variable V's name. */
+/* Return variable V's name, as a UTF-8 encoded string. */
 const char *
 var_get_name (const struct variable *v)
 {
   return v->name;
 }
 
-/* Sets V's name to NAME.
+/* Sets V's name to NAME, a UTF-8 encoded string.
    Do not use this function for a variable in a dictionary.  Use
    dict_rename_var instead. */
 void
 var_set_name (struct variable *v, const char *name)
 {
   assert (!var_has_vardict (v));
-  assert (var_is_plausible_name (name, false));
+  assert (id_is_plausible (name, false));
 
-  str_copy_trunc (v->name, sizeof v->name, name);
+  free (v->name);
+  v->name = xstrdup (name);
   dict_var_changed (v);
 }
 
-/* Returns true if NAME is an acceptable name for a variable,
-   false otherwise.  If ISSUE_ERROR is true, issues an
-   explanatory error message on failure. */
-bool
-var_is_valid_name (const char *name, bool issue_error)
-{
-  bool plausible;
-  size_t length, i;
-
-  /* Note that strlen returns number of BYTES, not the number of
-     CHARACTERS */
-  length = strlen (name);
-
-  plausible = var_is_plausible_name(name, issue_error);
-
-  if ( ! plausible )
-    return false;
-
-
-  if (!lex_is_id1 (name[0]))
-    {
-      if (issue_error)
-        msg (SE, _("Character `%c' (in %s) may not appear "
-                   "as the first character in a variable name."),
-             name[0], name);
-      return false;
-    }
-
-
-  for (i = 0; i < length; i++)
-    {
-    if (!lex_is_idn (name[i]))
-      {
-        if (issue_error)
-          msg (SE, _("Character `%c' (in %s) may not appear in "
-                     "a variable name."),
-               name[i], name);
-        return false;
-      }
-    }
-
-  return true;
-}
-
-/* Returns true if NAME is an plausible name for a variable,
-   false otherwise.  If ISSUE_ERROR is true, issues an
-   explanatory error message on failure.
-   This function makes no use of LC_CTYPE.
-*/
-bool
-var_is_plausible_name (const char *name, bool issue_error)
-{
-  size_t length;
-
-  /* Note that strlen returns number of BYTES, not the number of
-     CHARACTERS */
-  length = strlen (name);
-  if (length < 1)
-    {
-      if (issue_error)
-        msg (SE, _("Variable name cannot be empty string."));
-      return false;
-    }
-  else if (length > VAR_NAME_LEN)
-    {
-      if (issue_error)
-        msg (SE, _("Variable name %s exceeds %d-character limit."),
-             name, (int) VAR_NAME_LEN);
-      return false;
-    }
-
-  if (lex_id_to_token (ss_cstr (name)) != T_ID)
-    {
-      if (issue_error)
-        msg (SE, _("`%s' may not be used as a variable name because it "
-                   "is a reserved word."), name);
-      return false;
-    }
-
-  return true;
-}
-
 /* Returns VAR's dictionary class. */
 enum dict_class
 var_get_dict_class (const struct variable *var)
@@ -505,9 +427,11 @@ alloc_value_labels (struct variable *v)
     v->val_labs = val_labs_create (v->width);
 }
 
-/* Attempts to add a value label with the given VALUE and LABEL
-   to V.  Returns true if successful, false otherwise (probably
-   due to an existing label). */
+/* Attempts to add a value label with the given VALUE and UTF-8 encoded LABEL
+   to V.  Returns true if successful, false otherwise (probably due to an
+   existing label).
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 bool
 var_add_value_label (struct variable *v,
                      const union value *value, const char *label)
@@ -516,9 +440,10 @@ var_add_value_label (struct variable *v,
   return val_labs_add (v->val_labs, value, label);
 }
 
-/* Adds or replaces a value label with the given VALUE and LABEL
+/* Adds or replaces a value label with the given VALUE and UTF-8 encoded LABEL
    to V.
-*/
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 void
 var_replace_value_label (struct variable *v,
                          const union value *value, const char *label)
@@ -534,8 +459,8 @@ var_clear_value_labels (struct variable *v)
   var_set_value_labels (v, NULL);
 }
 
-/* Returns the label associated with VALUE for variable V,
-   or a null pointer if none. */
+/* Returns the label associated with VALUE for variable V, as a UTF-8 string in
+   a format suitable for output, or a null pointer if none. */
 const char *
 var_lookup_value_label (const struct variable *v, const union value *value)
 {
@@ -641,33 +566,58 @@ var_get_label (const struct variable *v)
   return v->label;
 }
 
-/* Sets V's variable label to LABEL, stripping off leading and
-   trailing white space and truncating to 255 characters.
-   If LABEL is a null pointer or if LABEL is an empty string
-   (after stripping white space), then V's variable label (if
-   any) is removed. */
-void
-var_set_label (struct variable *v, const char *label)
+/* Sets V's variable label to UTF-8 encoded string LABEL, stripping off leading
+   and trailing white space.  If LABEL is a null pointer or if LABEL is an
+   empty string (after stripping white space), then V's variable label (if any)
+   is removed.
+
+   Variable labels are limited to 255 bytes in V's encoding (as returned by
+   var_get_encoding()).  If LABEL fits within this limit, this function returns
+   true.  Otherwise, the variable label is set to a truncated value, this
+   function returns false and, if ISSUE_WARNING is true, issues a warning.  */
+bool
+var_set_label (struct variable *v, const char *label, bool issue_warning)
 {
+  bool truncated = false;
+
   free (v->label);
   v->label = NULL;
 
-  if (label != NULL)
+  if (label != NULL && label[strspn (label, CC_SPACES)])
     {
+      const char *dict_encoding = var_get_encoding (v);
       struct substring s = ss_cstr (label);
-      ss_trim (&s, ss_cstr (CC_SPACES));
-      ss_truncate (&s, 255);
-      if (!ss_is_empty (s))
+      size_t trunc_len;
+
+      if (dict_encoding != NULL)
+        {
+          enum { MAX_LABEL_LEN = 255 };
+
+          trunc_len = utf8_encoding_trunc_len (label, dict_encoding,
+                                               MAX_LABEL_LEN);
+          if (ss_length (s) > trunc_len)
+            {
+              if (issue_warning)
+                msg (SW, _("Truncating variable label for variable `%s' to %d "
+                           "bytes."), var_get_name (v), MAX_LABEL_LEN);
+              ss_truncate (&s, trunc_len);
+              truncated = true;
+            }
+        }
+
         v->label = ss_xstrdup (s);
     }
+
   dict_var_changed (v);
+
+  return truncated;
 }
 
 /* Removes any variable label from V. */
 void
 var_clear_label (struct variable *v)
 {
-  var_set_label (v, NULL);
+  var_set_label (v, NULL, false);
 }
 
 /* Returns true if V has a variable V,
@@ -686,6 +636,26 @@ measure_is_valid (enum measure m)
   return m == MEASURE_NOMINAL || m == MEASURE_ORDINAL || m == MEASURE_SCALE;
 }
 
+/* Returns a string version of measurement level M, for display to a user. */
+const char *
+measure_to_string (enum measure m)
+{
+  switch (m)
+    {
+    case MEASURE_NOMINAL:
+      return _("Nominal");
+
+    case MEASURE_ORDINAL:
+      return _("Ordinal");
+
+    case MEASURE_SCALE:
+      return _("Scale");
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's measurement level. */
 enum measure
 var_get_measure (const struct variable *v)
@@ -750,6 +720,26 @@ alignment_is_valid (enum alignment a)
   return a == ALIGN_LEFT || a == ALIGN_RIGHT || a == ALIGN_CENTRE;
 }
 
+/* Returns a string version of alignment A, for display to a user. */
+const char *
+alignment_to_string (enum alignment a)
+{
+  switch (a)
+    {
+    case ALIGN_LEFT:
+      return _("Left");
+
+    case ALIGN_RIGHT:
+      return _("Right");
+
+    case ALIGN_CENTRE:
+      return _("Center");
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's display alignment, which applies only to GUIs. */
 enum alignment
 var_get_alignment (const struct variable *v)
@@ -829,14 +819,16 @@ var_get_short_name (const struct variable *var, size_t idx)
   return idx < var->short_name_cnt ? var->short_names[idx] : NULL;
 }
 
-/* Sets VAR's short name with the given IDX to SHORT_NAME,
-   truncating it to SHORT_NAME_LEN characters and converting it
-   to uppercase in the process.  Specifying a null pointer for
-   SHORT_NAME clears the specified short name. */
+/* Sets VAR's short name with the given IDX to the UTF-8 string SHORT_NAME.
+   The caller must already have checked that, in the dictionary encoding,
+   SHORT_NAME is no more than SHORT_NAME_LEN bytes long.  The new short name
+   will be converted to uppercase.
+
+   Specifying a null pointer for SHORT_NAME clears the specified short name. */
 void
 var_set_short_name (struct variable *var, size_t idx, const char *short_name)
 {
-  assert (short_name == NULL || var_is_plausible_name (short_name, false));
+  assert (short_name == NULL || id_is_plausible (short_name, false));
 
   /* Clear old short name numbered IDX, if any. */
   if (idx < var->short_name_cnt) 
@@ -858,7 +850,7 @@ var_set_short_name (struct variable *var, size_t idx, const char *short_name)
           for (i = old_cnt; i < var->short_name_cnt; i++)
             var->short_names[i] = NULL;
         }
-      var->short_names[idx] = xstrndup (short_name, MAX_SHORT_STRING);
+      var->short_names[idx] = xstrdup (short_name);
       str_uppercase (var->short_names[idx]);
     }
 
index 524a6be2be0d73c60b376aeb510079f0ad512ea3..aeed5a5e09e14e63e5c2ff73d70009c8b0a0c8c7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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,9 +19,9 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <data/dict-class.h>
-#include <data/missing-values.h>
-#include <data/val-type.h>
+#include "data/dict-class.h"
+#include "data/missing-values.h"
+#include "data/val-type.h"
 
 union value;
 
@@ -34,12 +34,8 @@ struct variable *var_clone (const struct variable *);
 void var_destroy (struct variable *);
 
 /* Variable names. */
-#define VAR_NAME_LEN 64 /* Maximum length of variable name, in bytes. */
-
 const char *var_get_name (const struct variable *);
 void var_set_name (struct variable *, const char *);
-bool var_is_valid_name (const char *, bool issue_error);
-bool var_is_plausible_name (const char *name, bool issue_error);
 enum dict_class var_get_dict_class (const struct variable *);
 
 int compare_vars_by_name (const void *, const void *, const void *);
@@ -102,7 +98,7 @@ struct fmt_spec var_default_formats (int width);
 /* Variable labels. */
 const char *var_to_string (const struct variable *);
 const char *var_get_label (const struct variable *);
-void var_set_label (struct variable *, const char *);
+bool var_set_label (struct variable *, const char *label, bool issue_warning);
 void var_clear_label (struct variable *);
 bool var_has_label (const struct variable *);
 
@@ -116,6 +112,8 @@ enum measure
   };
 
 bool measure_is_valid (enum measure);
+const char *measure_to_string (enum measure);
+
 enum measure var_get_measure (const struct variable *);
 void var_set_measure (struct variable *, enum measure);
 
@@ -132,11 +130,12 @@ enum alignment
   {
     ALIGN_LEFT = 0,
     ALIGN_RIGHT = 1,
-    ALIGN_CENTRE = 2,
-    n_ALIGN
+    ALIGN_CENTRE = 2
   };
 
 bool alignment_is_valid (enum alignment);
+const char *alignment_to_string (enum alignment);
+
 enum alignment var_get_alignment (const struct variable *);
 void var_set_alignment (struct variable *, enum alignment);
 
index fd65d284d43ea6d75d1db2885f1b9ad87d37bce9..87046ad42b8127853f7a67b75bb2f07dc4583121 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006  Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011  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 "vector.h"
 
-#include "dictionary.h"
+#include "data/vector.h"
 
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+#include <stdlib.h>
 
-#include "xalloc.h"
+#include "data/dictionary.h"
+#include "data/identifier.h"
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 /* Vector of variables. */
 struct vector
   {
-    char name[VAR_NAME_LEN + 1];       /* Name. */
+    char *name;                         /* Name. */
     struct variable **vars;             /* Set of variables. */
     size_t var_cnt;                     /* Number of variables. */
   };
@@ -44,19 +47,18 @@ check_widths (const struct vector *vector)
     assert (width == var_get_width (vector->vars[i]));
 }
 
-/* Creates and returns a new vector with the given NAME
+/* Creates and returns a new vector with the given UTF-8 encoded NAME
    that contains the VAR_CNT variables in VARS.
    All variables in VARS must have the same type and width. */
 struct vector *
-vector_create (const char *name,
-               struct variable **vars, size_t var_cnt)
+vector_create (const char *name, struct variable **vars, size_t var_cnt)
 {
   struct vector *vector = xmalloc (sizeof *vector);
 
   assert (var_cnt > 0);
-  assert (var_is_plausible_name (name, false));
-  str_copy_trunc (vector->name, sizeof vector->name, name);
+  assert (id_is_plausible (name, false));
 
+  vector->name = xstrdup (name);
   vector->vars = xmemdup (vars, var_cnt * sizeof *vector->vars);
   vector->var_cnt = var_cnt;
   check_widths (vector);
@@ -77,8 +79,7 @@ vector_clone (const struct vector *old,
   struct vector *new = xmalloc (sizeof *new);
   size_t i;
 
-  strcpy (new->name, old->name);
-
+  new->name = xstrdup (old->name);
   new->vars = xnmalloc (old->var_cnt, sizeof *new->vars);
   new->var_cnt = old->var_cnt;
   for (i = 0; i < new->var_cnt; i++)
@@ -96,11 +97,12 @@ vector_clone (const struct vector *old,
 void
 vector_destroy (struct vector *vector)
 {
+  free (vector->name);
   free (vector->vars);
   free (vector);
 }
 
-/* Returns VECTOR's name. */
+/* Returns VECTOR's name, as a UTF-8 encoded string. */
 const char *
 vector_get_name (const struct vector *vector)
 {
index b009fcb2922f3ac4c7a67422e2089cef1311c5bf..f8fe0888497cc543a8a87e91b8c705ddcfd71cb1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006  Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011  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
@@ -18,7 +18,7 @@
 #define DATA_VECTOR_H 1
 
 #include <stddef.h>
-#include <data/variable.h>
+#include "data/variable.h"
 
 struct dictionary;
 
@@ -34,6 +34,8 @@ enum val_type vector_get_type (const struct vector *);
 struct variable *vector_get_var (const struct vector *, size_t idx);
 size_t vector_get_var_cnt (const struct vector *);
 
+bool vector_is_valid_name (const char *name, bool issue_error);
+
 int compare_vector_ptrs_by_name (const void *a_, const void *b_);
 
 #endif /* data/vector.h */
index 3052b52353ca54416ffbb53f66c4354787bf6924..6c0eaa90a05927d81c4bd2db4ff47dfa6b76341d 100644 (file)
@@ -14,12 +14,6 @@ noinst_LTLIBRARIES +=  src/language/liblanguage.la
 
 
 src_language_liblanguage_la_SOURCES = \
-       src/language/syntax-file.c \
-       src/language/syntax-file.h \
-       src/language/syntax-string-source.c \
-       src/language/syntax-string-source.h \
-       src/language/prompt.c \
-       src/language/prompt.h \
        src/language/command.c \
        src/language/command.h \
        src/language/command.def \
index 9f90db93a941af0762b20e4f02b3f6e4758d8732..ff2b030ce0e206f3af47c48f090368027dd60e4c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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 <errno.h>
 
 #include "data/casereader.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
-#include "data/procedure.h"
+#include "data/session.h"
 #include "data/settings.h"
 #include "data/variable.h"
+#include "language/lexer/command-name.h"
 #include "language/lexer/lexer.h"
-#include "language/prompt.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
-#include "libpspp/getl.h"
 #include "output/text-item.h"
 
 #include "xalloc.h"
@@ -76,8 +77,8 @@ cmd_result_is_failure (enum cmd_result result)
 /* Command processing states. */
 enum states
   {
-    S_INITIAL = 0x01,         /* Allowed before active file defined. */
-    S_DATA = 0x02,            /* Allowed after active file defined. */
+    S_INITIAL = 0x01,         /* Allowed before active dataset defined. */
+    S_DATA = 0x02,            /* Allowed after active dataset defined. */
     S_INPUT_PROGRAM = 0x04,   /* Allowed in INPUT PROGRAM. */
     S_FILE_TYPE = 0x08,       /* Allowed in FILE TYPE. */
     S_ANY = 0x0f              /* Allowed anywhere. */
@@ -88,7 +89,6 @@ enum flags
   {
     F_ENHANCED = 0x10,        /* Allowed only in enhanced syntax mode. */
     F_TESTING = 0x20,         /* Allowed only in testing mode. */
-    F_KEEP_FINAL_TOKEN = 0x40,/* Don't skip final token in command name. */
     F_ABBREV = 0x80           /* Not a candidate for name completion. */
   };
 
@@ -115,12 +115,12 @@ static const size_t command_cnt = sizeof commands / sizeof *commands;
 
 static bool in_correct_state (const struct command *, enum cmd_state);
 static bool report_state_mismatch (const struct command *, enum cmd_state);
-static const struct command *find_command (const char *name);
 static void set_completion_state (enum cmd_state);
 \f
 /* Command parser. */
 
-static const struct command *parse_command_name (struct lexer *lexer);
+static const struct command *parse_command_name (struct lexer *,
+                                                 int *n_tokens);
 static enum cmd_result do_parse_command (struct lexer *, struct dataset *, enum cmd_state);
 
 /* Parses an entire command, from command name to terminating
@@ -130,10 +130,12 @@ enum cmd_result
 cmd_parse_in_state (struct lexer *lexer, struct dataset *ds,
                    enum cmd_state state)
 {
+  struct session *session = dataset_session (ds);
   int result;
 
   result = do_parse_command (lexer, ds, state);
 
+  ds = session_active_dataset (session);
   assert (!proc_is_open (ds));
   unset_cmd_algorithm ();
   dict_clear_aux (dataset_dict (ds));
@@ -148,7 +150,7 @@ cmd_parse (struct lexer *lexer, struct dataset *ds)
 {
   const struct dictionary *dict = dataset_dict (ds);
   return cmd_parse_in_state (lexer, ds,
-                            proc_has_active_file (ds) &&
+                            dataset_has_source (ds) &&
                             dict_get_var_cnt (dict) > 0 ?
                             CMD_STATE_DATA : CMD_STATE_INITIAL);
 }
@@ -163,27 +165,24 @@ do_parse_command (struct lexer *lexer,
   const struct command *command = NULL;
   enum cmd_result result;
   bool opened = false;
+  int n_tokens;
 
   /* Read the command's first token. */
-  prompt_set_style (PROMPT_FIRST);
   set_completion_state (state);
-  lex_get (lexer);
   if (lex_token (lexer) == T_STOP)
     {
       result = CMD_EOF;
       goto finish;
     }
-  else if (lex_token (lexer) == '.')
+  else if (lex_token (lexer) == T_ENDCMD)
     {
       /* Null commands can result from extra empty lines. */
       result = CMD_SUCCESS;
       goto finish;
     }
 
-  prompt_set_style (PROMPT_LATER);
-
   /* Parse the command name. */
-  command = parse_command_name (lexer);
+  command = parse_command_name (lexer, &n_tokens);
   if (command == NULL)
     {
       result = CMD_FAILURE;
@@ -216,22 +215,24 @@ do_parse_command (struct lexer *lexer,
   else
     {
       /* Execute command. */
+      int i;
+
+      for (i = 0; i < n_tokens; i++)
+        lex_get (lexer);
       result = command->function (lexer, ds);
     }
 
   assert (cmd_result_is_valid (result));
 
- finish:
+finish:
   if (cmd_result_is_failure (result))
-    {
-      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;
-       }
-    }
+    lex_interactive_reset (lexer);
+  else if (result == CMD_SUCCESS)
+    result = lex_end_of_command (lexer);
+
+  lex_discard_rest_of_command (lexer);
+  while (lex_token (lexer) == T_ENDCMD)
+    lex_get (lexer);
 
   if (opened)
     text_item_submit (text_item_create (TEXT_ITEM_COMMAND_CLOSE,
@@ -240,352 +241,105 @@ do_parse_command (struct lexer *lexer,
   return result;
 }
 
-static size_t
-match_strings (const char *a, size_t a_len,
-               const char *b, size_t b_len)
-{
-  size_t match_len = 0;
-
-  while (a_len > 0 && b_len > 0)
-    {
-      /* Mismatch always returns zero. */
-      if (toupper ((unsigned char) *a++) != toupper ((unsigned char) *b++))
-        return 0;
-
-      /* Advance. */
-      a_len--;
-      b_len--;
-      match_len++;
-    }
-
-  return match_len;
-}
-
-/* Returns the first character in the first word in STRING,
-   storing the word's length in *WORD_LEN.  If no words remain,
-   returns a null pointer and stores 0 in *WORD_LEN.  Words are
-   sequences of alphanumeric characters or single
-   non-alphanumeric characters.  Words are delimited by
-   spaces. */
-static const char *
-find_word (const char *string, size_t *word_len)
-{
-  /* Skip whitespace and asterisks. */
-  while (isspace ((unsigned char) *string))
-    string++;
-
-  /* End of string? */
-  if (*string == '\0')
-    {
-      *word_len = 0;
-      return NULL;
-    }
-
-  /* Special one-character word? */
-  if (!isalnum ((unsigned char) *string))
-    {
-      *word_len = 1;
-      return string;
-    }
-
-  /* Alphanumeric word. */
-  *word_len = 1;
-  while (isalnum ((unsigned char) string[*word_len]))
-    (*word_len)++;
-
-  return string;
-}
-
-/* Returns true if strings A and B can be confused based on
-   their first three letters. */
-static bool
-conflicting_3char_prefixes (const char *a, const char *b)
-{
-  size_t aw_len, bw_len;
-  const char *aw, *bw;
-
-  aw = find_word (a, &aw_len);
-  bw = find_word (b, &bw_len);
-  assert (aw != NULL && bw != NULL);
-
-  /* Words that are the same don't conflict. */
-  if (aw_len == bw_len && !buf_compare_case (aw, bw, aw_len))
-    return false;
-
-  /* Words that are otherwise the same in the first three letters
-     do conflict. */
-  return ((aw_len > 3 && bw_len > 3)
-          || (aw_len == 3 && bw_len > 3)
-          || (bw_len == 3 && aw_len > 3)) && !buf_compare_case (aw, bw, 3);
-}
-
-/* Returns true if CMD can be confused with another command
-   based on the first three letters of its first word. */
-static bool
-conflicting_3char_prefix_command (const struct command *cmd)
-{
-  assert (cmd >= commands && cmd < commands + command_cnt);
-
-  return ((cmd > commands
-           && conflicting_3char_prefixes (cmd[-1].name, cmd[0].name))
-          || (cmd < commands + command_cnt
-              && conflicting_3char_prefixes (cmd[0].name, cmd[1].name)));
-}
-
-/* Ways that a set of words can match a command name. */
-enum command_match
-  {
-    MISMATCH,           /* Not a match. */
-    PARTIAL_MATCH,      /* The words begin the command name. */
-    COMPLETE_MATCH      /* The words are the command name. */
-  };
-
-/* Figures out how well the WORD_CNT words in WORDS match CMD,
-   and returns the appropriate enum value.  If WORDS are a
-   partial match for CMD and the next word in CMD is a dash, then
-   *DASH_POSSIBLE is set to 1 if DASH_POSSIBLE is non-null;
-   otherwise, *DASH_POSSIBLE is unchanged. */
-static enum command_match
-cmd_match_words (const struct command *cmd,
-                 char *const words[], size_t word_cnt,
-                 int *dash_possible)
-{
-  const char *word;
-  size_t word_len;
-  size_t word_idx;
-
-  for (word = find_word (cmd->name, &word_len), word_idx = 0;
-       word != NULL && word_idx < word_cnt;
-       word = find_word (word + word_len, &word_len), word_idx++)
-    if (word_len != strlen (words[word_idx])
-        || buf_compare_case (word, words[word_idx], word_len))
-      {
-        size_t match_chars = match_strings (word, word_len,
-                                            words[word_idx],
-                                            strlen (words[word_idx]));
-        if (match_chars == 0)
-          {
-            /* Mismatch. */
-            return MISMATCH;
-          }
-        else if (match_chars == 1 || match_chars == 2)
-          {
-            /* One- and two-character abbreviations are not
-               acceptable. */
-            return MISMATCH;
-          }
-        else if (match_chars == 3)
-          {
-            /* Three-character abbreviations are acceptable
-               in the first word of a command if there are
-               no name conflicts.  They are always
-               acceptable after the first word. */
-            if (word_idx == 0 && conflicting_3char_prefix_command (cmd))
-              return MISMATCH;
-          }
-        else /* match_chars > 3 */
-          {
-            /* Four-character and longer abbreviations are
-               always acceptable.  */
-          }
-      }
-
-  if (word == NULL && word_idx == word_cnt)
-    {
-      /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR"}. */
-      return COMPLETE_MATCH;
-    }
-  else if (word == NULL)
-    {
-      /* cmd->name = "FOO BAR", words[] = {"FOO", "BAR", "BAZ"}. */
-      return MISMATCH;
-    }
-  else
-    {
-      /* cmd->name = "FOO BAR BAZ", words[] = {"FOO", "BAR"}. */
-      if (word[0] == '-' && dash_possible != NULL)
-        *dash_possible = 1;
-      return PARTIAL_MATCH;
-    }
-}
-
-/* Returns the number of commands for which the WORD_CNT words in
-   WORDS are a partial or complete match.  If some partial match
-   has a dash as the next word, then *DASH_POSSIBLE is set to 1,
-   otherwise it is set to 0. */
 static int
-count_matching_commands (char *const words[], size_t word_cnt,
-                         int *dash_possible)
-{
-  const struct command *cmd;
-  int cmd_match_count;
-
-  cmd_match_count = 0;
-  *dash_possible = 0;
-  for (cmd = commands; cmd < commands + command_cnt; cmd++)
-    if (cmd_match_words (cmd, words, word_cnt, dash_possible) != MISMATCH)
-      cmd_match_count++;
-
-  return cmd_match_count;
-}
-
-/* Returns the command for which the WORD_CNT words in WORDS are
-   a complete match.  Returns a null pointer if no such command
-   exists. */
-static const struct command *
-get_complete_match (char *const words[], size_t word_cnt)
+find_best_match (struct substring s, const struct command **matchp)
 {
   const struct command *cmd;
+  struct command_matcher cm;
+  int missing_words;
 
-  for (cmd = commands; cmd < commands + command_cnt; cmd++)
-    if (cmd_match_words (cmd, words, word_cnt, NULL) == COMPLETE_MATCH)
-      return cmd;
+  command_matcher_init (&cm, s);
+  for (cmd = commands; cmd < &commands[command_cnt]; cmd++)
+    command_matcher_add (&cm, ss_cstr (cmd->name), CONST_CAST (void *, cmd));
 
-  return NULL;
-}
+  *matchp = command_matcher_get_match (&cm);
+  missing_words = command_matcher_get_missing_words (&cm);
 
-/* Returns the command with the given exact NAME.
-   Aborts if no such command exists. */
-static const struct command *
-find_command (const char *name)
-{
-  const struct command *cmd;
+  command_matcher_destroy (&cm);
 
-  for (cmd = commands; cmd < commands + command_cnt; cmd++)
-    if (!strcmp (cmd->name, name))
-      return cmd;
-  NOT_REACHED ();
+  return missing_words;
 }
 
-/* Frees the WORD_CNT words in WORDS. */
-static void
-free_words (char *words[], size_t word_cnt)
+static bool
+parse_command_word (struct lexer *lexer, struct string *s, int n)
 {
-  size_t idx;
+  bool need_space = ds_last (s) != EOF && ds_last (s) != '-';
 
-  for (idx = 0; idx < word_cnt; idx++)
-    free (words[idx]);
-}
-
-/* Flags an error that the command whose name is given by the
-   WORD_CNT words in WORDS is unknown. */
-static void
-unknown_command_error (struct lexer *lexer, char *const words[], size_t word_cnt)
-{
-  if (word_cnt == 0)
-    lex_error (lexer, _("expecting command name"));
-  else
+  switch (lex_next_token (lexer, n))
     {
-      struct string s;
-      size_t i;
-
-      ds_init_empty (&s);
-      for (i = 0; i < word_cnt; i++)
+    case T_DASH:
+      ds_put_byte (s, '-');
+      return true;
+
+    case T_ID:
+      if (need_space)
+        ds_put_byte (s, ' ');
+      ds_put_cstr (s, lex_next_tokcstr (lexer, n));
+      return true;
+
+    case T_POS_NUM:
+      if (lex_next_is_integer (lexer, n))
         {
-          if (i != 0)
-            ds_put_char (&s, ' ');
-          ds_put_cstr (&s, words[i]);
+          int integer = lex_next_integer (lexer, n);
+          if (integer >= 0)
+            {
+              if (need_space)
+                ds_put_byte (s, ' ');
+              ds_put_format (s, "%ld", lex_next_integer (lexer, n));
+              return true;
+            }
         }
+      return false;
 
-      msg (SE, _("Unknown command %s."), ds_cstr (&s));
-
-      ds_destroy (&s);
+    default:
+      return false;
     }
 }
 
-/* Parse the command name and return a pointer to the corresponding
-   struct command if successful.
-   If not successful, return a null pointer. */
+/* Parses the command name.  On success returns a pointer to the corresponding
+   struct command and stores the number of tokens in the command name into
+   *N_TOKENS.  On failure, returns a null pointer and stores the number of
+   tokens required to determine that no command name was present into
+   *N_TOKENS. */
 static const struct command *
-parse_command_name (struct lexer *lexer)
+parse_command_name (struct lexer *lexer, int *n_tokens)
 {
-  char *words[16];
-  int word_cnt;
-  int complete_word_cnt;
-  int dash_possible;
-
-  if (lex_token (lexer) == T_EXP ||
-                 lex_token (lexer) == '*' || lex_token (lexer) == '[')
-    return find_command ("COMMENT");
-
-  dash_possible = 0;
-  word_cnt = complete_word_cnt = 0;
-  while (lex_token (lexer) == T_ID || (dash_possible && lex_token (lexer) == '-'))
+  const struct command *command;
+  int missing_words;
+  struct string s;
+  int word;
+
+  command = NULL;
+  missing_words = 0;
+  ds_init_empty (&s);
+  word = 0;
+  while (parse_command_word (lexer, &s, word))
     {
-      int cmd_match_cnt;
-
-      assert (word_cnt < sizeof words / sizeof *words);
-      if (lex_token (lexer) == T_ID)
-        {
-          words[word_cnt] = ds_xstrdup (lex_tokstr (lexer));
-          str_uppercase (words[word_cnt]);
-        }
-      else if (lex_token (lexer) == '-')
-        words[word_cnt] = xstrdup ("-");
-      word_cnt++;
-
-      cmd_match_cnt = count_matching_commands (words, word_cnt,
-                                               &dash_possible);
-      if (cmd_match_cnt == 0)
+      missing_words = find_best_match (ds_ss (&s), &command);
+      if (missing_words <= 0)
         break;
-      else if (cmd_match_cnt == 1)
-        {
-          const struct command *command = get_complete_match (words, word_cnt);
-          if (command != NULL)
-            {
-              if (!(command->flags & F_KEEP_FINAL_TOKEN))
-                lex_get (lexer);
-              free_words (words, word_cnt);
-              return command;
-            }
-        }
-      else /* cmd_match_cnt > 1 */
-        {
-          /* Do we have a complete command name so far? */
-          if (get_complete_match (words, word_cnt) != NULL)
-            complete_word_cnt = word_cnt;
-        }
-      lex_get (lexer);
+      word++;
     }
 
-  /* If we saw a complete command name earlier, drop back to
-     it. */
-  if (complete_word_cnt)
+  if (command == NULL && missing_words > 0)
     {
-      int pushback_word_cnt;
-      const struct command *command;
-
-      /* Get the command. */
-      command = get_complete_match (words, complete_word_cnt);
-      assert (command != NULL);
-
-      /* Figure out how many words we want to keep.
-         We normally want to swallow the entire command. */
-      pushback_word_cnt = complete_word_cnt + 1;
-      if (command->flags & F_KEEP_FINAL_TOKEN)
-        pushback_word_cnt--;
-
-      /* FIXME: We only support one-token pushback. */
-      assert (pushback_word_cnt + 1 >= word_cnt);
-
-      while (word_cnt > pushback_word_cnt)
-        {
-          word_cnt--;
-          if (strcmp (words[word_cnt], "-"))
-            lex_put_back_id (lexer, words[word_cnt]);
-          else
-            lex_put_back (lexer, '-');
-          free (words[word_cnt]);
-        }
+      ds_put_cstr (&s, " .");
+      missing_words = find_best_match (ds_ss (&s), &command);
+      ds_truncate (&s, ds_length (&s) - 2);
+    }
 
-      free_words (words, word_cnt);
-      return command;
+  if (command == NULL)
+    {
+      if (ds_is_empty (&s))
+        lex_error (lexer, _("expecting command name"));
+      else
+        msg (SE, _("Unknown command `%s'."), ds_cstr (&s));
     }
 
-  /* We didn't get a valid command name. */
-  unknown_command_error (lexer, words, word_cnt);
-  free_words (words, word_cnt);
-  return NULL;
+  ds_destroy (&s);
+
+  *n_tokens = (word + 1) + missing_words;
+  return command;
 }
 
 /* Returns true if COMMAND is allowed in STATE,
@@ -612,11 +366,11 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
         {
           /* One allowed state. */
         case S_INITIAL:
-          msg (SE, _("%s is allowed only before the active file has "
+          msg (SE, _("%s is allowed only before the active dataset has "
                      "been defined."), command->name);
           break;
         case S_DATA:
-          msg (SE, _("%s is allowed only after the active file has "
+          msg (SE, _("%s is allowed only after the active dataset has "
                      "been defined."), command->name);
           break;
         case S_INPUT_PROGRAM:
@@ -631,19 +385,19 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
         case S_INITIAL | S_DATA:
           NOT_REACHED ();
         case S_INITIAL | S_INPUT_PROGRAM:
-          msg (SE, _("%s is allowed only before the active file has "
+          msg (SE, _("%s is allowed only before the active dataset has "
                      "been defined or inside INPUT PROGRAM."), command->name);
           break;
         case S_INITIAL | S_FILE_TYPE:
-          msg (SE, _("%s is allowed only before the active file has "
+          msg (SE, _("%s is allowed only before the active dataset has "
                      "been defined or inside FILE TYPE."), command->name);
           break;
         case S_DATA | S_INPUT_PROGRAM:
-          msg (SE, _("%s is allowed only after the active file has "
+          msg (SE, _("%s is allowed only after the active dataset has "
                      "been defined or inside INPUT PROGRAM."), command->name);
           break;
         case S_DATA | S_FILE_TYPE:
-          msg (SE, _("%s is allowed only after the active file has "
+          msg (SE, _("%s is allowed only after the active dataset has "
                      "been defined or inside FILE TYPE."), command->name);
           break;
         case S_INPUT_PROGRAM | S_FILE_TYPE:
@@ -653,12 +407,12 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
 
           /* Three allowed states. */
         case S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE:
-          msg (SE, _("%s is allowed only after the active file has "
+          msg (SE, _("%s is allowed only after the active dataset has "
                      "been defined, inside INPUT PROGRAM, or inside "
                      "FILE TYPE."), command->name);
           break;
         case S_INITIAL | S_INPUT_PROGRAM | S_FILE_TYPE:
-          msg (SE, _("%s is allowed only before the active file has "
+          msg (SE, _("%s is allowed only before the active dataset has "
                      "been defined, inside INPUT PROGRAM, or inside "
                      "FILE TYPE."), command->name);
           break;
@@ -676,7 +430,8 @@ report_state_mismatch (const struct command *command, enum cmd_state state)
         }
     }
   else if (state == CMD_STATE_INPUT_PROGRAM)
-    msg (SE, _("%s is not allowed inside %s."), command->name, "INPUT PROGRAM" );
+    msg (SE, _("%s is not allowed inside %s."),
+         command->name, "INPUT PROGRAM" );
   else if (state == CMD_STATE_FILE_TYPE)
     msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
 
@@ -738,23 +493,26 @@ cmd_n_of_cases (struct lexer *lexer, struct dataset *ds)
   if (!lex_match_id (lexer, "ESTIMATED"))
     dict_set_case_limit (dataset_dict (ds), x);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Parses, performs the EXECUTE procedure. */
 int
-cmd_execute (struct lexer *lexer, struct dataset *ds)
+cmd_execute (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   bool ok = casereader_destroy (proc_open (ds));
   if (!proc_commit (ds) || !ok)
     return CMD_CASCADING_FAILURE;
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Parses, performs the ERASE command. */
 int
 cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
 {
+  char *filename;
+  int retval;
+
   if (settings_get_safer_mode ())
     {
       msg (SE, _("This command not allowed when the SAFER option is set."));
@@ -763,33 +521,29 @@ cmd_erase (struct lexer *lexer, struct dataset *ds UNUSED)
 
   if (!lex_force_match_id (lexer, "FILE"))
     return CMD_FAILURE;
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
 
-  if (remove (ds_cstr (lex_tokstr (lexer))) == -1)
+  filename = utf8_to_filename (lex_tokcstr (lexer));
+  retval = remove (filename);
+  free (filename);
+
+  if (retval == -1)
     {
       msg (SW, _("Error removing `%s': %s."),
-          ds_cstr (lex_tokstr (lexer)), strerror (errno));
+           lex_tokcstr (lexer), strerror (errno));
       return CMD_FAILURE;
     }
+  lex_get (lexer);
 
   return CMD_SUCCESS;
 }
 
 /* Parses, performs the NEW FILE command. */
 int
-cmd_new_file (struct lexer *lexer, struct dataset *ds)
-{
-  proc_discard_active_file (ds);
-
-  return lex_end_of_command (lexer);
-}
-
-/* Parses a comment. */
-int
-cmd_comment (struct lexer *lexer, struct dataset *ds UNUSED)
+cmd_new_file (struct lexer *lexer UNUSED, struct dataset *ds)
 {
-  lex_skip_comment (lexer);
+  dataset_clear (ds);
   return CMD_SUCCESS;
 }
index adfaa950e1bec95a07bc9f61c0a9b5361c9dcc6e..016afcbbec1a0347fed92e42475372485b11bf96 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011 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
 
 /* Utility commands acceptable anywhere. */
 DEF_CMD (S_ANY, F_ENHANCED, "CLOSE FILE HANDLE", cmd_close_file_handle)
-DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "COMMENT", cmd_comment)
+DEF_CMD (S_ANY, 0, "CACHE", cmd_cache)
 DEF_CMD (S_ANY, 0, "CD", cmd_cd)
+DEF_CMD (S_ANY, 0, "DATASET ACTIVATE", cmd_dataset_activate)
+DEF_CMD (S_ANY, 0, "DATASET DECLARE", cmd_dataset_declare)
+DEF_CMD (S_ANY, 0, "DATASET CLOSE", cmd_dataset_close)
+DEF_CMD (S_ANY, 0, "DATASET COPY", cmd_dataset_copy)
+DEF_CMD (S_ANY, 0, "DATASET NAME", cmd_dataset_name)
+DEF_CMD (S_ANY, 0, "DATASET DISPLAY", cmd_dataset_display)
+DEF_CMD (S_ANY, 0, "DO REPEAT", cmd_do_repeat)
+DEF_CMD (S_ANY, 0, "END REPEAT", cmd_end_repeat)
 DEF_CMD (S_ANY, 0, "ECHO", cmd_echo)
 DEF_CMD (S_ANY, 0, "ERASE", cmd_erase)
 DEF_CMD (S_ANY, 0, "EXIT", cmd_finish)
 DEF_CMD (S_ANY, 0, "FILE HANDLE", cmd_file_handle)
-DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "FILE LABEL", cmd_file_label)
+DEF_CMD (S_ANY, 0, "FILE LABEL", cmd_file_label)
 DEF_CMD (S_ANY, 0, "FINISH", cmd_finish)
 DEF_CMD (S_ANY, 0, "HOST", cmd_host)
 DEF_CMD (S_ANY, 0, "INCLUDE", cmd_include)
@@ -37,11 +45,11 @@ DEF_CMD (S_ANY, 0, "QUIT", cmd_finish)
 DEF_CMD (S_ANY, 0, "RESTORE", cmd_restore)
 DEF_CMD (S_ANY, 0, "SET", cmd_set)
 DEF_CMD (S_ANY, 0, "SHOW", cmd_show)
-DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "SUBTITLE", cmd_subtitle)
+DEF_CMD (S_ANY, 0, "SUBTITLE", cmd_subtitle)
 DEF_CMD (S_ANY, 0, "SYSFILE INFO", cmd_sysfile_info)
-DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "TITLE", cmd_title)
+DEF_CMD (S_ANY, 0, "TITLE", cmd_title)
 
-/* Commands that define (or replace) the active file. */
+/* Commands that define (or replace) the active dataset. */
 DEF_CMD (S_INITIAL | S_DATA, 0, "ADD FILES", cmd_add_files)
 DEF_CMD (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE, 0, "DATA LIST", cmd_data_list)
 DEF_CMD (S_INITIAL | S_DATA, 0, "GET", cmd_get)
@@ -60,10 +68,8 @@ DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "BREAK", cmd_break)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "COMPUTE", cmd_compute)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DATAFILE ATTRIBUTE", cmd_datafile_attribute)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DISPLAY", cmd_display)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, F_KEEP_FINAL_TOKEN, "DOCUMENT", cmd_document)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DOCUMENT", cmd_document)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DO IF", cmd_do_if)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DO REPEAT", cmd_do_repeat)
-DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "END REPEAT", cmd_end_repeat)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "DROP DOCUMENTS", cmd_drop_documents)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE IF", cmd_else_if)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "ELSE", cmd_else)
@@ -97,10 +103,10 @@ DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WRITE", cmd_write)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, F_ENHANCED, "XEXPORT", cmd_xexport)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "XSAVE", cmd_xsave)
 
-/* Commands that may appear after active file definition. */
+/* Commands that may appear after active dataset definition. */
 DEF_CMD (S_DATA, 0, "AGGREGATE", cmd_aggregate)
 DEF_CMD (S_DATA, 0, "AUTORECODE", cmd_autorecode)
-DEF_CMD (S_DATA, F_KEEP_FINAL_TOKEN, "BEGIN DATA", cmd_begin_data)
+DEF_CMD (S_DATA, 0, "BEGIN DATA", cmd_begin_data)
 DEF_CMD (S_DATA, 0, "COUNT", cmd_count)
 DEF_CMD (S_DATA, 0, "CROSSTABS", cmd_crosstabs)
 DEF_CMD (S_DATA, 0, "CORRELATIONS", cmd_correlation)
@@ -118,6 +124,7 @@ DEF_CMD (S_DATA, 0, "MODIFY VARS", cmd_modify_vars)
 DEF_CMD (S_DATA, 0, "NPAR TESTS", cmd_npar_tests)
 DEF_CMD (S_DATA, 0, "ONEWAY", cmd_oneway)
 DEF_CMD (S_DATA, 0, "PEARSON CORRELATIONS", cmd_correlation)
+DEF_CMD (S_DATA, 0, "QUICK CLUSTER", cmd_quick_cluster)
 DEF_CMD (S_DATA, 0, "RANK", cmd_rank)
 DEF_CMD (S_DATA, 0, "REGRESSION", cmd_regression)
 DEF_CMD (S_DATA, 0, "RELIABILITY", cmd_reliability)
@@ -127,7 +134,6 @@ DEF_CMD (S_DATA, 0, "SAMPLE", cmd_sample)
 DEF_CMD (S_DATA, 0, "SAVE", cmd_save)
 DEF_CMD (S_DATA, 0, "SAVE TRANSLATE", cmd_save_translate)
 DEF_CMD (S_DATA, 0, "SORT CASES", cmd_sort_cases)
-DEF_CMD (S_DATA, F_ABBREV, "SORT", cmd_sort_cases)
 DEF_CMD (S_DATA, 0, "T-TEST", cmd_t_test)
 DEF_CMD (S_DATA, 0, "TEMPORARY", cmd_temporary)
 DEF_CMD (S_DATA, 0, "USE", cmd_use)
@@ -158,7 +164,7 @@ UNIMPL_CMD ("CASESTOVARS", "Restructure complex data")
 UNIMPL_CMD ("CATPCA", "Categorical principle components analysis")
 UNIMPL_CMD ("CATREG", "Categorical regression")
 UNIMPL_CMD ("CCF", "Time series cross correlation")
-UNIMPL_CMD ("CLEAR TRANSFORMATIONS", "Clears transformations from active file")
+UNIMPL_CMD ("CLEAR TRANSFORMATIONS", "Clears transformations from active dataset")
 UNIMPL_CMD ("CLUSTER", "Hierachial clustering")
 UNIMPL_CMD ("CONJOINT", "Analyse full concept data")
 UNIMPL_CMD ("CORRESPONDENCE", "Show correspondence")
@@ -172,12 +178,6 @@ UNIMPL_CMD ("CSSELECT", "Select complex samples")
 UNIMPL_CMD ("CSTABULATE", "Tabulate complex samples")
 UNIMPL_CMD ("CTABLES", "Display complex samples")
 UNIMPL_CMD ("CURVEFIT", "Fit curve to line plot")
-UNIMPL_CMD ("DATASET ACTIVATE", "Switch to alternate data set")
-UNIMPL_CMD ("DATASET CLOSE", "Delete alternate data set")
-UNIMPL_CMD ("DATASET COPY", "Duplicate alternate data set")
-UNIMPL_CMD ("DATASET DECLARE", "Start alternate data set")
-UNIMPL_CMD ("DATASET DISPLAY", "List alternate data sets")
-UNIMPL_CMD ("DATASET NAME", "Give the current data set a name")
 UNIMPL_CMD ("DATE", "Create time series data")
 UNIMPL_CMD ("DEFINE", "Syntax macros")
 UNIMPL_CMD ("DETECTANOMALY", "Find unusual cases")
@@ -235,7 +235,6 @@ UNIMPL_CMD ("PROBIT", "Probit analysis")
 UNIMPL_CMD ("PROCEDURE OUTPUT", "Specify output file")
 UNIMPL_CMD ("PROXIMITIES", "Pairwise similarity")
 UNIMPL_CMD ("PROXSCAL", "Multidimensional scaling of proximity data")
-UNIMPL_CMD ("QUICK CLUSTER", "Fast clustering")
 UNIMPL_CMD ("RATIO STATISTICS", "Descriptives of ratios")
 UNIMPL_CMD ("READ MODEL", "Read new model")
 UNIMPL_CMD ("RECORD TYPE", "Defines a type of record within FILE TYPE")
index 0c153becd74ddd4b8f06681f7f9d6afe176ee017..d99577c4d3151f931cf19d7ccc629ae13704a76b 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
@@ -45,8 +45,8 @@ bool cmd_result_is_failure (enum cmd_result);
 /* Command processing state. */
 enum cmd_state
   {
-    CMD_STATE_INITIAL,          /* No active file yet defined. */
-    CMD_STATE_DATA,             /* Active file has been defined. */
+    CMD_STATE_INITIAL,          /* No active dataset yet defined. */
+    CMD_STATE_DATA,             /* Active dataset has been defined. */
     CMD_STATE_INPUT_PROGRAM,    /* Inside INPUT PROGRAM. */
     CMD_STATE_FILE_TYPE         /* Inside FILE TYPE. */
   };
index e12813abdbb68eea3a2779f70f4e8a3df28b25f7..3e87e5a0b63d51c8b90aa78dcecb482c7303f587 100644 (file)
@@ -6,8 +6,7 @@ language_control_sources = \
        src/language/control/control-stack.h \
        src/language/control/do-if.c \
        src/language/control/loop.c \
-       src/language/control/temporary.c \
        src/language/control/repeat.c \
-       src/language/control/repeat.h
+       src/language/control/temporary.c
 
 EXTRA_DIST += src/language/control/OChangeLog
index 8456f819f53eaa13e0d77bda090883527aad3d03..f806c7803a5e01c7962ea5e1706f85329182e37b 100644 (file)
@@ -1,10 +1,14 @@
 #include <config.h>
-#include "control-stack.h"
+
+#include "language/control/control-stack.h"
+
 #include <assert.h>
 #include <stdlib.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include "xalloc.h"
+
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index b3b6135f6ec4336e26a30e71da855d25c41d1e4f..fe9ca73008e7ba8ed64e02621adbffbf2cd9bb60 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-2011 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 <stdlib.h>
 
-#include "control-stack.h"
-#include <data/case.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/value.h>
-#include <language/command.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/transformations.h"
+#include "data/value.h"
+#include "language/command.h"
+#include "language/control/control-stack.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -121,19 +121,19 @@ cmd_else_if (struct lexer *lexer, struct dataset *ds)
 
 /* Parse ELSE. */
 int
-cmd_else (struct lexer *lexer, struct dataset *ds)
+cmd_else (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
   assert (ds == do_if->ds);
   if (do_if == NULL || !must_not_have_else (do_if))
     return CMD_CASCADING_FAILURE;
   add_else (do_if);
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Parse END IF. */
 int
-cmd_end_if (struct lexer *lexer, struct dataset *ds)
+cmd_end_if (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   struct do_if_trns *do_if = ctl_stack_top (&do_if_class);
   assert (ds == do_if->ds);
@@ -143,7 +143,7 @@ cmd_end_if (struct lexer *lexer, struct dataset *ds)
 
   ctl_stack_pop (do_if);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Closes out DO_IF, by adding a sentinel ELSE clause if
@@ -204,7 +204,7 @@ parse_clause (struct lexer *lexer, struct do_if_trns *do_if, struct dataset *ds)
 
   add_clause (do_if, condition);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Adds a clause to DO_IF that tests for the given CONDITION and,
index f5d205d4303e864bf2a6203c3f6bc5792bed1657..e91d9438f39c131836141ee2be53d47c970d2904 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-2011 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 "control-stack.h"
-
-#include <data/case.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "language/control/control-stack.h"
+
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -103,7 +103,7 @@ cmd_loop (struct lexer *lexer, struct dataset *ds)
   bool ok = true;
 
   loop = create_loop_trns (ds);
-  while (lex_token (lexer) != '.' && ok)
+  while (lex_token (lexer) != T_ENDCMD && ok)
     {
       if (lex_match_id (lexer, "IF"))
         ok = parse_if_clause (lexer, loop, &loop->loop_condition);
@@ -154,7 +154,7 @@ cmd_end_loop (struct lexer *lexer, struct dataset *ds)
 
 /* Parses BREAK. */
 int
-cmd_break (struct lexer *lexer, struct dataset *ds)
+cmd_break (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   struct ctl_stmt *loop = ctl_stack_search (&loop_class);
   if (loop == NULL)
@@ -162,7 +162,7 @@ cmd_break (struct lexer *lexer, struct dataset *ds)
 
   add_transformation (ds, break_trns_proc, NULL, loop);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Closes a LOOP construct by emitting the END LOOP
@@ -221,18 +221,18 @@ parse_index_clause (struct dataset *ds, struct lexer *lexer,
       return false;
     }
 
-  loop->index_var = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer));
+  loop->index_var = dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer));
   if (loop->index_var != NULL)
     *created_index_var = false;
   else
     {
       loop->index_var = dict_create_var_assert (dataset_dict (ds),
-                                                lex_tokid (lexer), 0);
+                                                lex_tokcstr (lexer), 0);
       *created_index_var = true;
     }
   lex_get (lexer);
 
-  if (!lex_force_match (lexer, '='))
+  if (!lex_force_match (lexer, T_EQUALS))
     return false;
 
   loop->first_expr = expr_parse_pool (lexer, loop->pool,
index 69c92ac108c439ebf141242a5565281070d60861..68e69a4f225853d68d9859a86f629723311c39db 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009-2011 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 "repeat.h"
-
-#include <ctype.h>
-#include <math.h>
 #include <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <libpspp/getl.h>
-#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>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <data/variable.h>
-
-#include "intprops.h"
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/segment.h"
+#include "language/lexer/token.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/cast.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmap.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/ftoastr.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* A line repeated by DO REPEAT. */
-struct repeat_line
-  {
-    struct ll ll;               /* In struct repeat_block line_list. */
-    const char *file_name;      /* File name. */
-    int line_number;            /* Line number. */
-    struct substring text;     /* Contents. */
-  };
-
-/* The type of substitution made for a DO REPEAT macro. */
-enum repeat_macro_type
-  {
-    VAR_NAMES,
-    OTHER
-  };
-
-/* Describes one DO REPEAT macro. */
-struct repeat_macro
+struct dummy_var
   {
-    struct ll ll;                       /* In struct repeat_block macros. */
-    enum repeat_macro_type type;        /* Types of replacements. */
-    struct substring name;              /* Macro name. */
-    struct substring *replacements;     /* Macro replacement. */
+    struct hmap_node hmap_node;
+    char *name;
+    char **values;
+    size_t n_values;
   };
 
-/* A DO REPEAT...END REPEAT block. */
-struct repeat_block
-  {
-    struct getl_interface parent;
-
-    struct pool *pool;                  /* Pool used for storage. */
-    struct dataset *ds;                 /* The dataset for this block */
-
-    struct ll_list lines;               /* Lines in buffer. */
-    struct ll *cur_line;                /* Last line output. */
-    int loop_cnt;                       /* Number of loops. */
-    int loop_idx;                       /* Number of loops so far. */
+static bool parse_specification (struct lexer *, struct dictionary *,
+                                 struct hmap *dummies);
+static bool parse_commands (struct lexer *, struct hmap *dummies);
+static void destroy_dummies (struct hmap *dummies);
 
-    struct ll_list macros;              /* Table of macros. */
+static bool parse_ids (struct lexer *, const struct dictionary *,
+                       struct dummy_var *);
+static bool parse_numbers (struct lexer *, struct dummy_var *);
+static bool parse_strings (struct lexer *, struct dummy_var *);
 
-    bool print;                         /* Print lines as executed? */
-  };
-
-static bool parse_specification (struct lexer *, struct repeat_block *);
-static bool parse_lines (struct lexer *, struct repeat_block *);
-static void create_vars (struct repeat_block *);
+int
+cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
+{
+  struct hmap dummies;
+  bool ok;
 
-static struct repeat_macro *find_macro (struct repeat_block *,
-                                        struct substring name);
+  if (!parse_specification (lexer, dataset_dict (ds), &dummies))
+    return CMD_CASCADING_FAILURE;
 
-static int parse_ids (struct lexer *, const struct dictionary *dict,
-                     struct repeat_macro *, struct pool *);
+  ok = parse_commands (lexer, &dummies);
 
-static int parse_numbers (struct lexer *, struct repeat_macro *,
-                         struct pool *);
+  destroy_dummies (&dummies);
 
-static int parse_strings (struct lexer *, struct repeat_macro *,
-                         struct pool *);
+  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
+}
 
-static void do_repeat_filter (struct getl_interface *,
-                              struct string *);
-static bool do_repeat_read (struct getl_interface *,
-                            struct string *);
-static void do_repeat_close (struct getl_interface *);
-static bool always_false (const struct getl_interface *);
-static const char *do_repeat_name (const struct getl_interface *);
-static int do_repeat_location (const struct getl_interface *);
+static unsigned int
+hash_dummy (const char *name, size_t name_len)
+{
+  return hash_case_bytes (name, name_len, 0);
+}
 
-int
-cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
+static const struct dummy_var *
+find_dummy_var (struct hmap *hmap, const char *name, size_t name_len)
 {
-  struct repeat_block *block;
-
-  block = pool_create_container (struct repeat_block, pool);
-  block->ds = ds;
-  ll_init (&block->lines);
-  block->cur_line = ll_null (&block->lines);
-  block->loop_idx = 0;
-  ll_init (&block->macros);
-
-  if (!parse_specification (lexer, block) || !parse_lines (lexer, block))
-    goto error;
-
-  create_vars (block);
-
-  block->parent.read = do_repeat_read;
-  block->parent.close = do_repeat_close;
-  block->parent.filter = do_repeat_filter;
-  block->parent.interactive = always_false;
-  block->parent.name = do_repeat_name;
-  block->parent.location = do_repeat_location;
-
-  if (!ll_is_empty (&block->lines))
-    getl_include_source (lex_get_source_stream (lexer),
-                        &block->parent,
-                        lex_current_syntax_mode (lexer),
-                        lex_current_error_mode (lexer)
-                        );
-  else
-    pool_destroy (block->pool);
+  const struct dummy_var *dv;
 
-  return CMD_SUCCESS;
+  HMAP_FOR_EACH_WITH_HASH (dv, struct dummy_var, hmap_node,
+                           hash_dummy (name, name_len), hmap)
+    if (strcasecmp (dv->name, name))
+      return dv;
 
- error:
-  pool_destroy (block->pool);
-  return CMD_CASCADING_FAILURE;
+  return NULL;
 }
 
 /* Parses the whole DO REPEAT command specification.
    Returns success. */
 static bool
-parse_specification (struct lexer *lexer, struct repeat_block *block)
+parse_specification (struct lexer *lexer, struct dictionary *dict,
+                     struct hmap *dummies)
 {
-  struct substring first_name;
+  struct dummy_var *first_dv = NULL;
 
-  block->loop_cnt = 0;
+  hmap_init (dummies);
   do
     {
-      struct repeat_macro *macro;
-      struct dictionary *dict = dataset_dict (block->ds);
-      int count;
+      struct dummy_var *dv;
+      const char *name;
+      bool ok;
 
       /* Get a stand-in variable name and make sure it's unique. */
       if (!lex_force_id (lexer))
-       return false;
-      if (dict_lookup_var (dict, lex_tokid (lexer)))
-        msg (SW, _("Dummy variable name `%s' hides dictionary "
-                   "variable `%s'."),
-             lex_tokid (lexer), lex_tokid (lexer));
-      if (find_macro (block, ss_cstr (lex_tokid (lexer))))
-         {
-           msg (SE, _("Dummy variable name `%s' is given twice."),
-                lex_tokid (lexer));
-           return false;
-         }
+       goto error;
+      name = lex_tokcstr (lexer);
+      if (dict_lookup_var (dict, name))
+        msg (SW, _("Dummy variable name `%s' hides dictionary variable `%s'."),
+             name, name);
+      if (find_dummy_var (dummies, name, strlen (name)))
+        {
+          msg (SE, _("Dummy variable name `%s' is given twice."), name);
+          goto error;
+        }
 
       /* Make a new macro. */
-      macro = pool_alloc (block->pool, sizeof *macro);
-      ss_alloc_substring_pool (&macro->name, ss_cstr (lex_tokid (lexer)),
-                               block->pool);
-      ll_push_tail (&block->macros, &macro->ll);
+      dv = xmalloc (sizeof *dv);
+      dv->name = xstrdup (name);
+      dv->values = NULL;
+      dv->n_values = 0;
+      hmap_insert (dummies, &dv->hmap_node, hash_dummy (name, strlen (name)));
 
       /* Skip equals sign. */
       lex_get (lexer);
-      if (!lex_force_match (lexer, '='))
-       return false;
+      if (!lex_force_match (lexer, T_EQUALS))
+       goto error;
 
       /* Get the details of the variable's possible values. */
-      if (lex_token (lexer) == T_ID)
-       count = parse_ids (lexer, dict, macro, block->pool);
+      if (lex_token (lexer) == T_ID || lex_token (lexer) == T_ALL)
+       ok = parse_ids (lexer, dict, dv);
       else if (lex_is_number (lexer))
-       count = parse_numbers (lexer, macro, block->pool);
+       ok = parse_numbers (lexer, dv);
       else if (lex_is_string (lexer))
-       count = parse_strings (lexer, macro, block->pool);
+       ok = parse_strings (lexer, dv);
       else
        {
          lex_error (lexer, NULL);
-         return false;
+         goto error;
        }
-      if (count == 0)
-       return false;
-      if (lex_token (lexer) != '/' && lex_token (lexer) != '.')
+      if (!ok)
+       goto error;
+      assert (dv->n_values > 0);
+      if (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
         {
           lex_error (lexer, NULL);
-          return false;
+          goto error;
         }
 
-      /* If this is the first variable then it defines how many
-        replacements there must be; otherwise enforce this number of
-        replacements. */
-      if (block->loop_cnt == 0)
+      /* If this is the first variable then it defines how many replacements
+        there must be; otherwise enforce this number of replacements. */
+      if (first_dv == NULL)
+        first_dv = dv;
+      else if (first_dv->n_values != dv->n_values)
        {
-         block->loop_cnt = count;
-         first_name = macro->name;
-       }
-      else if (block->loop_cnt != count)
-       {
-         msg (SE, _("Dummy variable `%.*s' had %d "
-                     "substitutions, so `%.*s' must also, but %d "
-                     "were specified."),
-              (int) ss_length (first_name), ss_data (first_name),
-               block->loop_cnt,
-               (int) ss_length (macro->name), ss_data (macro->name),
-               count);
-         return false;
+         msg (SE, _("Dummy variable `%s' had %zu substitutions, so `%s' must "
+                     "also, but %zu were specified."),
+               first_dv->name, first_dv->n_values,
+               dv->name, dv->n_values);
+         goto error;
        }
 
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
     }
-  while (lex_token (lexer) != '.');
+  while (!lex_match (lexer, T_ENDCMD));
 
-  return true;
-}
+  while (lex_match (lexer, T_ENDCMD))
+    continue;
 
-/* Finds and returns a DO REPEAT macro with the given NAME, or
-   NULL if there is none */
-static struct repeat_macro *
-find_macro (struct repeat_block *block, struct substring name)
-{
-  struct repeat_macro *macro;
-
-  ll_for_each (macro, struct repeat_macro, ll, &block->macros)
-    if (ss_equals (macro->name, name))
-      return macro;
+  return true;
 
-  return NULL;
+error:
+  destroy_dummies (dummies);
+  return false;
 }
 
-/* Advances LINE past white space and an identifier, if present.
-   Returns true if KEYWORD matches the identifer, false
-   otherwise. */
-static bool
-recognize_keyword (struct substring *line, const char *keyword)
+static size_t
+count_values (struct hmap *dummies)
 {
-  struct substring id;
-  ss_ltrim (line, ss_cstr (CC_SPACES));
-  ss_get_chars (line, lex_id_get_length (*line), &id);
-  return lex_id_match (ss_cstr (keyword), id);
+  const struct dummy_var *dv;
+  dv = HMAP_FIRST (struct dummy_var, hmap_node, dummies);
+  return dv->n_values;
 }
 
-/* Returns true if LINE contains a DO REPEAT command, false
-   otherwise. */
-static bool
-recognize_do_repeat (struct substring line)
+static void
+do_parse_commands (struct substring s, enum lex_syntax_mode syntax_mode,
+                   struct hmap *dummies,
+                   struct string *outputs, size_t n_outputs)
 {
-  return (recognize_keyword (&line, "do")
-          && recognize_keyword (&line, "repeat"));
-}
+  struct segmenter segmenter;
 
-/* Returns true if LINE contains an END REPEAT command, false
-   otherwise.  Sets *PRINT to true for END REPEAT PRINT, false
-   otherwise. */
-static bool
-recognize_end_repeat (struct substring line, bool *print)
-{
-  if (!recognize_keyword (&line, "end")
-      || !recognize_keyword (&line, "repeat"))
-    return false;
+  segmenter_init (&segmenter, syntax_mode);
 
-  *print = recognize_keyword (&line, "print");
-  return true;
-}
+  while (!ss_is_empty (s))
+    {
+      enum segment_type type;
+      int n;
 
-/* Read all the lines we are going to substitute, inside the DO
-   REPEAT...END REPEAT block. */
-static bool
-parse_lines (struct lexer *lexer, struct repeat_block *block)
-{
-  char *previous_file_name;
-  int nesting_level;
+      n = segmenter_push (&segmenter, s.string, s.length, &type);
+      assert (n >= 0);
 
-  previous_file_name = NULL;
-  nesting_level = 0;
+      if (type == SEG_DO_REPEAT_COMMAND)
+        {
+          for (;;)
+            {
+              int k;
 
-  for (;;)
-    {
-      const char *cur_file_name;
-      struct repeat_line *line;
-      struct string text;
-      bool command_ends_before_line, command_ends_after_line;
+              k = segmenter_push (&segmenter, s.string + n, s.length - n,
+                                  &type);
+              if (type != SEG_NEWLINE && type != SEG_DO_REPEAT_COMMAND)
+                break;
 
-      /* Retrieve an input line and make a copy of it. */
-      if (!lex_get_line_raw (lexer))
-        {
-          msg (SE, _("DO REPEAT without END REPEAT."));
-          return false;
-        }
-      ds_init_string (&text, lex_entire_line_ds (lexer));
-
-      /* Record file name. */
-      cur_file_name = getl_source_name (lex_get_source_stream (lexer));
-      if (cur_file_name != NULL &&
-         (previous_file_name == NULL
-           || !strcmp (cur_file_name, previous_file_name)))
-        previous_file_name = pool_strdup (block->pool, cur_file_name);
-
-      /* Create a line structure. */
-      line = pool_alloc (block->pool, sizeof *line);
-      line->file_name = previous_file_name;
-      line->line_number = getl_source_location (lex_get_source_stream (lexer));
-      ss_alloc_substring_pool (&line->text, ds_ss (&text), block->pool);
-
-
-      /* Check whether the line contains a DO REPEAT or END
-         REPEAT command. */
-      lex_preprocess_line (&text,
-                          lex_current_syntax_mode (lexer),
-                           &command_ends_before_line,
-                           &command_ends_after_line);
-      if (recognize_do_repeat (ds_ss (&text)))
-        {
-          if (settings_get_syntax () == COMPATIBLE)
-            msg (SE, _("DO REPEAT may not nest in compatibility mode."));
-          else
-            nesting_level++;
+              n += k;
+            }
+
+          do_parse_commands (ss_head (s, n), syntax_mode, dummies,
+                             outputs, n_outputs);
         }
-      else if (recognize_end_repeat (ds_ss (&text), &block->print)
-               && nesting_level-- == 0)
+      else if (type != SEG_END)
         {
-          lex_discard_line (lexer);
-         ds_destroy (&text);
-          return true;
+          const struct dummy_var *dv;
+          size_t i;
+
+          dv = (type == SEG_IDENTIFIER
+                ? find_dummy_var (dummies, s.string, n)
+                : NULL);
+          for (i = 0; i < n_outputs; i++)
+            if (dv != NULL)
+              ds_put_cstr (&outputs[i], dv->values[i]);
+            else
+              ds_put_substring (&outputs[i], ss_head (s, n));
         }
-      ds_destroy (&text);
 
-      /* Add the line to the list. */
-      ll_push_tail (&block->lines, &line->ll);
+      ss_advance (&s, n);
     }
 }
 
-/* Creates variables for the given DO REPEAT. */
+static bool
+parse_commands (struct lexer *lexer, struct hmap *dummies)
+{
+  struct string *outputs;
+  struct string input;
+  size_t input_len;
+  size_t n_values;
+  char *file_name;
+  int line_number;
+  bool ok;
+  size_t i;
+
+  if (lex_get_file_name (lexer) != NULL)
+    file_name = xstrdup (lex_get_file_name (lexer));
+  else
+    file_name = NULL;
+  line_number = lex_get_first_line_number (lexer, 0);
+
+  ds_init_empty (&input);
+  while (lex_is_string (lexer))
+    {
+      ds_put_substring (&input, lex_tokss (lexer));
+      ds_put_byte (&input, '\n');
+      lex_get (lexer);
+    }
+  if (ds_is_empty (&input))
+    ds_put_byte (&input, '\n');
+  ds_put_byte (&input, '\0');
+  input_len = ds_length (&input);
+
+  n_values = count_values (dummies);
+  outputs = xmalloc (n_values * sizeof *outputs);
+  for (i = 0; i < n_values; i++)
+    ds_init_empty (&outputs[i]);
+
+  do_parse_commands (ds_ss (&input), lex_get_syntax_mode (lexer),
+                     dummies, outputs, n_values);
+
+  ds_destroy (&input);
+
+  while (lex_match (lexer, T_ENDCMD))
+    continue;
+
+  ok = (lex_force_match_id (lexer, "END")
+        && lex_force_match_id (lexer, "REPEAT"));
+  if (ok)
+    lex_match_id (lexer, "PRINT"); /* XXX */
+
+  lex_discard_rest_of_command (lexer);
+
+  for (i = 0; i < n_values; i++)
+    {
+      struct string *output = &outputs[n_values - i - 1];
+      struct lex_reader *reader;
+
+      reader = lex_reader_for_substring_nocopy (ds_ss (output));
+      lex_reader_set_file_name (reader, file_name);
+      reader->line_number = line_number;
+      lex_include (lexer, reader);
+    }
+  free (file_name);
+
+  return ok;
+}
+
 static void
-create_vars (struct repeat_block *block)
+destroy_dummies (struct hmap *dummies)
 {
-  struct repeat_macro *macro;
-
-  ll_for_each (macro, struct repeat_macro, ll, &block->macros)
-    if (macro->type == VAR_NAMES)
-      {
-        int i;
-
-        for (i = 0; i < block->loop_cnt; i++)
-          {
-            /* Ignore return value: if the variable already
-               exists there is no harm done. */
-            char *var_name = ss_xstrdup (macro->replacements[i]);
-            dict_create_var (dataset_dict (block->ds), var_name, 0);
-            free (var_name);
-          }
-      }
+  struct dummy_var *dv, *next;
+
+  HMAP_FOR_EACH_SAFE (dv, next, struct dummy_var, hmap_node, dummies)
+    {
+      size_t i;
+
+      hmap_delete (dummies, &dv->hmap_node);
+
+      free (dv->name);
+      for (i = 0; i < dv->n_values; i++)
+        free (dv->values[i]);
+      free (dv->values);
+      free (dv);
+    }
+  hmap_destroy (dummies);
 }
 
 /* Parses a set of ids for DO REPEAT. */
-static int
+static bool
 parse_ids (struct lexer *lexer, const struct dictionary *dict,
-          struct repeat_macro *macro, struct pool *pool)
+          struct dummy_var *dv)
 {
-  char **replacements;
-  size_t n, i;
-
-  macro->type = VAR_NAMES;
-  if (!parse_mixed_vars_pool (lexer, dict, pool, &replacements, &n, PV_NONE))
-    return 0;
-
-  macro->replacements = pool_nalloc (pool, n, sizeof *macro->replacements);
-  for (i = 0; i < n; i++)
-    macro->replacements[i] = ss_cstr (replacements[i]);
-  return n;
+  return parse_mixed_vars (lexer, dict, &dv->values, &dv->n_values, PV_NONE);
 }
 
 /* Adds REPLACEMENT to MACRO's list of replacements, which has
    *USED elements and has room for *ALLOCATED.  Allocates memory
    from POOL. */
 static void
-add_replacement (struct substring replacement,
-                 struct repeat_macro *macro, struct pool *pool,
-                 size_t *used, size_t *allocated)
+add_replacement (struct dummy_var *dv, char *value, size_t *allocated)
 {
-  if (*used == *allocated)
-    macro->replacements = pool_2nrealloc (pool, macro->replacements, allocated,
-                                          sizeof *macro->replacements);
-  macro->replacements[(*used)++] = replacement;
+  if (dv->n_values == *allocated)
+    dv->values = x2nrealloc (dv->values, allocated, sizeof *dv->values);
+  dv->values[dv->n_values++] = value;
 }
 
 /* Parses a list or range of numbers for DO REPEAT. */
-static int
-parse_numbers (struct lexer *lexer, struct repeat_macro *macro,
-              struct pool *pool)
+static bool
+parse_numbers (struct lexer *lexer, struct dummy_var *dv)
 {
-  size_t used = 0;
   size_t allocated = 0;
 
-  macro->type = OTHER;
-  macro->replacements = NULL;
-
   do
     {
-      bool integer_value_seen;
-      double a, b, i;
-
-      /* Parse A TO B into a, b. */
       if (!lex_force_num (lexer))
-       return 0;
+       return false;
 
-      if ( (integer_value_seen = lex_is_integer (lexer) ) )
-       a = lex_integer (lexer);
-      else
-       a = lex_number (lexer);
+      if (lex_next_token (lexer, 1) == T_TO)
+        {
+          long int a, b;
+          long int i;
 
-      lex_get (lexer);
-      if (lex_token (lexer) == T_TO)
-       {
-         if ( !integer_value_seen )
+          if (!lex_is_integer (lexer))
            {
-             msg (SE, _("Ranges may only have integer bounds"));
-             return 0;
+             msg (SE, _("Ranges may only have integer bounds."));
+             return false;
            }
-         lex_get (lexer);
-         if (!lex_force_int (lexer))
-           return 0;
+
+          a = lex_integer (lexer);
+          lex_get (lexer);
+          lex_get (lexer);
+
+          if (!lex_force_int (lexer))
+            return false;
+
          b = lex_integer (lexer);
           if (b < a)
             {
-              msg (SE, _("%g TO %g is an invalid range."), a, b);
-              return 0;
+              msg (SE, _("%ld TO %ld is an invalid range."), a, b);
+              return false;
             }
          lex_get (lexer);
-       }
+
+          for (i = a; i <= b; i++)
+            add_replacement (dv, xasprintf ("%ld", i), &allocated);
+        }
       else
-        b = a;
+        {
+          char s[DBL_BUFSIZE_BOUND];
 
-      for (i = a; i <= b; i++)
-        add_replacement (ss_cstr (pool_asprintf (pool, "%g", i)),
-                         macro, pool, &used, &allocated);
+          dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
+          add_replacement (dv, xstrdup (s), &allocated);
+          lex_get (lexer);
+        }
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
 
-  return used;
+  return true;
 }
 
 /* Parses a list of strings for DO REPEAT. */
-int
-parse_strings (struct lexer *lexer, struct repeat_macro *macro, struct pool *pool)
+static bool
+parse_strings (struct lexer *lexer, struct dummy_var *dv)
 {
-  size_t used = 0;
   size_t allocated = 0;
 
-  macro->type = OTHER;
-  macro->replacements = NULL;
-
   do
     {
-      char *string;
-
       if (!lex_force_string (lexer))
        {
          msg (SE, _("String expected."));
-         return 0;
+         return false;
        }
 
-      string = lex_token_representation (lexer);
-      pool_register (pool, free, string);
-      add_replacement (ss_cstr (string), macro, pool, &used, &allocated);
+      add_replacement (dv, token_to_string (lex_next (lexer, 0)), &allocated);
 
       lex_get (lexer);
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
 
-  return used;
+  return true;
 }
 \f
 int
@@ -503,128 +431,3 @@ cmd_end_repeat (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
   msg (SE, _("No matching DO REPEAT."));
   return CMD_CASCADING_FAILURE;
 }
-\f
-/* Finds a DO REPEAT macro with the given NAME and returns the
-   appropriate substitution if found, or NAME otherwise. */
-static struct substring
-find_substitution (struct repeat_block *block, struct substring name)
-{
-  struct repeat_macro *macro = find_macro (block, name);
-  return macro ? macro->replacements[block->loop_idx] : name;
-}
-
-/* Makes appropriate DO REPEAT macro substitutions within the
-   repeated lines. */
-static void
-do_repeat_filter (struct getl_interface *interface, struct string *line)
-{
-  struct repeat_block *block
-    = UP_CAST (interface, struct repeat_block, parent);
-  bool in_apos, in_quote, dot;
-  struct substring input;
-  struct string output;
-  int c;
-
-  ds_init_empty (&output);
-
-  /* Strip trailing whitespace, check for & remove terminal dot. */
-  ds_rtrim (line, ss_cstr (CC_SPACES));
-  dot = ds_chomp (line, settings_get_endcmd ());
-  input = ds_ss (line);
-  in_apos = in_quote = false;
-  while ((c = ss_first (input)) != EOF)
-    {
-      if (c == '\'' && !in_quote)
-       in_apos = !in_apos;
-      else if (c == '"' && !in_apos)
-       in_quote = !in_quote;
-
-      if (in_quote || in_apos || !lex_is_id1 (c))
-        {
-          ds_put_char (&output, c);
-          ss_advance (&input, 1);
-        }
-      else
-        {
-          struct substring id;
-          ss_get_chars (&input, lex_id_get_length (input), &id);
-          ds_put_substring (&output, find_substitution (block, id));
-        }
-    }
-  if (dot)
-    ds_put_char (&output, settings_get_endcmd ());
-
-  ds_swap (line, &output);
-  ds_destroy (&output);
-}
-
-static struct repeat_line *
-current_line (const struct getl_interface *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);
-}
-
-/* Function called by getl to read a line.  Puts the line in
-   OUTPUT and its syntax mode in *SYNTAX.  Returns true if a line
-   was obtained, false if the source is exhausted. */
-static bool
-do_repeat_read  (struct getl_interface *interface,
-                 struct string *output)
-{
-  struct repeat_block *block
-    = UP_CAST (interface, struct repeat_block, parent);
-  struct repeat_line *line;
-
-  block->cur_line = ll_next (block->cur_line);
-  if (block->cur_line == ll_null (&block->lines))
-    {
-      block->loop_idx++;
-      if (block->loop_idx >= block->loop_cnt)
-        return false;
-
-      block->cur_line = ll_head (&block->lines);
-    }
-
-  line = current_line (interface);
-  ds_assign_substring (output, line->text);
-  return true;
-}
-
-/* Frees a DO REPEAT block.
-   Called by getl to close out the DO REPEAT block. */
-static void
-do_repeat_close (struct getl_interface *interface)
-{
-  struct repeat_block *block
-    = UP_CAST (interface, struct repeat_block, parent);
-  pool_destroy (block->pool);
-}
-
-
-static bool
-always_false (const struct getl_interface *i UNUSED)
-{
-  return false;
-}
-
-/* Returns the name of the source file from which the previous
-   line was originally obtained, or a null pointer if none. */
-static const char *
-do_repeat_name (const struct getl_interface *interface)
-{
-  struct repeat_line *line = current_line (interface);
-  return line ? line->file_name : NULL;
-}
-
-/* Returns the line number in the source file from which the
-   previous line was originally obtained, or 0 if none. */
-static int
-do_repeat_location (const struct getl_interface *interface)
-{
-  struct repeat_line *line = current_line (interface);
-  return line ? line->line_number : 0;
-}
diff --git a/src/language/control/repeat.h b/src/language/control/repeat.h
deleted file mode 100644 (file)
index 700bf64..0000000
+++ /dev/null
@@ -1,22 +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 !INCLUDED_REPEAT_H
-#define INCLUDED_REPEAT_H 1
-
-void perform_DO_REPEAT_substitutions (void);
-
-#endif /* repeat.h */
index bc3c767cdb416a587d154405f941641bfd3e6e54..7ebcc5ad9c8b92092a8850ddd05d547e58be4ffb 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, 2011 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 <stddef.h>
 #include <stdlib.h>
 
-#include "control-stack.h"
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/control/control-stack.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
 /* Parses the TEMPORARY command. */
 int
-cmd_temporary (struct lexer *lexer, struct dataset *ds)
+cmd_temporary (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   if (!proc_in_temporary_transformations (ds))
     proc_start_temporary_transformations (ds);
   else
     msg (SE, _("This command may only appear once between "
                "procedures and procedure-like commands."));
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index 63c2c96a3402b7d418a698e0e88d9fe9b3dfed84..0695bd5d901f660431084878ad06a2e911291f33 100644 (file)
@@ -13,6 +13,7 @@ language_data_io_sources = \
        src/language/data-io/data-reader.h \
        src/language/data-io/data-writer.c \
        src/language/data-io/data-writer.h \
+       src/language/data-io/dataset.c \
        src/language/data-io/file-handle.h \
        src/language/data-io/get-data.c \
        src/language/data-io/get.c \
index fd57beced05ff7f45630294b802baf7aa9daf325..e09b36ecad9dde80b16e521ef21cfe22c9bbc01a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011 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 <stdlib.h>
 
-#include <data/any-reader.h>
-#include <data/case-matcher.h>
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/subcase.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/trim.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <language/stats/sort-criteria.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/taint.h>
-#include <math/sort.h>
-
-#include "xalloc.h"
+#include "data/any-reader.h"
+#include "data/case-matcher.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/trim.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "language/stats/sort-criteria.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/string-array.h"
+#include "libpspp/taint.h"
+#include "math/sort.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -78,7 +80,7 @@ struct comb_file
     bool is_sorted;             /* Is file presorted on the BY variables? */
 
     /* IN subcommand. */
-    char in_name[VAR_NAME_LEN + 1];
+    char *in_name;
     struct variable *in_var;
   };
 
@@ -147,8 +149,8 @@ combine_files (enum comb_command_type command,
   bool saw_sort = false;
   struct casereader *active_file = NULL;
 
-  char first_name[VAR_NAME_LEN + 1] = "";
-  char last_name[VAR_NAME_LEN + 1] = "";
+  char *first_name = NULL;
+  char *last_name = NULL;
 
   struct taint *taint = NULL;
 
@@ -159,7 +161,7 @@ combine_files (enum comb_command_type command,
 
   proc.files = NULL;
   proc.n_files = 0;
-  proc.dict = dict_create ();
+  proc.dict = dict_create (get_default_encoding ());
   proc.output = NULL;
   proc.matcher = NULL;
   subcase_init_empty (&proc.by_vars);
@@ -170,7 +172,7 @@ combine_files (enum comb_command_type command,
 
   dict_set_case_limit (proc.dict, dict_get_case_limit (dataset_dict (ds)));
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   for (;;)
     {
       struct comb_file *file;
@@ -185,7 +187,7 @@ combine_files (enum comb_command_type command,
         }
       else
         break;
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
 
       if (proc.n_files >= allocated_files)
         proc.files = x2nrealloc (proc.files, &allocated_files,
@@ -200,28 +202,28 @@ combine_files (enum comb_command_type command,
       file->reader = NULL;
       file->data = NULL;
       file->is_sorted = true;
-      file->in_name[0] = '\0';
+      file->in_name = NULL;
       file->in_var = NULL;
 
-      if (lex_match (lexer, '*'))
+      if (lex_match (lexer, T_ASTERISK))
         {
-          if (!proc_has_active_file (ds))
+          if (!dataset_has_source (ds))
             {
-              msg (SE, _("Cannot specify the active file since no active "
-                         "file has been defined."));
+              msg (SE, _("Cannot specify the active dataset since none "
+                         "has been defined."));
               goto error;
             }
 
           if (proc_make_temporary_transformations_permanent (ds))
             msg (SE, _("This command may not be used after TEMPORARY when "
-                       "the active file is an input source.  "
+                       "the active dataset is an input source.  "
                        "Temporary transformations will be made permanent."));
 
           file->dict = dict_clone (dataset_dict (ds));
         }
       else
         {
-          file->handle = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
+          file->handle = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
           if (file->handle == NULL)
             goto error;
 
@@ -230,7 +232,7 @@ combine_files (enum comb_command_type command,
             goto error;
         }
 
-      while (lex_match (lexer, '/'))
+      while (lex_match (lexer, T_SLASH))
         if (lex_match_id (lexer, "RENAME"))
           {
             if (!parse_dict_rename (lexer, file->dict))
@@ -238,20 +240,20 @@ combine_files (enum comb_command_type command,
           }
         else if (lex_match_id (lexer, "IN"))
           {
-            lex_match (lexer, '=');
+            lex_match (lexer, T_EQUALS);
             if (lex_token (lexer) != T_ID)
               {
                 lex_error (lexer, NULL);
                 goto error;
               }
 
-            if (file->in_name[0])
+            if (file->in_name)
               {
                 msg (SE, _("Multiple IN subcommands for a single FILE or "
                            "TABLE."));
                 goto error;
               }
-            strcpy (file->in_name, lex_tokid (lexer));
+            file->in_name = xstrdup (lex_tokcstr (lexer));
             lex_get (lexer);
           }
         else if (lex_match_id (lexer, "SORT"))
@@ -263,7 +265,7 @@ combine_files (enum comb_command_type command,
       merge_dictionary (proc.dict, file);
     }
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       if (lex_match (lexer, T_BY))
        {
@@ -278,7 +280,7 @@ combine_files (enum comb_command_type command,
            }
           saw_by = true;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (!parse_sort_criteria (lexer, proc.dict, &proc.by_vars,
                                     &by_vars, NULL))
            goto error;
@@ -302,7 +304,8 @@ combine_files (enum comb_command_type command,
                         msg (SE, _("File %s lacks BY variable %s."),
                              fh_get_name (file->handle), name);
                       else
-                        msg (SE, _("Active file lacks BY variable %s."), name);
+                        msg (SE, _("Active dataset lacks BY variable %s."),
+                             name);
                       ok = false;
                     }
                 }
@@ -316,30 +319,30 @@ combine_files (enum comb_command_type command,
        }
       else if (command != COMB_UPDATE && lex_match_id (lexer, "FIRST"))
         {
-          if (first_name[0] != '\0')
+          if (first_name != NULL)
             {
               lex_sbc_only_once ("FIRST");
               goto error;
             }
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (!lex_force_id (lexer))
             goto error;
-          strcpy (first_name, lex_tokid (lexer));
+          first_name = xstrdup (lex_tokcstr (lexer));
           lex_get (lexer);
         }
       else if (command != COMB_UPDATE && lex_match_id (lexer, "LAST"))
         {
-          if (last_name[0] != '\0')
+          if (last_name != NULL)
             {
               lex_sbc_only_once ("LAST");
               goto error;
             }
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (!lex_force_id (lexer))
             goto error;
-          strcpy (last_name, lex_tokid (lexer));
+          last_name = xstrdup (lex_tokcstr (lexer));
           lex_get (lexer);
         }
       else if (lex_match_id (lexer, "MAP"))
@@ -362,7 +365,7 @@ combine_files (enum comb_command_type command,
          goto error;
        }
 
-      if (!lex_match (lexer, '/') && lex_token (lexer) != '.')
+      if (!lex_match (lexer, T_SLASH) && lex_token (lexer) != T_ENDCMD)
         {
           lex_end_of_command (lexer);
           goto error;
@@ -465,12 +468,16 @@ combine_files (enum comb_command_type command,
   if (active_file != NULL)
     proc_commit (ds);
 
-  proc_set_active_file (ds, casewriter_make_reader (proc.output), proc.dict);
+  dataset_set_dict (ds, proc.dict);
+  dataset_set_source (ds, casewriter_make_reader (proc.output));
   proc.dict = NULL;
   proc.output = NULL;
 
   free_comb_proc (&proc);
 
+  free (first_name);
+  free (last_name);
+
   return taint_destroy (taint) ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 
  error:
@@ -478,6 +485,8 @@ combine_files (enum comb_command_type command,
     proc_commit (ds);
   free_comb_proc (&proc);
   taint_destroy (taint);
+  free (first_name);
+  free (last_name);
   return CMD_CASCADING_FAILURE;
 }
 
@@ -486,9 +495,8 @@ static bool
 merge_dictionary (struct dictionary *const m, struct comb_file *f)
 {
   struct dictionary *d = f->dict;
-  const char *d_docs, *m_docs;
+  const struct string_array *d_docs, *m_docs;
   int i;
-  const char *file_encoding;
 
   if (dict_get_label (m) == NULL)
     dict_set_label (m, dict_get_label (d));
@@ -502,17 +510,9 @@ merge_dictionary (struct dictionary *const m, struct comb_file *f)
      The correct thing to do would be to convert to an encoding
      which can cope with all the input files (eg UTF-8).
    */
-  file_encoding = dict_get_encoding (f->dict);
-  if ( file_encoding != NULL)
-    {
-      if ( dict_get_encoding (m) == NULL)
-       dict_set_encoding (m, file_encoding);
-      else if ( 0 != strcmp (file_encoding, dict_get_encoding (m)))
-       {
-         msg (MW,
-              _("Combining files with incompatible encodings. String data may not be represented correctly."));
-       }
-    }
+  if ( 0 != strcmp (dict_get_encoding (f->dict), dict_get_encoding (m)))
+    msg (MW, _("Combining files with incompatible encodings. String data may "
+               "not be represented correctly."));
 
   if (d_docs != NULL)
     {
@@ -520,9 +520,19 @@ merge_dictionary (struct dictionary *const m, struct comb_file *f)
         dict_set_documents (m, d_docs);
       else
         {
-          char *new_docs = xasprintf ("%s%s", m_docs, d_docs);
-          dict_set_documents (m, new_docs);
-          free (new_docs);
+          struct string_array new_docs;
+          size_t i;
+
+          new_docs.n = m_docs->n + d_docs->n;
+          new_docs.strings = xmalloc (new_docs.n * sizeof *new_docs.strings);
+          for (i = 0; i < m_docs->n; i++)
+            new_docs.strings[i] = m_docs->strings[i];
+          for (i = 0; i < d_docs->n; i++)
+            new_docs.strings[m_docs->n + i] = d_docs->strings[i];
+
+          dict_set_documents (m, &new_docs);
+
+          free (new_docs.strings);
         }
     }
 
@@ -572,7 +582,7 @@ merge_dictionary (struct dictionary *const m, struct comb_file *f)
           if (var_has_missing_values (dv) && !var_has_missing_values (mv))
             var_set_missing_values (mv, var_get_missing_values (dv));
           if (var_get_label (dv) && !var_get_label (mv))
-            var_set_label (mv, var_get_label (dv));
+            var_set_label (mv, var_get_label (dv), false);
         }
       else
         mv = dict_clone_var_assert (m, dv);
@@ -581,18 +591,19 @@ merge_dictionary (struct dictionary *const m, struct comb_file *f)
   return true;
 }
 
-/* If VAR_NAME is a non-empty string, attempts to create a
+/* If VAR_NAME is non-NULL, attempts to create a
    variable named VAR_NAME, with format F1.0, in DICT, and stores
    a pointer to the variable in *VAR.  Returns true if
    successful, false if the variable name is a duplicate (in
    which case a message saying that the variable specified on the
-   given SUBCOMMAND is a duplicate is emitted).  Also returns
-   true, without doing anything, if VAR_NAME is null or empty. */
+   given SUBCOMMAND is a duplicate is emitted).
+
+   Does nothing and returns true if VAR_NAME is null. */
 static bool
 create_flag_var (const char *subcommand, const char *var_name,
                  struct dictionary *dict, struct variable **var)
 {
-  if (var_name[0] != '\0')
+  if (var_name != NULL)
     {
       struct fmt_spec format = fmt_for_output (FMT_F, 1, 0);
       *var = dict_create_var (dict, var_name, 0);
@@ -626,6 +637,7 @@ close_all_comb_files (struct comb_proc *proc)
       dict_destroy (file->dict);
       casereader_destroy (file->reader);
       case_unref (file->data);
+      free (file->in_name);
     }
   free (proc->files);
   proc->files = NULL;
index 80c9849b55b61c9812551278115756135d920813..9beaea9c4cc831571c27e2a5ddb47dd2f0cdb546 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/data-in.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/data-parser.h>
-#include <language/data-io/data-reader.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/inpt-pgm.h>
-#include <language/data-io/placement-parser.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "xsize.h"
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/data-in.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/data-parser.h"
+#include "language/data-io/data-reader.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/inpt-pgm.h"
+#include "language/data-io/placement-parser.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xsize.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -85,46 +86,48 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
   struct pool *tmp_pool;
   bool ok;
 
-  dict = in_input_program () ? dataset_dict (ds) : dict_create ();
+  dict = (in_input_program ()
+          ? dataset_dict (ds)
+          : dict_create (get_default_encoding ()));
   parser = data_parser_create (dict);
   reader = NULL;
 
   table = -1;                /* Print table if nonzero, -1=undecided. */
   has_type = false;
 
-  while (lex_token (lexer) != '/')
+  while (lex_token (lexer) != T_SLASH)
     {
       if (lex_match_id (lexer, "FILE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           fh_unref (fh);
-         fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
+         fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE, NULL);
          if (fh == NULL)
            goto error;
        }
       else if (lex_match_id (lexer, "ENCODING"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!lex_force_string (lexer))
            goto error;
 
-         ds_init_string (&encoding, lex_tokstr (lexer));
+         ds_init_substring (&encoding, lex_tokss (lexer));
 
          lex_get (lexer);
        }
       else if (lex_match_id (lexer, "RECORDS"))
        {
-         lex_match (lexer, '=');
-         lex_match (lexer, '(');
+         lex_match (lexer, T_EQUALS);
+         lex_match (lexer, T_LPAREN);
          if (!lex_force_int (lexer))
            goto error;
           data_parser_set_records (parser, lex_integer (lexer));
          lex_get (lexer);
-         lex_match (lexer, ')');
+         lex_match (lexer, T_RPAREN);
        }
       else if (lex_match_id (lexer, "SKIP"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!lex_force_int (lexer))
            goto error;
           data_parser_set_skip (parser, lex_integer (lexer));
@@ -144,12 +147,12 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
              goto error;
            }
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!lex_force_id (lexer))
            goto error;
-         end = dict_lookup_var (dict, lex_tokid (lexer));
+         end = dict_lookup_var (dict, lex_tokcstr (lexer));
          if (!end)
-            end = dict_create_var_assert (dict, lex_tokid (lexer), 0);
+            end = dict_create_var_assert (dict, lex_tokcstr (lexer), 0);
          lex_get (lexer);
        }
       else if (lex_match_id (lexer, "NOTABLE"))
@@ -186,31 +189,32 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
 
           if (data_parser_get_type (parser) == DP_DELIMITED)
             {
-              if (lex_match (lexer, '('))
+              if (lex_match (lexer, T_LPAREN))
                 {
                   struct string delims = DS_EMPTY_INITIALIZER;
 
-                  while (!lex_match (lexer, ')'))
+                  while (!lex_match (lexer, T_RPAREN))
                     {
                       int delim;
 
                       if (lex_match_id (lexer, "TAB"))
                         delim = '\t';
                       else if (lex_is_string (lexer)
-                               && ds_length (lex_tokstr (lexer)) == 1)
+                               && ss_length (lex_tokss (lexer)) == 1)
                         {
-                          delim = ds_first (lex_tokstr (lexer));
+                          delim = ss_first (lex_tokss (lexer));
                           lex_get (lexer);
                         }
                       else
                         {
+                          /* XXX should support multibyte UTF-8 characters */
                           lex_error (lexer, NULL);
                           ds_destroy (&delims);
                           goto error;
                         }
-                      ds_put_char (&delims, delim);
+                      ds_put_byte (&delims, delim);
 
-                      lex_match (lexer, ',');
+                      lex_match (lexer, T_COMMA);
                     }
 
                   data_parser_set_empty_line_has_field (parser, true);
@@ -237,13 +241,9 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
     }
   type = data_parser_get_type (parser);
 
-  if (! ds_is_empty (&encoding))
-    {
-      if ( NULL == fh)
-       msg (MW, _("Encoding should not be specified for inline data. It will be ignored."));
-      else
-       dict_set_encoding (dict, ds_cstr (&encoding));
-    }
+  if (! ds_is_empty (&encoding) && NULL == fh)
+    msg (MW, _("Encoding should not be specified for inline data. It will be "
+               "ignored."));
 
   if (fh == NULL)
     fh = fh_inline_file ();
@@ -321,7 +321,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
   int record = 0;
   int column = 1;
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       char **names;
       size_t name_cnt, name_idx;
@@ -330,7 +330,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
 
       /* Parse everything. */
       if (!parse_record_placement (lexer, &record, &column)
-          || !parse_DATA_LIST_vars_pool (lexer, tmp_pool,
+          || !parse_DATA_LIST_vars_pool (lexer, dict, tmp_pool,
                                         &names, &name_cnt, PV_NONE)
           || !parse_var_placements (lexer, tmp_pool, name_cnt, true,
                                     &formats, &format_cnt))
@@ -415,22 +415,22 @@ parse_free (struct lexer *lexer, struct dictionary *dict,
             struct pool *tmp_pool, struct data_parser *parser)
 {
   lex_get (lexer);
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       struct fmt_spec input, output;
       char **name;
       size_t name_cnt;
       size_t i;
 
-      if (!parse_DATA_LIST_vars_pool (lexer, tmp_pool,
+      if (!parse_DATA_LIST_vars_pool (lexer, dict, tmp_pool,
                                      &name, &name_cnt, PV_NONE))
        return false;
 
-      if (lex_match (lexer, '('))
+      if (lex_match (lexer, T_LPAREN))
        {
          if (!parse_format_specifier (lexer, &input)
               || !fmt_check_input (&input)
-              || !lex_force_match (lexer, ')'))
+              || !lex_force_match (lexer, T_RPAREN))
             return NULL;
 
           /* As a special case, N format is treated as F format
@@ -442,7 +442,7 @@ parse_free (struct lexer *lexer, struct dictionary *dict,
        }
       else
        {
-         lex_match (lexer, '*');
+         lex_match (lexer, T_ASTERISK);
           input = fmt_for_input (FMT_F, 8, 0);
          output = *settings_get_format ();
        }
index 714b2a952e32c8d96d29af7c958e6e2c64e40a79..aea3bbd0374693ca6bd1846aaa96ce9cfb041ca3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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 <language/data-io/data-parser.h>
+#include "language/data-io/data-parser.h"
 
 #include <stdint.h>
 #include <stdlib.h>
 
-#include <data/casereader-provider.h>
-#include <data/data-in.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/file-handle-def.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <language/data-io/data-reader.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <output/tab.h>
+#include "data/casereader-provider.h"
+#include "data/data-in.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/file-handle-def.h"
+#include "data/settings.h"
+#include "language/data-io/data-reader.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "output/tab.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -450,19 +450,19 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
     }
 
   *first_column = dfm_column_start (reader);
-  if (ss_find_char (parser->quotes, ss_first (p)) != SIZE_MAX)
+  if (ss_find_byte (parser->quotes, ss_first (p)) != SIZE_MAX)
     {
       /* Quoted field. */
-      int quote = ss_get_char (&p);
+      int quote = ss_get_byte (&p);
       if (!ss_get_until (&p, quote, field))
         msg (SW, _("Quoted string extends beyond end of line."));
       if (parser->quote_escape && ss_first (p) == quote)
         {
           ds_assign_substring (tmp, *field);
-          while (ss_match_char (&p, quote))
+          while (ss_match_byte (&p, quote))
             {
               struct substring ss;
-              ds_put_char (tmp, quote);
+              ds_put_byte (tmp, quote);
               if (!ss_get_until (&p, quote, &ss))
                 msg (SW, _("Quoted string extends beyond end of line."));
               ds_put_substring (tmp, ss);
@@ -475,17 +475,17 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
          if present. */
       ss_ltrim (&p, parser->soft_seps);
       if (!ss_is_empty (p)
-          && ss_find_char (parser->hard_seps, ss_first (p)) != SIZE_MAX)
+          && ss_find_byte (parser->hard_seps, ss_first (p)) != SIZE_MAX)
         ss_advance (&p, 1);
     }
   else
     {
       /* Regular field. */
-      ss_get_chars (&p, ss_cspan (p, ds_ss (&parser->any_sep)), field);
+      ss_get_bytes (&p, ss_cspan (p, ds_ss (&parser->any_sep)), field);
       *last_column = *first_column + ss_length (*field);
 
       if (!ss_ltrim (&p, parser->soft_seps) || ss_is_empty (p)
-          || ss_find_char (parser->hard_seps, p.string[0]) != SIZE_MAX)
+          || ss_find_byte (parser->hard_seps, p.string[0]) != SIZE_MAX)
         {
           /* Advance past a trailing hard separator,
              regardless of whether one actually existed.  If
@@ -508,10 +508,11 @@ parse_error (const struct dfm_reader *reader, const struct field *field,
 
   m.category = MSG_C_DATA;
   m.severity = MSG_S_WARNING;
-  m.where.file_name = CONST_CAST (char *, dfm_get_file_name (reader));
-  m.where.line_number = dfm_get_line_number (reader);
-  m.where.first_column = first_column;
-  m.where.last_column = last_column;
+  m.file_name = CONST_CAST (char *, dfm_get_file_name (reader));
+  m.first_line = dfm_get_line_number (reader);
+  m.last_line = m.first_line + 1;
+  m.first_column = first_column;
+  m.last_column = last_column;
   m.text = xasprintf (_("Data for variable %s is not valid as format %s: %s"),
                       field->name, fmt_name (field->format.type), error);
   msg_emit (&m);
@@ -761,7 +762,7 @@ struct data_parser_casereader
 
 static const struct casereader_class data_parser_casereader_class;
 
-/* Replaces DS's active file by an input program that reads data
+/* Replaces DS's active dataset by an input program that reads data
    from READER according to the rules in PARSER, using DICT as
    the underlying dictionary.  Ownership of PARSER and READER is
    transferred to the input program, and ownership of DICT is
@@ -781,7 +782,8 @@ data_parser_make_active_file (struct data_parser *parser, struct dataset *ds,
   casereader = casereader_create_sequential (NULL, r->proto,
                                              CASENUMBER_MAX,
                                              &data_parser_casereader_class, r);
-  proc_set_active_file (ds, casereader, dict);
+  dataset_set_dict (ds, dict);
+  dataset_set_source (ds, casereader);
 }
 
 static struct ccase *
index 5a53a2f64ddcc3ab5c30286f438df15158014e4a..013e707858e5a9ee60bf6c7692654d95270512ac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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,8 +20,8 @@
 /* Abstraction of a DATA LIST or GET DATA TYPE=TXT data parser. */
 
 #include <stdbool.h>
-#include <data/case.h>
-#include <libpspp/str.h>
+#include "data/case.h"
+#include "libpspp/str.h"
 
 struct dataset;
 struct dfm_reader;
index 061505f889075cf2ea66d5709c1bc1e5563ad344..0f96e589cc3bd7b1547110088efee015dce3d2de 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2004, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-2004, 2006, 2010, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <language/data-io/data-reader.h>
+#include "language/data-io/data-reader.h"
 
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include <data/casereader.h>
-#include <data/file-handle-def.h>
-#include <data/file-name.h>
-#include <data/procedure.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#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>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -53,6 +52,7 @@ enum dfm_reader_flags
     DFM_SAW_BEGIN_DATA = 004,   /* For inline_file only, whether we've
                                    already read a BEGIN DATA line. */
     DFM_TABS_EXPANDED = 010,    /* Tabs have been expanded. */
+    DFM_CONSUME = 020           /* read_inline_record() should get a token? */
   };
 
 /* Data file reader. */
@@ -60,7 +60,7 @@ struct dfm_reader
   {
     struct file_handle *fh;     /* File handle. */
     struct fh_lock *lock;       /* Mutual exclusion lock for file. */
-    struct msg_locator where;   /* Current location in data file. */
+    int line_number;            /* Current line or record number. */
     struct string line;         /* Current line. */
     struct string scratch;      /* Extra line buffer. */
     enum dfm_reader_flags flags; /* Zero or more of DFM_*. */
@@ -141,8 +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 = CONST_CAST (char *, fh_get_file_name (fh));
-      r->where.line_number = 0;
+      r->line_number = 0;
       r->file = fn_open (fh_get_file_name (fh), "rb");
       if (r->file == NULL)
         {
@@ -177,33 +176,37 @@ read_inline_record (struct dfm_reader *r)
   if ((r->flags & DFM_SAW_BEGIN_DATA) == 0)
     {
       r->flags |= DFM_SAW_BEGIN_DATA;
+      r->flags &= ~DFM_CONSUME;
 
-      while (lex_token (r->lexer) == '.')
+      while (lex_token (r->lexer) == T_ENDCMD)
         lex_get (r->lexer);
-      if (!lex_force_match_id (r->lexer, "BEGIN") || !lex_force_match_id (r->lexer, "DATA"))
+
+      if (!lex_force_match_id (r->lexer, "BEGIN")
+          || !lex_force_match_id (r->lexer, "DATA"))
         return false;
-      prompt_set_style (PROMPT_DATA);
-    }
 
-  if (!lex_get_line_raw (r->lexer))
-    {
-      lex_discard_line (r->lexer);
-      msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
-                 "DATA.  This probably indicates "
-                 "a missing or misformatted END DATA command.  "
-                 "END DATA must appear by itself on a single line "
-                 "with exactly one space between words."));
-      return false;
+      lex_match (r->lexer, T_ENDCMD);
     }
 
-  if (ds_length (lex_entire_line_ds (r->lexer) ) >= 8
-      && !strncasecmp (lex_entire_line (r->lexer), "end data", 8))
+  if (r->flags & DFM_CONSUME)
+    lex_get (r->lexer);
+
+  if (!lex_is_string (r->lexer))
     {
-      lex_discard_line (r->lexer);
+      if (!lex_match_id (r->lexer, "END") || !lex_match_id (r->lexer, "DATA"))
+        {
+          msg (SE, _("Missing END DATA while reading inline data.  "
+                     "This probably indicates a missing or incorrectly "
+                     "formatted END DATA command.  END DATA must appear "
+                     "by itself on a single line with exactly one space "
+                     "between words."));
+          lex_discard_rest_of_command (r->lexer);
+        }
       return false;
     }
 
-  ds_assign_string (&r->line, lex_entire_line_ds (r->lexer) );
+  ds_assign_substring (&r->line, lex_tokss (r->lexer));
+  r->flags |= DFM_CONSUME;
 
   return true;
 }
@@ -343,7 +346,7 @@ read_file_record (struct dfm_reader *r)
     case FH_MODE_TEXT:
       if (ds_read_line (&r->line, r->file, SIZE_MAX))
         {
-          ds_chomp (&r->line, '\n');
+          ds_chomp_byte (&r->line, '\n');
           return true;
         }
       else
@@ -352,7 +355,6 @@ read_file_record (struct dfm_reader *r)
             read_error (r);
           return false;
         }
-      return true;
 
     case FH_MODE_FIXED:
       if (ds_read_stream (&r->line, 1, fh_get_record_width (r->fh), r->file))
@@ -365,7 +367,6 @@ read_file_record (struct dfm_reader *r)
             partial_record (r);
           return false;
         }
-      return true;
 
     case FH_MODE_VARIABLE:
       {
@@ -482,7 +483,7 @@ read_record (struct dfm_reader *r)
     {
       bool ok = read_file_record (r);
       if (ok)
-        r->where.line_number++;
+        r->line_number++;
       return ok;
     }
   else
@@ -556,7 +557,7 @@ dfm_expand_tabs (struct dfm_reader *r)
   if (r->fh != fh_inline_file ()
       && (fh_get_mode (r->fh) != FH_MODE_TEXT
           || fh_get_tab_width (r->fh) == 0
-          || ds_find_char (&r->line, '\t') == SIZE_MAX))
+          || ds_find_byte (&r->line, '\t') == SIZE_MAX))
     return;
 
   /* Expand tabs from r->line into r->scratch, and figure out
@@ -573,11 +574,11 @@ dfm_expand_tabs (struct dfm_reader *r)
 
       c = ds_data (&r->line)[ofs];
       if (c != '\t')
-        ds_put_char (&r->scratch, c);
+        ds_put_byte (&r->scratch, c);
       else
         {
           do
-            ds_put_char (&r->scratch, ' ');
+            ds_put_byte (&r->scratch, ' ');
           while (ds_length (&r->scratch) % tab_width != 0);
         }
     }
@@ -680,13 +681,15 @@ dfm_get_column (const struct dfm_reader *r, const char *p)
 const char *
 dfm_get_file_name (const struct dfm_reader *r)
 {
-  return fh_get_referent (r->fh) == FH_REF_FILE ? r->where.file_name : NULL;
+  return (fh_get_referent (r->fh) == FH_REF_FILE
+          ? fh_get_file_name (r->fh)
+          : NULL);
 }
 
 int
 dfm_get_line_number (const struct dfm_reader *r)
 {
-  return fh_get_referent (r->fh) == FH_REF_FILE ? r->where.line_number : -1;
+  return fh_get_referent (r->fh) == FH_REF_FILE ? r->line_number : -1;
 }
 \f
 /* BEGIN DATA...END DATA procedure. */
@@ -704,13 +707,14 @@ cmd_begin_data (struct lexer *lexer, struct dataset *ds)
                  "input program does not access the inline file."));
       return CMD_CASCADING_FAILURE;
     }
+  lex_match (lexer, T_ENDCMD);
 
   /* Open inline file. */
   r = dfm_open_reader (fh_inline_file (), lexer);
   r->flags |= DFM_SAW_BEGIN_DATA;
+  r->flags &= ~DFM_CONSUME;
 
   /* Input procedure reads from inline file. */
-  prompt_set_style (PROMPT_DATA);
   casereader_destroy (proc_open (ds));
   ok = proc_commit (ds);
   dfm_close_reader (r);
index 7f7355da07fef98725608c403ccc01e1790ff288..affff788153401961dde16d0247a793f288fff8a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011 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
@@ -25,7 +25,6 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/legacy-encoding.h>
 
 struct file_handle;
 struct string;
index fd77d504f8f995c3e6cb5894358f1c90f3b44bf8..113be58805f979c63bd736a85f5c473e5595b006 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2004, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-2004, 2006, 2010, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <language/data-io/data-writer.h>
+#include "language/data-io/data-writer.h"
 
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include <data/file-name.h>
-#include <data/make-file.h>
-#include <language/data-io/file-handle.h>
-#include <libpspp/assertion.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/file-name.h"
+#include "data/make-file.h"
+#include "language/data-io/file-handle.h"
+#include "libpspp/assertion.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
diff --git a/src/language/data-io/dataset.c b/src/language/data-io/dataset.c
new file mode 100644 (file)
index 0000000..dbf0d35
--- /dev/null
@@ -0,0 +1,279 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/command.h"
+
+#include "data/dataset.h"
+#include "data/session.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "output/tab.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+\f
+static int
+parse_window (struct lexer *lexer, unsigned int allowed,
+              enum dataset_display def)
+{
+  if (!lex_match_id (lexer, "WINDOW"))
+    return def;
+  lex_match (lexer, T_EQUALS);
+
+  if (allowed & (1 << DATASET_MINIMIZED) && lex_match_id (lexer, "MINIMIZED"))
+    return DATASET_MINIMIZED;
+  else if (allowed & (1 << DATASET_ASIS) && lex_match_id (lexer, "ASIS"))
+    return DATASET_ASIS;
+  else if (allowed & (1 << DATASET_FRONT) && lex_match_id (lexer, "FRONT"))
+    return DATASET_FRONT;
+  else if (allowed & (1 << DATASET_HIDDEN) && lex_match_id (lexer, "HIDDEN"))
+    return DATASET_HIDDEN;
+
+  lex_error (lexer, NULL);
+  return -1;
+}
+
+static struct dataset *
+parse_dataset_name (struct lexer *lexer, struct session *session)
+{
+  struct dataset *ds;
+
+  if (!lex_force_id (lexer))
+    return NULL;
+
+  ds = session_lookup_dataset (session, lex_tokcstr (lexer));
+  if (ds != NULL)
+    lex_get (lexer);
+  else
+    msg (SE, _("There is no dataset named %s."), lex_tokcstr (lexer));
+  return ds;
+}
+
+int
+cmd_dataset_name (struct lexer *lexer, struct dataset *active)
+{
+  int display;
+
+  if (!lex_force_id (lexer))
+    return CMD_FAILURE;
+  dataset_set_name (active, lex_tokcstr (lexer));
+  lex_get (lexer);
+
+  display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
+                          DATASET_ASIS);
+  if (display < 0)
+    return CMD_FAILURE;
+  else if (display != DATASET_ASIS)
+    dataset_set_display (active, display);
+
+  return CMD_SUCCESS;
+}
+
+int
+cmd_dataset_activate (struct lexer *lexer, struct dataset *active)
+{
+  struct session *session = dataset_session (active);
+  struct dataset *ds;
+  int display;
+
+  ds = parse_dataset_name (lexer, session);
+  if (ds == NULL)
+    return CMD_FAILURE;
+
+  if (ds != active)
+    {
+      proc_execute (active);
+      session_set_active_dataset (session, ds);
+      if (dataset_name (active)[0] == '\0')
+        dataset_destroy (active);
+      return CMD_SUCCESS;
+    }
+
+  display = parse_window (lexer, (1 << DATASET_ASIS) | (1 << DATASET_FRONT),
+                          DATASET_ASIS);
+  if (display < 0)
+    return CMD_FAILURE;
+  else if (display != DATASET_ASIS)
+    dataset_set_display (ds, display);
+
+  return CMD_SUCCESS;
+}
+
+int
+cmd_dataset_copy (struct lexer *lexer, struct dataset *old)
+{
+  struct session *session = dataset_session (old);
+  struct dataset *new;
+  int display;
+  char *name;
+
+  /* Parse the entire command first.  proc_execute() can attempt to parse
+     BEGIN DATA...END DATA and it will fail confusingly if we are in the
+     middle of the command at the point.  */
+  if (!lex_force_id (lexer))
+    return CMD_FAILURE;
+  name = xstrdup (lex_tokcstr (lexer));
+  lex_get (lexer);
+
+  display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
+                                  | (1 << DATASET_HIDDEN)
+                                  | (1 << DATASET_FRONT)),
+                          DATASET_MINIMIZED);
+  if (display < 0)
+    {
+      free (name);
+      return CMD_FAILURE;
+    }
+
+  if (session_lookup_dataset (session, name) == old)
+    {
+      new = old;
+      dataset_set_name (old, "");
+    }
+  else
+    {
+      proc_execute (old);
+      new = dataset_clone (old, name);
+    }
+  dataset_set_display (new, display);
+
+  free (name);
+  return CMD_SUCCESS;
+}
+
+int
+cmd_dataset_declare (struct lexer *lexer, struct dataset *ds)
+{
+  struct session *session = dataset_session (ds);
+  struct dataset *new;
+  int display;
+
+  if (!lex_force_id (lexer))
+    return CMD_FAILURE;
+
+  new = session_lookup_dataset (session, lex_tokcstr (lexer));
+  if (new == NULL)
+    new = dataset_create (session, lex_tokcstr (lexer));
+  lex_get (lexer);
+
+  display = parse_window (lexer, ((1 << DATASET_MINIMIZED)
+                                  | (1 << DATASET_HIDDEN)
+                                  | (1 << DATASET_FRONT)),
+                          DATASET_MINIMIZED);
+  if (display < 0)
+    return CMD_FAILURE;
+  dataset_set_display (new, display);
+
+  return CMD_SUCCESS;
+}
+
+static void
+dataset_close_cb (struct dataset *ds, void *session_)
+{
+  struct session *session = session_;
+
+  if (ds != session_active_dataset (session))
+    dataset_destroy (ds);
+}
+
+int
+cmd_dataset_close (struct lexer *lexer, struct dataset *ds)
+{
+  struct session *session = dataset_session (ds);
+
+  if (lex_match (lexer, T_ALL))
+    {
+      session_for_each_dataset (session, dataset_close_cb, session);
+      dataset_set_name (session_active_dataset (session), "");
+    }
+  else
+    {
+      if (!lex_match (lexer, T_ASTERISK))
+        {
+          ds = parse_dataset_name (lexer, session);
+          if (ds == NULL)
+            return CMD_FAILURE;
+        }
+
+      if (ds == session_active_dataset (session))
+        dataset_set_name (ds, "");
+      else
+        dataset_destroy (ds);
+    }
+
+  return CMD_SUCCESS;
+}
+
+static void
+dataset_display_cb (struct dataset *ds, void *p_)
+{
+  struct dataset ***p = p_;
+  **p = ds;
+  (*p)++;
+}
+
+static int
+sort_datasets (const void *a_, const void *b_)
+{
+  struct dataset *const *a = a_;
+  struct dataset *const *b = b_;
+
+  return strcmp (dataset_name (*a), dataset_name (*b));
+}
+
+int
+cmd_dataset_display (struct lexer *lexer UNUSED, struct dataset *ds)
+{
+  struct session *session = dataset_session (ds);
+  struct dataset **datasets, **p;
+  struct tab_table *t;
+  size_t i, n;
+
+  n = session_n_datasets (session);
+  datasets = xmalloc (n * sizeof *datasets);
+  p = datasets;
+  session_for_each_dataset (session, dataset_display_cb, &p);
+  qsort (datasets, n, sizeof *datasets, sort_datasets);
+
+  t = tab_create (1, n + 1);
+  tab_headers (t, 0, 0, 1, 0);
+  tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
+  tab_hline (t, TAL_2, 0, 0, 1);
+  tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Dataset"));
+  for (i = 0; i < n; i++)
+    {
+      struct dataset *ds = datasets[i];
+      const char *name;
+
+      name = dataset_name (ds);
+      if (name[0] == '\0')
+        name = _("unnamed dataset");
+
+      if (ds == session_active_dataset (session))
+        tab_text_format (t, 0, i + 1, TAB_LEFT, "%s %s",
+                         name, _("(active dataset)"));
+      else
+        tab_text (t, 0, i + 1, TAB_LEFT, name);
+    }
+  tab_title (t, "Open datasets.");
+  tab_submit (t);
+
+  free (datasets);
+
+  return CMD_SUCCESS;
+}
index 86518f7327f8a025b3b4ef50b320d1dd2ce89995..e2a2b56ed3f7a22a3cf6259d76a6457ec84b1080 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, 2011 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 !file_handle_h
-#define file_handle_h 1
+#ifndef LANGUAGE_DATA_IO_FILE_HANDLE_H
+#define LANGUAGE_DATA_IO_FILE_HANDLE_H 1
 
-/* File handles. */
+/* Parsing file handles. */
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <data/file-handle-def.h>
+#include "data/file-handle-def.h"
 
-struct lexer ;
-struct file_handle *fh_parse (struct lexer *, enum fh_referent);
+struct lexer;
+struct session;
 
-#endif /* !file_handle.h */
+struct file_handle *fh_parse (struct lexer *, enum fh_referent,
+                              struct session *);
+
+#endif  /* language/data-io/file-handle.h */
index 71081b922ac0601835fec8b13a819aa4f2a17dc3..9bf6a6bf52ffaa664aaea7db9717fcefbc23aee9 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, 2011 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 <limits.h>
-#include <language/data-io/file-handle.h>
-#include <libpspp/message.h>
 #include <errno.h>
 #include <stdlib.h>
-#include <data/file-name.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <data/variable.h>
-#include <data/file-handle-def.h>
 
-#include "xalloc.h"
+#include "data/file-name.h"
+#include "data/session.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "data/variable.h"
+#include "data/file-handle-def.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -42,7 +44,7 @@
      name=string;
      lrecl=integer;
      tabwidth=integer "x>=0" "%s must be nonnegative";
-     mode=mode:!character/binary/image/360/scratch;
+     mode=mode:!character/binary/image/360;
      recform=recform:fixed/f/variable/v/spanned/vs.
 */
 /* (declarations) */
 int
 cmd_file_handle (struct lexer *lexer, struct dataset *ds)
 {
-  char handle_name[VAR_NAME_LEN + 1];
+  struct fh_properties properties;
   struct cmd_file_handle cmd;
   struct file_handle *handle;
+  enum cmd_result result;
+  char *handle_name;
 
+  result = CMD_CASCADING_FAILURE;
   if (!lex_force_id (lexer))
-    return CMD_CASCADING_FAILURE;
-  str_copy_trunc (handle_name, sizeof handle_name, lex_tokid (lexer));
+    goto exit;
 
+  handle_name = xstrdup (lex_tokcstr (lexer));
   handle = fh_from_id (handle_name);
   if (handle != NULL)
     {
       msg (SE, _("File handle %s is already defined.  "
                  "Use CLOSE FILE HANDLE before redefining a file handle."),
           handle_name);
-      return CMD_CASCADING_FAILURE;
+      goto exit_free_handle_name;
     }
 
   lex_get (lexer);
-  if (!lex_force_match (lexer, '/'))
-    return CMD_CASCADING_FAILURE;
+  if (!lex_force_match (lexer, T_SLASH))
+    goto exit_free_handle_name;
 
   if (!parse_file_handle (lexer, ds, &cmd, NULL))
-    return CMD_CASCADING_FAILURE;
+    goto exit_free_handle_name;
 
   if (lex_end_of_command (lexer) != CMD_SUCCESS)
-    goto lossage;
+    goto exit_free_cmd;
 
-  if (cmd.mode != FH_SCRATCH)
+  properties = *fh_default_properties ();
+  if (cmd.s_name == NULL)
     {
-      struct fh_properties properties = *fh_default_properties ();
+      lex_sbc_missing (lexer, "NAME");
+      goto exit_free_cmd;
+    }
 
-      if (cmd.s_name == NULL)
+  switch (cmd.mode)
+    {
+    case FH_CHARACTER:
+      properties.mode = FH_MODE_TEXT;
+      if (cmd.sbc_tabwidth)
+        properties.tab_width = cmd.n_tabwidth[0];
+      break;
+    case FH_IMAGE:
+      properties.mode = FH_MODE_FIXED;
+      break;
+    case FH_BINARY:
+      properties.mode = FH_MODE_VARIABLE;
+      break;
+    case FH_360:
+      properties.encoding = "EBCDIC-US";
+      if (cmd.recform == FH_FIXED || cmd.recform == FH_F)
+        properties.mode = FH_MODE_FIXED;
+      else if (cmd.recform == FH_VARIABLE || cmd.recform == FH_V)
         {
-          lex_sbc_missing (lexer, "NAME");
-          goto lossage;
+          properties.mode = FH_MODE_360_VARIABLE;
+          properties.record_width = 8192;
         }
-
-      switch (cmd.mode)
+      else if (cmd.recform == FH_SPANNED || cmd.recform == FH_VS)
         {
-        case FH_CHARACTER:
-          properties.mode = FH_MODE_TEXT;
-          if (cmd.sbc_tabwidth)
-            properties.tab_width = cmd.n_tabwidth[0];
-          break;
-        case FH_IMAGE:
-          properties.mode = FH_MODE_FIXED;
-          break;
-        case FH_BINARY:
-          properties.mode = FH_MODE_VARIABLE;
-          break;
-        case FH_360:
-          properties.encoding = "EBCDIC-US";
-          if (cmd.recform == FH_FIXED || cmd.recform == FH_F)
-            properties.mode = FH_MODE_FIXED;
-          else if (cmd.recform == FH_VARIABLE || cmd.recform == FH_V)
-            {
-              properties.mode = FH_MODE_360_VARIABLE;
-              properties.record_width = 8192;
-            }
-          else if (cmd.recform == FH_SPANNED || cmd.recform == FH_VS)
-            {
-              properties.mode = FH_MODE_360_SPANNED;
-              properties.record_width = 8192;
-            }
-          else
-            {
-              msg (SE, _("RECFORM must be specified with MODE=360."));
-              goto lossage;
-            }
-          break;
-        default:
-          NOT_REACHED ();
+          properties.mode = FH_MODE_360_SPANNED;
+          properties.record_width = 8192;
         }
-
-      if (properties.mode == FH_MODE_FIXED || cmd.n_lrecl[0] != LONG_MIN)
+      else
         {
-          if (cmd.n_lrecl[0] == LONG_MIN)
-            msg (SE, _("The specified file mode requires LRECL.  "
-                       "Assuming %zu-character records."),
-                 properties.record_width);
-          else if (cmd.n_lrecl[0] < 1 || cmd.n_lrecl[0] >= (1UL << 31))
-            msg (SE, _("Record length (%ld) must be between 1 and %lu bytes.  "
-                       "Assuming %d-character records."),
-                 cmd.n_lrecl[0], (1UL << 31) - 1, properties.record_width);
-          else
-            properties.record_width = cmd.n_lrecl[0];
+          msg (SE, _("RECFORM must be specified with MODE=360."));
+          goto exit_free_cmd;
         }
+      break;
+    default:
+      NOT_REACHED ();
+    }
 
-      fh_create_file (handle_name, cmd.s_name, &properties);
+  if (properties.mode == FH_MODE_FIXED || cmd.n_lrecl[0] != LONG_MIN)
+    {
+      if (cmd.n_lrecl[0] == LONG_MIN)
+        msg (SE, _("The specified file mode requires LRECL.  "
+                   "Assuming %zu-character records."),
+             properties.record_width);
+      else if (cmd.n_lrecl[0] < 1 || cmd.n_lrecl[0] >= (1UL << 31))
+        msg (SE, _("Record length (%ld) must be between 1 and %lu bytes.  "
+                   "Assuming %zu-character records."),
+             cmd.n_lrecl[0], (1UL << 31) - 1, properties.record_width);
+      else
+        properties.record_width = cmd.n_lrecl[0];
     }
-  else
-    fh_create_scratch (handle_name);
 
-  free_file_handle (&cmd);
-  return CMD_SUCCESS;
+  fh_create_file (handle_name, cmd.s_name, &properties);
+
+  result = CMD_SUCCESS;
 
- lossage:
+exit_free_cmd:
   free_file_handle (&cmd);
-  return CMD_CASCADING_FAILURE;
+exit_free_handle_name:
+  free (handle_name);
+exit:
+  return result;
 }
 
 int
@@ -159,7 +160,7 @@ cmd_close_file_handle (struct lexer *lexer, struct dataset *ds UNUSED)
 
   if (!lex_force_id (lexer))
     return CMD_CASCADING_FAILURE;
-  handle = fh_from_id (lex_tokid (lexer));
+  handle = fh_from_id (lex_tokcstr (lexer));
   if (handle == NULL)
     return CMD_CASCADING_FAILURE;
 
@@ -177,25 +178,47 @@ referent_name (enum fh_referent referent)
       return _("file");
     case FH_REF_INLINE:
       return _("inline file");
-    case FH_REF_SCRATCH:
-      return _("scratch file");
+    case FH_REF_DATASET:
+      return _("dataset");
     default:
       NOT_REACHED ();
     }
 }
 
-/* Parses a file handle name, which may be a file name as a string
-   or a file handle name as an identifier.  The allowed types of
-   file handle are restricted to those in REFERENT_MASK.  Returns
-   the file handle when successful, a null pointer on failure.
+/* Parses a file handle name:
+
+      - If SESSION is nonnull, then the parsed syntax may be the name of a
+        dataset within SESSION.  Dataset names take precedence over file handle
+        names.
+
+      - If REFERENT_MASK includes FH_REF_FILE, the parsed syntax may be a file
+        name as a string or a file handle name as an identifier.
 
-   The caller is responsible for fh_unref()'ing the returned
-   file handle when it is no longer needed. */
+      - If REFERENT_MASK includes FH_REF_INLINE, the parsed syntax may be the
+        identifier INLINE to represent inline data.
+
+   Returns the file handle when successful, a null pointer on failure.
+
+   The caller is responsible for fh_unref()'ing the returned file handle when
+   it is no longer needed. */
 struct file_handle *
-fh_parse (struct lexer *lexer, enum fh_referent referent_mask)
+fh_parse (struct lexer *lexer, enum fh_referent referent_mask,
+          struct session *session)
 {
   struct file_handle *handle;
 
+  if (session != NULL && lex_token (lexer) == T_ID)
+    {
+      struct dataset *ds;
+
+      ds = session_lookup_dataset (session, lex_tokcstr (lexer));
+      if (ds != NULL)
+        {
+          lex_get (lexer);
+          return fh_create_dataset (ds);
+        }
+    }
+
   if (lex_match_id (lexer, "INLINE"))
     handle = fh_inline_file ();
   else
@@ -208,15 +231,10 @@ fh_parse (struct lexer *lexer, enum fh_referent referent_mask)
 
       handle = NULL;
       if (lex_token (lexer) == T_ID)
-        handle = fh_from_id (lex_tokid (lexer));
+        handle = fh_from_id (lex_tokcstr (lexer));
       if (handle == NULL)
-        {
-          if (lex_token (lexer) != T_ID || lex_tokid (lexer)[0] != '#' || settings_get_syntax () != ENHANCED)
-            handle = fh_create_file (NULL, ds_cstr (lex_tokstr (lexer)),
+            handle = fh_create_file (NULL, lex_tokcstr (lexer),
                                      fh_default_properties ());
-          else
-            handle = fh_create_scratch (lex_tokid (lexer));
-        }
       lex_get (lexer);
     }
 
index 94fadd604a205663b31261177a7a1789b27fcdaf..47b65b445adfc44ffa15e9b72c9738703fc687a0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010, 2011 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 <stdlib.h>
 
-#include <data/gnumeric-reader.h>
-#include <data/psql-reader.h>
-
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <language/command.h>
-#include <language/data-io/data-parser.h>
-#include <language/data-io/data-reader.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/placement-parser.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/gnumeric-reader.h"
+#include "data/psql-reader.h"
+#include "data/settings.h"
+#include "language/command.h"
+#include "language/data-io/data-parser.h"
+#include "language/data-io/data-reader.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/placement-parser.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -47,12 +47,12 @@ static int parse_get_psql (struct lexer *lexer, struct dataset *);
 int
 cmd_get_data (struct lexer *lexer, struct dataset *ds)
 {
-  lex_force_match (lexer, '/');
+  lex_force_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "TYPE"))
     return CMD_FAILURE;
 
-  lex_force_match (lexer, '=');
+  lex_force_match (lexer, T_EQUALS);
 
   if (lex_match_id (lexer, "GNM"))
     return parse_get_gnm (lexer, ds);
@@ -61,7 +61,7 @@ cmd_get_data (struct lexer *lexer, struct dataset *ds)
   else if (lex_match_id (lexer, "PSQL"))
     return parse_get_psql (lexer, ds);
 
-  msg (SE, _("Unsupported TYPE %s"), lex_tokid (lexer));
+  msg (SE, _("Unsupported TYPE %s."), lex_tokcstr (lexer));
   return CMD_FAILURE;
 }
 
@@ -75,31 +75,31 @@ parse_get_psql (struct lexer *lexer, struct dataset *ds)
   psql.bsize = -1;
   ds_init_empty (&psql.sql);
 
-  lex_force_match (lexer, '/');
+  lex_force_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "CONNECT"))
     goto error;
 
-  lex_force_match (lexer, '=');
+  lex_force_match (lexer, T_EQUALS);
 
   if (!lex_force_string (lexer))
     goto error;
 
-  psql.conninfo = xstrdup (ds_cstr (lex_tokstr (lexer)));
+  psql.conninfo = ss_xstrdup (lex_tokss (lexer));
 
   lex_get (lexer);
 
-  while (lex_match (lexer, '/') )
+  while (lex_match (lexer, T_SLASH) )
     {
       if ( lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          psql.str_width = lex_integer (lexer);
          lex_get (lexer);
        }
       else if ( lex_match_id (lexer, "BSIZE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          psql.bsize = lex_integer (lexer);
          lex_get (lexer);
        }
@@ -109,11 +109,11 @@ parse_get_psql (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "SQL"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if ( ! lex_force_string (lexer) )
            goto error;
 
-         ds_put_substring (&psql.sql,  lex_tokstr (lexer)->ss);
+         ds_put_substring (&psql.sql, lex_tokss (lexer));
          lex_get (lexer);
        }
      }
@@ -122,7 +122,10 @@ parse_get_psql (struct lexer *lexer, struct dataset *ds)
     struct casereader *reader = psql_open_reader (&psql, &dict);
 
     if ( reader )
-      proc_set_active_file (ds, reader, dict);
+      {
+        dataset_set_dict (ds, dict);
+        dataset_set_source (ds, reader);
+      }
   }
 
   ds_destroy (&psql.sql);
@@ -143,67 +146,71 @@ parse_get_gnm (struct lexer *lexer, struct dataset *ds)
 {
   struct gnumeric_read_info gri  = {NULL, NULL, NULL, 1, true, -1};
 
-  lex_force_match (lexer, '/');
+  lex_force_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "FILE"))
     goto error;
 
-  lex_force_match (lexer, '=');
+  lex_force_match (lexer, T_EQUALS);
 
   if (!lex_force_string (lexer))
     goto error;
 
-  gri.file_name = xstrdup (ds_cstr (lex_tokstr (lexer)));
+  gri.file_name = utf8_to_filename (lex_tokcstr (lexer));
 
   lex_get (lexer);
 
-  while (lex_match (lexer, '/') )
+  while (lex_match (lexer, T_SLASH) )
     {
       if ( lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          gri.asw = lex_integer (lexer);
+         lex_get (lexer);
        }
       else if (lex_match_id (lexer, "SHEET"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "NAME"))
            {
              if ( ! lex_force_string (lexer) )
                goto error;
 
-             gri.sheet_name = xstrdup (ds_cstr (lex_tokstr (lexer)));
+             gri.sheet_name = ss_xstrdup (lex_tokss (lexer));
              gri.sheet_index = -1;
+
+             lex_get (lexer);
            }
          else if (lex_match_id (lexer, "INDEX"))
            {
              gri.sheet_index = lex_integer (lexer);
+             lex_get (lexer);
            }
          else
            goto error;
        }
       else if (lex_match_id (lexer, "CELLRANGE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
          if (lex_match_id (lexer, "FULL"))
            {
              gri.cell_range = NULL;
-             lex_put_back (lexer, T_ID);
            }
          else if (lex_match_id (lexer, "RANGE"))
            {
              if ( ! lex_force_string (lexer) )
                goto error;
 
-             gri.cell_range = xstrdup (ds_cstr (lex_tokstr (lexer)));
+             gri.cell_range = ss_xstrdup (lex_tokss (lexer));
+             lex_get (lexer);
            }
          else
            goto error;
        }
       else if (lex_match_id (lexer, "READNAMES"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
          if ( lex_match_id (lexer, "ON"))
            {
@@ -215,13 +222,12 @@ parse_get_gnm (struct lexer *lexer, struct dataset *ds)
            }
          else
            goto error;
-         lex_put_back (lexer, T_ID);
        }
       else
        {
+         lex_error (lexer, NULL);
          goto error;
        }
-      lex_get (lexer);
     }
 
   {
@@ -229,7 +235,10 @@ parse_get_gnm (struct lexer *lexer, struct dataset *ds)
     struct casereader *reader = gnumeric_open_reader (&gri, &dict);
 
     if ( reader )
-      proc_set_active_file (ds, reader, dict);
+      {
+        dataset_set_dict (ds, dict);
+        dataset_set_source (ds, reader);
+      }
   }
 
   free (gri.file_name);
@@ -270,20 +279,21 @@ static int
 parse_get_txt (struct lexer *lexer, struct dataset *ds)
 {
   struct data_parser *parser = NULL;
-  struct dictionary *dict = dict_create ();
+  struct dictionary *dict = dict_create (get_default_encoding ());
   struct file_handle *fh = NULL;
   struct dfm_reader *reader = NULL;
+  char *name = NULL;
 
   int record;
   enum data_parser_type type;
   bool has_type;
 
-  lex_force_match (lexer, '/');
+  lex_force_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "FILE"))
     goto error;
-  lex_force_match (lexer, '=');
-  fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
+  lex_force_match (lexer, T_EQUALS);
+  fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE, NULL);
   if (fh == NULL)
     goto error;
 
@@ -296,14 +306,14 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
 
   for (;;)
     {
-      if (!lex_force_match (lexer, '/'))
+      if (!lex_force_match (lexer, T_SLASH))
         goto error;
 
       if (lex_match_id (lexer, "ARRANGEMENT"))
         {
           bool ok;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "FIXED"))
             ok = set_type (parser, "ARRANGEMENT=FIXED", DP_FIXED, &has_type);
           else if (lex_match_id (lexer, "DELIMITED"))
@@ -319,7 +329,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         }
       else if (lex_match_id (lexer, "FIRSTCASE"))
         {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (!lex_force_int (lexer))
             goto error;
           if (lex_integer (lexer) < 1)
@@ -334,7 +344,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         {
           if (!set_type (parser, "DELCASE", DP_DELIMITED, &has_type))
             goto error;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "LINE"))
             data_parser_set_span (parser, false);
           else if (lex_match_id (lexer, "VARIABLES"))
@@ -357,7 +367,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         {
           if (!set_type (parser, "FIXCASE", DP_FIXED, &has_type))
             goto error;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (!lex_force_int (lexer))
             goto error;
           if (lex_integer (lexer) < 1)
@@ -370,7 +380,7 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         }
       else if (lex_match_id (lexer, "IMPORTCASES"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match (lexer, T_ALL))
             {
               data_parser_set_case_limit (parser, -1);
@@ -410,21 +420,22 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
 
           if (!set_type (parser, "DELIMITERS", DP_DELIMITED, &has_type))
             goto error;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
           if (!lex_force_string (lexer))
             goto error;
 
-          s = ds_ss (lex_tokstr (lexer));
+          /* XXX should support multibyte UTF-8 characters */
+          s = lex_tokss (lexer);
           if (ss_match_string (&s, ss_cstr ("\\t")))
             ds_put_cstr (&hard_seps, "\t");
           if (ss_match_string (&s, ss_cstr ("\\\\")))
             ds_put_cstr (&hard_seps, "\\");
-          while ((c = ss_get_char (&s)) != EOF)
+          while ((c = ss_get_byte (&s)) != EOF)
             if (c == ' ')
               soft_seps = " ";
             else
-              ds_put_char (&hard_seps, c);
+              ds_put_byte (&hard_seps, c);
           data_parser_set_soft_delimiters (parser, ss_cstr (soft_seps));
           data_parser_set_hard_delimiters (parser, ds_ss (&hard_seps));
           ds_destroy (&hard_seps);
@@ -435,20 +446,21 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         {
           if (!set_type (parser, "QUALIFIERS", DP_DELIMITED, &has_type))
             goto error;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
           if (!lex_force_string (lexer))
             goto error;
 
+          /* XXX should support multibyte UTF-8 characters */
           if (settings_get_syntax () == COMPATIBLE
-              && ds_length (lex_tokstr (lexer)) != 1)
+              && ss_length (lex_tokss (lexer)) != 1)
             {
               msg (SE, _("In compatible syntax mode, the QUALIFIER string "
                          "must contain exactly one character."));
               goto error;
             }
 
-          data_parser_set_quotes (parser, ds_ss (lex_tokstr (lexer)));
+          data_parser_set_quotes (parser, lex_tokss (lexer));
           lex_get (lexer);
         }
       else if (settings_get_syntax () == ENHANCED
@@ -462,19 +474,17 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           goto error;
         }
     }
-  lex_match (lexer, '=');
-
+  lex_match (lexer, T_EQUALS);
 
   record = 1;
   type = data_parser_get_type (parser);
   do
     {
-      char name[VAR_NAME_LEN + 1];
       struct fmt_spec input, output;
-      int fc, lc;
       struct variable *v;
+      int fc, lc;
 
-      while (type == DP_FIXED && lex_match (lexer, '/'))
+      while (type == DP_FIXED && lex_match (lexer, T_SLASH))
         {
           if (!lex_force_int (lexer))
             goto error;
@@ -499,9 +509,10 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           lex_get (lexer);
         }
 
-      if (!lex_force_id (lexer))
+      if (!lex_force_id (lexer)
+          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
         goto error;
-      strcpy (name, lex_tokid (lexer));
+      name = xstrdup (lex_tokcstr (lexer));
       lex_get (lexer);
 
       if (type == DP_DELIMITED)
@@ -509,19 +520,46 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           if (!parse_format_specifier (lexer, &input)
               || !fmt_check_input (&input))
             goto error;
+
+          output = fmt_for_output_from_input (&input);
         }
       else
         {
+          char fmt_type_name[FMT_TYPE_LEN_MAX + 1];
+          enum fmt_type fmt_type;
+          int w, d;
+
           if (!parse_column_range (lexer, 0, &fc, &lc, NULL))
             goto error;
-          if (!parse_format_specifier_name (lexer, &input.type))
+
+          /* Accept a format (e.g. F8.2) or just a type name (e.g. DOLLAR).  */
+          if (!parse_abstract_format_specifier (lexer, fmt_type_name, &w, &d))
             goto error;
+          if (!fmt_from_name (fmt_type_name, &fmt_type))
+            {
+              msg (SE, _("Unknown format type `%s'."), fmt_type_name);
+              goto error;
+            }
+
+          /* Compose input format. */
+          input.type = fmt_type;
           input.w = lc - fc + 1;
           input.d = 0;
           if (!fmt_check_input (&input))
             goto error;
+
+          /* Compose output format. */
+          if (w != 0)
+            {
+              output.type = fmt_type;
+              output.w = w;
+              output.d = d;
+              if (!fmt_check_output (&output))
+                goto error;
+            }
+          else
+            output = fmt_for_output_from_input (&input);
         }
-      output = fmt_for_output_from_input (&input);
 
       v = dict_create_var (dict, name, fmt_var_width (&input));
       if (v == NULL)
@@ -538,8 +576,10 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
       else
         data_parser_add_fixed_field (parser, &input, var_get_case_index (v),
                                      name, record, fc);
+      free (name);
+      name = NULL;
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
 
   reader = dfm_open_reader (fh, lexer);
   if (reader == NULL)
@@ -553,5 +593,6 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
   data_parser_destroy (parser);
   dict_destroy (dict);
   fh_unref (fh);
+  free (name);
   return CMD_CASCADING_FAILURE;
 }
index cf59c8e0fbadc78f904fe9049d84341c5bf04e60..0e542ef0d28dc50b08ea97bd780424da5aede1d1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2010, 2011 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 <stdlib.h>
 
-#include <data/any-reader.h>
-#include <data/case.h>
-#include <data/case-map.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/por-file-writer.h>
-#include <data/procedure.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/trim.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/compiler.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/any-reader.h"
+#include "data/case-map.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/por-file-writer.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/trim.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -75,20 +75,20 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, enum reader_command
 
   for (;;)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "FILE") || lex_is_string (lexer))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
           fh_unref (fh);
-         fh = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
+         fh = fh_parse (lexer, FH_REF_FILE, NULL);
          if (fh == NULL)
             goto error;
        }
       else if (type == IMPORT_CMD && lex_match_id (lexer, "TYPE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
          if (lex_match_id (lexer, "COMM"))
            type = PFM_COMM;
@@ -116,9 +116,9 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, enum reader_command
 
   case_map_prepare_dict (dict);
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
       if (!parse_dict_trim (lexer, dict))
         goto error;
     }
@@ -128,7 +128,8 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, enum reader_command
   if (map != NULL)
     reader = case_map_create_input_translator (map, reader);
 
-  proc_set_active_file (ds, reader, dict);
+  dataset_set_dict (ds, dict);
+  dataset_set_source (ds, reader);
 
   fh_unref (fh);
   return CMD_SUCCESS;
index 8cadb94b1e31d9ba5bdbdbef5810e1a0423166d6..eac1f06fca4789c751e6b229ef4aea116692d106 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, 2011 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 <language/data-io/inpt-pgm.h>
-
 #include <float.h>
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/caseinit.h>
-#include <data/casereader-provider.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/data-reader.h>
-#include <language/data-io/file-handle.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/caseinit.h"
+#include "data/casereader-provider.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/data-reader.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/inpt-pgm.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 /* Private result codes for use within INPUT PROGRAM. */
 enum cmd_result_extensions
   {
-    CMD_END_INPUT_PROGRAM = CMD_PRIVATE_FIRST,
-    CMD_END_CASE
+    CMD_END_CASE = CMD_PRIVATE_FIRST
   };
 
 /* Indicates how a `union value' should be initialized. */
-enum value_init_type
-  {
-    INP_NUMERIC = 01,          /* Numeric. */
-    INP_STRING = 0,            /* String. */
-
-    INP_INIT_ONCE = 02,                /* Initialize only once. */
-    INP_REINIT = 0,            /* Reinitialize for each iteration. */
-  };
-
 struct input_program_pgm
   {
     struct trns_chain *trns_chain;
@@ -104,8 +92,8 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
   struct input_program_pgm *inp;
   bool saw_END_CASE = false;
 
-  proc_discard_active_file (ds);
-  if (lex_token (lexer) != '.')
+  dataset_clear (ds);
+  if (!lex_match (lexer, T_ENDCMD))
     return lex_end_of_command (lexer);
 
   inp = xmalloc (sizeof *inp);
@@ -114,12 +102,12 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
   inp->proto = NULL;
 
   inside_input_program = true;
-  for (;;)
+  while (!lex_match_phrase (lexer, "END INPUT PROGRAM"))
     {
-      enum cmd_result result = cmd_parse_in_state (lexer, ds, CMD_STATE_INPUT_PROGRAM);
-      if (result == CMD_END_INPUT_PROGRAM)
-        break;
-      else if (result == CMD_END_CASE)
+      enum cmd_result result;
+
+      result = cmd_parse_in_state (lexer, ds, CMD_STATE_INPUT_PROGRAM);
+      if (result == CMD_END_CASE)
         {
           emit_END_CASE (ds, inp);
           saw_END_CASE = true;
@@ -129,7 +117,7 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
           if (result == CMD_EOF)
             msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
           inside_input_program = false;
-          proc_discard_active_file (ds);
+          dataset_clear (ds);
           destroy_input_program (inp);
           return result;
         }
@@ -141,7 +129,7 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
   if (dict_get_next_value_idx (dataset_dict (ds)) == 0)
     {
       msg (SE, _("Input program did not create any variables."));
-      proc_discard_active_file (ds);
+      dataset_clear (ds);
       destroy_input_program (inp);
       return CMD_FAILURE;
     }
@@ -156,7 +144,7 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
   caseinit_mark_for_init (inp->init, dataset_dict (ds));
   inp->proto = caseproto_ref (dict_get_proto (dataset_dict (ds)));
 
-  proc_set_active_file_data (
+  dataset_set_source (
     ds, casereader_create_sequential (NULL, inp->proto, CASENUMBER_MAX,
                                       &input_program_casereader_class, inp));
 
@@ -166,8 +154,12 @@ cmd_input_program (struct lexer *lexer, struct dataset *ds)
 int
 cmd_end_input_program (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
-  assert (in_input_program ());
-  return CMD_END_INPUT_PROGRAM;
+  /* Inside INPUT PROGRAM, this should get caught at the top of the loop in
+     cmd_input_program().
+
+     Outside of INPUT PROGRAM, the command parser should reject this
+     command. */
+  NOT_REACHED ();
 }
 
 /* Returns true if STATE is valid given the transformations that
@@ -245,9 +237,9 @@ int
 cmd_end_case (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   assert (in_input_program ());
-  if (lex_token (lexer) == '.')
+  if (lex_token (lexer) == T_ENDCMD)
     return CMD_END_CASE;
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Outputs the current case */
@@ -277,11 +269,11 @@ cmd_reread (struct lexer *lexer, struct dataset *ds)
 
   fh = fh_get_default_handle ();
   e = NULL;
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       if (lex_match_id (lexer, "COLUMN"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
          if (e)
            {
@@ -296,9 +288,9 @@ cmd_reread (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "FILE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           fh_unref (fh);
-          fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
+          fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE, NULL);
          if (fh == NULL)
            {
              expr_free (e);
@@ -358,13 +350,13 @@ reread_trns_free (void *t_)
 
 /* Parses END FILE command. */
 int
-cmd_end_file (struct lexer *lexer, struct dataset *ds)
+cmd_end_file (struct lexer *lexer UNUSED, struct dataset *ds)
 {
   assert (in_input_program ());
 
   add_transformation (ds, end_file_trns_proc, NULL, NULL);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Executes an END FILE transformation. */
index 738b667183523a210d6530b74ef4f15ea2b598e8..ddc072a46b5ebaad10b5ed03dc6d0136d5c824f3 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-2011 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 <stdlib.h>
 
-#include "intprops.h"
-#include "xmalloca.h"
-
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/data-out.h>
-#include <data/format.h>
-#include <data/procedure.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/ll.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <output/tab.h>
-#include <output/table-item.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/data-out.h"
+#include "data/format.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/ll.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "output/tab.h"
+#include "output/table-item.h"
+
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xmalloca.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -131,13 +130,6 @@ cmd_list (struct lexer *lexer, struct dataset *ds)
       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)
         {
@@ -145,6 +137,13 @@ cmd_list (struct lexer *lexer, struct dataset *ds)
           case_unref (ccase);
         }
 
+      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);
+
       if (cmd.numbering == LST_NUMBERED)
         {
           struct fmt_spec fmt;
index 4f1d062cb8d3b18734afacfc427f1bfd5b1b5408..4d0a0b4c3b17d180e4465a00bda54bc4aed8e359 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011 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 <language/data-io/placement-parser.h>
+#include "language/data-io/placement-parser.h"
 
 #include <assert.h>
 
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
+#include "data/format.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
 
-#include <data/format.h>
-
-#include "xalloc.h"
-#include "xsize.h"
+#include "gl/xalloc.h"
+#include "gl/xsize.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -70,7 +69,7 @@ parse_var_placements (struct lexer *lexer, struct pool *pool, size_t var_cnt, bo
   assert (var_cnt > 0);
   if (lex_is_number (lexer))
     return fixed_parse_columns (lexer, pool, var_cnt, for_input, formats, format_cnt);
-  else if (lex_match (lexer, '('))
+  else if (lex_match (lexer, T_LPAREN))
     {
       size_t assignment_cnt;
       size_t i;
@@ -123,14 +122,14 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
     }
 
   /* Format specifier. */
-  if (lex_match (lexer, '('))
+  if (lex_match (lexer, T_LPAREN))
     {
       /* Get format type. */
       if (lex_token (lexer) == T_ID)
        {
          if (!parse_format_specifier_name (lexer, &format.type))
             return false;
-         lex_match (lexer, ',');
+         lex_match (lexer, T_COMMA);
        }
       else
        format.type = FMT_F;
@@ -144,7 +143,7 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
       else
        format.d = 0;
 
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
        return false;
     }
   else
@@ -173,7 +172,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
   size_t formats_used = 0;
 
   *formats = NULL;
-  while (!lex_match (lexer, ')'))
+  while (!lex_match (lexer, T_RPAREN))
     {
       struct fmt_spec f;
       struct fmt_spec *new_formats;
@@ -191,7 +190,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
        count = 1;
 
       /* Parse format specifier. */
-      if (lex_match (lexer, '('))
+      if (lex_match (lexer, T_LPAREN))
         {
           /* Call ourselves recursively to handle parentheses. */
           if (!fixed_parse_fortran (lexer, pool, for_input,
@@ -202,7 +201,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
         {
           new_formats = &f;
           new_format_cnt = 1;
-          if (lex_match (lexer, '/'))
+          if (lex_match (lexer, T_SLASH))
             f.type = PRS_TYPE_NEW_REC;
           else
             {
@@ -253,7 +252,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
           formats_used += new_format_cnt;
         }
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
 
   *format_cnt = formats_used;
@@ -293,12 +292,10 @@ execute_placement_format (const struct fmt_spec *format,
    stores a 1-based column number into *COLUMN if successful,
    otherwise emits an error message and returns false. */
 static bool
-parse_column (struct lexer *lexer, int base, int *column)
+parse_column (int value, int base, int *column)
 {
   assert (base == 0 || base == 1);
-  if (!lex_force_int (lexer))
-    return false;
-  *column = lex_integer (lexer) - base + 1;
+  *column = value - base + 1;
   if (*column < 1)
     {
       if (base == 1)
@@ -307,7 +304,6 @@ parse_column (struct lexer *lexer, int base, int *column)
         msg (SE, _("Column positions for fields must not be negative."));
       return false;
     }
-  lex_get (lexer);
   return true;
 }
 
@@ -330,15 +326,18 @@ parse_column_range (struct lexer *lexer, int base,
                     bool *range_specified)
 {
   /* First column. */
-  if (!parse_column (lexer, base, first_column))
+  if (!lex_force_int (lexer)
+      || !parse_column (lex_integer (lexer), base, first_column))
     return false;
+  lex_get (lexer);
 
   /* Last column. */
-  lex_negative_to_dash (lexer);
-  if (lex_match (lexer, '-'))
+  if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
     {
-      if (!parse_column (lexer, base, last_column))
+      if (!parse_column (-lex_integer (lexer), base, last_column))
         return false;
+      lex_get (lexer);
+
       if (*last_column < *first_column)
        {
          msg (SE, _("The ending column for a field must be "
@@ -369,7 +368,7 @@ parse_column_range (struct lexer *lexer, int base,
 bool
 parse_record_placement (struct lexer *lexer, int *record, int *column)
 {
-  while (lex_match (lexer, '/'))
+  while (lex_match (lexer, T_SLASH))
     {
       if (lex_is_integer (lexer))
         {
index 25bcc750516964264f5bf99e9fd15fed251ed405..b7245e629bdc2c551efe30950434cacee9877127 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011 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 <limits.h>
 #include <stdlib.h>
 
-#include <data/procedure.h>
-#include <data/value.h>
-#include <language/command.h>
-#include <language/data-io/data-writer.h>
-#include <language/data-io/file-handle.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <output/text-item.h>
+#include "data/dataset.h"
+#include "data/value.h"
+#include "language/command.h"
+#include "language/data-io/data-writer.h"
+#include "language/data-io/file-handle.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "output/text-item.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -54,20 +54,19 @@ cmd_print_space (struct lexer *lexer, struct dataset *ds)
 
   if (lex_match_id (lexer, "OUTFILE"))
     {
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
 
-      handle = fh_parse (lexer, FH_REF_FILE);
+      handle = fh_parse (lexer, FH_REF_FILE, NULL);
       if (handle == NULL)
        return CMD_FAILURE;
-      lex_get (lexer);
     }
   else
     handle = NULL;
 
-  if (lex_token (lexer) != '.')
+  if (lex_token (lexer) != T_ENDCMD)
     {
       expr = expr_parse (lexer, ds, EXPR_NUMBER);
-      if (lex_token (lexer) != '.')
+      if (lex_token (lexer) != T_ENDCMD)
        {
          expr_free (expr);
          lex_error (lexer, _("expecting end of command"));
index 164d992759614b421cb72eddee77fc2c6f3254e4..7b795f1ade5c8365e5a4bf68e7cd039c6a9a14c6 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/data-out.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <language/command.h>
-#include <language/data-io/data-writer.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/placement-parser.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/i18n.h>
-#include <libpspp/compiler.h>
-#include <libpspp/ll.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <output/text-item.h>
-#include <output/tab.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/data-out.h"
+#include "data/format.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/data-writer.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/placement-parser.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/ll.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "output/tab.h"
+#include "output/text-item.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -150,25 +150,25 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds,
   tmp_pool = pool_create_subpool (trns->pool);
 
   /* Parse the command options. */
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
     {
       if (lex_match_id (lexer, "OUTFILE"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
-         fh = fh_parse (lexer, FH_REF_FILE);
+         fh = fh_parse (lexer, FH_REF_FILE, NULL);
          if (fh == NULL)
            goto error;
        }
       else if (lex_match_id (lexer, "RECORDS"))
        {
-         lex_match (lexer, '=');
-         lex_match (lexer, '(');
+         lex_match (lexer, T_EQUALS);
+         lex_match (lexer, T_LPAREN);
          if (!lex_force_int (lexer))
            goto error;
          trns->record_cnt = lex_integer (lexer);
          lex_get (lexer);
-         lex_match (lexer, ')');
+         lex_match (lexer, T_RPAREN);
        }
       else if (lex_match_id (lexer, "TABLE"))
        print_table = true;
@@ -200,7 +200,7 @@ internal_cmd_print (struct lexer *lexer, struct dataset *ds,
       trns->encoding = dfm_writer_get_legacy_encoding (trns->writer);
     }
   else
-    trns->encoding = LEGACY_NATIVE;
+    trns->encoding = UTF8;
 
   /* Output the variable table if requested. */
   if (print_table)
@@ -239,13 +239,13 @@ parse_specs (struct lexer *lexer, struct pool *tmp_pool, struct print_trns *trns
   int record = 0;
   int column = 1;
 
-  if (lex_token (lexer) == '.')
+  if (lex_token (lexer) == T_ENDCMD)
     {
       trns->record_cnt = 1;
       return true;
     }
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       bool ok;
 
@@ -260,7 +260,7 @@ parse_specs (struct lexer *lexer, struct pool *tmp_pool, struct print_trns *trns
       if (!ok)
        return 0;
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
 
   if (trns->record_cnt != 0 && trns->record_cnt != record)
@@ -280,7 +280,7 @@ parse_string_argument (struct lexer *lexer, struct print_trns *trns, int record,
   spec->type = PRT_LITERAL;
   spec->record = record;
   spec->first_column = *column;
-  ds_init_string (&spec->string, lex_tokstr (lexer));
+  ds_init_substring (&spec->string, lex_tokss (lexer));
   ds_register_pool (&spec->string, trns->pool);
   lex_get (lexer);
 
@@ -323,7 +323,7 @@ parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
                             &vars, &var_cnt, PV_DUPLICATE))
     return false;
 
-  if (lex_is_number (lexer) || lex_token (lexer) == '(')
+  if (lex_is_number (lexer) || lex_token (lexer) == T_LPAREN)
     {
       if (!parse_var_placements (lexer, tmp_pool, var_cnt, false,
                                  &formats, &format_cnt))
@@ -334,7 +334,7 @@ parse_variable_argument (struct lexer *lexer, const struct dictionary *dict,
     {
       size_t i;
 
-      lex_match (lexer, '*');
+      lex_match (lexer, T_ASTERISK);
 
       formats = pool_nmalloc (tmp_pool, var_cnt, sizeof *formats);
       format_cnt = var_cnt;
@@ -454,12 +454,12 @@ print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
 {
   struct print_trns *trns = trns_;
   bool eject = trns->eject;
-  char encoded_space = legacy_from_native (trns->encoding, ' ');
+  char encoded_space = recode_byte (trns->encoding, C_ENCODING, ' ');
   int record = 1;
   struct prt_out_spec *spec;
 
   ds_clear (&trns->line);
-  ds_put_char (&trns->line, ' ');
+  ds_put_byte (&trns->line, ' ');
   ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
     {
       flush_records (trns, spec->record, &eject, &record);
@@ -468,22 +468,22 @@ print_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
       if (spec->type == PRT_VAR)
         {
           const union value *input = case_data (*c, spec->var);
-          char *output = ds_put_uninit (&trns->line, spec->format.w);
           if (!spec->sysmis_as_spaces || input->f != SYSMIS)
-            data_out_legacy (input, trns->encoding, &spec->format, output);
+            data_out_recode (input, var_get_encoding (spec->var),
+                             &spec->format, &trns->line, trns->encoding);
           else
-            memset (output, encoded_space, spec->format.w);
+            ds_put_byte_multiple (&trns->line, encoded_space, spec->format.w);
           if (spec->add_space)
-            ds_put_char (&trns->line, encoded_space);
+            ds_put_byte (&trns->line, encoded_space);
         }
       else
         {
           ds_put_substring (&trns->line, ds_ss (&spec->string));
-          if (0 != strcmp (trns->encoding, LEGACY_NATIVE))
+          if (0 != strcmp (trns->encoding, C_ENCODING))
             {
               size_t length = ds_length (&spec->string);
               char *data = ss_data (ds_tail (&trns->line, length));
-             char *s = recode_string (trns->encoding, LEGACY_NATIVE, data, length);
+             char *s = recode_string (trns->encoding, C_ENCODING, data, length);
              memcpy (data, s, length);
              free (s);
             }
@@ -518,7 +518,7 @@ flush_records (struct print_trns *trns, int target_record,
           else
             leader = '1';
         }
-      line[0] = legacy_from_native (trns->encoding, leader);
+      line[0] = recode_byte (trns->encoding, C_ENCODING, leader);
 
       if (trns->writer == NULL)
         tab_output_text (TAB_FIX, &line[1]);
index 4cf5e71eaa18b6c696ed682e925572978f5ec658..f6487c57932e3faad8a64e45adcf570e9ab7b897 100644 (file)
 #include "data/casereader.h"
 #include "data/casewriter.h"
 #include "data/csv-file-writer.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
 #include "data/file-name.h"
 #include "data/format.h"
-#include "data/procedure.h"
 #include "data/settings.h"
 #include "language/command.h"
 #include "language/data-io/file-handle.h"
@@ -84,7 +84,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
   case_map_prepare_dict (dict);
   dict_delete_scratch_vars (dict);
 
-  while (lex_match (lexer, '/'))
+  while (lex_match (lexer, T_SLASH))
     {
       if (lex_match_id (lexer, "OUTFILE"))
        {
@@ -94,9 +94,9 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
               goto error;
             }
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
-         handle = fh_parse (lexer, FH_REF_FILE);
+         handle = fh_parse (lexer, FH_REF_FILE, NULL);
          if (handle == NULL)
            goto error;
        }
@@ -108,7 +108,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
               goto error;
             }
 
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "CSV"))
             type = CSV_FILE;
           else if (lex_match_id (lexer, "TAB"))
@@ -125,7 +125,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
         include_var_names = true;
       else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "IGNORE"))
             recode_user_missing = false;
           else if (lex_match_id (lexer, "RECODE"))
@@ -138,7 +138,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
         }
       else if (lex_match_id (lexer, "CELLS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "VALUES"))
             use_value_labels = false;
           else if (lex_match_id (lexer, "LABELS"))
@@ -151,40 +151,42 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
         }
       else if (lex_match_id (lexer, "TEXTOPTIONS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           for (;;)
             {
               if (lex_match_id (lexer, "DELIMITER"))
                 {
-                  lex_match (lexer, '=');
+                  lex_match (lexer, T_EQUALS);
                   if (!lex_force_string (lexer))
                     goto error;
-                  if (ds_length (lex_tokstr (lexer)) != 1)
+                  /* XXX should support multibyte UTF-8 delimiters */
+                  if (ss_length (lex_tokss (lexer)) != 1)
                     {
                       msg (SE, _("The %s string must contain exactly one "
                                  "character."), "DELIMITER");
                       goto error;
                     }
-                  delimiter = ds_first (lex_tokstr (lexer));
+                  delimiter = ss_first (lex_tokss (lexer));
                   lex_get (lexer);
                 }
               else if (lex_match_id (lexer, "QUALIFIER"))
                 {
-                  lex_match (lexer, '=');
+                  lex_match (lexer, T_EQUALS);
                   if (!lex_force_string (lexer))
                     goto error;
-                  if (ds_length (lex_tokstr (lexer)) != 1)
+                  /* XXX should support multibyte UTF-8 qualifiers */
+                  if (ss_length (lex_tokss (lexer)) != 1)
                     {
                       msg (SE, _("The %s string must contain exactly one "
                                  "character."), "QUALIFIER");
                       goto error;
                     }
-                  qualifier = ds_first (lex_tokstr (lexer));
+                  qualifier = ss_first (lex_tokss (lexer));
                   lex_get (lexer);
                 }
               else if (lex_match_id (lexer, "DECIMAL"))
                 {
-                  lex_match (lexer, '=');
+                  lex_match (lexer, T_EQUALS);
                   if (lex_match_id (lexer, "DOT"))
                     decimal = '.';
                   else if (lex_match_id (lexer, "COMMA"))
@@ -198,7 +200,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
                 }
               else if (lex_match_id (lexer, "FORMAT"))
                 {
-                  lex_match (lexer, '=');
+                  lex_match (lexer, T_EQUALS);
                   if (lex_match_id (lexer, "PLAIN"))
                     use_print_formats = false;
                   else if (lex_match_id (lexer, "VARIABLE"))
@@ -216,7 +218,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
         }
       else if (lex_match_id (lexer, "UNSELECTED"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "RETAIN"))
             retain_unselected = true;
           else if (lex_match_id (lexer, "DELETE"))
index 91fbc2fd3bfcb6f6a55ff202698f9c237f52e853..cf847361264d618b1001677bd86c62661e73d3cb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011 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 <stdlib.h>
 
-#include <data/any-writer.h>
-#include <data/case-map.h>
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/por-file-writer.h>
-#include <data/procedure.h>
-#include <data/sys-file-writer.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/data-io/trim.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-
-#include "xalloc.h"
+#include "data/any-writer.h"
+#include "data/case-map.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/por-file-writer.h"
+#include "data/sys-file-writer.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/data-io/trim.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -183,7 +183,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
   case_map_prepare_dict (dict);
   dict_delete_scratch_vars (dict);
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   for (;;)
     {
       if (lex_match_id (lexer, "OUTFILE"))
@@ -194,9 +194,9 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
               goto error;
             }
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
 
-         handle = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
+         handle = fh_parse (lexer, FH_REF_FILE, NULL);
          if (handle == NULL)
            goto error;
        }
@@ -206,7 +206,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
         {
           bool cw;
 
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "READONLY"))
             cw = false;
           else if (lex_match_id (lexer, "WRITEABLE"))
@@ -221,7 +221,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
         }
       else if (command_type == PROC_CMD && lex_match_id (lexer, "UNSELECTED"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "RETAIN"))
             *retain_unselected = true;
           else if (lex_match_id (lexer, "DELETE"))
@@ -241,7 +241,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
       else if (writer_type == SYSFILE_WRITER
                && lex_match_id (lexer, "VERSION"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!lex_force_int (lexer))
             goto error;
           sysfile_opts.version = lex_integer (lexer);
@@ -249,7 +249,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
        }
       else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "TYPE"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "COMMUNICATIONS"))
             porfile_opts.type = PFM_COMM;
           else if (lex_match_id (lexer, "TAPE"))
@@ -262,7 +262,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
         }
       else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "DIGITS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (!lex_force_int (lexer))
             goto error;
           porfile_opts.digits = lex_integer (lexer);
@@ -271,7 +271,7 @@ parse_write_command (struct lexer *lexer, struct dataset *ds,
       else if (!parse_dict_trim (lexer, dict))
         goto error;
 
-      if (!lex_match (lexer, '/'))
+      if (!lex_match (lexer, T_SLASH))
        break;
     }
   if (lex_end_of_command (lexer) != CMD_SUCCESS)
index 5817fd02ccb4db835416fd8182b2d469219375a5..63041f25f10465dde398a80b863a9d46bf186340 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2010, 2011 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 <language/data-io/trim.h>
+#include "language/data-io/trim.h"
 
 #include <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -72,29 +72,30 @@ parse_dict_rename (struct lexer *lexer, struct dictionary *dict)
 
   int group;
 
-  lex_match (lexer, '=');
-  if (lex_token (lexer) != '(')
+  lex_match (lexer, T_EQUALS);
+  if (lex_token (lexer) != T_LPAREN)
     {
       struct variable *v;
 
       v = parse_variable (lexer, dict);
       if (v == NULL)
        return 0;
-      if (!lex_force_match (lexer, '=')
-         || !lex_force_id (lexer))
+      if (!lex_force_match (lexer, T_EQUALS)
+         || !lex_force_id (lexer)
+          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
        return 0;
-      if (dict_lookup_var (dict, lex_tokid (lexer)) != NULL)
+      if (dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL)
        {
          msg (SE, _("Cannot rename %s as %s because there already exists "
                     "a variable named %s.  To rename variables with "
                     "overlapping names, use a single RENAME subcommand "
                     "such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, "
                     "`/RENAME (A B C=B C A)'."),
-               var_get_name (v), lex_tokid (lexer), lex_tokid (lexer));
+               var_get_name (v), lex_tokcstr (lexer), lex_tokcstr (lexer));
          return 0;
        }
 
-      dict_rename_var (dict, v, lex_tokid (lexer));
+      dict_rename_var (dict, v, lex_tokcstr (lexer));
       lex_get (lexer);
       return 1;
     }
@@ -103,18 +104,18 @@ parse_dict_rename (struct lexer *lexer, struct dictionary *dict)
   v = NULL;
   new_names = 0;
   group = 1;
-  while (lex_match (lexer, '('))
+  while (lex_match (lexer, T_LPAREN))
     {
       size_t old_nv = nv;
 
       if (!parse_variables (lexer, dict, &v, &nv, PV_NO_DUPLICATE | PV_APPEND))
        goto done;
-      if (!lex_match (lexer, '='))
+      if (!lex_match (lexer, T_EQUALS))
        {
          msg (SE, _("`=' expected after variable list."));
          goto done;
        }
-      if (!parse_DATA_LIST_vars (lexer, &new_names, &nn,
+      if (!parse_DATA_LIST_vars (lexer, dict, &new_names, &nn,
                                  PV_APPEND | PV_NO_SCRATCH | PV_NO_DUPLICATE))
        goto done;
       if (nn != nv)
@@ -125,7 +126,7 @@ parse_dict_rename (struct lexer *lexer, struct dictionary *dict)
               nv - old_nv, nn - old_nv, group);
          goto done;
        }
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
        goto done;
       group++;
     }
@@ -155,7 +156,7 @@ parse_dict_drop (struct lexer *lexer, struct dictionary *dict)
   struct variable **v;
   size_t nv;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
     return false;
   dict_delete_vars (dict, v, nv);
@@ -179,7 +180,7 @@ parse_dict_keep (struct lexer *lexer, struct dictionary *dict)
   size_t nv;
   size_t i;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
     return false;
 
index 3e1df58fd85b186673f9663cb770ecb0ed440f29..c2de9318ae81b13462c940aae839a580f886c2d4 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, 2011 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 <stdlib.h>
 
-#include <data/any-reader.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/missing-values.h>
-#include <data/procedure.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/any-reader.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/missing-values.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -48,9 +48,9 @@ cmd_apply_dictionary (struct lexer *lexer, struct dataset *ds)
   int i;
 
   lex_match_id (lexer, "FROM");
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
-  handle = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
+  handle = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
   if (!handle)
     return CMD_FAILURE;
   reader = any_reader_open (handle, &dict);
@@ -79,12 +79,8 @@ cmd_apply_dictionary (struct lexer *lexer, struct dataset *ds)
          continue;
        }
 
-      if (var_get_label (s))
-        {
-          const char *label = var_get_label (s);
-          if (strcspn (label, " ") != strlen (label))
-            var_set_label (t, label);
-        }
+      if (var_has_label (s))
+        var_set_label (t, var_get_label (s), false);
 
       if (var_has_value_labels (s))
         {
@@ -129,5 +125,5 @@ cmd_apply_dictionary (struct lexer *lexer, struct dataset *ds)
         dict_set_weight (dataset_dict (ds), new_weight);
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index ee309ae31d84e15f40741b8c64fa4af3508eef0d..c7598d1c45b37899ecba1d7a375e3dbaea3d9987 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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 <stdlib.h>
 
-#include <data/attributes.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
+#include "data/attributes.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static enum cmd_result parse_attributes (struct lexer *, struct attrset **,
-                                         size_t n);
+static enum cmd_result parse_attributes (struct lexer *,
+                                         const char *dict_encoding,
+                                         struct attrset **, size_t n);
 
 /* Parses the DATAFILE ATTRIBUTE command. */
 int
 cmd_datafile_attribute (struct lexer *lexer, struct dataset *ds)
 {
-  struct attrset *set = dict_get_attributes (dataset_dict (ds));
-  return parse_attributes (lexer, &set, 1);
+  struct dictionary *dict = dataset_dict (ds);
+  struct attrset *set = dict_get_attributes (dict);
+  return parse_attributes (lexer, dict_get_encoding (dict), &set, 1);
 }
 
 /* Parses the VARIABLE ATTRIBUTE command. */
 int
 cmd_variable_attribute (struct lexer *lexer, struct dataset *ds)
 {
+  struct dictionary *dict = dataset_dict (ds);
+  const char *dict_encoding = dict_get_encoding (dict);
+
   do 
     {
       struct variable **vars;
@@ -55,81 +60,81 @@ cmd_variable_attribute (struct lexer *lexer, struct dataset *ds)
       bool ok;
 
       if (!lex_force_match_id (lexer, "VARIABLES")
-          || !lex_force_match (lexer, '=')
-          || !parse_variables (lexer, dataset_dict (ds), &vars, &n_vars,
-                               PV_NONE))
+          || !lex_force_match (lexer, T_EQUALS)
+          || !parse_variables (lexer, dict, &vars, &n_vars, PV_NONE))
         return CMD_FAILURE;
 
       sets = xmalloc (n_vars * sizeof *sets);
       for (i = 0; i < n_vars; i++)
         sets[i] = var_get_attributes (vars[i]);
 
-      ok = parse_attributes (lexer, sets, n_vars);
+      ok = parse_attributes (lexer, dict_encoding, sets, n_vars);
       free (vars);
       free (sets);
       if (!ok)
         return CMD_FAILURE;
     }
-  while (lex_match (lexer, '/'));
+  while (lex_match (lexer, T_SLASH));
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
-static bool
-match_subcommand (struct lexer *lexer, const char *keyword) 
+/* Parses an attribute name and verifies that it is valid in DICT_ENCODING,
+   optionally followed by an index inside square brackets.  Returns the
+   attribute name or NULL if there was a parse error.  Stores the index into
+   *INDEX. */
+static char *
+parse_attribute_name (struct lexer *lexer, const char *dict_encoding,
+                      size_t *index)
 {
-  if (lex_token (lexer) == T_ID
-      && lex_id_match (ss_cstr (lex_tokid (lexer)), ss_cstr (keyword))
-      && lex_look_ahead (lexer) == '=') 
-    {
-      lex_get (lexer);          /* Skip keyword. */
-      lex_get (lexer);          /* Skip '='. */
-      return true;
-    }
-  else
-    return false;
-}
+  char *name;
 
-static bool
-parse_attribute_name (struct lexer *lexer, char name[VAR_NAME_LEN + 1],
-                      size_t *index) 
-{
-  if (!lex_force_id (lexer))
-    return false;
-  strcpy (name, lex_tokid (lexer));
+  if (!lex_force_id (lexer)
+      || !id_is_valid (lex_tokcstr (lexer), dict_encoding, true))
+    return NULL;
+  name = xstrdup (lex_tokcstr (lexer));
   lex_get (lexer);
 
-  if (lex_match (lexer, '[')) 
+  if (lex_match (lexer, T_LBRACK))
     {
       if (!lex_force_int (lexer))
-        return false;
+        goto error;
       if (lex_integer (lexer) < 1 || lex_integer (lexer) > 65535)
         {
           msg (SE, _("Attribute array index must be between 1 and 65535."));
-          return false;
+          goto error;
         }
       *index = lex_integer (lexer);
       lex_get (lexer);
-      if (!lex_force_match (lexer, ']'))
-        return false;
+      if (!lex_force_match (lexer, T_RBRACK))
+        goto error;
     }
   else
     *index = 0;
-  return true;
+  return name;
+
+error:
+  free (name);
+  return NULL;
 }
 
 static bool
-add_attribute (struct lexer *lexer, struct attrset **sets, size_t n) 
+add_attribute (struct lexer *lexer, const char *dict_encoding,
+               struct attrset **sets, size_t n) 
 {
-  char name[VAR_NAME_LEN + 1];
+  const char *value;
   size_t index, i;
-  char *value;
+  char *name;
 
-  if (!parse_attribute_name (lexer, name, &index)
-      || !lex_force_match (lexer, '(')
-      || !lex_force_string (lexer))
+  name = parse_attribute_name (lexer, dict_encoding, &index);
+  if (name == NULL)
     return false;
-  value = ds_cstr (lex_tokstr (lexer));
+  if (!lex_force_match (lexer, T_LPAREN) || !lex_force_string (lexer))
+    {
+      free (name);
+      return false;
+    }
+  value = lex_tokcstr (lexer);
 
   for (i = 0; i < n; i++)
     {
@@ -143,16 +148,19 @@ add_attribute (struct lexer *lexer, struct attrset **sets, size_t n)
     }
 
   lex_get (lexer);
-  return lex_force_match (lexer, ')');
+  free (name);
+  return lex_force_match (lexer, T_RPAREN);
 }
 
 static bool
-delete_attribute (struct lexer *lexer, struct attrset **sets, size_t n) 
+delete_attribute (struct lexer *lexer, const char *dict_encoding,
+                  struct attrset **sets, size_t n) 
 {
-  char name[VAR_NAME_LEN + 1];
   size_t index, i;
+  char *name;
 
-  if (!parse_attribute_name (lexer, name, &index))
+  name = parse_attribute_name (lexer, dict_encoding, &index);
+  if (name == NULL)
     return false;
 
   for (i = 0; i < n; i++) 
@@ -171,18 +179,21 @@ delete_attribute (struct lexer *lexer, struct attrset **sets, size_t n)
             }
         }
     }
+
+  free (name);
   return true;
 }
 
 static enum cmd_result
-parse_attributes (struct lexer *lexer, struct attrset **sets, size_t n) 
+parse_attributes (struct lexer *lexer, const char *dict_encoding,
+                  struct attrset **sets, size_t n) 
 {
   enum { UNKNOWN, ADD, DELETE } command = UNKNOWN;
   do 
     {
-      if (match_subcommand (lexer, "ATTRIBUTE"))
+      if (lex_match_phrase (lexer, "ATTRIBUTE="))
         command = ADD;
-      else if (match_subcommand (lexer, "DELETE"))
+      else if (lex_match_phrase (lexer, "DELETE="))
         command = DELETE;
       else if (command == UNKNOWN)
         {
@@ -191,10 +202,10 @@ parse_attributes (struct lexer *lexer, struct attrset **sets, size_t n)
         }
 
       if (!(command == ADD
-            ? add_attribute (lexer, sets, n)
-            : delete_attribute (lexer, sets, n)))
+            ? add_attribute (lexer, dict_encoding, sets, n)
+            : delete_attribute (lexer, dict_encoding, sets, n)))
         return CMD_FAILURE;
     }
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
index bfb74e84d9eba795137fe47367932e2cab1092d6..c9040adc934a898a985c0c1101f6f54322a913c0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2010, 2011 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 <stdlib.h>
 
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <language/command.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "language/command.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -40,13 +40,13 @@ cmd_delete_variables (struct lexer *lexer, struct dataset *ds)
     msg (SE, _("DELETE VARIABLES may not be used after TEMPORARY.  "
                "Temporary transformations will be made permanent."));
 
-  if (!parse_variables (lexer, dataset_dict (ds), &vars, &var_cnt,
-                             PV_NONE))
+  if (!parse_variables (lexer, dataset_dict (ds), &vars, &var_cnt, PV_NONE))
     goto error;
   if (var_cnt == dict_get_var_cnt (dataset_dict (ds)))
     {
       msg (SE, _("DELETE VARIABLES may not be used to delete all variables "
-                 "from the active file dictionary.  Use NEW FILE instead."));
+                 "from the active dataset dictionary.  "
+                 "Use NEW FILE instead."));
       goto error;
     }
 
index 640246c9df2a8b86b571b036ae78f05a3bc83535..2244ef7715018a5ff1ef9a55618f3cc4d42a1eab 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, 2011 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 <stdlib.h>
 
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <language/command.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -67,35 +67,32 @@ internal_cmd_formats (struct lexer *lexer, struct dataset *ds, int which)
   struct variable **v;
   size_t cv;
 
-  /* Format to set the variables to. */
-  struct fmt_spec f;
-
-  /* Numeric or string. */
-  int type;
-
-  /* Counter. */
-  size_t i;
-
   for (;;)
     {
-      if (lex_token (lexer) == '.')
+      struct fmt_spec f;
+      int width;
+      size_t i;
+
+      lex_match (lexer, T_SLASH);
+
+      if (lex_token (lexer) == T_ENDCMD)
        break;
 
-      if (!parse_variables (lexer, dataset_dict (ds), &v, &cv, PV_NUMERIC))
+      if (!parse_variables (lexer, dataset_dict (ds), &v, &cv, PV_SAME_WIDTH))
        return CMD_FAILURE;
-      type = var_get_type (v[0]);
+      width = var_get_width (v[0]);
 
-      if (!lex_match (lexer, '('))
+      if (!lex_match (lexer, T_LPAREN))
        {
          msg (SE, _("`(' expected after variable list."));
          goto fail;
        }
       if (!parse_format_specifier (lexer, &f)
           || !fmt_check_output (&f)
-          || !fmt_check_type_compat (&f, VAL_NUMERIC))
+          || !fmt_check_width_compat (&f, width))
        goto fail;
 
-      if (!lex_match (lexer, ')'))
+      if (!lex_match (lexer, T_RPAREN))
        {
          msg (SE, _("`)' expected after output format."));
          goto fail;
index 912c58cf5a0bdee053d7adc9adb86ab2cc4d5105..a906b8a8f3cacbd889bce5b9be004357e687dc39 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 <stdlib.h>
 
-#include <data/data-in.h>
-#include <data/missing-values.h>
-#include <data/procedure.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/value-parser.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/data-in.h"
+#include "data/dictionary.h"
+#include "data/dataset.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 int
 cmd_missing_values (struct lexer *lexer, struct dataset *ds)
 {
+  struct dictionary *dict = dataset_dict (ds);
   struct variable **v = NULL;
   size_t nv;
 
-  int retval = CMD_FAILURE;
-  bool deferred_errors = false;
+  bool ok = true;
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       size_t i;
 
-      if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
-        goto done;
+      if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
+        goto error;
 
-      if (!lex_force_match (lexer, '('))
-        goto done;
+      if (!lex_force_match (lexer, T_LPAREN))
+        goto error;
 
       for (i = 0; i < nv; i++)
         var_clear_missing_values (v[i]);
 
-      if (!lex_match (lexer, ')'))
+      if (!lex_match (lexer, T_RPAREN))
         {
           struct missing_values mv;
 
@@ -69,60 +70,66 @@ cmd_missing_values (struct lexer *lexer, struct dataset *ds)
                 msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
                            "string variables (e.g. %s) within a single list."),
                      var_get_name (n), var_get_name (s));
-                goto done;
+                goto error;
               }
 
           if (var_is_numeric (v[0]))
             {
               mv_init (&mv, 0);
-              while (!lex_match (lexer, ')'))
+              while (!lex_match (lexer, T_RPAREN))
                 {
                   enum fmt_type type = var_get_print_format (v[0])->type;
                   double x, y;
                   bool ok;
 
                   if (!parse_num_range (lexer, &x, &y, &type))
-                    goto done;
+                    goto error;
 
                   ok = (x == y
                         ? mv_add_num (&mv, x)
                         : mv_add_range (&mv, x, y));
                   if (!ok)
-                    deferred_errors = true;
+                    ok = false;
 
-                  lex_match (lexer, ',');
+                  lex_match (lexer, T_COMMA);
                 }
             }
           else
             {
               mv_init (&mv, MV_MAX_STRING);
-              while (!lex_match (lexer, ')'))
+              while (!lex_match (lexer, T_RPAREN))
                 {
                   uint8_t value[MV_MAX_STRING];
+                  char *dict_mv;
                   size_t length;
 
                   if (!lex_force_string (lexer))
                     {
-                      deferred_errors = true;
+                      ok = false;
                       break;
                     }
 
-                  length = ds_length (lex_tokstr (lexer));
+                  dict_mv = recode_string (dict_get_encoding (dict), "UTF-8",
+                                           lex_tokcstr (lexer),
+                                           ss_length (lex_tokss (lexer)));
+                  length = strlen (dict_mv);
                   if (length > MV_MAX_STRING)
                     {
+                      /* XXX truncate graphemes not bytes */
                       msg (SE, _("Truncating missing value to maximum "
                                  "acceptable length (%d bytes)."),
                            MV_MAX_STRING);
                       length = MV_MAX_STRING;
                     }
                   memset (value, ' ', MV_MAX_STRING);
-                  memcpy (value, ds_data (lex_tokstr (lexer)), length);
+                  memcpy (value, dict_mv, length);
+                  free (dict_mv);
 
                   if (!mv_add_str (&mv, value))
-                    deferred_errors = true;
+                    ok = false;
 
                   lex_get (lexer);
-                  lex_match (lexer, ',');
+                  lex_match (lexer, T_COMMA);
                 }
             }
 
@@ -135,23 +142,23 @@ cmd_missing_values (struct lexer *lexer, struct dataset *ds)
                   msg (SE, _("Missing values provided are too long to assign "
                              "to variable of width %d."),
                        var_get_width (v[i]));
-                  deferred_errors = true;
+                  ok = false;
                 }
             }
 
           mv_destroy (&mv);
         }
 
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
       free (v);
       v = NULL;
     }
-  retval = lex_end_of_command (lexer);
 
- done:
   free (v);
-  if (deferred_errors)
-    retval = CMD_FAILURE;
-  return retval;
+  return ok ? CMD_SUCCESS : CMD_FAILURE;
+
+error:
+  free (v);
+  return CMD_FAILURE;
 }
 
index 8de2ee18183161d824cf187743dbcf95276cdfb6..b9a8a28eecc06cad545030837b75fa893f919e8b 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, 2011 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 <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/array.h>
-#include <libpspp/bit-vector.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/bit-vector.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -79,7 +79,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
      this type. */
   unsigned already_encountered = 0;
 
-  /* What we're gonna do to the active file. */
+  /* What we are going to do to the active dataset. */
   struct var_modification vm;
 
   /* Return code. */
@@ -100,7 +100,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
   vm.drop_cnt = 0;
 
   /* Parse each subcommand. */
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   for (;;)
     {
       if (lex_match_id (lexer, "REORDER"))
@@ -115,7 +115,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
            }
          already_encountered |= 1;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          do
            {
               struct ordering ordering;
@@ -129,7 +129,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
              else if (lex_match_id (lexer, "ALPHA"))
                ordering.positional = 0;
 
-             if (lex_match (lexer, T_ALL) || lex_token (lexer) == '/' || lex_token (lexer) == '.')
+             if (lex_match (lexer, T_ALL) || lex_token (lexer) == T_SLASH || lex_token (lexer) == T_ENDCMD)
                {
                  if (prev_nv != 0)
                    {
@@ -141,7 +141,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
                }
              else
                {
-                 if (!lex_match (lexer, '('))
+                 if (!lex_match (lexer, T_LPAREN))
                    {
                      msg (SE, _("`(' expected on %s subcommand."), "REORDER");
                      free (v);
@@ -153,7 +153,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
                      free (v);
                      goto done;
                    }
-                 if (!lex_match (lexer, ')'))
+                 if (!lex_match (lexer, T_RPAREN))
                    {
                      msg (SE, _("`)' expected following variable names on "
                           "REORDER subcommand."));
@@ -164,7 +164,8 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
              sort (&v[prev_nv], nv - prev_nv, sizeof *v,
                     compare_variables_given_ordering, &ordering);
            }
-         while (lex_token (lexer) != '/' && lex_token (lexer) != '.');
+         while (lex_token (lexer) != T_SLASH
+                 && lex_token (lexer) != T_ENDCMD);
 
          vm.reorder_vars = v;
           vm.reorder_cnt = nv;
@@ -178,13 +179,13 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
            }
          already_encountered |= 2;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          do
            {
              size_t prev_nv_1 = vm.rename_cnt;
              size_t prev_nv_2 = vm.rename_cnt;
 
-             if (!lex_match (lexer, '('))
+             if (!lex_match (lexer, T_LPAREN))
                {
                  msg (SE, _("`(' expected on %s subcommand."), "RENAME");
                  goto done;
@@ -193,14 +194,14 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
                                    &vm.rename_vars, &vm.rename_cnt,
                                    PV_APPEND | PV_NO_DUPLICATE))
                goto done;
-             if (!lex_match (lexer, '='))
+             if (!lex_match (lexer, T_EQUALS))
                {
                  msg (SE, _("`=' expected between lists of new and old variable "
                       "names on RENAME subcommand."));
                  goto done;
                }
-             if (!parse_DATA_LIST_vars (lexer, &vm.new_names,
-                                        &prev_nv_1, PV_APPEND))
+             if (!parse_DATA_LIST_vars (lexer, dataset_dict (ds),
+                                         &vm.new_names, &prev_nv_1, PV_APPEND))
                goto done;
              if (prev_nv_1 != vm.rename_cnt)
                {
@@ -213,14 +214,15 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
                  vm.new_names = NULL;
                  goto done;
                }
-             if (!lex_match (lexer, ')'))
+             if (!lex_match (lexer, T_RPAREN))
                {
                  msg (SE, _("`)' expected after variable lists on RENAME "
                       "subcommand."));
                  goto done;
                }
            }
-         while (lex_token (lexer) != '.' && lex_token (lexer) != '/');
+         while (lex_token (lexer) != T_ENDCMD
+                 && lex_token (lexer) != T_SLASH);
        }
       else if (lex_match_id (lexer, "KEEP"))
        {
@@ -235,7 +237,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
            }
          already_encountered |= 4;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!parse_variables (lexer, dataset_dict (ds), &keep_vars, &keep_cnt, PV_NONE))
            goto done;
 
@@ -279,7 +281,7 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
            }
          already_encountered |= 4;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!parse_variables (lexer, dataset_dict (ds), &drop_vars, &drop_cnt, PV_NONE))
            goto done;
           vm.drop_vars = drop_vars;
@@ -298,15 +300,15 @@ cmd_modify_vars (struct lexer *lexer, struct dataset *ds)
       else
        {
          if (lex_token (lexer) == T_ID)
-           msg (SE, _("Unrecognized subcommand name `%s'."), lex_tokid (lexer));
+           msg (SE, _("Unrecognized subcommand name `%s'."), lex_tokcstr (lexer));
          else
            msg (SE, _("Subcommand name expected."));
          goto done;
        }
 
-      if (lex_token (lexer) == '.')
+      if (lex_token (lexer) == T_ENDCMD)
        break;
-      if (lex_token (lexer) != '/')
+      if (lex_token (lexer) != T_SLASH)
        {
          msg (SE, _("`/' or `.' expected."));
          goto done;
@@ -366,7 +368,7 @@ compare_variables_given_ordering (const void *a_, const void *b_,
 struct var_renaming
   {
     struct variable *var;
-    char new_name[VAR_NAME_LEN + 1];
+    const char *new_name;
   };
 
 /* A algo_compare_func that compares new_name members in struct
@@ -429,7 +431,7 @@ validate_var_modification (const struct dictionary *d,
   for (i = 0; i < keep_cnt; i++)
     {
       var_renaming[i].var = keep_vars[i];
-      strcpy (var_renaming[i].new_name, var_get_name (keep_vars[i]));
+      var_renaming[i].new_name = var_get_name (keep_vars[i]);
     }
 
   /* Rename variables in var_renaming array. */
@@ -447,7 +449,7 @@ validate_var_modification (const struct dictionary *d,
         continue;
       vr = var_renaming + (kv - keep_vars);
 
-      strcpy (vr->new_name, vm->new_names[i]);
+      vr->new_name = vm->new_names[i];
     }
 
   /* Sort var_renaming array by new names and check for
index 96f1a110f5a5066be42ca24d08b5a48f4761cc3d..621cdc884b1e2fff1eaa256a30314243e242f201 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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,9 +17,9 @@
 #include <config.h>
 
 #include "data/data-out.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
 #include "data/mrset.h"
-#include "data/procedure.h"
 #include "data/value-labels.h"
 #include "data/variable.h"
 #include "language/command.h"
@@ -27,6 +27,7 @@
 #include "language/lexer/variable-parser.h"
 #include "libpspp/assertion.h"
 #include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 #include "libpspp/stringi-map.h"
@@ -47,7 +48,7 @@ cmd_mrsets (struct lexer *lexer, struct dataset *ds)
 {
   struct dictionary *dict = dataset_dict (ds);
 
-  while (lex_match (lexer, '/'))
+  while (lex_match (lexer, T_SLASH))
     {
       bool ok;
 
@@ -69,7 +70,7 @@ cmd_mrsets (struct lexer *lexer, struct dataset *ds)
         return CMD_FAILURE;
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 static bool
@@ -87,27 +88,22 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
 
   labelsource_varlabel = false;
   has_value = false;
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
     {
       if (lex_match_id (lexer, "NAME"))
         {
-          if (!lex_force_match (lexer, '=') || !lex_force_id (lexer))
+          if (!lex_force_match (lexer, T_EQUALS) || !lex_force_id (lexer)
+              || !mrset_is_valid_name (lex_tokcstr (lexer),
+                                       dict_get_encoding (dict), true))
             goto error;
-          if (lex_tokid (lexer)[0] != '$')
-            {
-              msg (SE, _("%s is not a valid name for a multiple response "
-                         "set.  Multiple response set names must begin with "
-                         "`$'."), lex_tokid (lexer));
-              goto error;
-            }
 
           free (mrset->name);
-          mrset->name = xstrdup (lex_tokid (lexer));
+          mrset->name = xstrdup (lex_tokcstr (lexer));
           lex_get (lexer);
         }
       else if (lex_match_id (lexer, "VARIABLES"))
         {
-          if (!lex_force_match (lexer, '='))
+          if (!lex_force_match (lexer, T_EQUALS))
             goto error;
 
           free (mrset->vars);
@@ -125,16 +121,16 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
         }
       else if (lex_match_id (lexer, "LABEL"))
         {
-          if (!lex_force_match (lexer, '=') || !lex_force_string (lexer))
+          if (!lex_force_match (lexer, T_EQUALS) || !lex_force_string (lexer))
             goto error;
 
           free (mrset->label);
-          mrset->label = ds_xstrdup (lex_tokstr (lexer));
+          mrset->label = ss_xstrdup (lex_tokss (lexer));
           lex_get (lexer);
         }
       else if (type == MRSET_MD && lex_match_id (lexer, "LABELSOURCE"))
         {
-          if (!lex_force_match (lexer, '=')
+          if (!lex_force_match (lexer, T_EQUALS)
               || !lex_force_match_id (lexer, "VARLABEL"))
             goto error;
 
@@ -142,7 +138,7 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
         }
       else if (type == MRSET_MD && lex_match_id (lexer, "VALUE"))
         {
-          if (!lex_force_match (lexer, '='))
+          if (!lex_force_match (lexer, T_EQUALS))
             goto error;
 
           has_value = true;
@@ -159,12 +155,15 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
             }
           else if (lex_is_string (lexer))
             {
-              const char *s = ds_cstr (lex_tokstr (lexer));
-              int width;
+              size_t width;
+              char *s;
+
+              s = recode_string (dict_get_encoding (dict), "UTF-8",
+                                 lex_tokcstr (lexer), -1);
+              width = strlen (s);
 
               /* Trim off trailing spaces, but don't trim the string until
                  it's empty because a width of 0 is a numeric type. */
-              width = strlen (s);
               while (width > 1 && s[width - 1] == ' ')
                 width--;
 
@@ -172,6 +171,8 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
               value_init (&mrset->counted, width);
               memcpy (value_str_rw (&mrset->counted, width), s, width);
               mrset->width = width;
+
+              free (s);
             }
           else
             {
@@ -182,7 +183,7 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
         }
       else if (type == MRSET_MD && lex_match_id (lexer, "CATEGORYLABELS"))
         {
-          if (!lex_force_match (lexer, '='))
+          if (!lex_force_match (lexer, T_EQUALS))
             goto error;
 
           if (lex_match_id (lexer, "VARLABELS"))
@@ -469,24 +470,25 @@ static bool
 parse_mrset_names (struct lexer *lexer, struct dictionary *dict,
                    struct stringi_set *mrset_names)
 {
-  if (!lex_force_match_id (lexer, "NAME") || !lex_force_match (lexer, '='))
+  if (!lex_force_match_id (lexer, "NAME")
+      || !lex_force_match (lexer, T_EQUALS))
     return false;
 
   stringi_set_init (mrset_names);
-  if (lex_match (lexer, '['))
+  if (lex_match (lexer, T_LBRACK))
     {
-      while (!lex_match (lexer, ']'))
+      while (!lex_match (lexer, T_RBRACK))
         {
           if (!lex_force_id (lexer))
             return false;
-          if (dict_lookup_mrset (dict, lex_tokid (lexer)) == NULL)
+          if (dict_lookup_mrset (dict, lex_tokcstr (lexer)) == NULL)
             {
               msg (SE, _("No multiple response set named %s."),
-                   lex_tokid (lexer));
+                   lex_tokcstr (lexer));
               stringi_set_destroy (mrset_names);
               return false;
             }
-          stringi_set_insert (mrset_names, lex_tokid (lexer));
+          stringi_set_insert (mrset_names, lex_tokcstr (lexer));
           lex_get (lexer);
         }
     }
@@ -535,8 +537,8 @@ parse_display (struct lexer *lexer, struct dictionary *dict)
   if (n == 0)
     {
       if (dict_get_n_mrsets (dict) == 0)
-        msg (SN, _("The active file dictionary does not contain any multiple "
-                   "response sets."));
+        msg (SN, _("The active dataset dictionary does not contain any "
+                   "multiple response sets."));
       stringi_set_destroy (&mrset_names_set);
       return true;
     }
@@ -577,8 +579,14 @@ parse_display (struct lexer *lexer, struct dictionary *dict)
           if (mrset->width == 0)
             ds_put_format (&details, "%.0f\n", mrset->counted.f);
           else
-            ds_put_format (&details, "`%.*s'\n", mrset->width,
-                           value_str (&mrset->counted, mrset->width));
+            {
+              const uint8_t *raw = value_str (&mrset->counted, mrset->width);
+              char *utf8 = recode_string ("UTF-8", dict_get_encoding (dict),
+                                          CHAR_CAST (const char *, raw),
+                                          mrset->width);
+              ds_put_format (&details, "`%s'\n", utf8);
+              free (utf8);
+            }
           ds_put_format (&details, "%s: %s\n", _("Category label source"),
                          (mrset->cat_source == MRSET_VARLABELS
                           ? _("Variable labels")
index 41f3c79a67b8bcc3ea5b1194f770a93535f86713..7b367f9d1d65cfa5373109adadf2707670ca2374 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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 <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <data/format.h>
-#include <language/command.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "data/format.h"
+#include "language/command.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -49,11 +49,12 @@ cmd_numeric (struct lexer *lexer, struct dataset *ds)
         be used. */
       struct fmt_spec f;
 
-      if (!parse_DATA_LIST_vars (lexer, &v, &nv, PV_NO_DUPLICATE))
+      if (!parse_DATA_LIST_vars (lexer, dataset_dict (ds),
+                                 &v, &nv, PV_NO_DUPLICATE))
        return CMD_FAILURE;
 
       /* Get the optional format specification. */
-      if (lex_match (lexer, '('))
+      if (lex_match (lexer, T_LPAREN))
        {
          if (!parse_format_specifier (lexer, &f))
            goto fail;
@@ -69,7 +70,7 @@ cmd_numeric (struct lexer *lexer, struct dataset *ds)
              goto fail;
            }
 
-         if (!lex_match (lexer, ')'))
+         if (!lex_match (lexer, T_RPAREN))
            {
              msg (SE, _("`)' expected after output format."));
              goto fail;
@@ -96,9 +97,9 @@ cmd_numeric (struct lexer *lexer, struct dataset *ds)
        free (v[i]);
       free (v);
     }
-  while (lex_match (lexer, '/'));
+  while (lex_match (lexer, T_SLASH));
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
   /* If we have an error at a point where cleanup is required,
      flow-of-control comes here. */
@@ -127,12 +128,13 @@ cmd_string (struct lexer *lexer, struct dataset *ds)
 
   do
     {
-      if (!parse_DATA_LIST_vars (lexer, &v, &nv, PV_NO_DUPLICATE))
+      if (!parse_DATA_LIST_vars (lexer, dataset_dict (ds),
+                                 &v, &nv, PV_NO_DUPLICATE))
        return CMD_FAILURE;
 
-      if (!lex_force_match (lexer, '(')
+      if (!lex_force_match (lexer, T_LPAREN)
           || !parse_format_specifier (lexer, &f)
-          || !lex_force_match (lexer, ')'))
+          || !lex_force_match (lexer, T_RPAREN))
        goto fail;
       if (!fmt_is_string (f.type))
        {
@@ -162,9 +164,9 @@ cmd_string (struct lexer *lexer, struct dataset *ds)
        free (v[i]);
       free (v);
     }
-  while (lex_match (lexer, '/'));
+  while (lex_match (lexer, T_SLASH));
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
   /* If we have an error at a point where cleanup is required,
      flow-of-control comes here. */
@@ -190,5 +192,5 @@ cmd_leave (struct lexer *lexer, struct dataset *ds)
     var_set_leave (v[i], true);
   free (v);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index ecd13aa536e8d536ec30195d6147122540806979..82fc1d96c8117a1c6823c4a4a8be057570a2d3a0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011 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 <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -53,7 +53,7 @@ cmd_rename_variables (struct lexer *lexer, struct dataset *ds)
       size_t prev_nv_1 = rename_cnt;
       size_t prev_nv_2 = rename_cnt;
 
-      if (!lex_match (lexer, '('))
+      if (!lex_match (lexer, T_LPAREN))
        {
          msg (SE, _("`(' expected."));
          goto lossage;
@@ -61,12 +61,13 @@ cmd_rename_variables (struct lexer *lexer, struct dataset *ds)
       if (!parse_variables (lexer, dataset_dict (ds), &rename_vars, &rename_cnt,
                            PV_APPEND | PV_NO_DUPLICATE))
        goto lossage;
-      if (!lex_match (lexer, '='))
+      if (!lex_match (lexer, T_EQUALS))
        {
          msg (SE, _("`=' expected between lists of new and old variable names."));
          goto lossage;
        }
-      if (!parse_DATA_LIST_vars (lexer, &rename_new_names, &prev_nv_1,
+      if (!parse_DATA_LIST_vars (lexer, dataset_dict (ds),
+                                 &rename_new_names, &prev_nv_1,
                                  PV_APPEND | PV_NO_DUPLICATE))
        goto lossage;
       if (prev_nv_1 != rename_cnt)
@@ -82,13 +83,13 @@ cmd_rename_variables (struct lexer *lexer, struct dataset *ds)
          rename_new_names = NULL;
          goto lossage;
        }
-      if (!lex_match (lexer, ')'))
+      if (!lex_match (lexer, T_RPAREN))
        {
          msg (SE, _("`)' expected after variable names."));
          goto lossage;
        }
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
 
   if (!dict_rename_vars (dataset_dict (ds),
                          rename_vars, rename_new_names, rename_cnt,
index d27ab3a65b3ab1b34c6c74b9a8cb1b011287a7a2..28e6860e07b6e9db003975cdb0e929880be651d6 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/data-out.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <output/tab.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/data-out.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "output/tab.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -59,7 +59,7 @@ cmd_split_file (struct lexer *lexer, struct dataset *ds)
       free (v);
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Dumps out the values of all the split variables for the case C. */
index 24130cbc30abfa4830aff59ff96f7023cd2284d1..596329516cf7a4c8504349dbb6cc64c45e641e4a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 <ctype.h>
 #include <stdlib.h>
 
-#include <data/attributes.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/format.h>
-#include <data/missing-values.h>
-#include <data/procedure.h>
-#include <data/sys-file-reader.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <data/vector.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <output/tab.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/attributes.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/sys-file-reader.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "data/vector.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/string-array.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -75,9 +75,9 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   int r, i;
 
   lex_match_id (lexer, "FILE");
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
-  h = fh_parse (lexer, FH_REF_FILE);
+  h = fh_parse (lexer, FH_REF_FILE, NULL);
   if (!h)
     return CMD_FAILURE;
 
@@ -138,8 +138,7 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
 
 
   tab_text (t, 0, 10, TAB_LEFT, _("Charset:"));
-  tab_text (t, 1, 10, TAB_LEFT,
-            dict_get_encoding(d) ? dict_get_encoding(d) : _("Unknown"));
+  tab_text (t, 1, 10, TAB_LEFT, dict_get_encoding (d));
 
 
   tab_submit (t);
@@ -164,7 +163,7 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   dict_destroy (d);
 
   fh_unref (h);
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 \f
 /* DISPLAY utility. */
@@ -195,12 +194,10 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
        return CMD_FAILURE;
       if (dict_get_label (dataset_dict (ds)) == NULL)
        tab_output_text (TAB_LEFT,
-                        _("The active file does not have a file label."));
+                        _("The active dataset does not have a file label."));
       else
-       {
-         tab_output_text (TAB_LEFT | TAT_TITLE, _("File label:"));
-         tab_output_text (TAB_LEFT | TAB_FIX, dict_get_label (dataset_dict (ds)));
-       }
+        tab_output_text_format (TAB_LEFT, _("File label: %s"),
+                                dict_get_label (dataset_dict (ds)));
     }
   else
     {
@@ -211,7 +208,7 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
       if (lex_match_id (lexer, "VECTORS"))
        {
          display_vectors (dataset_dict(ds), sorted);
-         return lex_end_of_command (lexer);
+         return CMD_SUCCESS;
        }
       else if (lex_match_id (lexer, "SCRATCH")) 
         {
@@ -247,11 +244,11 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
                 break;
               }
 
-          lex_match (lexer, '/');
+          lex_match (lexer, T_SLASH);
           lex_match_id (lexer, "VARIABLES");
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
-          if (lex_token (lexer) != '.')
+          if (lex_token (lexer) != T_ENDCMD)
             {
               if (!parse_variables_const (lexer, dataset_dict (ds), &vl, &n,
                                           PV_NONE))
@@ -281,7 +278,7 @@ cmd_display (struct lexer *lexer, struct dataset *ds)
                                       flags);
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 static void
@@ -293,24 +290,19 @@ display_macros (void)
 static void
 display_documents (const struct dictionary *dict)
 {
-  const char *documents = dict_get_documents (dict);
+  const struct string_array *documents = dict_get_documents (dict);
 
-  if (documents == NULL)
-    tab_output_text (TAB_LEFT, _("The active file dictionary does not "
+  if (string_array_is_empty (documents))
+    tab_output_text (TAB_LEFT, _("The active dataset dictionary does not "
                                  "contain any documents."));
   else
     {
-      struct string line = DS_EMPTY_INITIALIZER;
       size_t i;
 
       tab_output_text (TAB_LEFT | TAT_TITLE,
-                      _("Documents in the active file:"));
+                      _("Documents in the active dataset:"));
       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, ds_cstr (&line));
-        }
-      ds_destroy (&line);
+        tab_output_text (TAB_LEFT | TAB_FIX, dict_get_document_line (dict, i));
     }
 }
 
@@ -401,7 +393,7 @@ display_attributes (struct tab_table *t, const struct attrset *set, int flags,
       for (i = 0; i < n_values; i++)
         {
           if (n_values > 1)
-            tab_text_format (t, c, r, TAB_LEFT, "%s[%d]", name, i + 1);
+            tab_text_format (t, c, r, TAB_LEFT, "%s[%zu]", name, i + 1);
           else
             tab_text (t, c, r, TAB_LEFT, name);
           tab_text (t, c + 1, r, TAB_LEFT, attribute_get_value (attr, i));
@@ -589,19 +581,9 @@ describe_variable (const struct variable *v, struct tab_table *t, int r,
       for (i = 0; i < n_labels; i++)
         {
           const struct val_lab *vl = labels[i];
-         char buf[MAX_STRING + 1];
 
-         if (var_is_alpha (v))
-           {
-              int width = var_get_width (v);
-             memcpy (buf, value_str (&vl->value, width), width);
-             buf[width] = 0;
-           }
-         else
-           sprintf (buf, "%g", vl->value.f);
-
-         tab_text (t, 1, r, TAB_NONE, buf);
-         tab_text (t, 2, r, TAB_LEFT, val_lab_get_label (vl));
+         tab_value (t, 1, r, TAB_NONE, &vl->value, v, NULL);
+         tab_text (t, 2, r, TAB_LEFT, val_lab_get_escaped_label (vl));
          r++;
        }
       free (labels);
index 226518f261c02c91983845f420e3e2b72ca5ba34..2dfe0885bffb46a81ee33e01ad513f84d9ccd55e 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, 2011 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 <stdlib.h>
 
-#include <data/procedure.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/value-parser.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -39,7 +41,8 @@
 static int do_value_labels (struct lexer *,
                            const struct dictionary *dict, bool);
 static void erase_labels (struct variable **vars, size_t var_cnt);
-static int get_label (struct lexer *, struct variable **vars, size_t var_cnt);
+static int get_label (struct lexer *, struct variable **vars, size_t var_cnt,
+                      const char *dict_encoding);
 \f
 /* Stubs. */
 
@@ -64,9 +67,9 @@ do_value_labels (struct lexer *lexer, const struct dictionary *dict, bool erase)
   size_t var_cnt;         /* Number of variables. */
   int parse_err=0;        /* true if error parsing variables */
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       parse_err = !parse_variables (lexer, dict, &vars, &var_cnt,
                                    PV_SAME_WIDTH);
@@ -77,11 +80,11 @@ do_value_labels (struct lexer *lexer, const struct dictionary *dict, bool erase)
        }
       if (erase)
         erase_labels (vars, var_cnt);
-      while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
-       if (!get_label (lexer, vars, var_cnt))
+      while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
+       if (!get_label (lexer, vars, var_cnt, dict_get_encoding (dict)))
           goto lossage;
 
-      if (lex_token (lexer) != '/')
+      if (lex_token (lexer) != T_SLASH)
        {
           free (vars);
           break;
@@ -92,10 +95,7 @@ do_value_labels (struct lexer *lexer, const struct dictionary *dict, bool erase)
       free (vars);
     }
 
-  if (parse_err)
-    return CMD_FAILURE;
-
-  return lex_end_of_command (lexer);
+  return parse_err ? CMD_FAILURE : CMD_SUCCESS;
 
  lossage:
   free (vars);
@@ -116,24 +116,27 @@ erase_labels (struct variable **vars, size_t var_cnt)
 /* Parse all the labels for the VAR_CNT variables in VARS and add
    the specified labels to those variables.  */
 static int
-get_label (struct lexer *lexer, struct variable **vars, size_t var_cnt)
+get_label (struct lexer *lexer, struct variable **vars, size_t var_cnt,
+           const char *dict_encoding)
 {
   /* Parse all the labels and add them to the variables. */
   do
     {
+      enum { MAX_LABEL_LEN = 255 };
       int width = var_get_width (vars[0]);
       union value value;
       struct string label;
+      size_t trunc_len;
       size_t i;
 
       /* Set value. */
       value_init (&value, width);
-      if (!parse_value (lexer, &value, width))
+      if (!parse_value (lexer, &value, vars[0]))
         {
           value_destroy (&value, width);
           return 0;
         }
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
 
       /* Set label. */
       if (lex_token (lexer) != T_ID && !lex_force_string (lexer))
@@ -142,12 +145,14 @@ get_label (struct lexer *lexer, struct variable **vars, size_t var_cnt)
           return 0;
         }
 
-      ds_init_string (&label, lex_tokstr (lexer));
+      ds_init_substring (&label, lex_tokss (lexer));
 
-      if (ds_length (&label) > 60)
+      trunc_len = utf8_encoding_trunc_len (ds_cstr (&label), dict_encoding,
+                                           MAX_LABEL_LEN);
+      if (ds_length (&label) > trunc_len)
        {
-         msg (SW, _("Truncating value label to 60 characters."));
-         ds_truncate (&label, 60);
+         msg (SW, _("Truncating value label to %d bytes."), MAX_LABEL_LEN);
+         ds_truncate (&label, trunc_len);
        }
 
       for (i = 0; i < var_cnt; i++)
@@ -157,9 +162,9 @@ get_label (struct lexer *lexer, struct variable **vars, size_t var_cnt)
       value_destroy (&value, width);
 
       lex_get (lexer);
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
-  while (lex_token (lexer) != '/' && lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD);
 
   return 1;
 }
index 83df065b99728e58745ffc72b08742a562b62e55..1ff5f465200a549c678c4c6eb17133079a7dc9ce 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, 2011 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 <stdlib.h>
 
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -51,7 +51,7 @@ cmd_variable_alignment (struct lexer *lexer, struct dataset *ds)
       if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
         return CMD_FAILURE;
 
-      if ( lex_force_match (lexer, '(') )
+      if ( lex_force_match (lexer, T_LPAREN) )
        {
          if ( lex_match_id (lexer, "LEFT"))
            align = ALIGN_LEFT;
@@ -65,7 +65,7 @@ cmd_variable_alignment (struct lexer *lexer, struct dataset *ds)
               return CMD_FAILURE;
             }
 
-         lex_force_match (lexer, ')');
+         lex_force_match (lexer, T_RPAREN);
        }
       else
         {
@@ -76,12 +76,12 @@ cmd_variable_alignment (struct lexer *lexer, struct dataset *ds)
       for( i = 0 ; i < nv ; ++i )
         var_set_alignment (v[i], align);
 
-      while (lex_token (lexer) == '/')
+      while (lex_token (lexer) == T_SLASH)
        lex_get (lexer);
       free (v);
 
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
 
@@ -102,14 +102,14 @@ cmd_variable_width (struct lexer *lexer, struct dataset *ds)
       if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
         return CMD_FAILURE;
 
-      if (!lex_force_match (lexer, '(') || !lex_force_int (lexer))
+      if (!lex_force_match (lexer, T_LPAREN) || !lex_force_int (lexer))
         {
           free (v);
           return CMD_FAILURE;
         }
       width = lex_integer (lexer);
       lex_get (lexer);
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         {
           free (v);
           return CMD_FAILURE;
@@ -126,12 +126,12 @@ cmd_variable_width (struct lexer *lexer, struct dataset *ds)
       for( i = 0 ; i < nv ; ++i )
         var_set_display_width (v[i], width);
 
-      while (lex_token (lexer) == '/')
+      while (lex_token (lexer) == T_SLASH)
        lex_get (lexer);
       free (v);
 
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
 
@@ -149,7 +149,7 @@ cmd_variable_level (struct lexer *lexer, struct dataset *ds)
       if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
         return CMD_FAILURE;
 
-      if ( lex_force_match (lexer, '(') )
+      if ( lex_force_match (lexer, T_LPAREN) )
        {
          if ( lex_match_id (lexer, "SCALE"))
            level = MEASURE_SCALE;
@@ -163,7 +163,7 @@ cmd_variable_level (struct lexer *lexer, struct dataset *ds)
               return CMD_FAILURE;
             }
 
-         lex_force_match (lexer, ')');
+         lex_force_match (lexer, T_RPAREN);
        }
       else
         {
@@ -175,11 +175,11 @@ cmd_variable_level (struct lexer *lexer, struct dataset *ds)
        var_set_measure (v[i], level);
 
 
-      while (lex_token (lexer) == '/')
+      while (lex_token (lexer) == T_SLASH)
        lex_get (lexer);
       free (v);
 
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
index fbf7e200ee3a4d89876b3b6f1a21e37292923a55..bceb84994eeacf5e678f97e3e212b9df213e9f37 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, 2011 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 <stdlib.h>
 
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 int
 cmd_variable_labels (struct lexer *lexer, struct dataset *ds)
 {
+  struct dictionary *dict = dataset_dict (ds);
+
   do
     {
       struct variable **v;
-      struct string label;
       size_t nv;
 
       size_t i;
 
-      if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
+      if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
         return CMD_FAILURE;
 
       if (!lex_force_string (lexer))
@@ -52,22 +53,15 @@ cmd_variable_labels (struct lexer *lexer, struct dataset *ds)
          return CMD_FAILURE;
        }
 
-      ds_init_string (&label, lex_tokstr (lexer) );
-      if (ds_length (&label) > 255)
-       {
-         msg (SW, _("Truncating variable label to 255 characters."));
-         ds_truncate (&label, 255);
-       }
       for (i = 0; i < nv; i++)
-        var_set_label (v[i], ds_cstr (&label));
-      ds_destroy (&label);
+        var_set_label (v[i], lex_tokcstr (lexer), i == 0);
 
       lex_get (lexer);
-      while (lex_token (lexer) == '/')
+      while (lex_token (lexer) == T_SLASH)
        lex_get (lexer);
       free (v);
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
 
index 1a616ab27ad858170f96ae7e99af12a91fe79c31..b0d696154b7f212a5c790a87efe7d69b1debd31a 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, 2011 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 <stdlib.h>
 
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "intprops.h"
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/format.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/intprops.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -50,7 +50,8 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
       size_t vector_cnt, vector_cap;
 
       /* Get the name(s) of the new vector(s). */
-      if (!lex_force_id (lexer))
+      if (!lex_force_id (lexer)
+          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
        return CMD_CASCADING_FAILURE;
 
       vectors = NULL;
@@ -59,33 +60,33 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
        {
           size_t i;
 
-         if (dict_lookup_vector (dict, lex_tokid (lexer)))
+         if (dict_lookup_vector (dict, lex_tokcstr (lexer)))
            {
              msg (SE, _("A vector named %s already exists."),
-                   lex_tokid (lexer));
+                   lex_tokcstr (lexer));
              goto fail;
            }
 
           for (i = 0; i < vector_cnt; i++)
-            if (!strcasecmp (vectors[i], lex_tokid (lexer)))
+            if (!strcasecmp (vectors[i], lex_tokcstr (lexer)))
              {
                msg (SE, _("Vector name %s is given twice."),
-                     lex_tokid (lexer));
+                     lex_tokcstr (lexer));
                goto fail;
              }
 
           if (vector_cnt == vector_cap)
             vectors = pool_2nrealloc (pool,
                                        vectors, &vector_cap, sizeof *vectors);
-          vectors[vector_cnt++] = pool_strdup (pool, lex_tokid (lexer));
+          vectors[vector_cnt++] = pool_strdup (pool, lex_tokcstr (lexer));
 
          lex_get (lexer);
-         lex_match (lexer, ',');
+         lex_match (lexer, T_COMMA);
        }
 
       /* Now that we have the names it's time to check for the short
          or long forms. */
-      if (lex_match (lexer, '='))
+      if (lex_match (lexer, T_EQUALS))
        {
          /* Long form. */
           struct variable **v;
@@ -104,7 +105,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
 
           dict_create_vector (dict, vectors[0], v, nv);
        }
-      else if (lex_match (lexer, '('))
+      else if (lex_match (lexer, T_LPAREN))
        {
           /* Short form. */
           struct fmt_spec format;
@@ -118,7 +119,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
           var_cnt = 0;
           format = fmt_for_output (FMT_F, 8, 2);
           seen_format = false;
-          while (!lex_match (lexer, ')'))
+          while (!lex_match (lexer, T_RPAREN))
             {
               if (lex_is_integer (lexer) && var_cnt == 0)
                 {
@@ -143,7 +144,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
                   lex_error (lexer, NULL);
                   goto fail;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
           if (var_cnt == 0)
             {
@@ -151,26 +152,26 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
               goto fail;
             }
 
-         /* Check that none of the variables exist and that
-             their names are no more than VAR_NAME_LEN bytes
-             long. */
+         /* Check that none of the variables exist and that their names are
+             not excessively long. */
           for (i = 0; i < vector_cnt; i++)
            {
               int j;
              for (j = 0; j < var_cnt; j++)
                {
-                  char name[VAR_NAME_LEN + INT_STRLEN_BOUND (int) + 1];
-                 sprintf (name, "%s%d", vectors[i], j + 1);
-                  if (strlen (name) > VAR_NAME_LEN)
+                  char *name = xasprintf ("%s%d", vectors[i], j + 1);
+                  if (!dict_id_is_valid (dict, name, true))
                     {
-                      msg (SE, _("%s is too long for a variable name."), name);
+                      free (name);
                       goto fail;
                     }
                   if (dict_lookup_var (dict, name))
                    {
+                      free (name);
                      msg (SE, _("%s is an existing variable name."), name);
                      goto fail;
                    }
+                  free (name);
                }
            }
 
@@ -181,10 +182,10 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
               int j;
              for (j = 0; j < var_cnt; j++)
                {
-                  char name[VAR_NAME_LEN + 1];
-                 sprintf (name, "%s%d", vectors[i], j + 1);
+                  char *name = xasprintf ("%s%d", vectors[i], j + 1);
                  vars[j] = dict_create_var_assert (dict, name, 0);
                   var_set_both_formats (vars[j], &format);
+                  free (name);
                }
               dict_create_vector_assert (dict, vectors[i], vars, var_cnt);
            }
@@ -195,10 +196,10 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
          goto fail;
        }
     }
-  while (lex_match (lexer, '/'));
+  while (lex_match (lexer, T_SLASH));
 
   pool_destroy (pool);
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
 fail:
   pool_destroy (pool);
index 7e25a64602511bba21b7e605767f30f7cfe7e139..185165dcbbfdb1cfe42e2bd0872e748432ff955a 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, 2011 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 <data/procedure.h>
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -58,5 +58,5 @@ cmd_weight (struct lexer *lexer, struct dataset *ds)
       dict_set_weight (dict, v);
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index 65404b43e4d4d6a725a57794811291881890d4c7..1736ab80e8f8b942832bf490875b2568279fb87f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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 "evaluate.h"
+
+#include "language/expressions/evaluate.h"
 
 #include <ctype.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <language/expressions/helpers.h>
-#include <language/expressions/private.h>
-#include <language/lexer/value-parser.h>
-#include <libpspp/pool.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "language/expressions/helpers.h"
+#include "language/expressions/private.h"
+#include "language/lexer/value-parser.h"
+#include "libpspp/pool.h"
 
 #include "xalloc.h"
 
@@ -102,8 +104,8 @@ expr_evaluate_str (struct expression *e, const struct ccase *c, int case_idx,
   buf_copy_rpad (dst, dst_size, s.string, s.length, ' ');
 }
 \f
-#include <language/lexer/lexer.h>
-#include <language/command.h>
+#include "language/lexer/lexer.h"
+#include "language/command.h"
 
 int
 cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
@@ -116,6 +118,8 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
 
   struct dataset *ds = NULL;
 
+  char *name = NULL;
+
   struct expression *expr;
 
   for (;;)
@@ -125,25 +129,24 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
         optimize = 0;
       else if (lex_match_id (lexer, "POSTFIX"))
         dump_postfix = 1;
-      else if (lex_match (lexer, '('))
+      else if (lex_match (lexer, T_LPAREN))
         {
-          char name[VAR_NAME_LEN + 1];
           struct variable *v;
           size_t old_value_cnt;
           int width;
 
           if (!lex_force_id (lexer))
             goto done;
-          strcpy (name, lex_tokid (lexer));
+          name = xstrdup (lex_tokcstr (lexer));
 
           lex_get (lexer);
-          if (!lex_force_match (lexer, '='))
+          if (!lex_force_match (lexer, T_EQUALS))
             goto done;
 
           if (lex_is_number (lexer))
             width = 0;
           else if (lex_is_string (lexer))
-            width = ds_length (lex_tokstr (lexer));
+            width = ss_length (lex_tokss (lexer));
           else
             {
               lex_error (lexer, _("expecting number or string"));
@@ -152,7 +155,7 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
 
          if  ( ds == NULL )
            {
-             ds = create_dataset ();
+             ds = dataset_create (NULL, "");
              d = dataset_dict (ds);
            }
 
@@ -163,24 +166,26 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
               msg (SE, _("Duplicate variable name %s."), name);
               goto done;
             }
+          free (name);
+          name = NULL;
 
           if (c == NULL)
             c = case_create (dict_get_proto (d));
           else
             c = case_unshare_and_resize (c, dict_get_proto (d));
 
-          if (!parse_value (lexer, case_data_rw (c, v), var_get_width (v)))
+          if (!parse_value (lexer, case_data_rw (c, v), v))
             NOT_REACHED ();
 
-          if (!lex_force_match (lexer, ')'))
+          if (!lex_force_match (lexer, T_RPAREN))
             goto done;
         }
       else
         break;
     }
-  if (lex_token (lexer) != '/')
+  if (lex_token (lexer) != T_SLASH)
     {
-      lex_force_match (lexer, '/');
+      lex_force_match (lexer, T_SLASH);
       goto done;
     }
 
@@ -237,11 +242,12 @@ cmd_debug_evaluate (struct lexer *lexer, struct dataset *dsother UNUSED)
   retval = CMD_SUCCESS;
 
  done:
-  if (ds)
-    destroy_dataset (ds);
+  dataset_destroy (ds);
 
   case_unref (c);
 
+  free (name);
+
   return retval;
 }
 
index ac17c1cece19ce842bde63ae9495daac3d6e0109..7c3371f5db97eb9daf3455c943014a035d178408 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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 "helpers.h"
+
+#include "language/expressions/helpers.h"
+
 #include <gsl/gsl_roots.h>
 #include <gsl/gsl_sf.h>
-#include <libpspp/assertion.h>
-#include <libpspp/pool.h>
-#include "private.h"
+
+#include "language/expressions/private.h"
+#include "libpspp/assertion.h"
+#include "libpspp/pool.h"
 
 const struct substring empty_string = {NULL, 0};
 
index cb59c206a7599334246402cc26265854562d8483..ef4fdadd4d310c2842fbaba74e0cfec2ef335b91 100644 (file)
 #include <math.h>
 #include <stdbool.h>
 
-#include <data/calendar.h>
-#include <data/case.h>
-#include <data/data-in.h>
-#include <data/data-out.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <data/vector.h>
-#include <language/expressions/public.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <math/moments.h>
-#include <math/random.h>
+#include "data/calendar.h"
+#include "data/case.h"
+#include "data/data-in.h"
+#include "data/data-out.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "data/vector.h"
+#include "language/expressions/public.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "math/moments.h"
+#include "math/random.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 0286acf91e393d917a1259181165d4c8c88c8934..207551b7eaf9c16c39bc0cec1c48173b396e3c7f 100644 (file)
@@ -1,7 +1,7 @@
 // -*- c -*-
 //
 // PSPP - a program for statistical analysis.
-// Copyright (C) 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
+// Copyright (C) 2005, 2006, 2009, 2010, 2011 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
@@ -585,12 +585,12 @@ function NUMBER (string s, ni_format f)
 
   if (s.length > f->w)
     s.length = f->w;
-  error = data_in (s, LEGACY_NATIVE, f->type, &out, 0, NULL);
+  error = data_in (s, C_ENCODING, f->type, &out, 0, NULL);
   if (error == NULL)
-  data_in_imply_decimals (s, LEGACY_NATIVE, f->type, f->d, &out);
+    data_in_imply_decimals (s, C_ENCODING, f->type, f->d, &out);
   else
     {
-      msg (SE, "Cannot parse \"%.*s\" as format %s: %s",
+      msg (SE, "Cannot parse `%.*s' as format %s: %s",
            (int) s.length, s.string, fmt_name (f->type), error);
       free (error);
     }
@@ -607,7 +607,7 @@ absorb_miss string function STRING (x, no_format f)
   v.f = x;
 
   assert (!fmt_is_string (f->type));
-  s = data_out (&v, LEGACY_NATIVE, f);
+  s = data_out (&v, C_ENCODING, f);
   dst = alloc_string (e, strlen (s));
   strcpy (dst.string, s);
   free (s);
index b0abd946c57b9868b6346f77d45d68cf5a45ccc3..8f090778ab9c80a20fc6f44a24e7a7ba5b5d21aa 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, 2011 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 "private.h"
+
+#include "language/expressions/private.h"
+
 #include <math.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
-#include <libpspp/assertion.h>
-#include <data/calendar.h>
-#include <data/data-in.h>
-#include <libpspp/message.h>
-#include "evaluate.h"
-#include "helpers.h"
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include "public.h"
-#include <libpspp/str.h>
-#include <data/variable.h>
-
-#include "xalloc.h"
+
+#include "data/calendar.h"
+#include "data/data-in.h"
+#include "data/variable.h"
+#include "language/expressions/evaluate.h"
+#include "language/expressions/helpers.h"
+#include "language/expressions/public.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 static union any_node *evaluate_tree (struct composite_node *,
                                       struct expression *);
index f2b4f1c78b4cc2b4a85f6ea752e74990d19c952b..ed5a07093c712b3b034b82f71d6af1fbdc4db0fd 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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 <limits.h>
 #include <stdlib.h>
 
-#include "helpers.h"
-#include <data/case.h>
-#include <data/dictionary.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "language/expressions/helpers.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 \f
 /* Declarations. */
 
@@ -499,16 +500,14 @@ match_operator (struct lexer *lexer, const struct operator ops[], size_t op_cnt,
   const struct operator *op;
 
   for (op = ops; op < ops + op_cnt; op++)
-    {
-      if (op->token == '-')
-        lex_negative_to_dash (lexer);
-      if (lex_match (lexer, op->token))
-        {
-          if (operator != NULL)
-            *operator = op;
-          return true;
-        }
-    }
+    if (lex_token (lexer) == op->token)
+      {
+        if (op->token != T_NEG_NUM)
+          lex_get (lexer);
+        if (operator != NULL)
+          *operator = op;
+        return true;
+      }
   if (operator != NULL)
     *operator = NULL;
   return false;
@@ -665,7 +664,7 @@ parse_rel (struct lexer *lexer, struct expression *e)
       {
         static const struct operator ops[] =
           {
-            { '=', OP_EQ, "numeric equality (`=')" },
+            { T_EQUALS, OP_EQ, "numeric equality (`=')" },
             { T_EQ, OP_EQ, "numeric equality (`EQ')" },
             { T_GE, OP_GE, "numeric greater-than-or-equal-to (`>=')" },
             { T_GT, OP_GT, "numeric greater than (`>')" },
@@ -683,7 +682,7 @@ parse_rel (struct lexer *lexer, struct expression *e)
       {
         static const struct operator ops[] =
           {
-            { '=', OP_EQ_STRING, "string equality (`=')" },
+            { T_EQUALS, OP_EQ_STRING, "string equality (`=')" },
             { T_EQ, OP_EQ_STRING, "string equality (`EQ')" },
             { T_GE, OP_GE_STRING, "string greater-than-or-equal-to (`>=')" },
             { T_GT, OP_GT_STRING, "string greater than (`>')" },
@@ -708,8 +707,9 @@ parse_add (struct lexer *lexer, struct expression *e)
 {
   static const struct operator ops[] =
     {
-      { '+', OP_ADD, "addition (`+')" },
-      { '-', OP_SUB, "subtraction (`-')" },
+      { T_PLUS, OP_ADD, "addition (`+')" },
+      { T_DASH, OP_SUB, "subtraction (`-')" },
+      { T_NEG_NUM, OP_ADD, "subtraction (`-')" },
     };
 
   return parse_binary_operators (lexer, e, parse_mul (lexer, e),
@@ -723,8 +723,8 @@ parse_mul (struct lexer *lexer, struct expression *e)
 {
   static const struct operator ops[] =
     {
-      { '*', OP_MUL, "multiplication (`*')" },
-      { '/', OP_DIV, "division (`/')" },
+      { T_ASTERISK, OP_MUL, "multiplication (`*')" },
+      { T_SLASH, OP_DIV, "division (`/')" },
     };
 
   return parse_binary_operators (lexer, e, parse_neg (lexer, e),
@@ -736,7 +736,7 @@ parse_mul (struct lexer *lexer, struct expression *e)
 static union any_node *
 parse_neg (struct lexer *lexer, struct expression *e)
 {
-  static const struct operator op = { '-', OP_NEG, "negation (`-')" };
+  static const struct operator op = { T_DASH, OP_NEG, "negation (`-')" };
   return parse_inverting_unary_operator (lexer, e, &op, parse_exp);
 }
 
@@ -752,8 +752,21 @@ parse_exp (struct lexer *lexer, struct expression *e)
       "That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'.  "
       "To disable this warning, insert parentheses.");
 
-  return parse_binary_operators (lexer, e, parse_primary (lexer, e), &op, 1,
-                                 parse_primary, chain_warning);
+  union any_node *lhs, *node;
+  bool negative = false;
+
+  if (lex_token (lexer) == T_NEG_NUM)
+    {
+      lhs = expr_allocate_number (e, -lex_tokval (lexer));
+      negative = true;
+      lex_get (lexer);
+    }
+  else
+    lhs = parse_primary (lexer, e);
+
+  node = parse_binary_operators (lexer, e, lhs, &op, 1,
+                                  parse_primary, chain_warning);
+  return negative ? expr_allocate_unary (e, OP_NEG, node) : node;
 }
 
 /* Parses system variables. */
@@ -773,12 +786,14 @@ parse_sysvar (struct lexer *lexer, struct expression *e)
       time_t last_proc_time = time_of_last_procedure (e->ds);
       struct tm *time;
       char temp_buf[10];
+      struct substring s;
 
       time = localtime (&last_proc_time);
       sprintf (temp_buf, "%02d %s %02d", abs (time->tm_mday) % 100,
                months[abs (time->tm_mon) % 12], abs (time->tm_year) % 100);
 
-      return expr_allocate_string_buffer (e, temp_buf, strlen (temp_buf));
+      ss_alloc_substring (&s, ss_cstr (temp_buf));
+      return expr_allocate_string (e, s);
     }
   else if (lex_match_id (lexer, "$TRUE"))
     return expr_allocate_boolean (e, 1.0);
@@ -812,7 +827,7 @@ parse_sysvar (struct lexer *lexer, struct expression *e)
     return expr_allocate_number (e, settings_get_viewwidth ());
   else
     {
-      msg (SE, _("Unknown system variable %s."), lex_tokid (lexer));
+      msg (SE, _("Unknown system variable %s."), lex_tokcstr (lexer));
       return NULL;
     }
 }
@@ -824,22 +839,22 @@ parse_primary (struct lexer *lexer, struct expression *e)
   switch (lex_token (lexer))
     {
     case T_ID:
-      if (lex_look_ahead (lexer) == '(')
+      if (lex_next_token (lexer, 1) == T_LPAREN)
         {
           /* An identifier followed by a left parenthesis may be
              a vector element reference.  If not, it's a function
              call. */
-          if (e->ds != NULL && dict_lookup_vector (dataset_dict (e->ds), lex_tokid (lexer)) != NULL)
+          if (e->ds != NULL && dict_lookup_vector (dataset_dict (e->ds), lex_tokcstr (lexer)) != NULL)
             return parse_vector_element (lexer, e);
           else
             return parse_function (lexer, e);
         }
-      else if (lex_tokid (lexer)[0] == '$')
+      else if (lex_tokcstr (lexer)[0] == '$')
         {
           /* $ at the beginning indicates a system variable. */
           return parse_sysvar (lexer, e);
         }
-      else if (e->ds != NULL && dict_lookup_var (dataset_dict (e->ds), lex_tokid (lexer)))
+      else if (e->ds != NULL && dict_lookup_var (dataset_dict (e->ds), lex_tokcstr (lexer)))
         {
           /* It looks like a user variable.
              (It could be a format specifier, but we'll assume
@@ -860,7 +875,7 @@ parse_primary (struct lexer *lexer, struct expression *e)
             return expr_allocate_format (e, &fmt);
 
           /* All attempts failed. */
-          msg (SE, _("Unknown identifier %s."), lex_tokid (lexer));
+          msg (SE, _("Unknown identifier %s."), lex_tokcstr (lexer));
           return NULL;
         }
       break;
@@ -875,18 +890,27 @@ parse_primary (struct lexer *lexer, struct expression *e)
 
     case T_STRING:
       {
-        union any_node *node = expr_allocate_string_buffer (
-          e, ds_cstr (lex_tokstr (lexer) ), ds_length (lex_tokstr (lexer) ));
+        const char *dict_encoding;
+        union any_node *node;
+        char *s;
+
+        dict_encoding = (e->ds != NULL
+                         ? dict_get_encoding (dataset_dict (e->ds))
+                         : "UTF-8");
+        s = recode_string (dict_encoding, "UTF-8", lex_tokcstr (lexer),
+                           ss_length (lex_tokss (lexer)));
+        node = expr_allocate_string (e, ss_cstr (s));
+
        lex_get (lexer);
        return node;
       }
 
-    case '(':
+    case T_LPAREN:
       {
         union any_node *node;
        lex_get (lexer);
        node = parse_or (lexer, e);
-       if (node != NULL && !lex_force_match (lexer, ')'))
+       if (node != NULL && !lex_force_match (lexer, T_RPAREN))
           return NULL;
         return node;
       }
@@ -906,19 +930,19 @@ parse_vector_element (struct lexer *lexer, struct expression *e)
   /* Find vector, skip token.
      The caller must already have verified that the current token
      is the name of a vector. */
-  vector = dict_lookup_vector (dataset_dict (e->ds), lex_tokid (lexer));
+  vector = dict_lookup_vector (dataset_dict (e->ds), lex_tokcstr (lexer));
   assert (vector != NULL);
   lex_get (lexer);
 
   /* Skip left parenthesis token.
      The caller must have verified that the lookahead is a left
      parenthesis. */
-  assert (lex_token (lexer) == '(');
+  assert (lex_token (lexer) == T_LPAREN);
   lex_get (lexer);
 
   element = parse_or (lexer, e);
   if (!type_coercion (e, OP_number, &element, "vector indexing")
-      || !lex_match (lexer, ')'))
+      || !lex_match (lexer, T_RPAREN))
     return NULL;
 
   return expr_allocate_binary (e, (vector_get_type (vector) == VAL_NUMERIC
@@ -1021,7 +1045,7 @@ lookup_function (const char *name,
 }
 
 static int
-extract_min_valid (char *s)
+extract_min_valid (const char *s)
 {
   char *p = strrchr (s, '.');
   if (p == NULL
@@ -1149,7 +1173,7 @@ put_invocation (struct string *s,
         ds_put_cstr (s, ", ");
       ds_put_cstr (s, operations[expr_node_returns (args[i])].prototype);
     }
-  ds_put_char (s, ')');
+  ds_put_byte (s, ')');
 }
 
 static void
@@ -1176,7 +1200,7 @@ no_match (const char *func_name,
       for (f = first; f < last; f++)
         ds_put_format (&s, "\n%s", f->prototype);
     }
-  ds_put_char (&s, '.');
+  ds_put_byte (&s, '.');
 
   msg (SE, "%s", ds_cstr (&s));
 
@@ -1197,17 +1221,17 @@ parse_function (struct lexer *lexer, struct expression *e)
 
   union any_node *n;
 
-  ds_init_string (&func_name, lex_tokstr (lexer));
-  min_valid = extract_min_valid (ds_cstr (lex_tokstr (lexer)));
-  if (!lookup_function (ds_cstr (lex_tokstr (lexer)), &first, &last))
+  ds_init_substring (&func_name, lex_tokss (lexer));
+  min_valid = extract_min_valid (lex_tokcstr (lexer));
+  if (!lookup_function (lex_tokcstr (lexer), &first, &last))
     {
-      msg (SE, _("No function or vector named %s."), ds_cstr (lex_tokstr (lexer)));
+      msg (SE, _("No function or vector named %s."), lex_tokcstr (lexer));
       ds_destroy (&func_name);
       return NULL;
     }
 
   lex_get (lexer);
-  if (!lex_force_match (lexer, '('))
+  if (!lex_force_match (lexer, T_LPAREN))
     {
       ds_destroy (&func_name);
       return NULL;
@@ -1215,11 +1239,11 @@ parse_function (struct lexer *lexer, struct expression *e)
 
   args = NULL;
   arg_cnt = arg_cap = 0;
-  if (lex_token (lexer) != ')')
+  if (lex_token (lexer) != T_RPAREN)
     for (;;)
       {
         if (lex_token (lexer) == T_ID
-            && toupper (lex_look_ahead (lexer)) == 'T')
+            && lex_next_token (lexer, 1) == T_TO)
           {
             const struct variable **vars;
             size_t var_cnt;
@@ -1240,9 +1264,9 @@ parse_function (struct lexer *lexer, struct expression *e)
 
             add_arg (&args, &arg_cnt, &arg_cap, arg);
           }
-        if (lex_match (lexer, ')'))
+        if (lex_match (lexer, T_RPAREN))
           break;
-        else if (!lex_match (lexer, ','))
+        else if (!lex_match (lexer, T_COMMA))
           {
             lex_error (lexer, _("expecting `,' or `)' invoking %s function"),
                        first->name);
@@ -1461,18 +1485,6 @@ expr_allocate_vector (struct expression *e, const struct vector *vector)
   return n;
 }
 
-union any_node *
-expr_allocate_string_buffer (struct expression *e,
-                             const char *string, size_t length)
-{
-  union any_node *n = pool_alloc (e->expr_pool, sizeof n->string);
-  n->type = OP_string;
-  if (length > MAX_STRING)
-    length = MAX_STRING;
-  n->string.s = copy_string (e, string, length);
-  return n;
-}
-
 union any_node *
 expr_allocate_string (struct expression *e, struct substring s)
 {
index 4283b4ae694236d6118eb48c9890cfc26b70fd5c..062d6f765185be6de3145397e4c30e7ae212394c 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, 2011 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 <assert.h>
 #include <stddef.h>
-#include <libpspp/str.h>
 
-#include "public.h"
-#include "operations.h"
-
-#include <data/format.h>
+#include "data/format.h"
+#include "language/expressions/operations.h"
+#include "language/expressions/public.h"
+#include "libpspp/str.h"
 
 enum operation_flags
   {
@@ -188,10 +187,7 @@ union any_node *expr_allocate_number (struct expression *e, double);
 union any_node *expr_allocate_boolean (struct expression *e, double);
 union any_node *expr_allocate_integer (struct expression *e, int);
 union any_node *expr_allocate_pos_int (struct expression *e, int);
-union any_node *expr_allocate_string_buffer (struct expression *e,
-                                             const char *string, size_t length);
-union any_node *expr_allocate_string (struct expression *e,
-                                      struct substring);
+union any_node *expr_allocate_string (struct expression *e, struct substring);
 union any_node *expr_allocate_variable (struct expression *e,
                                         const struct variable *);
 union any_node *expr_allocate_format (struct expression *e,
index aff3f2a2879d97869affded7a2f260401e657751..11771a248d5b7036cf3ea54b6ac435ca39852aee 100644 (file)
@@ -2,11 +2,22 @@
 
 
 language_lexer_sources = \
-       src/language/lexer/lexer.c  src/language/lexer/lexer.h \
+       src/language/lexer/command-name.c \
+       src/language/lexer/command-name.h \
+       src/language/lexer/include-path.c \
+       src/language/lexer/include-path.h \
+       src/language/lexer/lexer.c \
+       src/language/lexer/lexer.h \
        src/language/lexer/subcommand-list.c  \
        src/language/lexer/subcommand-list.h \
        src/language/lexer/format-parser.c \
        src/language/lexer/format-parser.h \
+       src/language/lexer/scan.c \
+       src/language/lexer/scan.h \
+       src/language/lexer/segment.c \
+       src/language/lexer/segment.h \
+       src/language/lexer/token.c \
+       src/language/lexer/token.h \
        src/language/lexer/value-parser.c \
        src/language/lexer/value-parser.h \
        src/language/lexer/variable-parser.c \
diff --git a/src/language/lexer/command-name.c b/src/language/lexer/command-name.c
new file mode 100644 (file)
index 0000000..8ef64d9
--- /dev/null
@@ -0,0 +1,235 @@
+/* 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 "language/lexer/command-name.h"
+
+#include <assert.h>
+#include <limits.h>
+
+#include "data/identifier.h"
+
+#include "gl/c-ctype.h"
+
+/* Stores the first word in S into WORD and advances S past that word.  Returns
+   true if successful, false if no word remained in S to be extracted.
+
+   A word is a sequence of digits, a letter possibly followed by a sequence of
+   letters or digits, or one character of another type.  Words may be delimited
+   by spaces. */
+static bool
+find_word (struct substring *s, struct substring *word)
+{
+  size_t ofs;
+  ucs4_t c;
+
+  /* Skip whitespace. */
+  for (;;)
+    {
+      c = ss_first_mb (*s);
+      if (c == UINT32_MAX)
+        {
+          *word = ss_empty ();
+          return false;
+        }
+      else if (lex_uc_is_space (c))
+        ss_get_mb (s);
+      else
+        break;
+    }
+
+  ofs = ss_first_mblen (*s);
+  if (lex_uc_is_id1 (c))
+    {
+      while (lex_uc_is_idn (ss_at_mb (*s, ofs)))
+        ofs += ss_at_mblen (*s, ofs);
+    }
+  else if (c_isdigit (c))
+    {
+      while (c_isdigit (s->string[ofs]))
+        ofs++;
+    }
+  ss_get_bytes (s, ofs, word);
+  return true;
+}
+
+/* Returns the number of words in S, as extracted by find_word(). */
+static int
+count_words (struct substring s)
+{
+  struct substring word;
+  int n;
+
+  n = 0;
+  while (find_word (&s, &word))
+    n++;
+  return n;
+}
+
+/* Compares STRING obtained from the user against the full name of a COMMAND,
+   using this algorithm:
+
+   1. Divide COMMAND into words C[0] through C[n - 1].
+
+   2. Divide STRING into words S[0] through S[m - 1].
+
+   3. Compare word C[i] against S[i] for 0 <= i < min(n, m), using the keyword
+      matching algorithm implemented by lex_id_match().  If any of them fail to
+      match, then STRING does not match COMMAND and the function returns false.
+
+   4. Otherwise, STRING and COMMAND match.  Set *MISSING_WORDS to n - m.  Set
+      *EXACT to false if any of the S[i] were found to be abbreviated in the
+      comparisons done in step 3, or to true if they were all exactly equal
+      (modulo case).  Return true. */
+bool
+command_match (struct substring command, struct substring string,
+               bool *exact, int *missing_words)
+{
+  *exact = true;
+  for (;;)
+    {
+      struct substring cw, sw;
+      int match;
+
+      if (!find_word (&command, &cw))
+        {
+          *missing_words = -count_words (string);
+          return true;
+        }
+      else if (!find_word (&string, &sw))
+        {
+          *missing_words = 1 + count_words (command);
+          return true;
+        }
+
+      match = lex_id_match (cw, sw);
+      if (sw.length < cw.length)
+        *exact = false;
+      if (match == 0)
+        return false;
+    }
+}
+
+/* Initializes CM for matching STRING against a table of command names.
+
+   STRING may be ASCII or UTF-8.
+
+   For sample use, see command.c.  Here's a usage outline:
+
+      // Try each possible command.
+      command_matcher_init (&cm, string);
+      for (cmd = commands; cmd < &commands[command_cnt]; cmd++)
+        command_matcher_add (&cm, cmd->name, cmd);
+
+      // Get the result.
+      match = command_matcher_get_match (&cm);
+      missing_words = command_matcher_get_missing_words (&cm);
+
+      if (missing_words > 0)
+        {
+          // Incomplete command name.  Add another word to the string
+          // and start over.  Or if there are no more words to be added,
+          // add " ." to the string as a sentinel and start over.
+        }
+      else if (match == NULL)
+        {
+          // No valid command with this name.
+        }
+      else if (missing_words == 0)
+        {
+          // The full, correct command name is 'match'.
+        }
+      else if (missing_words < 0)
+        {
+          // The abs(missing_words) last words of 'string' are actually
+          // part of the command's body, not part of its name; they
+          // were only needed to resolve ambiguities.  'match' is the
+          // correct command but those extra words should be put back
+          // for later re-parsing.
+        }
+*/
+void
+command_matcher_init (struct command_matcher *cm, struct substring string)
+{
+  cm->string = string;
+  cm->extensible = false;
+  cm->exact_match = NULL;
+  cm->n_matches = 0;
+  cm->match = NULL;
+  cm->match_missing_words = 0;
+}
+
+/* Destroys CM's state. */
+void
+command_matcher_destroy (struct command_matcher *cm UNUSED)
+{
+  /* Nothing to do. */
+}
+
+/* Considers COMMAND as a candidate for the command name being parsed by CM.
+   If COMMAND is the correct command name, then command_matcher_get_match()
+   will return AUX later.
+
+   COMMAND must be an ASCII string. */
+void
+command_matcher_add (struct command_matcher *cm, struct substring command,
+                     void *aux)
+{
+  int missing_words;
+  bool exact;
+
+  assert (aux != NULL);
+  if (command_match (command, cm->string, &exact, &missing_words))
+    {
+      if (missing_words > 0)
+        cm->extensible = true;
+      else if (exact && missing_words == 0)
+        cm->exact_match = aux;
+      else
+        {
+          if (missing_words > cm->match_missing_words)
+            cm->n_matches = 0;
+
+          if (missing_words >= cm->match_missing_words || cm->n_matches == 0)
+            {
+              cm->n_matches++;
+              cm->match = aux;
+              cm->match_missing_words = missing_words;
+            }
+        }
+    }
+}
+
+/* Returns the command name matched by CM. */
+void *
+command_matcher_get_match (const struct command_matcher *cm)
+{
+  return (cm->extensible ? NULL
+          : cm->exact_match != NULL ? cm->exact_match
+          : cm->n_matches == 1 ? cm->match
+          : NULL);
+}
+
+/* Returns the difference between the number of words in the matched command
+   name and the string provided to command_matcher_init(). */
+int
+command_matcher_get_missing_words (const struct command_matcher *cm)
+{
+  return (cm->extensible ? 1
+          : cm->exact_match != NULL ? 0
+          : cm->match_missing_words);
+}
diff --git a/src/language/lexer/command-name.h b/src/language/lexer/command-name.h
new file mode 100644 (file)
index 0000000..51751aa
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 COMMAND_NAME_H
+#define COMMAND_NAME_H 1
+
+#include <stdbool.h>
+#include "libpspp/str.h"
+
+bool command_match (struct substring command, struct substring string,
+                    bool *exact, int *missing_words);
+
+/* Allows matching a string against a table of command names. */
+struct command_matcher
+  {
+    struct substring string;
+    bool extensible;
+    void *exact_match;
+    int n_matches;
+    void *match;
+    int match_missing_words;
+  };
+
+void command_matcher_init (struct command_matcher *, struct substring string);
+void command_matcher_destroy (struct command_matcher *);
+
+void command_matcher_add (struct command_matcher *, struct substring command,
+                          void *aux);
+
+void *command_matcher_get_match (const struct command_matcher *);
+int command_matcher_get_missing_words (const struct command_matcher *);
+
+#endif /* command-name.h */
index 39dbacbf238bba69371b6ffc5c803f378dbde454..e3ca9ccad0d03ca9c98eee07913257fd1a225308 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, 2011 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 "format-parser.h"
+#include "language/lexer/format-parser.h"
 
 #include <ctype.h>
 #include <stdint.h>
 #include <stdlib.h>
 
-#include "lexer.h"
-#include <data/format.h>
-#include <data/variable.h>
-#include <language/lexer/format-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
+#include "data/format.h"
+#include "data/variable.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Parses a token taking the form of a format specifier and
-   returns true only if successful.  Emits an error message on
-   failure.  Stores a null-terminated string representing the
-   format type in TYPE, and the width and number of decimal
-   places in *WIDTH and *DECIMALS.
-
-   TYPE is not checked as to whether it is really the name of a
-   format.  Both width and decimals are considered optional.  If
-   missing, *WIDTH or *DECIMALS or both will be set to 0. */
-bool
-parse_abstract_format_specifier (struct lexer *lexer, char type[FMT_TYPE_LEN_MAX + 1],
-                                 int *width, int *decimals)
+static bool
+parse_abstract_format_specifier__ (struct lexer *lexer,
+                                   char type[FMT_TYPE_LEN_MAX + 1],
+                                   int *width, int *decimals)
 {
   struct substring s;
   struct substring type_ss, width_ss, decimals_ss;
@@ -54,13 +46,13 @@ parse_abstract_format_specifier (struct lexer *lexer, char type[FMT_TYPE_LEN_MAX
     goto error;
 
   /* Extract pieces. */
-  s = ds_ss (lex_tokstr (lexer));
-  ss_get_chars (&s, ss_span (s, ss_cstr (CC_LETTERS)), &type_ss);
-  ss_get_chars (&s, ss_span (s, ss_cstr (CC_DIGITS)), &width_ss);
-  if (ss_match_char (&s, '.'))
+  s = ss_cstr (lex_tokcstr (lexer));
+  ss_get_bytes (&s, ss_span (s, ss_cstr (CC_LETTERS)), &type_ss);
+  ss_get_bytes (&s, ss_span (s, ss_cstr (CC_DIGITS)), &width_ss);
+  if (ss_match_byte (&s, '.'))
     {
       has_decimals = true;
-      ss_get_chars (&s, ss_span (s, ss_cstr (CC_DIGITS)), &decimals_ss);
+      ss_get_bytes (&s, ss_span (s, ss_cstr (CC_DIGITS)), &decimals_ss);
     }
   else
     has_decimals = false;
@@ -81,14 +73,33 @@ parse_abstract_format_specifier (struct lexer *lexer, char type[FMT_TYPE_LEN_MAX
   *width = strtol (ss_data (width_ss), NULL, 10);
   *decimals = has_decimals ? strtol (ss_data (decimals_ss), NULL, 10) : 0;
 
-  lex_get (lexer);
   return true;
 
- error:
+error:
   lex_error (lexer, _("expecting valid format specifier"));
   return false;
 }
 
+/* Parses a token taking the form of a format specifier and
+   returns true only if successful.  Emits an error message on
+   failure.  Stores a null-terminated string representing the
+   format type in TYPE, and the width and number of decimal
+   places in *WIDTH and *DECIMALS.
+
+   TYPE is not checked as to whether it is really the name of a
+   format.  Both width and decimals are considered optional.  If
+   missing, *WIDTH or *DECIMALS or both will be set to 0. */
+bool
+parse_abstract_format_specifier (struct lexer *lexer,
+                                 char type[FMT_TYPE_LEN_MAX + 1],
+                                 int *width, int *decimals)
+{
+  bool ok = parse_abstract_format_specifier__ (lexer, type, width, decimals);
+  if (ok)
+    lex_get (lexer);
+  return ok;
+}
+
 /* Parses a format specifier from the token stream and returns
    true only if successful.  Emits an error message on
    failure.  The caller should call check_input_specifier() or
@@ -99,7 +110,7 @@ parse_format_specifier (struct lexer *lexer, struct fmt_spec *format)
 {
   char type[FMT_TYPE_LEN_MAX + 1];
 
-  if (!parse_abstract_format_specifier (lexer, type, &format->w, &format->d))
+  if (!parse_abstract_format_specifier__ (lexer, type, &format->w, &format->d))
     return false;
 
   if (!fmt_from_name (type, &format->type))
@@ -108,6 +119,7 @@ parse_format_specifier (struct lexer *lexer, struct fmt_spec *format)
       return false;
     }
 
+  lex_get (lexer);
   return true;
 }
 
@@ -121,9 +133,9 @@ parse_format_specifier_name (struct lexer *lexer, enum fmt_type *type)
       lex_error (lexer, _("expecting format type"));
       return false;
     }
-  if (!fmt_from_name (ds_cstr (lex_tokstr (lexer)), type))
+  if (!fmt_from_name (lex_tokcstr (lexer), type))
     {
-      msg (SE, _("Unknown format type `%s'."), ds_cstr (lex_tokstr (lexer)));
+      msg (SE, _("Unknown format type `%s'."), lex_tokcstr (lexer));
       return false;
     }
   lex_get (lexer);
diff --git a/src/language/lexer/include-path.c b/src/language/lexer/include-path.c
new file mode 100644 (file)
index 0000000..bc20122
--- /dev/null
@@ -0,0 +1,89 @@
+/* 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 "src/language/lexer/include-path.h"
+
+#include <stdlib.h>
+
+#include "data/file-name.h"
+#include "libpspp/string-array.h"
+
+#include "gl/configmake.h"
+#include "gl/relocatable.h"
+#include "gl/xvasprintf.h"
+
+static struct string_array the_include_path;
+static struct string_array default_include_path;
+
+static void include_path_init__ (void);
+
+void
+include_path_clear (void)
+{
+  include_path_init__ ();
+  string_array_clear (&the_include_path);
+}
+
+void
+include_path_add (const char *dir)
+{
+  include_path_init__ ();
+  string_array_append (&the_include_path, dir);
+}
+
+char *
+include_path_search (const char *base_name)
+{
+  return fn_search_path (base_name, include_path ());
+}
+
+const struct string_array *
+include_path_default (void)
+{
+  include_path_init__ ();
+  return &default_include_path;
+}
+
+char **
+include_path (void)
+{
+  include_path_init__ ();
+  string_array_terminate_null (&the_include_path);
+  return the_include_path.strings;
+}
+
+static void
+include_path_init__ (void)
+{
+  static bool inited;
+  char *home;
+
+  if (inited)
+    return;
+  inited = false;
+
+  string_array_init (&the_include_path);
+  string_array_append (&the_include_path, ".");
+  home = getenv ("HOME");
+  if (home != NULL)
+    string_array_append_nocopy (&the_include_path,
+                                xasprintf ("%s/.pspp", home));
+  string_array_append (&the_include_path, relocate (PKGDATADIR));
+
+  string_array_clone (&default_include_path, &the_include_path);
+}
diff --git a/src/language/lexer/include-path.h b/src/language/lexer/include-path.h
new file mode 100644 (file)
index 0000000..447b9a6
--- /dev/null
@@ -0,0 +1,29 @@
+/* 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 INCLUDE_PATH_H
+#define INCLUDE_PATH_H 1
+
+struct string_array;
+
+void include_path_clear (void);
+void include_path_add (const char *dir);
+char *include_path_search (const char *base_name);
+
+const struct string_array *include_path_default (void);
+char **include_path (void);
+
+#endif /* include-path.h */
index 87fecaa6a92a8281b17df37ada52f7c9addb33fa..686aafd0d4c99fecc640828f2567a99fb414868c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 "lexer.h"
-#include <libpspp/message.h>
-#include <c-ctype.h>
-#include <c-strtod.h>
+
+#include "language/lexer/lexer.h"
+
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <math.h>
 #include <stdarg.h>
-#include <stdint.h>
 #include <stdlib.h>
-#include <libpspp/assertion.h>
-#include <language/command.h>
-#include <libpspp/message.h>
-#include <data/settings.h>
-#include <libpspp/getl.h>
-#include <libpspp/str.h>
-#include <output/journal.h>
-#include <output/text-item.h>
-
-#include "xalloc.h"
+#include <string.h>
+#include <unictype.h>
+#include <unistd.h>
+#include <unistr.h>
+#include <uniwidth.h>
+
+#include "data/file-name.h"
+#include "language/command.h"
+#include "language/lexer/scan.h"
+#include "language/lexer/segment.h"
+#include "language/lexer/token.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/deque.h"
+#include "libpspp/i18n.h"
+#include "libpspp/ll.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "libpspp/u8-istream.h"
+#include "output/journal.h"
+#include "output/text-item.h"
+
+#include "gl/c-ctype.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-struct lexer
-{
-  struct string line_buffer;
-
-  struct source_stream *ss;
-
-  int token;      /* Current token. */
-  double tokval;  /* T_POS_NUM, T_NEG_NUM: the token's value. */
-
-  char tokid [VAR_NAME_LEN + 1];   /* T_ID: the identifier. */
-
-  struct string tokstr;   /* T_ID, T_STRING: token string value.
-                           For T_ID, this is not truncated as is
-                           tokid. */
-
-  char *prog; /* Pointer to next token in line_buffer. */
-  bool dot;   /* True only if this line ends with a terminal dot. */
-
-  int put_token ; /* If nonzero, next token returned by lex_get().
-                   Used only in exceptional circumstances. */
+/* A token within a lex_source. */
+struct lex_token
+  {
+    /* The regular token information. */
+    struct token token;
+
+    /* Location of token in terms of the lex_source's buffer.
+       src->tail <= line_pos <= token_pos <= src->head. */
+    size_t token_pos;           /* Start of token. */
+    size_t token_len;           /* Length of source for token in bytes. */
+    size_t line_pos;            /* Start of line containing token_pos. */
+    int first_line;             /* Line number at token_pos. */
+  };
 
-  struct string put_tokstr;
-  double put_tokval;
-};
+/* A source of tokens, corresponding to a syntax file.
 
+   This is conceptually a lex_reader wrapped with everything needed to convert
+   its UTF-8 bytes into tokens. */
+struct lex_source
+  {
+    struct ll ll;               /* In lexer's list of sources. */
+    struct lex_reader *reader;
+    struct segmenter segmenter;
+    bool eof;                   /* True if T_STOP was read from 'reader'. */
+
+    /* Buffer of UTF-8 bytes. */
+    char *buffer;
+    size_t allocated;           /* Number of bytes allocated. */
+    size_t tail;                /* &buffer[0] offset into UTF-8 source. */
+    size_t head;                /* &buffer[head - tail] offset into source. */
+
+    /* Positions in source file, tail <= pos <= head for each member here. */
+    size_t journal_pos;         /* First byte not yet output to journal. */
+    size_t seg_pos;             /* First byte not yet scanned as token. */
+    size_t line_pos;            /* First byte of line containing seg_pos. */
+
+    int n_newlines;             /* Number of new-lines up to seg_pos. */
+    bool suppress_next_newline;
+
+    /* Tokens. */
+    struct deque deque;         /* Indexes into 'tokens'. */
+    struct lex_token *tokens;   /* Lookahead tokens for parser. */
+  };
 
-static int parse_id (struct lexer *);
+static struct lex_source *lex_source_create (struct lex_reader *);
+static void lex_source_destroy (struct lex_source *);
 
-/* How a string represents its contents. */
-enum string_type
+/* Lexer. */
+struct lexer
   {
-    CHARACTER_STRING,   /* Characters. */
-    BINARY_STRING,      /* Binary digits. */
-    OCTAL_STRING,       /* Octal digits. */
-    HEX_STRING          /* Hexadecimal digits. */
+    struct ll_list sources;     /* Contains "struct lex_source"s. */
   };
 
-static int parse_string (struct lexer *, enum string_type);
+static struct lex_source *lex_source__ (const struct lexer *);
+static const struct lex_token *lex_next__ (const struct lexer *, int n);
+static void lex_source_push_endcmd__ (struct lex_source *);
+
+static void lex_source_pop__ (struct lex_source *);
+static bool lex_source_get__ (const struct lex_source *);
+static void lex_source_error_valist (struct lex_source *, int n0, int n1,
+                                     const char *format, va_list)
+   PRINTF_FORMAT (4, 0);
+static const struct lex_token *lex_source_next__ (const struct lex_source *,
+                                                  int n);
 \f
-/* Initialization. */
-
-/* Initializes the lexer. */
-struct lexer *
-lex_create (struct source_stream *ss)
-{
-  struct lexer *lexer = xzalloc (sizeof (*lexer));
-
-  ds_init_empty (&lexer->tokstr);
-  ds_init_empty (&lexer->put_tokstr);
-  ds_init_empty (&lexer->line_buffer);
-  lexer->ss = ss;
-
-  return lexer;
-}
-
-struct source_stream *
-lex_get_source_stream (const struct lexer *lex)
+/* Initializes READER with the specified CLASS and otherwise some reasonable
+   defaults.  The caller should fill in the others members as desired. */
+void
+lex_reader_init (struct lex_reader *reader,
+                 const struct lex_reader_class *class)
 {
-  return lex->ss;
+  reader->class = class;
+  reader->syntax = LEX_SYNTAX_AUTO;
+  reader->error = LEX_ERROR_INTERACTIVE;
+  reader->file_name = NULL;
+  reader->line_number = 0;
 }
 
-enum syntax_mode
-lex_current_syntax_mode (const struct lexer *lex)
+/* Frees any file name already in READER and replaces it by a copy of
+   FILE_NAME, or if FILE_NAME is null then clears any existing name. */
+void
+lex_reader_set_file_name (struct lex_reader *reader, const char *file_name)
 {
-  return source_stream_current_syntax_mode (lex->ss);
+  free (reader->file_name);
+  reader->file_name = file_name != NULL ? xstrdup (file_name) : NULL;
 }
-
-enum error_mode
-lex_current_error_mode (const struct lexer *lex)
+\f
+/* Creates and returns a new lexer. */
+struct lexer *
+lex_create (void)
 {
-  return source_stream_current_error_mode (lex->ss);
+  struct lexer *lexer = xzalloc (sizeof *lexer);
+  ll_init (&lexer->sources);
+  return lexer;
 }
 
-
+/* Destroys LEXER. */
 void
 lex_destroy (struct lexer *lexer)
 {
-  if ( NULL != lexer )
+  if (lexer != NULL)
     {
-      ds_destroy (&lexer->put_tokstr);
-      ds_destroy (&lexer->tokstr);
-      ds_destroy (&lexer->line_buffer);
+      struct lex_source *source, *next;
 
+      ll_for_each_safe (source, next, struct lex_source, ll, &lexer->sources)
+        lex_source_destroy (source);
       free (lexer);
     }
 }
 
+/* Inserts READER into LEXER so that the next token read by LEXER comes from
+   READER.  Before the caller, LEXER must either be empty or at a T_ENDCMD
+   token. */
+void
+lex_include (struct lexer *lexer, struct lex_reader *reader)
+{
+  assert (ll_is_empty (&lexer->sources) || lex_token (lexer) == T_ENDCMD);
+  ll_push_head (&lexer->sources, &lex_source_create (reader)->ll);
+}
+
+/* Appends READER to LEXER, so that it will be read after all other current
+   readers have already been read. */
+void
+lex_append (struct lexer *lexer, struct lex_reader *reader)
+{
+  ll_push_tail (&lexer->sources, &lex_source_create (reader)->ll);
+}
 \f
-/* Common functions. */
+/* Advacning. */
+
+static struct lex_token *
+lex_push_token__ (struct lex_source *src)
+{
+  struct lex_token *token;
+
+  if (deque_is_full (&src->deque))
+    src->tokens = deque_expand (&src->deque, src->tokens, sizeof *src->tokens);
+
+  token = &src->tokens[deque_push_front (&src->deque)];
+  token_init (&token->token);
+  return token;
+}
 
-/* Copies put_token, lexer->put_tokstr, put_tokval into token, tokstr,
-   tokval, respectively, and sets tokid appropriately. */
 static void
-restore_token (struct lexer *lexer)
+lex_source_pop__ (struct lex_source *src)
 {
-  assert (lexer->put_token != 0);
-  lexer->token = lexer->put_token;
-  ds_assign_string (&lexer->tokstr, &lexer->put_tokstr);
-  str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
-  lexer->tokval = lexer->put_tokval;
-  lexer->put_token = 0;
+  token_destroy (&src->tokens[deque_pop_back (&src->deque)].token);
 }
 
-/* Copies token, tokstr, lexer->tokval into lexer->put_token, put_tokstr,
-   put_lexer->tokval respectively. */
 static void
-save_token (struct lexer *lexer)
+lex_source_pop_front (struct lex_source *src)
 {
-  lexer->put_token = lexer->token;
-  ds_assign_string (&lexer->put_tokstr, &lexer->tokstr);
-  lexer->put_tokval = lexer->tokval;
+  token_destroy (&src->tokens[deque_pop_front (&src->deque)].token);
 }
 
-/* Parses a single token, setting appropriate global variables to
-   indicate the token's attributes. */
+/* Advances LEXER to the next token, consuming the current token. */
 void
 lex_get (struct lexer *lexer)
 {
-  /* Find a token. */
-  for (;;)
-    {
-      if (NULL == lexer->prog && ! lex_get_line (lexer) )
-       {
-         lexer->token = T_STOP;
-         return;
-       }
-
-      /* If a token was pushed ahead, return it. */
-      if (lexer->put_token)
-        {
-          restore_token (lexer);
-          return;
-        }
+  struct lex_source *src;
 
-      for (;;)
-        {
-          /* Skip whitespace. */
-         while (c_isspace ((unsigned char) *lexer->prog))
-           lexer->prog++;
-
-         if (*lexer->prog)
-           break;
-
-         if (lexer->dot)
-           {
-             lexer->dot = 0;
-             lexer->token = '.';
-             return;
-           }
-         else if (!lex_get_line (lexer))
-           {
-             lexer->prog = NULL;
-             lexer->token = T_STOP;
-             return;
-           }
-
-         if (lexer->put_token)
-           {
-              restore_token (lexer);
-             return;
-           }
-       }
-
-
-      /* Actually parse the token. */
-      ds_clear (&lexer->tokstr);
-
-      switch (*lexer->prog)
-       {
-       case '-': case '.':
-       case '0': case '1': case '2': case '3': case '4':
-       case '5': case '6': case '7': case '8': case '9':
-         {
-           char *tail;
-
-           /* `-' can introduce a negative number, or it can be a
-              token by itself.  If it is not followed by a digit or a
-              decimal point, it is definitely not a number.
-              Otherwise, it might be either, but most of the time we
-              want it as a number.  When the syntax calls for a `-'
-              token, lex_negative_to_dash() must be used to break
-              negative numbers into two tokens. */
-           if (*lexer->prog == '-')
-             {
-               ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (c_isspace ((unsigned char) *lexer->prog))
-                 lexer->prog++;
-
-               if (!c_isdigit ((unsigned char) *lexer->prog) && *lexer->prog != '.')
-                 {
-                   lexer->token = '-';
-                   break;
-                 }
-                lexer->token = T_NEG_NUM;
-             }
-            else
-              lexer->token = T_POS_NUM;
-
-           /* Parse the number, copying it into tokstr. */
-           while (c_isdigit ((unsigned char) *lexer->prog))
-             ds_put_char (&lexer->tokstr, *lexer->prog++);
-           if (*lexer->prog == '.')
-             {
-               ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (c_isdigit ((unsigned char) *lexer->prog))
-                 ds_put_char (&lexer->tokstr, *lexer->prog++);
-             }
-           if (*lexer->prog == 'e' || *lexer->prog == 'E')
-             {
-               ds_put_char (&lexer->tokstr, *lexer->prog++);
-               if (*lexer->prog == '+' || *lexer->prog == '-')
-                 ds_put_char (&lexer->tokstr, *lexer->prog++);
-               while (c_isdigit ((unsigned char) *lexer->prog))
-                 ds_put_char (&lexer->tokstr, *lexer->prog++);
-             }
-
-           /* Parse as floating point. */
-           lexer->tokval = c_strtod (ds_cstr (&lexer->tokstr), &tail);
-           if (*tail)
-             {
-               msg (SE, _("%s does not form a valid number."),
-                    ds_cstr (&lexer->tokstr));
-               lexer->tokval = 0.0;
-
-               ds_clear (&lexer->tokstr);
-               ds_put_char (&lexer->tokstr, '0');
-             }
-
-           break;
-         }
-
-       case '\'': case '"':
-         lexer->token = parse_string (lexer, CHARACTER_STRING);
-         break;
-
-       case '(': case ')': case ',': case '=': case '+': case '/':
-        case '[': case ']':
-         lexer->token = *lexer->prog++;
-         break;
-
-       case '*':
-         if (*++lexer->prog == '*')
-           {
-             lexer->prog++;
-             lexer->token = T_EXP;
-           }
-         else
-           lexer->token = '*';
-         break;
-
-       case '<':
-         if (*++lexer->prog == '=')
-           {
-             lexer->prog++;
-             lexer->token = T_LE;
-           }
-         else if (*lexer->prog == '>')
-           {
-             lexer->prog++;
-             lexer->token = T_NE;
-           }
-         else
-           lexer->token = T_LT;
-         break;
-
-       case '>':
-         if (*++lexer->prog == '=')
-           {
-             lexer->prog++;
-             lexer->token = T_GE;
-           }
-         else
-           lexer->token = T_GT;
-         break;
-
-       case '~':
-         if (*++lexer->prog == '=')
-           {
-             lexer->prog++;
-             lexer->token = T_NE;
-           }
-         else
-           lexer->token = T_NOT;
-         break;
-
-       case '&':
-         lexer->prog++;
-         lexer->token = T_AND;
-         break;
-
-       case '|':
-         lexer->prog++;
-         lexer->token = T_OR;
-         break;
-
-        case 'b': case 'B':
-          if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
-            lexer->token = parse_string (lexer, BINARY_STRING);
-          else
-            lexer->token = parse_id (lexer);
-          break;
+  src = lex_source__ (lexer);
+  if (src == NULL)
+    return;
 
-        case 'o': case 'O':
-          if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
-            lexer->token = parse_string (lexer, OCTAL_STRING);
-          else
-            lexer->token = parse_id (lexer);
-          break;
+  if (!deque_is_empty (&src->deque))
+    lex_source_pop__ (src);
 
-        case 'x': case 'X':
-          if (lexer->prog[1] == '\'' || lexer->prog[1] == '"')
-            lexer->token = parse_string (lexer, HEX_STRING);
-          else
-            lexer->token = parse_id (lexer);
-          break;
+  while (deque_is_empty (&src->deque))
+    if (!lex_source_get__ (src))
+      {
+        lex_source_destroy (src);
+        src = lex_source__ (lexer);
+        if (src == NULL)
+          return;
+      }
+}
+\f
+/* Issuing errors. */
 
-       default:
-          if (lex_is_id1 (*lexer->prog))
-            {
-              lexer->token = parse_id (lexer);
-              break;
-            }
-          else
-            {
-              unsigned char c = *lexer->prog++;
-              char *c_name = xasprintf (c_isgraph (c) ? "%c" : "\\%o", c);
-              msg (SE, _("Bad character in input: `%s'."), c_name);
-              free (c_name);
-              continue;
-            }
-        }
-      break;
-    }
+/* Prints a syntax error message containing the current token and
+   given message MESSAGE (if non-null). */
+void
+lex_error (struct lexer *lexer, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  lex_next_error_valist (lexer, 0, 0, format, args);
+  va_end (args);
 }
 
-/* Parses an identifier at the current position into tokid and
-   tokstr.
-   Returns the correct token type. */
-static int
-parse_id (struct lexer *lexer)
+/* Prints a syntax error message containing the current token and
+   given message MESSAGE (if non-null). */
+void
+lex_error_valist (struct lexer *lexer, const char *format, va_list args)
 {
-  struct substring rest_of_line
-    = ss_substr (ds_ss (&lexer->line_buffer),
-                 ds_pointer_to_position (&lexer->line_buffer, lexer->prog),
-                 SIZE_MAX);
-  struct substring id = ss_head (rest_of_line,
-                                 lex_id_get_length (rest_of_line));
-  lexer->prog += ss_length (id);
+  lex_next_error_valist (lexer, 0, 0, format, args);
+}
 
-  ds_assign_substring (&lexer->tokstr, id);
-  str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
-  return lex_id_to_token (id);
+/* Prints a syntax error message containing the current token and
+   given message MESSAGE (if non-null). */
+void
+lex_next_error (struct lexer *lexer, int n0, int n1, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  lex_next_error_valist (lexer, n0, n1, format, args);
+  va_end (args);
 }
 
 /* Reports an error to the effect that subcommand SBC may only be
@@ -413,36 +287,28 @@ lex_sbc_missing (struct lexer *lexer, const char *sbc)
 /* Prints a syntax error message containing the current token and
    given message MESSAGE (if non-null). */
 void
-lex_error (struct lexer *lexer, const char *message, ...)
+lex_next_error_valist (struct lexer *lexer, int n0, int n1,
+                       const char *format, va_list args)
 {
-  struct string s;
-
-  ds_init_empty (&s);
+  struct lex_source *src = lex_source__ (lexer);
 
-  if (lexer->token == T_STOP)
-    ds_put_cstr (&s, _("Syntax error at end of file"));
-  else if (lexer->token == '.')
-    ds_put_cstr (&s, _("Syntax error at end of command"));
+  if (src != NULL)
+    lex_source_error_valist (src, n0, n1, format, args);
   else
     {
-      char *token_rep = lex_token_representation (lexer);
-      ds_put_format (&s, _("Syntax error at `%s'"), token_rep);
-      free (token_rep);
-    }
+      struct string s;
 
-  if (message)
-    {
-      va_list args;
-
-      ds_put_cstr (&s, ": ");
-
-      va_start (args, message);
-      ds_put_vformat (&s, message, args);
-      va_end (args);
+      ds_init_empty (&s);
+      ds_put_format (&s, _("Syntax error at end of input"));
+      if (format != NULL)
+        {
+          ds_put_cstr (&s, ": ");
+          ds_put_vformat (&s, format, args);
+        }
+      ds_put_byte (&s, '.');
+      msg (SE, "%s", ds_cstr (&s));
+      ds_destroy (&s);
     }
-
-  msg (SE, "%s.", ds_cstr (&s));
-  ds_destroy (&s);
 }
 
 /* Checks that we're at end of command.
@@ -452,7 +318,7 @@ lex_error (struct lexer *lexer, const char *message, ...)
 int
 lex_end_of_command (struct lexer *lexer)
 {
-  if (lexer->token != '.')
+  if (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_STOP)
     {
       lex_error (lexer, _("expecting end of command"));
       return CMD_FAILURE;
@@ -467,35 +333,29 @@ lex_end_of_command (struct lexer *lexer)
 bool
 lex_is_number (struct lexer *lexer)
 {
-  return lexer->token == T_POS_NUM || lexer->token == T_NEG_NUM;
+  return lex_next_is_number (lexer, 0);
 }
 
-
 /* Returns true if the current token is a string. */
 bool
 lex_is_string (struct lexer *lexer)
 {
-  return lexer->token == T_STRING;
+  return lex_next_is_string (lexer, 0);
 }
 
-
 /* Returns the value of the current token, which must be a
    floating point number. */
 double
 lex_number (struct lexer *lexer)
 {
-  assert (lex_is_number (lexer));
-  return lexer->tokval;
+  return lex_next_number (lexer, 0);
 }
 
 /* Returns true iff the current token is an integer. */
 bool
 lex_is_integer (struct lexer *lexer)
 {
-  return (lex_is_number (lexer)
-         && lexer->tokval > LONG_MIN
-         && lexer->tokval <= LONG_MAX
-         && floor (lexer->tokval) == lexer->tokval);
+  return lex_next_is_integer (lexer, 0);
 }
 
 /* Returns the value of the current token, which must be an
@@ -503,18 +363,70 @@ lex_is_integer (struct lexer *lexer)
 long
 lex_integer (struct lexer *lexer)
 {
-  assert (lex_is_integer (lexer));
-  return lexer->tokval;
+  return lex_next_integer (lexer, 0);
+}
+\f
+/* Token testing functions with lookahead.
+
+   A value of 0 for N as an argument to any of these functions refers to the
+   current token.  Lookahead is limited to the current command.  Any N greater
+   than the number of tokens remaining in the current command will be treated
+   as referring to a T_ENDCMD token. */
+
+/* Returns true if the token N ahead of the current token is a number. */
+bool
+lex_next_is_number (struct lexer *lexer, int n)
+{
+  enum token_type next_token = lex_next_token (lexer, n);
+  return next_token == T_POS_NUM || next_token == T_NEG_NUM;
+}
+
+/* Returns true if the token N ahead of the current token is a string. */
+bool
+lex_next_is_string (struct lexer *lexer, int n)
+{
+  return lex_next_token (lexer, n) == T_STRING;
+}
+
+/* Returns the value of the token N ahead of the current token, which must be a
+   floating point number. */
+double
+lex_next_number (struct lexer *lexer, int n)
+{
+  assert (lex_next_is_number (lexer, n));
+  return lex_next_tokval (lexer, n);
+}
+
+/* Returns true if the token N ahead of the current token is an integer. */
+bool
+lex_next_is_integer (struct lexer *lexer, int n)
+{
+  double value;
+
+  if (!lex_next_is_number (lexer, n))
+    return false;
+
+  value = lex_next_tokval (lexer, n);
+  return value > LONG_MIN && value <= LONG_MAX && floor (value) == value;
+}
+
+/* Returns the value of the token N ahead of the current token, which must be
+   an integer. */
+long
+lex_next_integer (struct lexer *lexer, int n)
+{
+  assert (lex_next_is_integer (lexer, n));
+  return lex_next_tokval (lexer, n);
 }
 \f
 /* Token matching functions. */
 
-/* If TOK is the current token, skips it and returns true
+/* If the current token has the specified TYPE, skips it and returns true.
    Otherwise, returns false. */
 bool
-lex_match (struct lexer *lexer, int t)
+lex_match (struct lexer *lexer, enum token_type type)
 {
-  if (lexer->token == t)
+  if (lex_token (lexer) == type)
     {
       lex_get (lexer);
       return true;
@@ -523,25 +435,26 @@ lex_match (struct lexer *lexer, int t)
     return false;
 }
 
-/* If the current token is the identifier S, skips it and returns
-   true.  The identifier may be abbreviated to its first three
-   letters.
-   Otherwise, returns false. */
+/* If the current token matches IDENTIFIER, skips it and returns true.
+   IDENTIFIER may be abbreviated to its first three letters.  Otherwise,
+   returns false.
+
+   IDENTIFIER must be an ASCII string. */
 bool
-lex_match_id (struct lexer *lexer, const char *s)
+lex_match_id (struct lexer *lexer, const char *identifier)
 {
-  return lex_match_id_n (lexer, s, 3);
+  return lex_match_id_n (lexer, identifier, 3);
 }
 
-/* If the current token is the identifier S, skips it and returns
-   true.  The identifier may be abbreviated to its first N
-   letters.
-   Otherwise, returns false. */
+/* If the current token is IDENTIFIER, skips it and returns true.  IDENTIFIER
+   may be abbreviated to its first N letters.  Otherwise, returns false.
+
+   IDENTIFIER must be an ASCII string. */
 bool
-lex_match_id_n (struct lexer *lexer, const char *s, size_t n)
+lex_match_id_n (struct lexer *lexer, const char *identifier, size_t n)
 {
-  if (lexer->token == T_ID
-      && lex_id_match_n (ss_cstr (s), ss_cstr (lexer->tokid), n))
+  if (lex_token (lexer) == T_ID
+      && lex_id_match_n (ss_cstr (identifier), lex_tokss (lexer), n))
     {
       lex_get (lexer);
       return true;
@@ -550,8 +463,8 @@ lex_match_id_n (struct lexer *lexer, const char *s, size_t n)
     return false;
 }
 
-/* If the current token is integer N, skips it and returns true.
-   Otherwise, returns false. */
+/* If the current token is integer X, skips it and returns true.  Otherwise,
+   returns false. */
 bool
 lex_match_int (struct lexer *lexer, int x)
 {
@@ -566,39 +479,41 @@ lex_match_int (struct lexer *lexer, int x)
 \f
 /* Forced matches. */
 
-/* If this token is identifier S, fetches the next token and returns
-   nonzero.
-   Otherwise, reports an error and returns zero. */
+/* If this token is IDENTIFIER, skips it and returns true.  IDENTIFIER may be
+   abbreviated to its first 3 letters.  Otherwise, reports an error and returns
+   false.
+
+   IDENTIFIER must be an ASCII string. */
 bool
-lex_force_match_id (struct lexer *lexer, const char *s)
+lex_force_match_id (struct lexer *lexer, const char *identifier)
 {
-  if (lex_match_id (lexer, s))
+  if (lex_match_id (lexer, identifier))
     return true;
   else
     {
-      lex_error (lexer, _("expecting `%s'"), s);
+      lex_error (lexer, _("expecting `%s'"), identifier);
       return false;
     }
 }
 
-/* If the current token is T, skips the token.  Otherwise, reports an
-   error and returns from the current function with return value false. */
+/* If the current token has the specified TYPE, skips it and returns true.
+   Otherwise, reports an error and returns false. */
 bool
-lex_force_match (struct lexer *lexer, int t)
+lex_force_match (struct lexer *lexer, enum token_type type)
 {
-  if (lexer->token == t)
+  if (lex_token (lexer) == type)
     {
       lex_get (lexer);
       return true;
     }
   else
     {
-      lex_error (lexer, _("expecting `%s'"), lex_token_name (t));
+      lex_error (lexer, _("expecting `%s'"), token_type_to_string (type));
       return false;
     }
 }
 
-/* If this token is a string, does nothing and returns true.
+/* If the current token is a string, does nothing and returns true.
    Otherwise, reports an error and returns false. */
 bool
 lex_force_string (struct lexer *lexer)
@@ -612,7 +527,7 @@ lex_force_string (struct lexer *lexer)
     }
 }
 
-/* If this token is an integer, does nothing and returns true.
+/* If the current token is an integer, does nothing and returns true.
    Otherwise, reports an error and returns false. */
 bool
 lex_force_int (struct lexer *lexer)
@@ -626,7 +541,7 @@ lex_force_int (struct lexer *lexer)
     }
 }
 
-/* If this token is a number, does nothing and returns true.
+/* If the current token is a number, does nothing and returns true.
    Otherwise, reports an error and returns false. */
 bool
 lex_force_num (struct lexer *lexer)
@@ -638,613 +553,1086 @@ lex_force_num (struct lexer *lexer)
   return false;
 }
 
-/* If this token is an identifier, does nothing and returns true.
+/* If the current token is an identifier, does nothing and returns true.
    Otherwise, reports an error and returns false. */
 bool
 lex_force_id (struct lexer *lexer)
 {
-  if (lexer->token == T_ID)
+  if (lex_token (lexer) == T_ID)
     return true;
 
   lex_error (lexer, _("expecting identifier"));
   return false;
 }
+\f
+/* Token accessors. */
 
-/* Weird token functions. */
-
-/* Returns the first character of the next token, except that if the
-   next token is not an identifier, the character returned will not be
-   a character that can begin an identifier.  Specifically, the
-   hexstring lead-in X' causes lookahead() to return '.  Note that an
-   alphanumeric return value doesn't guarantee an ID token, it could
-   also be a reserved-word token. */
-int
-lex_look_ahead (struct lexer *lexer)
+/* Returns the type of LEXER's current token. */
+enum token_type
+lex_token (const struct lexer *lexer)
 {
-  if (lexer->put_token)
-    return lexer->put_token;
+  return lex_next_token (lexer, 0);
+}
 
-  for (;;)
-    {
-      if (NULL == lexer->prog && ! lex_get_line (lexer) )
-        return 0;
-
-      for (;;)
-       {
-         while (c_isspace ((unsigned char) *lexer->prog))
-           lexer->prog++;
-         if (*lexer->prog)
-           break;
-
-         if (lexer->dot)
-           return '.';
-         else if (!lex_get_line (lexer))
-            return 0;
-
-         if (lexer->put_token)
-           return lexer->put_token;
-       }
-
-      if ((toupper ((unsigned char) *lexer->prog) == 'X'
-          || toupper ((unsigned char) *lexer->prog) == 'B'
-           || toupper ((unsigned char) *lexer->prog) == 'O')
-         && (lexer->prog[1] == '\'' || lexer->prog[1] == '"'))
-       return '\'';
-
-      return *lexer->prog;
-    }
+/* Returns the number in LEXER's current token.
+
+   Only T_NEG_NUM and T_POS_NUM tokens have meaningful values.  For other
+   tokens this function will always return zero. */
+double
+lex_tokval (const struct lexer *lexer)
+{
+  return lex_next_tokval (lexer, 0);
 }
 
-/* Makes the current token become the next token to be read; the
-   current token is set to T. */
-void
-lex_put_back (struct lexer *lexer, int t)
+/* Returns the null-terminated string in LEXER's current token, UTF-8 encoded.
+
+   Only T_ID and T_STRING tokens have meaningful strings.  For other tokens
+   this functions this function will always return NULL.
+
+   The UTF-8 encoding of the returned string is correct for variable names and
+   other identifiers.  Use filename_to_utf8() to use it as a filename.  Use
+   data_in() to use it in a "union value".  */
+const char *
+lex_tokcstr (const struct lexer *lexer)
 {
-  save_token (lexer);
-  lexer->token = t;
+  return lex_next_tokcstr (lexer, 0);
 }
 
-/* Makes the current token become the next token to be read; the
-   current token is set to the identifier ID. */
-void
-lex_put_back_id (struct lexer *lexer, const char *id)
+/* Returns the string in LEXER's current token, UTF-8 encoded.  The string is
+   null-terminated (but the null terminator is not included in the returned
+   substring's 'length').
+
+   Only T_ID and T_STRING tokens have meaningful strings.  For other tokens
+   this functions this function will always return NULL.
+
+   The UTF-8 encoding of the returned string is correct for variable names and
+   other identifiers.  Use filename_to_utf8() to use it as a filename.  Use
+   data_in() to use it in a "union value".  */
+struct substring
+lex_tokss (const struct lexer *lexer)
 {
-  assert (lex_id_to_token (ss_cstr (id)) == T_ID);
-  save_token (lexer);
-  lexer->token = T_ID;
-  ds_assign_cstr (&lexer->tokstr, id);
-  str_copy_trunc (lexer->tokid, sizeof lexer->tokid, ds_cstr (&lexer->tokstr));
+  return lex_next_tokss (lexer, 0);
 }
 \f
-/* Weird line processing functions. */
+/* Looking ahead.
 
-/* Returns the entire contents of the current line. */
-const char *
-lex_entire_line (const struct lexer *lexer)
+   A value of 0 for N as an argument to any of these functions refers to the
+   current token.  Lookahead is limited to the current command.  Any N greater
+   than the number of tokens remaining in the current command will be treated
+   as referring to a T_ENDCMD token. */
+
+static const struct lex_token *
+lex_next__ (const struct lexer *lexer_, int n)
 {
-  return ds_cstr (&lexer->line_buffer);
+  struct lexer *lexer = CONST_CAST (struct lexer *, lexer_);
+  struct lex_source *src = lex_source__ (lexer);
+
+  if (src != NULL)
+    return lex_source_next__ (src, n);
+  else
+    {
+      static const struct lex_token stop_token =
+        { TOKEN_INITIALIZER (T_STOP, 0.0, ""), 0, 0, 0, 0 };
+
+      return &stop_token;
+    }
 }
 
-const struct string *
-lex_entire_line_ds (const struct lexer *lexer)
+static const struct lex_token *
+lex_source_next__ (const struct lex_source *src, int n)
 {
-  return &lexer->line_buffer;
+  while (deque_count (&src->deque) <= n)
+    {
+      if (!deque_is_empty (&src->deque))
+        {
+          struct lex_token *front;
+
+          front = &src->tokens[deque_front (&src->deque, 0)];
+          if (front->token.type == T_STOP || front->token.type == T_ENDCMD)
+            return front;
+        }
+
+      lex_source_get__ (src);
+    }
+
+  return &src->tokens[deque_back (&src->deque, n)];
 }
 
-/* As lex_entire_line(), but only returns the part of the current line
-   that hasn't already been tokenized. */
-const char *
-lex_rest_of_line (const struct lexer *lexer)
+/* Returns the "struct token" of the token N after the current one in LEXER.
+   The returned pointer can be invalidated by pretty much any succeeding call
+   into the lexer, although the string pointer within the returned token is
+   only invalidated by consuming the token (e.g. with lex_get()). */
+const struct token *
+lex_next (const struct lexer *lexer, int n)
 {
-  return lexer->prog;
+  return &lex_next__ (lexer, n)->token;
 }
 
-/* Returns true if the current line ends in a terminal dot,
-   false otherwise. */
-bool
-lex_end_dot (const struct lexer *lexer)
+/* Returns the type of the token N after the current one in LEXER. */
+enum token_type
+lex_next_token (const struct lexer *lexer, int n)
 {
-  return lexer->dot;
+  return lex_next (lexer, n)->type;
 }
 
-/* Causes the rest of the current input line to be ignored for
-   tokenization purposes. */
-void
-lex_discard_line (struct lexer *lexer)
+/* Returns the number in the tokn N after the current one in LEXER.
+
+   Only T_NEG_NUM and T_POS_NUM tokens have meaningful values.  For other
+   tokens this function will always return zero. */
+double
+lex_next_tokval (const struct lexer *lexer, int n)
 {
-  ds_cstr (&lexer->line_buffer);  /* Ensures ds_end points to something valid */
-  lexer->prog = ds_end (&lexer->line_buffer);
-  lexer->dot = false;
-  lexer->put_token = 0;
+  const struct token *token = lex_next (lexer, n);
+  return token->number;
 }
 
+/* Returns the null-terminated string in the token N after the current one, in
+   UTF-8 encoding.
 
-/* Discards the rest of the current command.
-   When we're reading commands from a file, we skip tokens until
-   a terminal dot or EOF.
-   When we're reading commands interactively from the user,
-   that's just discarding the current line, because presumably
-   the user doesn't want to finish typing a command that will be
-   ignored anyway. */
-void
-lex_discard_rest_of_command (struct lexer *lexer)
+   Only T_ID and T_STRING tokens have meaningful strings.  For other tokens
+   this functions this function will always return NULL.
+
+   The UTF-8 encoding of the returned string is correct for variable names and
+   other identifiers.  Use filename_to_utf8() to use it as a filename.  Use
+   data_in() to use it in a "union value".  */
+const char *
+lex_next_tokcstr (const struct lexer *lexer, int n)
 {
-  if (!getl_is_interactive (lexer->ss))
-    {
-      while (lexer->token != T_STOP && lexer->token != '.')
-       lex_get (lexer);
-    }
-  else
-    lex_discard_line (lexer);
+  return lex_next_tokss (lexer, n).string;
 }
-\f
-/* Weird line reading functions. */
 
-/* Remove C-style comments in STRING, begun by slash-star and
-   terminated by star-slash or newline. */
-static void
-strip_comments (struct string *string)
+/* Returns the string in the token N after the current one, in UTF-8 encoding.
+   The string is null-terminated (but the null terminator is not included in
+   the returned substring's 'length').
+
+   Only T_ID and T_STRING tokens have meaningful strings.  For other tokens
+   this functions this function will always return NULL.
+
+   The UTF-8 encoding of the returned string is correct for variable names and
+   other identifiers.  Use filename_to_utf8() to use it as a filename.  Use
+   data_in() to use it in a "union value".  */
+struct substring
+lex_next_tokss (const struct lexer *lexer, int n)
+{
+  return lex_next (lexer, n)->string;
+}
+
+/* If LEXER is positioned at the (pseudo)identifier S, skips it and returns
+   true.  Otherwise, returns false.
+
+   S may consist of an arbitrary number of identifiers, integers, and
+   punctuation e.g. "KRUSKAL-WALLIS", "2SLS", or "END INPUT PROGRAM".
+   Identifiers may be abbreviated to their first three letters.  Currently only
+   hyphens, slashes, and equals signs are supported as punctuation (but it
+   would be easy to add more).
+
+   S must be an ASCII string. */
+bool
+lex_match_phrase (struct lexer *lexer, const char *s)
 {
-  char *cp;
-  int quote;
-  bool in_comment;
+  int tok_idx;
 
-  in_comment = false;
-  quote = EOF;
-  for (cp = ds_cstr (string); *cp; )
+  for (tok_idx = 0; ; tok_idx++)
     {
-      /* If we're not in a comment, check for quote marks. */
-      if (!in_comment)
+      enum token_type token;
+      unsigned char c;
+
+      while (c_isspace (*s))
+        s++;
+
+      c = *s;
+      if (c == '\0')
         {
-          if (*cp == quote)
-            quote = EOF;
-          else if (*cp == '\'' || *cp == '"')
-            quote = *cp;
+          int i;
+
+          for (i = 0; i < tok_idx; i++)
+            lex_get (lexer);
+          return true;
         }
 
-      /* If we're not inside a quotation, check for comment. */
-      if (quote == EOF)
+      token = lex_next_token (lexer, tok_idx);
+      switch (c)
         {
-          if (cp[0] == '/' && cp[1] == '*')
-            {
-              in_comment = true;
-              *cp++ = ' ';
-              *cp++ = ' ';
-              continue;
-            }
-          else if (in_comment && cp[0] == '*' && cp[1] == '/')
+        case '-':
+          if (token != T_DASH)
+            return false;
+          s++;
+          break;
+
+        case '/':
+          if (token != T_SLASH)
+            return false;
+          s++;
+          break;
+
+        case '=':
+          if (token != T_EQUALS)
+            return false;
+          s++;
+          break;
+
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+          {
+            unsigned int value;
+
+            if (token != T_POS_NUM)
+              return false;
+
+            value = 0;
+            do
+              {
+                value = value * 10 + (*s++ - '0');
+              }
+            while (c_isdigit (*s));
+
+            if (lex_next_tokval (lexer, tok_idx) != value)
+              return false;
+          }
+          break;
+
+        default:
+          if (lex_is_id1 (c))
             {
-              in_comment = false;
-              *cp++ = ' ';
-              *cp++ = ' ';
-              continue;
+              int len;
+
+              if (token != T_ID)
+                return false;
+
+              len = lex_id_get_length (ss_cstr (s));
+              if (!lex_id_match (ss_buffer (s, len),
+                                 lex_next_tokss (lexer, tok_idx)))
+                return false;
+
+              s += len;
             }
+          else
+            NOT_REACHED ();
         }
+    }
+}
+
+static int
+lex_source_get_first_line_number (const struct lex_source *src, int n)
+{
+  return lex_source_next__ (src, n)->first_line;
+}
+
+static int
+count_newlines (char *s, size_t length)
+{
+  int n_newlines = 0;
+  char *newline;
 
-      /* Check commenting. */
-      if (in_comment)
-        *cp = ' ';
-      cp++;
+  while ((newline = memchr (s, '\n', length)) != NULL)
+    {
+      n_newlines++;
+      length -= (newline + 1) - s;
+      s = newline + 1;
     }
+
+  return n_newlines;
 }
 
-/* Prepares LINE, which is subject to the given SYNTAX rules, for
-   tokenization by stripping comments and determining whether it
-   is the beginning or end of a command and storing into
-   *LINE_STARTS_COMMAND and *LINE_ENDS_COMMAND appropriately. */
-void
-lex_preprocess_line (struct string *line,
-                     enum syntax_mode syntax,
-                     bool *line_starts_command,
-                     bool *line_ends_command)
-{
-  strip_comments (line);
-  ds_rtrim (line, ss_cstr (CC_SPACES));
-  *line_ends_command = (ds_chomp (line, settings_get_endcmd ())
-                        || (ds_is_empty (line) && settings_get_nulline ()));
-  *line_starts_command = false;
-  if (syntax == GETL_BATCH)
+static int
+lex_source_get_last_line_number (const struct lex_source *src, int n)
+{
+  const struct lex_token *token = lex_source_next__ (src, n);
+
+  if (token->first_line == 0)
+    return 0;
+  else
     {
-      int first = ds_first (line);
-      *line_starts_command = !c_isspace (first);
-      if (first == '+' || first == '-')
-        *ds_data (line) = ' ';
+      char *token_str = &src->buffer[token->token_pos - src->tail];
+      return token->first_line + count_newlines (token_str, token->token_len) + 1;
     }
 }
 
-/* Reads a line, without performing any preprocessing. */
-bool
-lex_get_line_raw (struct lexer *lexer)
+static int
+count_columns (const char *s_, size_t length)
 {
-  bool ok = getl_read_line (lexer->ss, &lexer->line_buffer);
-  if (ok)
+  const uint8_t *s = CHAR_CAST (const uint8_t *, s_);
+  int columns;
+  size_t ofs;
+  int mblen;
+
+  columns = 0;
+  for (ofs = 0; ofs < length; ofs += mblen)
     {
-      const char *line = ds_cstr (&lexer->line_buffer);
-      text_item_submit (text_item_create (TEXT_ITEM_SYNTAX, line));
+      ucs4_t uc;
+
+      mblen = u8_mbtouc (&uc, s + ofs, length - ofs);
+      if (uc != '\t')
+        {
+          int width = uc_width (uc, "UTF-8");
+          if (width > 0)
+            columns += width;
+        }
+      else
+        columns = ROUND_UP (columns + 1, 8);
     }
-  else
-    lexer->prog = NULL;
-  return ok;
+
+  return columns + 1;
 }
 
-/* Reads a line for use by the tokenizer, and preprocesses it by
-   removing comments, stripping trailing whitespace and the
-   terminal dot, and removing leading indentors. */
-bool
-lex_get_line (struct lexer *lexer)
+static int
+lex_source_get_first_column (const struct lex_source *src, int n)
 {
-  bool line_starts_command;
+  const struct lex_token *token = lex_source_next__ (src, n);
+  return count_columns (&src->buffer[token->line_pos - src->tail],
+                        token->token_pos - token->line_pos);
+}
 
-  if (!lex_get_line_raw (lexer))
-    return false;
+static int
+lex_source_get_last_column (const struct lex_source *src, int n)
+{
+  const struct lex_token *token = lex_source_next__ (src, n);
+  char *start, *end, *newline;
+
+  start = &src->buffer[token->line_pos - src->tail];
+  end = &src->buffer[(token->token_pos + token->token_len) - src->tail];
+  newline = memrchr (start, '\n', end - start);
+  if (newline != NULL)
+    start = newline + 1;
+  return count_columns (start, end - start);
+}
 
-  lex_preprocess_line (&lexer->line_buffer,
-                      lex_current_syntax_mode (lexer),
-                       &line_starts_command, &lexer->dot);
+/* Returns the 1-based line number of the start of the syntax that represents
+   the token N after the current one in LEXER.  Returns 0 for a T_STOP token or
+   if the token is drawn from a source that does not have line numbers. */
+int
+lex_get_first_line_number (const struct lexer *lexer, int n)
+{
+  const struct lex_source *src = lex_source__ (lexer);
+  return src != NULL ? lex_source_get_first_line_number (src, n) : 0;
+}
 
-  if (line_starts_command)
-    lexer->put_token = '.';
+/* Returns the 1-based line number of the end of the syntax that represents the
+   token N after the current one in LEXER, plus 1.  Returns 0 for a T_STOP
+   token or if the token is drawn from a source that does not have line
+   numbers.
 
-  lexer->prog = ds_cstr (&lexer->line_buffer);
-  return true;
+   Most of the time, a single token is wholly within a single line of syntax,
+   but there are two exceptions: a T_STRING token can be made up of multiple
+   segments on adjacent lines connected with "+" punctuators, and a T_NEG_NUM
+   token can consist of a "-" on one line followed by the number on the next.
+ */
+int
+lex_get_last_line_number (const struct lexer *lexer, int n)
+{
+  const struct lex_source *src = lex_source__ (lexer);
+  return src != NULL ? lex_source_get_last_line_number (src, n) : 0;
 }
-\f
-/* Token names. */
 
-/* Returns the name of a token. */
+/* Returns the 1-based column number of the start of the syntax that represents
+   the token N after the current one in LEXER.  Returns 0 for a T_STOP
+   token.
+
+   Column numbers are measured according to the width of characters as shown in
+   a typical fixed-width font, in which CJK characters have width 2 and
+   combining characters have width 0.  */
+int
+lex_get_first_column (const struct lexer *lexer, int n)
+{
+  const struct lex_source *src = lex_source__ (lexer);
+  return src != NULL ? lex_source_get_first_column (src, n) : 0;
+}
+
+/* Returns the 1-based column number of the end of the syntax that represents
+   the token N after the current one in LEXER, plus 1.  Returns 0 for a T_STOP
+   token.
+
+   Column numbers are measured according to the width of characters as shown in
+   a typical fixed-width font, in which CJK characters have width 2 and
+   combining characters have width 0.  */
+int
+lex_get_last_column (const struct lexer *lexer, int n)
+{
+  const struct lex_source *src = lex_source__ (lexer);
+  return src != NULL ? lex_source_get_last_column (src, n) : 0;
+}
+
+/* Returns the name of the syntax file from which the current command is drawn.
+   Returns NULL for a T_STOP token or if the command's source does not have
+   line numbers.
+
+   There is no version of this function that takes an N argument because
+   lookahead only works to the end of a command and any given command is always
+   within a single syntax file. */
 const char *
-lex_token_name (int token)
+lex_get_file_name (const struct lexer *lexer)
 {
-  if (lex_is_keyword (token))
-    return lex_id_name (token);
-  else if (token < 256)
-    {
-      static char t[256][2];
-      char *s = t[token];
-      s[0] = token;
-      s[1] = '\0';
-      return s;
-    }
-  else
-    NOT_REACHED ();
+  struct lex_source *src = lex_source__ (lexer);
+  return src == NULL ? NULL : src->reader->file_name;
 }
 
-/* Returns an ASCII representation of the current token as a
-   malloc()'d string. */
-char *
-lex_token_representation (struct lexer *lexer)
+/* Returns the syntax mode for the syntax file from which the current drawn is
+   drawn.  Returns LEX_SYNTAX_AUTO for a T_STOP token or if the command's
+   source does not have line numbers.
+
+   There is no version of this function that takes an N argument because
+   lookahead only works to the end of a command and any given command is always
+   within a single syntax file. */
+enum lex_syntax_mode
+lex_get_syntax_mode (const struct lexer *lexer)
 {
-  char *token_rep;
+  struct lex_source *src = lex_source__ (lexer);
+  return src == NULL ? LEX_SYNTAX_AUTO : src->reader->syntax;
+}
+
+/* Returns the error mode for the syntax file from which the current drawn is
+   drawn.  Returns LEX_ERROR_INTERACTIVE for a T_STOP token or if the command's
+   source does not have line numbers.
+
+   There is no version of this function that takes an N argument because
+   lookahead only works to the end of a command and any given command is always
+   within a single syntax file. */
+enum lex_error_mode
+lex_get_error_mode (const struct lexer *lexer)
+{
+  struct lex_source *src = lex_source__ (lexer);
+  return src == NULL ? LEX_ERROR_INTERACTIVE : src->reader->error;
+}
+
+/* If the source that LEXER is currently reading has error mode
+   LEX_ERROR_INTERACTIVE, discards all buffered input and tokens, so that the
+   next token to be read comes directly from whatever is next read from the
+   stream.
 
-  switch (lexer->token)
+   It makes sense to call this function after encountering an error in a
+   command entered on the console, because usually the user would prefer not to
+   have cascading errors. */
+void
+lex_interactive_reset (struct lexer *lexer)
+{
+  struct lex_source *src = lex_source__ (lexer);
+  if (src != NULL && src->reader->error == LEX_ERROR_INTERACTIVE)
     {
-    case T_ID:
-    case T_POS_NUM:
-    case T_NEG_NUM:
-      return ds_xstrdup (&lexer->tokstr);
-      break;
+      src->head = src->tail = 0;
+      src->journal_pos = src->seg_pos = src->line_pos = 0;
+      src->n_newlines = 0;
+      src->suppress_next_newline = false;
+      segmenter_init (&src->segmenter, segmenter_get_mode (&src->segmenter));
+      while (!deque_is_empty (&src->deque))
+        lex_source_pop__ (src);
+      lex_source_push_endcmd__ (src);
+    }
+}
 
-    case T_STRING:
-      {
-       int hexstring = 0;
-       char *sp, *dp;
-
-       for (sp = ds_cstr (&lexer->tokstr); sp < ds_end (&lexer->tokstr); sp++)
-         if (!c_isprint ((unsigned char) *sp))
-           {
-             hexstring = 1;
-             break;
-           }
-
-       token_rep = xmalloc (2 + ds_length (&lexer->tokstr) * 2 + 1 + 1);
-
-       dp = token_rep;
-       if (hexstring)
-         *dp++ = 'X';
-       *dp++ = '\'';
-
-       if (!hexstring)
-         for (sp = ds_cstr (&lexer->tokstr); *sp; )
-           {
-             if (*sp == '\'')
-               *dp++ = '\'';
-             *dp++ = (unsigned char) *sp++;
-           }
-       else
-         for (sp = ds_cstr (&lexer->tokstr); sp < ds_end (&lexer->tokstr); sp++)
-           {
-             *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
-             *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
-           }
-       *dp++ = '\'';
-       *dp = '\0';
-
-       return token_rep;
-      }
-    break;
+/* Advances past any tokens in LEXER up to a T_ENDCMD or T_STOP. */
+void
+lex_discard_rest_of_command (struct lexer *lexer)
+{
+  while (lex_token (lexer) != T_STOP && lex_token (lexer) != T_ENDCMD)
+    lex_get (lexer);
+}
 
-    case T_STOP:
-      token_rep = xmalloc (1);
-      *token_rep = '\0';
-      return token_rep;
+/* Discards all lookahead tokens in LEXER, then discards all input sources
+   until it encounters one with error mode LEX_ERROR_INTERACTIVE or until it
+   runs out of input sources. */
+void
+lex_discard_noninteractive (struct lexer *lexer)
+{
+  struct lex_source *src = lex_source__ (lexer);
 
-    case T_EXP:
-      return xstrdup ("**");
+  if (src != NULL)
+    {
+      while (!deque_is_empty (&src->deque))
+        lex_source_pop__ (src);
 
-    default:
-      return xstrdup (lex_token_name (lexer->token));
+      for (; src != NULL && src->reader->error != LEX_ERROR_INTERACTIVE;
+           src = lex_source__ (lexer))
+        lex_source_destroy (src);
     }
-
-  NOT_REACHED ();
 }
 \f
-/* Really weird functions. */
+static size_t
+lex_source_max_tail__ (const struct lex_source *src)
+{
+  const struct lex_token *token;
+  size_t max_tail;
 
-/* Most of the time, a `-' is a lead-in to a negative number.  But
-   sometimes it's actually part of the syntax.  If a dash can be part
-   of syntax then this function is called to rip it off of a
-   number. */
-void
-lex_negative_to_dash (struct lexer *lexer)
+  assert (src->seg_pos >= src->line_pos);
+  max_tail = MIN (src->journal_pos, src->line_pos);
+
+  /* Use the oldest token also.  (We know that src->deque cannot be empty
+     because we are in the process of adding a new token, which is already
+     initialized enough to use here.) */
+  token = &src->tokens[deque_back (&src->deque, 0)];
+  assert (token->token_pos >= token->line_pos);
+  max_tail = MIN (max_tail, token->line_pos);
+
+  return max_tail;
+}
+
+static void
+lex_source_expand__ (struct lex_source *src)
 {
-  if (lexer->token == T_NEG_NUM)
+  if (src->head - src->tail >= src->allocated)
+    {
+      size_t max_tail = lex_source_max_tail__ (src);
+      if (max_tail > src->tail)
+        {
+          /* Advance the tail, freeing up room at the head. */
+          memmove (src->buffer, src->buffer + (max_tail - src->tail),
+                   src->head - max_tail);
+          src->tail = max_tail;
+        }
+      else
+        {
+          /* Buffer is completely full.  Expand it. */
+          src->buffer = x2realloc (src->buffer, &src->allocated);
+        }
+    }
+  else
     {
-      lexer->token = T_POS_NUM;
-      lexer->tokval = -lexer->tokval;
-      ds_assign_substring (&lexer->tokstr, ds_substr (&lexer->tokstr, 1, SIZE_MAX));
-      save_token (lexer);
-      lexer->token = '-';
+      /* There's space available at the head of the buffer.  Nothing to do. */
     }
 }
 
-/* Skip a COMMENT command. */
-void
-lex_skip_comment (struct lexer *lexer)
+static void
+lex_source_read__ (struct lex_source *src)
 {
-  for (;;)
+  do
     {
-      if (!lex_get_line (lexer))
+      size_t head_ofs;
+      size_t n;
+
+      lex_source_expand__ (src);
+
+      head_ofs = src->head - src->tail;
+      n = src->reader->class->read (src->reader, &src->buffer[head_ofs],
+                                    src->allocated - head_ofs,
+                                    segmenter_get_prompt (&src->segmenter));
+      if (n == 0)
         {
-          lexer->put_token = T_STOP;
-         lexer->prog = NULL;
+          /* End of input.
+
+             Ensure that the input always ends in a new-line followed by a null
+             byte, as required by the segmenter library. */
+
+          if (src->head == src->tail
+              || src->buffer[src->head - src->tail - 1] != '\n')
+            src->buffer[src->head++ - src->tail] = '\n';
+
+          lex_source_expand__ (src);
+          src->buffer[src->head++ - src->tail] = '\0';
+
           return;
         }
 
-      if (lexer->put_token == '.')
-       break;
+      src->head += n;
+    }
+  while (!memchr (&src->buffer[src->seg_pos - src->tail], '\n',
+                  src->head - src->seg_pos));
+}
+
+static struct lex_source *
+lex_source__ (const struct lexer *lexer)
+{
+  return (ll_is_empty (&lexer->sources) ? NULL
+          : ll_data (ll_head (&lexer->sources), struct lex_source, ll));
+}
+
+static struct substring
+lex_source_get_syntax__ (const struct lex_source *src, int n0, int n1)
+{
+  const struct lex_token *token0 = lex_source_next__ (src, n0);
+  const struct lex_token *token1 = lex_source_next__ (src, MAX (n0, n1));
+  size_t start = token0->token_pos;
+  size_t end = token1->token_pos + token1->token_len;
+
+  return ss_buffer (&src->buffer[start - src->tail], end - start);
+}
+
+static void
+lex_ellipsize__ (struct substring in, char *out, size_t out_size)
+{
+  size_t out_maxlen;
+  size_t out_len;
+  int mblen;
 
-      ds_cstr (&lexer->line_buffer); /* Ensures ds_end will point to a valid char */
-      lexer->prog = ds_end (&lexer->line_buffer);
-      if (lexer->dot)
-       break;
+  assert (out_size >= 16);
+  out_maxlen = out_size - (in.length >= out_size ? 3 : 0) - 1;
+  for (out_len = 0; out_len < in.length; out_len += mblen)
+    {
+      if (in.string[out_len] == '\n'
+          || (in.string[out_len] == '\r'
+              && out_len + 1 < in.length
+              && in.string[out_len + 1] == '\n'))
+        break;
+
+      mblen = u8_mblen (CHAR_CAST (const uint8_t *, in.string + out_len),
+                        in.length - out_len);
+      if (out_len + mblen > out_maxlen)
+        break;
     }
+
+  memcpy (out, in.string, out_len);
+  strcpy (&out[out_len], out_len < in.length ? "..." : "");
 }
-\f
-/* Private functions. */
 
-/* When invoked, tokstr contains a string of binary, octal, or
-   hex digits, according to TYPE.  The string is converted to
-   characters having the specified values. */
 static void
-convert_numeric_string_to_char_string (struct lexer *lexer,
-                                      enum string_type type)
+lex_source_error_valist (struct lex_source *src, int n0, int n1,
+                         const char *format, va_list args)
 {
-  const char *base_name;
-  int base;
-  int chars_per_byte;
-  size_t byte_cnt;
-  size_t i;
-  char *p;
+  const struct lex_token *token;
+  struct string s;
+  struct msg m;
 
-  switch (type)
+  ds_init_empty (&s);
+
+  token = lex_source_next__ (src, n0);
+  if (token->token.type == T_ENDCMD)
+    ds_put_cstr (&s, _("Syntax error at end of command"));
+  else
+    {
+      struct substring syntax = lex_source_get_syntax__ (src, n0, n1);
+      if (!ss_is_empty (syntax))
+        {
+          char syntax_cstr[64];
+
+          lex_ellipsize__ (syntax, syntax_cstr, sizeof syntax_cstr);
+          ds_put_format (&s, _("Syntax error at `%s'"), syntax_cstr);
+        }
+      else
+        ds_put_cstr (&s, _("Syntax error"));
+    }
+
+  if (format)
     {
-    case BINARY_STRING:
-      base_name = _("binary");
-      base = 2;
-      chars_per_byte = 8;
+      ds_put_cstr (&s, ": ");
+      ds_put_vformat (&s, format, args);
+    }
+  ds_put_byte (&s, '.');
+
+  m.category = MSG_C_SYNTAX;
+  m.severity = MSG_S_ERROR;
+  m.file_name = src->reader->file_name;
+  m.first_line = lex_source_get_first_line_number (src, n0);
+  m.last_line = lex_source_get_last_line_number (src, n1);
+  m.first_column = lex_source_get_first_column (src, n0);
+  m.last_column = lex_source_get_last_column (src, n1);
+  m.text = ds_steal_cstr (&s);
+  msg_emit (&m);
+}
+
+static void PRINTF_FORMAT (2, 3)
+lex_get_error (struct lex_source *src, const char *format, ...)
+{
+  va_list args;
+  int n;
+
+  va_start (args, format);
+
+  n = deque_count (&src->deque) - 1;
+  lex_source_error_valist (src, n, n, format, args);
+  lex_source_pop_front (src);
+
+  va_end (args);
+}
+
+static bool
+lex_source_get__ (const struct lex_source *src_)
+{
+  struct lex_source *src = CONST_CAST (struct lex_source *, src_);
+
+  struct state
+    {
+      struct segmenter segmenter;
+      enum segment_type last_segment;
+      int newlines;
+      size_t line_pos;
+      size_t seg_pos;
+    };
+
+  struct state state, saved;
+  enum scan_result result;
+  struct scanner scanner;
+  struct lex_token *token;
+  int n_lines;
+  int i;
+
+  if (src->eof)
+    return false;
+
+  state.segmenter = src->segmenter;
+  state.newlines = 0;
+  state.seg_pos = src->seg_pos;
+  state.line_pos = src->line_pos;
+  saved = state;
+
+  token = lex_push_token__ (src);
+  scanner_init (&scanner, &token->token);
+  token->line_pos = src->line_pos;
+  token->token_pos = src->seg_pos;
+  if (src->reader->line_number > 0)
+    token->first_line = src->reader->line_number + src->n_newlines;
+  else
+    token->first_line = 0;
+
+  for (;;)
+    {
+      enum segment_type type;
+      const char *segment;
+      size_t seg_maxlen;
+      int seg_len;
+
+      segment = &src->buffer[state.seg_pos - src->tail];
+      seg_maxlen = src->head - state.seg_pos;
+      seg_len = segmenter_push (&state.segmenter, segment, seg_maxlen, &type);
+      if (seg_len < 0)
+        {
+          lex_source_read__ (src);
+          continue;
+        }
+
+      state.last_segment = type;
+      state.seg_pos += seg_len;
+      if (type == SEG_NEWLINE)
+        {
+          state.newlines++;
+          state.line_pos = state.seg_pos;
+        }
+
+      result = scanner_push (&scanner, type, ss_buffer (segment, seg_len),
+                             &token->token);
+      if (result == SCAN_SAVE)
+        saved = state;
+      else if (result == SCAN_BACK)
+        {
+          state = saved;
+          break;
+        }
+      else if (result == SCAN_DONE)
+        break;
+    }
+
+  n_lines = state.newlines;
+  if (state.last_segment == SEG_END_COMMAND && !src->suppress_next_newline)
+    {
+      n_lines++;
+      src->suppress_next_newline = true;
+    }
+  else if (n_lines > 0 && src->suppress_next_newline)
+    {
+      n_lines--;
+      src->suppress_next_newline = false;
+    }
+  for (i = 0; i < n_lines; i++)
+    {
+      const char *newline;
+      const char *line;
+      size_t line_len;
+      char *syntax;
+
+      line = &src->buffer[src->journal_pos - src->tail];
+      newline = rawmemchr (line, '\n');
+      line_len = newline - line;
+      if (line_len > 0 && line[line_len - 1] == '\r')
+        line_len--;
+
+      syntax = malloc (line_len + 2);
+      memcpy (syntax, line, line_len);
+      syntax[line_len] = '\n';
+      syntax[line_len + 1] = '\0';
+
+      text_item_submit (text_item_create_nocopy (TEXT_ITEM_SYNTAX, syntax));
+
+      src->journal_pos += newline - line + 1;
+    }
+
+  token->token_len = state.seg_pos - src->seg_pos;
+
+  src->segmenter = state.segmenter;
+  src->seg_pos = state.seg_pos;
+  src->line_pos = state.line_pos;
+  src->n_newlines += state.newlines;
+
+  switch (token->token.type)
+    {
+    default:
       break;
-    case OCTAL_STRING:
-      base_name = _("octal");
-      base = 8;
-      chars_per_byte = 3;
+
+    case T_STOP:
+      token->token.type = T_ENDCMD;
+      src->eof = true;
       break;
-    case HEX_STRING:
-      base_name = _("hex");
-      base = 16;
-      chars_per_byte = 2;
+
+    case SCAN_BAD_HEX_LENGTH:
+      lex_get_error (src, _("String of hex digits has %d characters, which "
+                            "is not a multiple of 2"),
+                     (int) token->token.number);
+      break;
+
+    case SCAN_BAD_HEX_DIGIT:
+    case SCAN_BAD_UNICODE_DIGIT:
+      lex_get_error (src, _("`%c' is not a valid hex digit"),
+                     (int) token->token.number);
+      break;
+
+    case SCAN_BAD_UNICODE_LENGTH:
+      lex_get_error (src, _("Unicode string contains %d bytes, which is "
+                            "not in the valid range of 1 to 8 bytes"),
+                     (int) token->token.number);
+      break;
+
+    case SCAN_BAD_UNICODE_CODE_POINT:
+      lex_get_error (src, _("U+%04X is not a valid Unicode code point"),
+                     (int) token->token.number);
+      break;
+
+    case SCAN_EXPECTED_QUOTE:
+      lex_get_error (src, _("Unterminated string constant"));
+      break;
+
+    case SCAN_EXPECTED_EXPONENT:
+      lex_get_error (src, _("Missing exponent following `%s'"),
+                     token->token.string.string);
+      break;
+
+    case SCAN_UNEXPECTED_DOT:
+      lex_get_error (src, _("Unexpected `.' in middle of command"));
+      break;
+
+    case SCAN_UNEXPECTED_CHAR:
+      {
+        char c_name[16];
+        lex_get_error (src, _("Bad character %s in input"),
+                       uc_name (token->token.number, c_name));
+      }
+      break;
+
+    case SCAN_SKIP:
+      lex_source_pop_front (src);
       break;
-    default:
-      NOT_REACHED ();
     }
 
-  byte_cnt = ds_length (&lexer->tokstr) / chars_per_byte;
-  if (ds_length (&lexer->tokstr) % chars_per_byte)
-    msg (SE, _("String of %s digits has %zu characters, which is not a "
-              "multiple of %d."),
-        base_name, ds_length (&lexer->tokstr), chars_per_byte);
+  return true;
+}
+\f
+static void
+lex_source_push_endcmd__ (struct lex_source *src)
+{
+  struct lex_token *token = lex_push_token__ (src);
+  token->token.type = T_ENDCMD;
+  token->token_pos = 0;
+  token->token_len = 0;
+  token->line_pos = 0;
+  token->first_line = 0;
+}
+
+static struct lex_source *
+lex_source_create (struct lex_reader *reader)
+{
+  struct lex_source *src;
+  enum segmenter_mode mode;
+
+  src = xzalloc (sizeof *src);
+  src->reader = reader;
+
+  if (reader->syntax == LEX_SYNTAX_AUTO)
+    mode = SEG_MODE_AUTO;
+  else if (reader->syntax == LEX_SYNTAX_INTERACTIVE)
+    mode = SEG_MODE_INTERACTIVE;
+  else if (reader->syntax == LEX_SYNTAX_BATCH)
+    mode = SEG_MODE_BATCH;
+  else
+    NOT_REACHED ();
+  segmenter_init (&src->segmenter, mode);
+
+  src->tokens = deque_init (&src->deque, 4, sizeof *src->tokens);
+
+  lex_source_push_endcmd__ (src);
+
+  return src;
+}
 
-  p = ds_cstr (&lexer->tokstr);
-  for (i = 0; i < byte_cnt; i++)
+static void
+lex_source_destroy (struct lex_source *src)
+{
+  char *file_name = src->reader->file_name;
+  if (src->reader->class->close != NULL)
+    src->reader->class->close (src->reader);
+  free (file_name);
+  free (src->buffer);
+  while (!deque_is_empty (&src->deque))
+    lex_source_pop__ (src);
+  free (src->tokens);
+  ll_remove (&src->ll);
+  free (src);
+}
+\f
+struct lex_file_reader
+  {
+    struct lex_reader reader;
+    struct u8_istream *istream;
+    char *file_name;
+  };
+
+static struct lex_reader_class lex_file_reader_class;
+
+/* Creates and returns a new lex_reader that will read from file FILE_NAME (or
+   from stdin if FILE_NAME is "-").  The file is expected to be encoded with
+   ENCODING, which should take one of the forms accepted by
+   u8_istream_for_file().  SYNTAX and ERROR become the syntax mode and error
+   mode of the new reader, respectively.
+
+   Returns a null pointer if FILE_NAME cannot be opened. */
+struct lex_reader *
+lex_reader_for_file (const char *file_name, const char *encoding,
+                     enum lex_syntax_mode syntax,
+                     enum lex_error_mode error)
+{
+  struct lex_file_reader *r;
+  struct u8_istream *istream;
+
+  istream = (!strcmp(file_name, "-")
+             ? u8_istream_for_fd (encoding, STDIN_FILENO)
+             : u8_istream_for_file (encoding, file_name, O_RDONLY));
+  if (istream == NULL)
     {
-      int value;
-      int j;
-
-      value = 0;
-      for (j = 0; j < chars_per_byte; j++, p++)
-       {
-         int v;
-
-         if (*p >= '0' && *p <= '9')
-           v = *p - '0';
-         else
-           {
-             static const char alpha[] = "abcdef";
-             const char *q = strchr (alpha, tolower ((unsigned char) *p));
-
-             if (q)
-               v = q - alpha + 10;
-             else
-               v = base;
-           }
-
-         if (v >= base)
-           msg (SE, _("`%c' is not a valid %s digit."), *p, base_name);
-
-         value = value * base + v;
-       }
-
-      ds_cstr (&lexer->tokstr)[i] = (unsigned char) value;
+      msg (ME, _("Opening `%s': %s."), file_name, strerror (errno));
+      return NULL;
     }
 
-  ds_truncate (&lexer->tokstr, byte_cnt);
+  r = xmalloc (sizeof *r);
+  lex_reader_init (&r->reader, &lex_file_reader_class);
+  r->reader.syntax = syntax;
+  r->reader.error = error;
+  r->reader.file_name = xstrdup (file_name);
+  r->reader.line_number = 1;
+  r->istream = istream;
+  r->file_name = xstrdup (file_name);
+
+  return &r->reader;
 }
 
-/* Parses a string from the input buffer into tokstr.  The input
-   buffer pointer lexer->prog must point to the initial single or double
-   quote.  TYPE indicates the type of string to be parsed.
-   Returns token type. */
-static int
-parse_string (struct lexer *lexer, enum string_type type)
+static struct lex_file_reader *
+lex_file_reader_cast (struct lex_reader *r)
 {
-  if (type != CHARACTER_STRING)
-    lexer->prog++;
+  return UP_CAST (r, struct lex_file_reader, reader);
+}
 
-  /* Accumulate the entire string, joining sections indicated by +
-     signs. */
-  for (;;)
+static size_t
+lex_file_read (struct lex_reader *r_, char *buf, size_t n,
+               enum prompt_style prompt_style UNUSED)
+{
+  struct lex_file_reader *r = lex_file_reader_cast (r_);
+  ssize_t n_read = u8_istream_read (r->istream, buf, n);
+  if (n_read < 0)
     {
-      /* Single or double quote. */
-      int c = *lexer->prog++;
-
-      /* Accumulate section. */
-      for (;;)
-       {
-         /* Check end of line. */
-         if (*lexer->prog == '\0')
-           {
-             msg (SE, _("Unterminated string constant."));
-             goto finish;
-           }
-
-         /* Double quote characters to embed them in strings. */
-         if (*lexer->prog == c)
-           {
-             if (lexer->prog[1] == c)
-               lexer->prog++;
-             else
-               break;
-           }
-
-         ds_put_char (&lexer->tokstr, *lexer->prog++);
-       }
-      lexer->prog++;
-
-      /* Skip whitespace after final quote mark. */
-      if (lexer->prog == NULL)
-       break;
-      for (;;)
-       {
-         while (c_isspace ((unsigned char) *lexer->prog))
-           lexer->prog++;
-         if (*lexer->prog)
-           break;
-
-         if (lexer->dot)
-           goto finish;
-
-         if (!lex_get_line (lexer))
-            goto finish;
-       }
-
-      /* Skip plus sign. */
-      if (*lexer->prog != '+')
-       break;
-      lexer->prog++;
-
-      /* Skip whitespace after plus sign. */
-      if (lexer->prog == NULL)
-       break;
-      for (;;)
-       {
-         while (c_isspace ((unsigned char) *lexer->prog))
-           lexer->prog++;
-         if (*lexer->prog)
-           break;
-
-         if (lexer->dot)
-           goto finish;
-
-         if (!lex_get_line (lexer))
-            {
-              msg (SE, _("Unexpected end of file in string concatenation."));
-              goto finish;
-            }
-       }
-
-      /* Ensure that a valid string follows. */
-      if (*lexer->prog != '\'' && *lexer->prog != '"')
-       {
-         msg (SE, _("String expected following `+'."));
-         goto finish;
-       }
+      msg (ME, _("Error reading `%s': %s."), r->file_name, strerror (errno));
+      return 0;
     }
+  return n_read;
+}
+
+static void
+lex_file_close (struct lex_reader *r_)
+{
+  struct lex_file_reader *r = lex_file_reader_cast (r_);
 
-  /* We come here when we've finished concatenating all the string sections
-     into one large string. */
-finish:
-  if (type != CHARACTER_STRING)
-    convert_numeric_string_to_char_string (lexer, type);
+  if (u8_istream_fileno (r->istream) != STDIN_FILENO)
+    {
+      if (u8_istream_close (r->istream) != 0)
+        msg (ME, _("Error closing `%s': %s."), r->file_name, strerror (errno));
+    }
+  else
+    u8_istream_free (r->istream);
 
-  return T_STRING;
+  free (r->file_name);
+  free (r);
 }
+
+static struct lex_reader_class lex_file_reader_class =
+  {
+    lex_file_read,
+    lex_file_close
+  };
 \f
-/* Token Accessor Functions */
+struct lex_string_reader
+  {
+    struct lex_reader reader;
+    struct substring s;
+    size_t offset;
+  };
 
-int
-lex_token (const struct lexer *lexer)
+static struct lex_reader_class lex_string_reader_class;
+
+/* Creates and returns a new lex_reader for the contents of S, which must be
+   encoded in UTF-8.  The new reader takes ownership of S and will free it
+   with ss_dealloc() when it is closed. */
+struct lex_reader *
+lex_reader_for_substring_nocopy (struct substring s)
 {
-  return lexer->token;
+  struct lex_string_reader *r;
+
+  r = xmalloc (sizeof *r);
+  lex_reader_init (&r->reader, &lex_string_reader_class);
+  r->reader.syntax = LEX_SYNTAX_INTERACTIVE;
+  r->s = s;
+  r->offset = 0;
+
+  return &r->reader;
 }
 
-double
-lex_tokval (const struct lexer *lexer)
+/* Creates and returns a new lex_reader for a copy of null-terminated string S,
+   which must be encoded in UTF-8.  The caller retains ownership of S. */
+struct lex_reader *
+lex_reader_for_string (const char *s)
 {
-  return lexer->tokval;
+  struct substring ss;
+  ss_alloc_substring (&ss, ss_cstr (s));
+  return lex_reader_for_substring_nocopy (ss);
 }
 
-const char *
-lex_tokid (const struct lexer *lexer)
+/* Formats FORMAT as a printf()-like format string and creates and returns a
+   new lex_reader for the formatted result.  */
+struct lex_reader *
+lex_reader_for_format (const char *format, ...)
 {
-  return lexer->tokid;
+  struct lex_reader *r;
+  va_list args;
+
+  va_start (args, format);
+  r = lex_reader_for_substring_nocopy (ss_cstr (xvasprintf (format, args)));
+  va_end (args);
+
+  return r;
 }
 
-const struct string *
-lex_tokstr (const struct lexer *lexer)
+static struct lex_string_reader *
+lex_string_reader_cast (struct lex_reader *r)
 {
-  return &lexer->tokstr;
+  return UP_CAST (r, struct lex_string_reader, reader);
 }
 
-/* If the lexer is positioned at the (pseudo)identifier S, which
-   may contain a hyphen ('-'), skips it and returns true.  Each
-   half of the identifier may be abbreviated to its first three
-   letters.
-   Otherwise, returns false. */
-bool
-lex_match_hyphenated_word (struct lexer *lexer, const char *s)
-{
-  const char *hyphen = strchr (s, '-');
-  if (hyphen == NULL)
-    return lex_match_id (lexer, s);
-  else if (lexer->token != T_ID
-          || !lex_id_match (ss_buffer (s, hyphen - s), ss_cstr (lexer->tokid))
-          || lex_look_ahead (lexer) != '-')
-    return false;
-  else
-    {
-      lex_get (lexer);
-      lex_force_match (lexer, '-');
-      lex_force_match_id (lexer, hyphen + 1);
-      return true;
-    }
+static size_t
+lex_string_read (struct lex_reader *r_, char *buf, size_t n,
+                 enum prompt_style prompt_style UNUSED)
+{
+  struct lex_string_reader *r = lex_string_reader_cast (r_);
+  size_t chunk;
+
+  chunk = MIN (n, r->s.length - r->offset);
+  memcpy (buf, r->s.string + r->offset, chunk);
+  r->offset += chunk;
+
+  return chunk;
 }
 
+static void
+lex_string_close (struct lex_reader *r_)
+{
+  struct lex_string_reader *r = lex_string_reader_cast (r_);
+
+  ss_dealloc (&r->s);
+  free (r);
+}
+
+static struct lex_reader_class lex_string_reader_class =
+  {
+    lex_string_read,
+    lex_string_close
+  };
index 9e5d09aec03f8dee7f96dcd73e7067f650ca9a22..b9e936bf994c67cdb7d6952950196f57170b3cf3 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, 2011 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 !lexer_h
-#define lexer_h 1
+#ifndef LEXER_H
+#define LEXER_H 1
 
-#include <ctype.h>
 #include <stdbool.h>
 #include <stddef.h>
-#include <data/identifier.h>
-#include <data/variable.h>
-#include <libpspp/getl.h>
+
+#include "data/identifier.h"
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/prompt.h"
 
 struct lexer;
 
+/* The syntax mode for which a syntax file is intended. */
+enum lex_syntax_mode
+  {
+    LEX_SYNTAX_AUTO,            /* Try to guess intent. */
+    LEX_SYNTAX_INTERACTIVE,     /* Interactive mode. */
+    LEX_SYNTAX_BATCH            /* Batch mode. */
+  };
+
+/* Handling of errors. */
+enum lex_error_mode
+  {
+    LEX_ERROR_INTERACTIVE,     /* Always continue to next command. */
+    LEX_ERROR_CONTINUE,        /* Continue to next command, except for
+                                  cascading failures. */
+    LEX_ERROR_STOP             /* Stop processing. */
+  };
+
+/* Reads a single syntax file as a stream of bytes encoded in UTF-8.
+
+   Not opaque. */
+struct lex_reader
+  {
+    const struct lex_reader_class *class;
+    enum lex_syntax_mode syntax;
+    enum lex_error_mode error;
+    char *file_name;            /* NULL if not associated with a file. */
+    int line_number;            /* 1-based initial line number, 0 if none. */
+  };
+
+/* An implementation of a lex_reader. */
+struct lex_reader_class
+  {
+    /* Reads up to N bytes of data from READER into N.  Returns the positive
+       number of bytes read if successful, or zero at end of input or on
+       error.
+
+       STYLE provides a hint to interactive readers as to what kind of syntax
+       is being read right now. */
+    size_t (*read) (struct lex_reader *reader, char *buf, size_t n,
+                    enum prompt_style style);
+
+    /* Closes and destroys READER, releasing any allocated storage.
+
+       The caller will free the 'file_name' member of READER, so the
+       implementation should not do so. */
+    void (*close) (struct lex_reader *reader);
+  };
+
+/* Helper functions for lex_reader. */
+void lex_reader_init (struct lex_reader *, const struct lex_reader_class *);
+void lex_reader_set_file_name (struct lex_reader *, const char *file_name);
+
+/* Creating various kinds of lex_readers. */
+struct lex_reader *lex_reader_for_file (const char *file_name,
+                                        const char *encoding,
+                                        enum lex_syntax_mode syntax,
+                                        enum lex_error_mode error);
+struct lex_reader *lex_reader_for_string (const char *);
+struct lex_reader *lex_reader_for_format (const char *, ...)
+  PRINTF_FORMAT (1, 2);
+struct lex_reader *lex_reader_for_substring_nocopy (struct substring);
+
 /* Initialization. */
-struct lexer * lex_create (struct source_stream *);
+struct lexer *lex_create (void);
 void lex_destroy (struct lexer *);
 
-/* State accessors */
-struct source_stream * lex_get_source_stream (const struct lexer *);
-enum syntax_mode lex_current_syntax_mode (const struct lexer *);
-enum error_mode lex_current_error_mode (const struct lexer *);
+/* Files. */
+void lex_include (struct lexer *, struct lex_reader *);
+void lex_append (struct lexer *, struct lex_reader *);
 
-/* Common functions. */
+/* Advancing. */
 void lex_get (struct lexer *);
-void lex_error (struct lexer *, const char *, ...);
-void lex_sbc_only_once (const char *);
-void lex_sbc_missing (struct lexer *, const char *);
-int lex_end_of_command (struct lexer *);
 
 /* Token testing functions. */
 bool lex_is_number (struct lexer *);
@@ -49,55 +107,68 @@ bool lex_is_integer (struct lexer *);
 long lex_integer (struct lexer *);
 bool lex_is_string (struct lexer *);
 
+/* Token testing functions with lookahead. */
+bool lex_next_is_number (struct lexer *, int n);
+double lex_next_number (struct lexer *, int n);
+bool lex_next_is_integer (struct lexer *, int n);
+long lex_next_integer (struct lexer *, int n);
+bool lex_next_is_string (struct lexer *, int n);
 
 /* Token matching functions. */
-bool lex_match (struct lexer *, int);
+bool lex_match (struct lexer *, enum token_type);
 bool lex_match_id (struct lexer *, const char *);
 bool lex_match_id_n (struct lexer *, const char *, size_t n);
 bool lex_match_int (struct lexer *, int);
-bool lex_match_hyphenated_word (struct lexer *lexer, const char *s);
-
+bool lex_match_phrase (struct lexer *, const char *s);
 
 /* Forcible matching functions. */
-bool lex_force_match (struct lexer *, int);
+bool lex_force_match (struct lexer *, enum token_type);
 bool lex_force_match_id (struct lexer *, const char *);
 bool lex_force_int (struct lexer *);
 bool lex_force_num (struct lexer *);
 bool lex_force_id (struct lexer *);
 bool lex_force_string (struct lexer *);
 
-/* Weird token functions. */
-int lex_look_ahead (struct lexer *);
-void lex_put_back (struct lexer *, int);
-void lex_put_back_id (struct lexer *, const char *tokid);
-
-/* Weird line processing functions. */
-const char *lex_entire_line (const struct lexer *);
-const struct string *lex_entire_line_ds (const struct lexer *);
-const char *lex_rest_of_line (const struct lexer *);
-bool lex_end_dot (const struct lexer *);
-void lex_preprocess_line (struct string *, enum syntax_mode,
-                          bool *line_starts_command,
-                          bool *line_ends_command);
-void lex_discard_line (struct lexer *);
-void lex_discard_rest_of_command (struct lexer *);
-
-/* Weird line reading functions. */
-bool lex_get_line (struct lexer *);
-bool lex_get_line_raw (struct lexer *);
+/* Token accessors. */
+enum token_type lex_token (const struct lexer *);
+double lex_tokval (const struct lexer *);
+const char *lex_tokcstr (const struct lexer *);
+struct substring lex_tokss (const struct lexer *);
+
+/* Looking ahead. */
+const struct token *lex_next (const struct lexer *, int n);
+enum token_type lex_next_token (const struct lexer *, int n);
+const char *lex_next_tokcstr (const struct lexer *, int n);
+double lex_next_tokval (const struct lexer *, int n);
+struct substring lex_next_tokss (const struct lexer *, int n);
+
+/* Current position. */
+int lex_get_first_line_number (const struct lexer *, int n);
+int lex_get_last_line_number (const struct lexer *, int n);
+int lex_get_first_column (const struct lexer *, int n);
+int lex_get_last_column (const struct lexer *, int n);
+const char *lex_get_file_name (const struct lexer *);
+
+/* Issuing errors. */
+void lex_error (struct lexer *, const char *, ...) PRINTF_FORMAT (2, 3);
+void lex_next_error (struct lexer *, int n0, int n1, const char *, ...)
+  PRINTF_FORMAT (4, 5);
+int lex_end_of_command (struct lexer *);
 
-/* Token names. */
-const char *lex_token_name (int);
-char *lex_token_representation (struct lexer *);
+void lex_sbc_only_once (const char *);
+void lex_sbc_missing (struct lexer *, const char *);
 
-/* Token accessors */
-int lex_token (const struct lexer *);
-double lex_tokval (const struct lexer *);
-const char *lex_tokid (const struct lexer *);
-const struct string *lex_tokstr (const struct lexer *);
+void lex_error_valist (struct lexer *, const char *, va_list)
+  PRINTF_FORMAT (2, 0);
+void lex_next_error_valist (struct lexer *lexer, int n0, int n1,
+                            const char *format, va_list)
+  PRINTF_FORMAT (4, 0);
 
-/* Really weird functions. */
-void lex_negative_to_dash (struct lexer *);
-void lex_skip_comment (struct lexer *);
+/* Error handling. */
+enum lex_syntax_mode lex_get_syntax_mode (const struct lexer *);
+enum lex_error_mode lex_get_error_mode (const struct lexer *);
+void lex_discard_rest_of_command (struct lexer *);
+void lex_interactive_reset (struct lexer *);
+void lex_discard_noninteractive (struct lexer *);
 
-#endif /* !lexer_h */
+#endif /* lexer.h */
index cf8e53ee5cb881529ead693e0328f66e520a300b..f53ccfc33c181ad48cba48705f35e23d5cb2d552 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2008, 2010, 2011 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
@@ -1422,12 +1422,14 @@ make_match (const char *t)
            "|| lex_match_id (lexer, \"FALSE\"))");
   else if (isdigit ((unsigned char) t[0]))
     sprintf (s, "lex_match_int (lexer, %s)", t);
-  else
+  else if (strchr (t, hyphen_proxy))
     {
       char *c = unmunge (t);
-      sprintf (s, "lex_match_hyphenated_word (lexer, \"%s\")", c);
+      sprintf (s, "lex_match_phrase (lexer, \"%s\")", c);
       free (c);
     }
+  else
+    sprintf (s, "lex_match_id (lexer, \"%s\")", t);
 
   return s;
 }
@@ -1491,12 +1493,12 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
            {
              if (s->optvalue)
                {
-                 dump (1, "if (lex_match (lexer, '('))");
+                 dump (1, "if (lex_match (lexer, T_LPAREN))");
                  dump (1, "{");
                }
              else
                {
-                 dump (1, "if (!lex_match (lexer, '('))");
+                 dump (1, "if (!lex_match (lexer, T_LPAREN))");
                  dump (1, "{");
                  dump (0, "msg (SE, _(\"`(' expected after %s "
                        "specifier of %s subcommand.\"));",
@@ -1542,7 +1544,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
              dump (0, "goto lossage;");
              dump (-1, "}");
               dump (-1, "free (p->%s%s);", sbc->prefix, st_lower (s->valname));
-              dump (0, "p->%s%s = xstrdup (ds_cstr (lex_tokstr (lexer)));",
+              dump (0, "p->%s%s = ss_xstrdup (ss_tokss (lexer));",
                     sbc->prefix, st_lower (s->valname));
             }
           else
@@ -1575,7 +1577,7 @@ dump_specifier_parse (const specifier *spec, const subcommand *sbc)
 
          if (s->valtype == VT_PAREN)
            {
-             dump (1, "if (!lex_match (lexer, ')'))");
+             dump (1, "if (!lex_match (lexer, T_RPAREN))");
              dump (1, "{");
              dump (0, "msg (SE, _(\"`)' expected after argument for "
                    "%s specifier of %s.\"));",
@@ -1611,7 +1613,7 @@ dump_subcommand (const subcommand *sbc)
     {
       int count;
 
-      dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
+      dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
       dump (1, "{");
 
       {
@@ -1669,7 +1671,7 @@ dump_subcommand (const subcommand *sbc)
          }
       }
 
-      dump (0, "lex_match (lexer, ',');");
+      dump (0, "lex_match (lexer, T_COMMA);");
       dump (-1, "}");
       outdent ();
     }
@@ -1705,7 +1707,7 @@ dump_subcommand (const subcommand *sbc)
       outdent ();
       if (sbc->restriction)
        {
-         dump (0, "x = ds_length (lex_tokstr (lexer));");
+         dump (0, "x = ss_length (lex_tokss (lexer));");
          dump (1, "if (!(%s))", sbc->restriction);
          dump (1, "{");
          dump (0, "msg (SE, _(\"String for %s must be %s.\"));",
@@ -1715,7 +1717,7 @@ dump_subcommand (const subcommand *sbc)
          outdent ();
        }
       dump (0, "free(p->s_%s);", st_lower(sbc->name) );
-      dump (0, "p->s_%s = ds_xstrdup (lex_tokstr (lexer));",
+      dump (0, "p->s_%s = ss_xstrdup (lex_tokss (lexer));",
            st_lower (sbc->name));
       dump (0, "lex_get (lexer);");
       if (sbc->restriction)
@@ -1755,11 +1757,11 @@ dump_subcommand (const subcommand *sbc)
     }
   else if (sbc->type == SBC_PINT)
     {
-      dump (0, "lex_match (lexer, '(');");
+      dump (0, "lex_match (lexer, T_LPAREN);");
       dump (1, "if (!lex_force_int (lexer))");
       dump (0, "goto lossage;");
       dump (-1, "p->n_%s = lex_integer (lexer);", st_lower (sbc->name));
-      dump (0, "lex_match (lexer, ')');");
+      dump (0, "lex_match (lexer, T_RPAREN);");
     }
   else if (sbc->type == SBC_DBL_LIST || sbc->type == SBC_INT_LIST)
     {
@@ -1769,9 +1771,9 @@ dump_subcommand (const subcommand *sbc)
       dump (0, "goto lossage;");
       dump (-1,"}");
 
-      dump (1, "while (lex_token (lexer) != '/' && lex_token (lexer) != '.')");
+      dump (1, "while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)");
       dump (1, "{");
-      dump (0, "lex_match (lexer, ',');");
+      dump (0, "lex_match (lexer, T_COMMA);");
       dump (0, "if (!lex_force_num (lexer))");
       dump (1, "{");
       dump (0, "goto lossage;");
@@ -1833,13 +1835,13 @@ dump_parser (int persistent)
     {
       if (def->type == SBC_VARLIST)
        dump (1, "if (lex_token (lexer) == T_ID "
-              "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL "
-             "&& lex_look_ahead (lexer) != '=')");
+              "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) != NULL "
+             "&& lex_next_token (lexer, 1) != T_EQUALS)");
       else
        {
          dump (0, "if ((lex_token (lexer) == T_ID "
-                "&& dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) "
-               "&& lex_look_ahead () != '=')");
+                "&& dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) "
+               "&& lex_next_token (lexer, 1) != T_EQUALS)");
          dump (1, "     || token == T_ALL)");
        }
       dump (1, "{");
@@ -1883,7 +1885,7 @@ dump_parser (int persistent)
        f = 1;
        dump (1, "{");
 
-       dump (0, "lex_match (lexer, '=');");
+       dump (0, "lex_match (lexer, T_EQUALS);");
        dump (0, "p->sbc_%s++;", st_lower (sbc->name));
        if (sbc->arity != ARITY_MANY)
          {
@@ -1906,7 +1908,7 @@ dump_parser (int persistent)
   dump(1,"else if ( settings_get_syntax () != COMPATIBLE && lex_match_id(lexer, \"ALGORITHM\"))");
   dump(1,"{");
 
-  dump (0, "lex_match (lexer, '=');");
+  dump (0, "lex_match (lexer, T_EQUALS);");
 
   dump(1,"if (lex_match_id(lexer, \"COMPATIBLE\"))");
   dump(0,"settings_set_cmd_algorithm (COMPATIBLE);");
@@ -1919,12 +1921,12 @@ dump_parser (int persistent)
 
 
 
-  dump (1, "if (!lex_match (lexer, '/'))");
+  dump (1, "if (!lex_match (lexer, T_SLASH))");
   dump (0, "break;");
   dump (-2, "}");
   outdent ();
   dump_blank_line (0);
-  dump (1, "if (lex_token (lexer) != '.')");
+  dump (1, "if (lex_token (lexer) != T_ENDCMD)");
   dump (1, "{");
   dump (0, "lex_error (lexer, _(\"expecting end of command\"));");
   dump (0, "goto lossage;");
@@ -2126,17 +2128,19 @@ main (int argc, char *argv[])
          indent = 0;
 
          dump (0, "#include <stdlib.h>");
-         dump (0, "#include <libpspp/assertion.h>");
-         dump (0, "#include <libpspp/message.h>");
-         dump (0, "#include <language/lexer/lexer.h>");
-         dump (0, "#include <language/lexer/variable-parser.h>");
-          dump (0, "#include <data/settings.h>");
-         dump (0, "#include <libpspp/str.h>");
-          dump (0, "#include <language/lexer/subcommand-list.h>");
-         dump (0, "#include <data/variable.h>");
+          dump_blank_line (0);
+
+          dump (0, "#include \"data/settings.h\"");
+         dump (0, "#include \"data/variable.h\"");
+         dump (0, "#include \"language/lexer/lexer.h\"");
+          dump (0, "#include \"language/lexer/subcommand-list.h\"");
+         dump (0, "#include \"language/lexer/variable-parser.h\"");
+         dump (0, "#include \"libpspp/assertion.h\"");
+         dump (0, "#include \"libpspp/message.h\"");
+         dump (0, "#include \"libpspp/str.h\"");
          dump_blank_line (0);
 
-          dump (0, "#include \"xalloc.h\"");
+          dump (0, "#include \"gl/xalloc.h\"");
          dump_blank_line (0);
 
           dump (0, "#include \"gettext.h\"");
diff --git a/src/language/lexer/scan.c b/src/language/lexer/scan.c
new file mode 100644 (file)
index 0000000..caf294a
--- /dev/null
@@ -0,0 +1,596 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/lexer/scan.h"
+
+#include <limits.h>
+#include <unistr.h>
+
+#include "data/identifier.h"
+#include "language/lexer/token.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+
+#include "gl/c-ctype.h"
+#include "gl/xmemdup0.h"
+
+enum
+  {
+    S_START,
+    S_DASH,
+    S_STRING
+  };
+
+#define SS_NL_BEFORE_PLUS (1u << 0)
+#define SS_PLUS           (1u << 1)
+#define SS_NL_AFTER_PLUS  (1u << 2)
+
+/* Returns the integer value of (hex) digit C. */
+static int
+digit_value (int c)
+{
+  switch (c)
+    {
+    case '0': return 0;
+    case '1': return 1;
+    case '2': return 2;
+    case '3': return 3;
+    case '4': return 4;
+    case '5': return 5;
+    case '6': return 6;
+    case '7': return 7;
+    case '8': return 8;
+    case '9': return 9;
+    case 'a': case 'A': return 10;
+    case 'b': case 'B': return 11;
+    case 'c': case 'C': return 12;
+    case 'd': case 'D': return 13;
+    case 'e': case 'E': return 14;
+    case 'f': case 'F': return 15;
+    default: return INT_MAX;
+    }
+}
+
+static bool
+scan_quoted_string__ (struct substring s, struct token *token)
+{
+  int quote;
+
+  /* Trim ' or " from front and back. */
+  quote = s.string[s.length - 1];
+  s.string++;
+  s.length -= 2;
+
+  ss_realloc (&token->string, token->string.length + s.length + 1);
+
+  for (;;)
+    {
+      size_t pos = ss_find_byte (s, quote);
+      if (pos == SIZE_MAX)
+        break;
+
+      memcpy (ss_end (token->string), s.string, pos + 1);
+      token->string.length += pos + 1;
+      ss_advance (&s, pos + 2);
+    }
+
+  memcpy (ss_end (token->string), s.string, ss_length (s));
+  token->string.length += ss_length (s);
+
+  return true;
+}
+
+static bool
+scan_hex_string__ (struct substring s, struct token *token)
+{
+  uint8_t *dst;
+  size_t i;
+
+  /* Trim X' from front and ' from back. */
+  s.string += 2;
+  s.length -= 3;
+
+  if (s.length % 2 != 0)
+    {
+      token->type = SCAN_BAD_HEX_LENGTH;
+      token->number = s.length;
+      return false;
+    }
+
+  ss_realloc (&token->string, token->string.length + s.length / 2 + 1);
+  dst = CHAR_CAST (uint8_t *, ss_end (token->string));
+  token->string.length += s.length / 2;
+  for (i = 0; i < s.length; i += 2)
+    {
+      int hi = digit_value (s.string[i]);
+      int lo = digit_value (s.string[i + 1]);
+
+      if (hi >= 16 || lo >= 16)
+        {
+          token->type = SCAN_BAD_HEX_DIGIT;
+          token->number = s.string[hi >= 16 ? i : i + 1];
+          return false;
+        }
+
+      *dst++ = hi * 16 + lo;
+    }
+
+  return true;
+}
+
+static bool
+scan_unicode_string__ (struct substring s, struct token *token)
+{
+  uint8_t *dst;
+  ucs4_t uc;
+  size_t i;
+
+  /* Trim U' from front and ' from back. */
+  s.string += 2;
+  s.length -= 3;
+
+  if (s.length < 1 || s.length > 8)
+    {
+      token->type = SCAN_BAD_UNICODE_LENGTH;
+      token->number = s.length;
+      return 0;
+    }
+
+  ss_realloc (&token->string, token->string.length + 4 + 1);
+
+  uc = 0;
+  for (i = 0; i < s.length; i++)
+    {
+      int digit = digit_value (s.string[i]);
+      if (digit >= 16)
+        {
+          token->type = SCAN_BAD_UNICODE_DIGIT;
+          token->number = s.string[i];
+          return 0;
+        }
+      uc = uc * 16 + digit;
+    }
+
+  if ((uc >= 0xd800 && uc < 0xe000) || uc > 0x10ffff)
+    {
+      token->type = SCAN_BAD_UNICODE_CODE_POINT;
+      token->number = uc;
+      return 0;
+    }
+
+  dst = CHAR_CAST (uint8_t *, ss_end (token->string));
+  token->string.length += u8_uctomb (dst, uc, 4);
+
+  return true;
+}
+
+static enum scan_result
+scan_string_segment__ (struct scanner *scanner, enum segment_type type,
+                       struct substring s, struct token *token)
+{
+  bool ok;
+
+  switch (type)
+    {
+    case SEG_QUOTED_STRING:
+      ok = scan_quoted_string__ (s, token);
+      break;
+
+    case SEG_HEX_STRING:
+      ok = scan_hex_string__ (s, token);
+      break;
+
+    case SEG_UNICODE_STRING:
+      ok = scan_unicode_string__ (s, token);
+      break;
+
+    default:
+      NOT_REACHED ();
+    }
+
+  if (ok)
+    {
+      token->type = T_STRING;
+      token->string.string[token->string.length] = '\0';
+      scanner->state = S_STRING;
+      scanner->substate = 0;
+      return SCAN_SAVE;
+    }
+  else
+    {
+      /* The function we called above should have filled in token->type and
+         token->number properly to describe the error. */
+      ss_dealloc (&token->string);
+      token->string = ss_empty ();
+      return SCAN_DONE;
+    }
+
+}
+
+static enum scan_result
+add_bit (struct scanner *scanner, unsigned int bit)
+{
+  if (!(scanner->substate & bit))
+    {
+      scanner->substate |= bit;
+      return SCAN_MORE;
+    }
+  else
+    return SCAN_BACK;
+}
+
+static enum scan_result
+scan_string__ (struct scanner *scanner, enum segment_type type,
+               struct substring s, struct token *token)
+{
+  switch (type)
+    {
+    case SEG_SPACES:
+    case SEG_COMMENT:
+      return SCAN_MORE;
+
+    case SEG_NEWLINE:
+      if (scanner->substate & SS_PLUS)
+        return add_bit (scanner, SS_NL_AFTER_PLUS);
+      else
+        return add_bit (scanner, SS_NL_BEFORE_PLUS);
+
+    case SEG_PUNCT:
+      return (s.length == 1 && s.string[0] == '+'
+              ? add_bit (scanner, SS_PLUS)
+              : SCAN_BACK);
+
+    case SEG_QUOTED_STRING:
+    case SEG_HEX_STRING:
+    case SEG_UNICODE_STRING:
+      return (scanner->substate & SS_PLUS
+              ? scan_string_segment__ (scanner, type, s, token)
+              : SCAN_BACK);
+
+    default:
+      return SCAN_BACK;
+    }
+}
+
+static enum token_type
+scan_reserved_word__ (struct substring word)
+{
+  switch (c_toupper (word.string[0]))
+    {
+    case 'B':
+      return T_BY;
+
+    case 'E':
+      return T_EQ;
+
+    case 'G':
+      return c_toupper (word.string[1]) == 'E' ? T_GE : T_GT;
+
+    case 'L':
+      return c_toupper (word.string[1]) == 'E' ? T_LE : T_LT;
+
+    case 'N':
+      return word.length == 2 ? T_NE : T_NOT;
+
+    case 'O':
+      return T_OR;
+
+    case 'T':
+      return T_TO;
+
+    case 'A':
+      return c_toupper (word.string[1]) == 'L' ? T_ALL : T_AND;
+
+    case 'W':
+      return T_WITH;
+    }
+
+  NOT_REACHED ();
+}
+
+static enum token_type
+scan_punct1__ (char c0)
+{
+  switch (c0)
+    {
+    case '(': return T_LPAREN;
+    case ')': return T_RPAREN;
+    case ',': return T_COMMA;
+    case '=': return T_EQUALS;
+    case '-': return T_DASH;
+    case '[': return T_LBRACK;
+    case ']': return T_RBRACK;
+    case '&': return T_AND;
+    case '|': return T_OR;
+    case '+': return T_PLUS;
+    case '/': return T_SLASH;
+    case '*': return T_ASTERISK;
+    case '<': return T_LT;
+    case '>': return T_GT;
+    case '~': return T_NOT;
+    }
+
+  NOT_REACHED ();
+}
+
+static enum token_type
+scan_punct2__ (char c0, char c1)
+{
+  switch (c0)
+    {
+    case '*':
+      return T_EXP;
+
+    case '<':
+      return c1 == '=' ? T_LE : T_NE;
+
+    case '>':
+      return T_GE;
+
+    case '~':
+      return T_NE;
+
+    case '&':
+      return T_AND;
+
+    case '|':
+      return T_OR;
+    }
+
+  NOT_REACHED ();
+}
+
+static enum token_type
+scan_punct__ (struct substring s)
+{
+  return (s.length == 1
+          ? scan_punct1__ (s.string[0])
+          : scan_punct2__ (s.string[0], s.string[1]));
+}
+
+static double
+scan_number__ (struct substring s)
+{
+  char buf[128];
+  double number;
+  char *p;
+
+  if (s.length < sizeof buf)
+    {
+      p = buf;
+      memcpy (buf, s.string, s.length);
+      buf[s.length] = '\0';
+    }
+  else
+    p = xmemdup0 (s.string, s.length);
+
+  number = strtod (p, NULL);
+
+  if (p != buf)
+    free (p);
+
+  return number;
+}
+
+static enum scan_result
+scan_unexpected_char (const struct substring *s, struct token *token)
+{
+  ucs4_t uc;
+
+  token->type = SCAN_UNEXPECTED_CHAR;
+  u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, s->string), s->length);
+  token->number = uc;
+
+  return SCAN_DONE;
+}
+
+const char *
+scan_type_to_string (enum scan_type type)
+{
+  switch (type)
+    {
+#define SCAN_TYPE(NAME) case SCAN_##NAME: return #NAME;
+      SCAN_TYPES
+#undef SCAN_TYPE
+
+    default:
+      return token_type_to_name (type);
+    }
+}
+
+bool
+is_scan_type (enum scan_type type)
+{
+  return type > SCAN_FIRST && type < SCAN_LAST;
+}
+
+static enum scan_result
+scan_start__ (struct scanner *scanner, enum segment_type type,
+              struct substring s, struct token *token)
+{
+  switch (type)
+    {
+    case SEG_NUMBER:
+      token->type = T_POS_NUM;
+      token->number = scan_number__ (s);
+      return SCAN_DONE;
+
+    case SEG_QUOTED_STRING:
+    case SEG_HEX_STRING:
+    case SEG_UNICODE_STRING:
+      return scan_string_segment__ (scanner, type, s, token);
+
+    case SEG_UNQUOTED_STRING:
+    case SEG_DO_REPEAT_COMMAND:
+    case SEG_INLINE_DATA:
+    case SEG_DOCUMENT:
+      token->type = T_STRING;
+      ss_alloc_substring (&token->string, s);
+      return SCAN_DONE;
+
+    case SEG_RESERVED_WORD:
+      token->type = scan_reserved_word__ (s);
+      return SCAN_DONE;
+
+    case SEG_IDENTIFIER:
+      token->type = T_ID;
+      ss_alloc_substring (&token->string, s);
+      return SCAN_DONE;
+
+    case SEG_PUNCT:
+      if (s.length == 1 && s.string[0] == '-')
+        {
+          scanner->state = S_DASH;
+          return SCAN_SAVE;
+        }
+      else
+        {
+          token->type = scan_punct__ (s);
+          return SCAN_DONE;
+        }
+
+    case SEG_SHBANG:
+    case SEG_SPACES:
+    case SEG_COMMENT:
+    case SEG_NEWLINE:
+    case SEG_COMMENT_COMMAND:
+      token->type = SCAN_SKIP;
+      return SCAN_DONE;
+
+    case SEG_START_DOCUMENT:
+      token->type = T_ID;
+      ss_alloc_substring (&token->string, ss_cstr ("DOCUMENT"));
+      return SCAN_DONE;
+
+    case SEG_START_COMMAND:
+    case SEG_SEPARATE_COMMANDS:
+    case SEG_END_COMMAND:
+      token->type = T_ENDCMD;
+      return SCAN_DONE;
+
+    case SEG_END:
+      token->type = T_STOP;
+      return SCAN_DONE;
+
+    case SEG_EXPECTED_QUOTE:
+      token->type = SCAN_EXPECTED_QUOTE;
+      return SCAN_DONE;
+
+    case SEG_EXPECTED_EXPONENT:
+      token->type = SCAN_EXPECTED_EXPONENT;
+      ss_alloc_substring (&token->string, s);
+      return SCAN_DONE;
+
+    case SEG_UNEXPECTED_DOT:
+      token->type = SCAN_UNEXPECTED_DOT;
+      return SCAN_DONE;
+
+    case SEG_UNEXPECTED_CHAR:
+      return scan_unexpected_char (&s, token);
+
+    case SEG_N_TYPES:
+      NOT_REACHED ();
+    }
+
+  NOT_REACHED ();
+}
+
+static enum scan_result
+scan_dash__ (enum segment_type type, struct substring s, struct token *token)
+{
+  switch (type)
+    {
+    case SEG_SPACES:
+    case SEG_COMMENT:
+      return SCAN_MORE;
+
+    case SEG_NUMBER:
+      token->type = T_NEG_NUM;
+      token->number = -scan_number__ (s);
+      return SCAN_DONE;
+
+    default:
+      token->type = T_DASH;
+      return SCAN_BACK;
+    }
+}
+
+/* Initializes SCANNER for scanning a token from a sequence of segments.
+   Initializes TOKEN as the output token.  (The client retains ownership of
+   TOKEN, but it must be preserved across subsequent calls to scanner_push()
+   for SCANNER.)
+
+   A scanner only produces a single token.  To obtain the next token,
+   re-initialize it by calling this function again.
+
+   A scanner does not contain any external references, so nothing needs to be
+   done to destroy one.  For the same reason, scanners may be copied with plain
+   struct assignment (or memcpy). */
+void
+scanner_init (struct scanner *scanner, struct token *token)
+{
+  scanner->state = S_START;
+  token_init (token);
+}
+
+/* Adds the segment with type TYPE and UTF-8 text S to SCANNER.  TOKEN must be
+   the same token passed to scanner_init() for SCANNER, or a copy of it.
+   scanner_push() may modify TOKEN.  The client retains ownership of TOKEN,
+
+   The possible return values are:
+
+     - SCAN_DONE: All of the segments that have been passed to scanner_push()
+       form the token now stored in TOKEN.  SCANNER is now "used up" and must
+       be reinitialized with scanner_init() if it is to be used again.
+
+       Most tokens only consist of a single segment, so this is the most common
+       return value.
+
+     - SCAN_MORE: The segments passed to scanner_push() don't yet determine a
+       token.  The caller should call scanner_push() again with the next token.
+       (This won't happen if TYPE is SEG_END indicating the end of input.)
+
+     - SCAN_SAVE: This is similar to SCAN_MORE, with one difference: the caller
+       needs to "save its place" in the stream of segments for a possible
+       future SCAN_BACK return.  This value can be returned more than once in a
+       sequence of scanner_push() calls for SCANNER, but the caller only needs
+       to keep track of the most recent position.
+
+     - SCAN_BACK: This is similar to SCAN_DONE, but the token consists of only
+       the segments up to and including the segment for which SCAN_SAVE was
+       most recently returned.  Segments following that one should be passed to
+       the next scanner to be initialized.
+*/
+enum scan_result
+scanner_push (struct scanner *scanner, enum segment_type type,
+              struct substring s, struct token *token)
+{
+  switch (scanner->state)
+    {
+    case S_START:
+      return scan_start__ (scanner, type, s, token);
+
+    case S_DASH:
+      return scan_dash__ (type, s, token);
+
+    case S_STRING:
+      return scan_string__ (scanner, type, s, token);
+    }
+
+  NOT_REACHED ();
+}
diff --git a/src/language/lexer/scan.h b/src/language/lexer/scan.h
new file mode 100644 (file)
index 0000000..fdb5080
--- /dev/null
@@ -0,0 +1,93 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 SCAN_H
+#define SCAN_H 1
+
+#include "language/lexer/segment.h"
+#include "libpspp/str.h"
+
+struct token;
+
+/* PSPP syntax scanning.
+
+   PSPP divides traditional "lexical analysis" or "tokenization" into two
+   phases: a lower-level phase called "segmentation" and a higher-level phase
+   called "scanning".  segment.h provides declarations for the segmentation
+   phase.  This header file contains declarations for the scanning phase.
+
+   Scanning accepts as input a stream of segments, which are UTF-8 strings each
+   labeled with a segment type.  It outputs a stream of "scan tokens", which
+   are the same as the tokens used by the PSPP parser with a few additional
+   types.
+*/
+
+#define SCAN_TYPES                              \
+    SCAN_TYPE(BAD_HEX_LENGTH)                   \
+    SCAN_TYPE(BAD_HEX_DIGIT)                    \
+                                                \
+    SCAN_TYPE(BAD_UNICODE_LENGTH)               \
+    SCAN_TYPE(BAD_UNICODE_DIGIT)                \
+    SCAN_TYPE(BAD_UNICODE_CODE_POINT)           \
+                                                \
+    SCAN_TYPE(EXPECTED_QUOTE)                   \
+    SCAN_TYPE(EXPECTED_EXPONENT)                \
+    SCAN_TYPE(UNEXPECTED_DOT)                   \
+    SCAN_TYPE(UNEXPECTED_CHAR)                  \
+                                                \
+    SCAN_TYPE(SKIP)
+
+/* Types of scan tokens.
+
+   Scan token types are a superset of enum token_type.  Only the additional
+   scan token types are defined here, so see the definition of enum token_type
+   for the others. */
+enum scan_type
+  {
+#define SCAN_TYPE(TYPE) SCAN_##TYPE,
+    SCAN_FIRST = 255,
+    SCAN_TYPES
+    SCAN_LAST
+#undef SCAN_TYPE
+  };
+
+const char *scan_type_to_string (enum scan_type);
+bool is_scan_type (enum scan_type);
+
+/* A scanner.  Opaque. */
+struct scanner
+  {
+    unsigned char state;
+    unsigned char substate;
+  };
+
+/* scanner_push() return type. */
+enum scan_result
+  {
+    /* Complete token. */
+    SCAN_DONE,                  /* Token successfully scanned. */
+    SCAN_MORE,                  /* More segments needed to scan token. */
+
+    /* Incomplete token. */
+    SCAN_BACK,                  /* Done, but go back to saved position too. */
+    SCAN_SAVE                   /* Need more segments, and save position. */
+  };
+
+void scanner_init (struct scanner *, struct token *);
+enum scan_result scanner_push (struct scanner *, enum segment_type,
+                               struct substring, struct token *);
+
+#endif /* scan.h */
diff --git a/src/language/lexer/segment.c b/src/language/lexer/segment.c
new file mode 100644 (file)
index 0000000..0d83257
--- /dev/null
@@ -0,0 +1,1636 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/lexer/segment.h"
+
+#include <limits.h>
+#include <unistr.h>
+
+#include "data/identifier.h"
+#include "language/lexer/command-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+
+#include "gl/c-ctype.h"
+#include "gl/c-strcase.h"
+
+enum segmenter_state
+  {
+    S_SHBANG,
+    S_GENERAL,
+    S_COMMENT_1,
+    S_COMMENT_2,
+    S_DOCUMENT_1,
+    S_DOCUMENT_2,
+    S_DOCUMENT_3,
+    S_FILE_LABEL,
+    S_DO_REPEAT_1,
+    S_DO_REPEAT_2,
+    S_DO_REPEAT_3,
+    S_BEGIN_DATA_1,
+    S_BEGIN_DATA_2,
+    S_BEGIN_DATA_3,
+    S_BEGIN_DATA_4,
+    S_TITLE_1,
+    S_TITLE_2
+  };
+
+#define SS_START_OF_LINE (1u << 0)
+#define SS_START_OF_COMMAND (1u << 1)
+
+static int segmenter_detect_command_name__ (const char *input,
+                                            size_t n, int ofs);
+
+static int
+segmenter_u8_to_uc__ (ucs4_t *puc, const char *input_, size_t n)
+{
+  const uint8_t *input = CHAR_CAST (const uint8_t *, input_);
+  int mblen;
+
+  assert (n > 0);
+
+  mblen = u8_mbtoucr (puc, input, n);
+  return (mblen >= 0 ? mblen
+          : mblen == -2 ? -1
+          : u8_mbtouc (puc, input, n));
+}
+
+static int
+segmenter_parse_shbang__ (struct segmenter *s, const char *input, size_t n,
+                          enum segment_type *type)
+{
+  if (input[0] == '#')
+    {
+      if (n < 2)
+        return -1;
+      else if (input[1] == '!')
+        {
+          int ofs;
+
+          for (ofs = 2; ofs < n; ofs++)
+            if (input[ofs] == '\n')
+              {
+                if (input[ofs - 1] == '\r')
+                  ofs--;
+
+                s->state = S_GENERAL;
+                s->substate = SS_START_OF_COMMAND;
+                *type = SEG_SHBANG;
+                return ofs;
+              }
+
+          return -1;
+        }
+    }
+
+  s->state = S_GENERAL;
+  s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
+  return segmenter_push (s, input, n, type);
+}
+
+static int
+segmenter_parse_digraph__ (const char *seconds, struct segmenter *s,
+                           const char *input, size_t n,
+                           enum segment_type *type)
+{
+  assert (s->state == S_GENERAL);
+
+  if (n < 2)
+    return -1;
+
+  *type = SEG_PUNCT;
+  s->substate = 0;
+  return input[1] != '\0' && strchr (seconds, input[1]) != NULL ? 2 : 1;
+}
+
+static int
+skip_comment (const char *input, size_t n, size_t ofs)
+{
+  for (; ofs < n; ofs++)
+    {
+      if (input[ofs] == '\n')
+        return ofs;
+      else if (input[ofs] == '*')
+        {
+          if (ofs + 1 >= n)
+            return -1;
+          else if (input[ofs + 1] == '/')
+            return ofs + 2;
+        }
+    }
+  return -1;
+}
+
+static int
+skip_spaces_and_comments (const char *input, size_t n, int ofs)
+{
+  while (ofs < n)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      if (uc == '/')
+        {
+          if (ofs + 1 >= n)
+            return -1;
+          else if (input[ofs + 1] != '*')
+            return ofs;
+
+          ofs = skip_comment (input, n, ofs + 2);
+          if (ofs < 0)
+            return -1;
+        }
+      else if (lex_uc_is_space (uc) && uc != '\n')
+        ofs += mblen;
+      else
+        return ofs;
+    }
+
+  return -1;
+}
+
+static int
+is_end_of_line (const char *input, size_t n, int ofs)
+{
+  if (input[ofs] == '\n')
+    return 1;
+  else if (input[ofs] == '\r')
+    {
+      if (ofs + 1 >= n)
+        return -1;
+      return input[ofs + 1] == '\n';
+    }
+  else
+    return 0;
+}
+
+static int
+at_end_of_line (const char *input, size_t n, int ofs)
+{
+  ofs = skip_spaces_and_comments (input, n, ofs);
+  if (ofs < 0)
+    return -1;
+
+  return is_end_of_line (input, n, ofs);
+}
+
+
+static int
+segmenter_parse_newline__ (const char *input, size_t n,
+                           enum segment_type *type)
+{
+  int ofs;
+
+  if (input[0] == '\n')
+    ofs = 1;
+  else
+    {
+      if (n < 2)
+        return -1;
+
+      assert (input[0] == '\r');
+      assert (input[1] == '\n');
+      ofs = 2;
+    }
+
+  *type = SEG_NEWLINE;
+  return ofs;
+}
+
+static int
+skip_spaces (const char *input, size_t n, size_t ofs)
+{
+  while (ofs < n)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      if (!lex_uc_is_space (uc) || uc == '\n')
+        return ofs;
+
+      ofs += mblen;
+    }
+
+  return -1;
+}
+
+static int
+skip_digits (const char *input, size_t n, int ofs)
+{
+  for (; ofs < n; ofs++)
+    if (!c_isdigit (input[ofs]))
+      return ofs;
+  return -1;
+}
+
+static int
+segmenter_parse_number__ (struct segmenter *s, const char *input, size_t n,
+                          enum segment_type *type)
+{
+  int ofs;
+
+  assert (s->state == S_GENERAL);
+
+  ofs = skip_digits (input, n, 0);
+  if (ofs < 0)
+    return -1;
+
+  if (input[ofs] == '.')
+    {
+      ofs = skip_digits (input, n, ofs + 1);
+      if (ofs < 0)
+        return -1;
+    }
+
+  if (ofs >= n)
+    return -1;
+  if (input[ofs] == 'e' || input[ofs] == 'E')
+    {
+      ofs++;
+      if (ofs >= n)
+        return -1;
+
+      if (input[ofs] == '+' || input[ofs] == '-')
+        {
+          ofs++;
+          if (ofs >= n)
+            return -1;
+        }
+
+      if (!c_isdigit (input[ofs]))
+        {
+          *type = SEG_EXPECTED_EXPONENT;
+          s->substate = 0;
+          return ofs;
+        }
+
+      ofs = skip_digits (input, n, ofs);
+      if (ofs < 0)
+        return -1;
+    }
+
+  if (input[ofs - 1] == '.')
+    {
+      int eol = at_end_of_line (input, n, ofs);
+      if (eol < 0)
+        return -1;
+      else if (eol)
+        ofs--;
+    }
+
+  *type = SEG_NUMBER;
+  s->substate = 0;
+  return ofs;
+}
+
+static bool
+is_reserved_word (const char *s, int n)
+{
+  char s0, s1, s2, s3;
+
+  s0 = c_toupper (s[0]);
+  switch (n)
+    {
+    case 2:
+      s1 = c_toupper (s[1]);
+      return ((s0 == 'B' && s1 == 'Y')
+              || (s0 == 'E' && s1 == 'Q')
+              || (s0 == 'G' && (s1 == 'E' || s1 == 'T'))
+              || (s0 == 'L' && (s1 == 'E' || s1 == 'T'))
+              || (s0 == 'N' && s1 == 'E')
+              || (s0 == 'O' && s1 == 'R')
+              || (s0 == 'T' && s1 == 'O'));
+
+    case 3:
+      s1 = c_toupper (s[1]);
+      s2 = c_toupper (s[2]);
+      return ((s0 == 'A' && ((s1 == 'L' && s2 == 'L')
+                             || (s1 == 'N' && s2 == 'D')))
+              || (s0 == 'N' && s1 == 'O' && s2 == 'T'));
+
+    case 4:
+      s1 = c_toupper (s[1]);
+      s2 = c_toupper (s[2]);
+      s3 = c_toupper (s[3]);
+      return s0 == 'W' && s1 == 'I' && s2 == 'T' && s3 == 'H';
+
+    default:
+      return false;
+    }
+}
+
+static int
+segmenter_parse_comment_1__ (struct segmenter *s,
+                             const char *input, size_t n,
+                             enum segment_type *type)
+{
+  int endcmd;
+  int ofs;
+
+  endcmd = -2;
+  ofs = 0;
+  while (ofs < n)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      switch (uc)
+        {
+        case '.':
+          endcmd = ofs;
+          break;
+
+        case '\n':
+          if (ofs > 1 && input[ofs - 1] == '\r')
+            ofs--;
+
+          if (endcmd == -2)
+            {
+              /* Blank line ends comment command. */
+              s->state = S_GENERAL;
+              s->substate = SS_START_OF_COMMAND;
+              *type = SEG_SEPARATE_COMMANDS;
+              return ofs;
+            }
+          else if (endcmd >= 0)
+            {
+              /* '.' at end of line ends comment command. */
+              s->state = S_GENERAL;
+              s->substate = 0;
+              *type = SEG_COMMENT_COMMAND;
+              return endcmd;
+            }
+          else
+            {
+              /* Comment continues onto next line. */
+              *type = SEG_COMMENT_COMMAND;
+              s->state = S_COMMENT_2;
+              return ofs;
+            }
+          NOT_REACHED ();
+
+        default:
+          if (!lex_uc_is_space (uc))
+            endcmd = -1;
+          break;
+        }
+
+      ofs += mblen;
+    }
+  return -1;
+}
+
+static int
+segmenter_parse_comment_2__ (struct segmenter *s, const char *input, size_t n,
+                             enum segment_type *type)
+{
+  int new_cmd;
+  ucs4_t uc;
+  int mblen;
+  int ofs;
+
+  ofs = segmenter_parse_newline__ (input, n, type);
+  if (ofs < 0 || ofs >= n)
+    return -1;
+
+  mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+  if (mblen < 0)
+    return -1;
+
+  if (uc == '+' || uc == '-' || uc == '.')
+    new_cmd = true;
+  else if (!lex_uc_is_space (uc))
+    switch (s->mode)
+      {
+      case SEG_MODE_INTERACTIVE:
+        new_cmd = false;
+        break;
+
+      case SEG_MODE_BATCH:
+        new_cmd = true;
+        break;
+
+      case SEG_MODE_AUTO:
+        new_cmd = segmenter_detect_command_name__ (input, n, ofs);
+        if (new_cmd < 0)
+          return -1;
+        break;
+
+      default:
+        NOT_REACHED ();
+      }
+  else
+    new_cmd = false;
+
+  if (new_cmd)
+    {
+      s->state = S_GENERAL;
+      s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
+    }
+  else
+    s->state = S_COMMENT_1;
+  return ofs;
+}
+
+static int
+segmenter_parse_document_1__ (struct segmenter *s, const char *input, size_t n,
+                              enum segment_type *type)
+{
+  bool end_cmd;
+  int ofs;
+
+  end_cmd = false;
+  ofs = 0;
+  while (ofs < n)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      switch (uc)
+        {
+        case '.':
+          end_cmd = true;
+          break;
+
+        case '\n':
+          if (ofs > 1 && input[ofs - 1] == '\r')
+            ofs--;
+
+          *type = SEG_DOCUMENT;
+          s->state = end_cmd ? S_DOCUMENT_3 : S_DOCUMENT_2;
+          return ofs;
+
+        default:
+          if (!lex_uc_is_space (uc))
+            end_cmd = false;
+          break;
+        }
+
+      ofs += mblen;
+    }
+  return -1;
+}
+
+static int
+segmenter_parse_document_2__ (struct segmenter *s, const char *input, size_t n,
+                              enum segment_type *type)
+{
+  int ofs;
+
+  ofs = segmenter_parse_newline__ (input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  s->state = S_DOCUMENT_1;
+  return ofs;
+}
+
+static int
+segmenter_parse_document_3__ (struct segmenter *s, enum segment_type *type)
+{
+  *type = SEG_END_COMMAND;
+  s->state = S_GENERAL;
+  s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
+  return 0;
+}
+
+static int
+segmenter_unquoted (const char *input, size_t n, int ofs)
+
+{
+  char c;
+
+  ofs = skip_spaces_and_comments (input, n, ofs);
+  if (ofs < 0)
+    return -1;
+
+  c = input[ofs];
+  return c != '\'' && c != '"' && c != '\n' && c != '\0';
+}
+
+static int
+next_id_in_command (const struct segmenter *s, const char *input, size_t n,
+                    int ofs, char id[], size_t id_size)
+{
+  struct segmenter sub;
+
+  assert (id_size > 0);
+
+  sub.mode = s->mode;
+  sub.state = S_GENERAL;
+  sub.substate = 0;
+  for (;;)
+    {
+      enum segment_type type;
+      int retval;
+
+      retval = segmenter_push (&sub, input + ofs, n - ofs, &type);
+      if (retval < 0)
+        {
+          id[0] = '\0';
+          return -1;
+        }
+
+      switch (type)
+        {
+        case SEG_SHBANG:
+        case SEG_SPACES:
+        case SEG_COMMENT:
+        case SEG_NEWLINE:
+          break;
+
+        case SEG_IDENTIFIER:
+          if (retval < id_size)
+            {
+              memcpy (id, input + ofs, retval);
+              id[retval] = '\0';
+              return ofs + retval;
+            }
+          /* fall through */
+
+        case SEG_NUMBER:
+        case SEG_QUOTED_STRING:
+        case SEG_HEX_STRING:
+        case SEG_UNICODE_STRING:
+        case SEG_UNQUOTED_STRING:
+        case SEG_RESERVED_WORD:
+        case SEG_PUNCT:
+        case SEG_COMMENT_COMMAND:
+        case SEG_DO_REPEAT_COMMAND:
+        case SEG_INLINE_DATA:
+        case SEG_START_DOCUMENT:
+        case SEG_DOCUMENT:
+        case SEG_START_COMMAND:
+        case SEG_SEPARATE_COMMANDS:
+        case SEG_END_COMMAND:
+        case SEG_END:
+        case SEG_EXPECTED_QUOTE:
+        case SEG_EXPECTED_EXPONENT:
+        case SEG_UNEXPECTED_DOT:
+        case SEG_UNEXPECTED_CHAR:
+          id[0] = '\0';
+          return ofs + retval;
+
+        case SEG_N_TYPES:
+          NOT_REACHED ();
+        }
+      ofs += retval;
+    }
+}
+
+static int
+segmenter_parse_id__ (struct segmenter *s, const char *input, size_t n,
+                      enum segment_type *type)
+{
+  ucs4_t uc;
+  int ofs;
+
+  assert (s->state == S_GENERAL);
+
+  ofs = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, input), n);
+  for (;;)
+    {
+      int mblen;
+
+      if (ofs >= n)
+        return -1;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+      else if (!lex_uc_is_idn (uc))
+        break;
+
+      ofs += mblen;
+    }
+
+  if (input[ofs - 1] == '.')
+    {
+      int eol = at_end_of_line (input, n, ofs);
+      if (eol < 0)
+        return -1;
+      else if (eol)
+        ofs--;
+    }
+
+  if (is_reserved_word (input, ofs))
+    *type = SEG_RESERVED_WORD;
+  else
+    *type = SEG_IDENTIFIER;
+
+  if (s->substate & SS_START_OF_COMMAND)
+    {
+      struct substring word = ss_buffer (input, ofs);
+
+      if (lex_id_match_n (ss_cstr ("COMMENT"), word, 4))
+        {
+          s->state = S_COMMENT_1;
+          return segmenter_parse_comment_1__ (s, input, n, type);
+        }
+      else if (lex_id_match (ss_cstr ("DOCUMENT"), word))
+        {
+          s->state = S_DOCUMENT_1;
+          *type = SEG_START_DOCUMENT;
+          return 0;
+        }
+      else if (lex_id_match (ss_cstr ("TITLE"), word)
+               || lex_id_match (ss_cstr ("SUBTITLE"), word))
+        {
+          int result = segmenter_unquoted (input, n, ofs);
+          if (result < 0)
+            return -1;
+          else if (result)
+            {
+              s->state = S_TITLE_1;
+              return ofs;
+            }
+        }
+      else if (lex_id_match (ss_cstr ("FILE"), word))
+        {
+          char id[16];
+
+          if (next_id_in_command (s, input, n, ofs, id, sizeof id) < 0)
+            return -1;
+          else if (lex_id_match (ss_cstr ("LABEL"), ss_cstr (id)))
+            {
+              s->state = S_FILE_LABEL;
+              s->substate = 0;
+              return ofs;
+            }
+        }
+      else if (lex_id_match (ss_cstr ("DO"), word))
+        {
+          char id[16];
+
+          if (next_id_in_command (s, input, n, ofs, id, sizeof id) < 0)
+            return -1;
+          else if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
+            {
+              s->state = S_DO_REPEAT_1;
+              s->substate = 0;
+              return ofs;
+            }
+        }
+      else if (lex_id_match (ss_cstr ("BEGIN"), word))
+        {
+          char id[16];
+          int ofs2;
+
+          ofs2 = next_id_in_command (s, input, n, ofs, id, sizeof id);
+          if (ofs2 < 0)
+            return -1;
+          else if (lex_id_match (ss_cstr ("DATA"), ss_cstr (id)))
+            {
+              int eol;
+
+              ofs2 = skip_spaces_and_comments (input, n, ofs2);
+              if (ofs2 < 0)
+                return -1;
+
+              if (input[ofs2] == '.')
+                {
+                  ofs2 = skip_spaces_and_comments (input, n, ofs2 + 1);
+                  if (ofs2 < 0)
+                    return -1;
+                }
+
+              eol = is_end_of_line (input, n, ofs2);
+              if (eol < 0)
+                return -1;
+              else if (eol)
+                {
+                  if (memchr (input, '\n', ofs2))
+                    s->state = S_BEGIN_DATA_1;
+                  else
+                    s->state = S_BEGIN_DATA_2;
+                  s->substate = 0;
+                  return ofs;
+                }
+            }
+        }
+    }
+
+  s->substate = 0;
+  return ofs;
+}
+
+static int
+segmenter_parse_string__ (enum segment_type string_type,
+                          int ofs, struct segmenter *s,
+                          const char *input, size_t n, enum segment_type *type)
+{
+  int quote = input[ofs];
+
+  ofs++;
+  while (ofs < n)
+    if (input[ofs] == quote)
+      {
+        ofs++;
+        if (ofs >= n)
+          return -1;
+        else if (input[ofs] == quote)
+          ofs++;
+        else
+          {
+            *type = string_type;
+            s->substate = 0;
+            return ofs;
+          }
+      }
+    else if (input[ofs] == '\n' || input[ofs] == '\0')
+      {
+        *type = SEG_EXPECTED_QUOTE;
+        s->substate = 0;
+        return ofs;
+      }
+    else
+      ofs++;
+
+  return -1;
+}
+
+static int
+segmenter_maybe_parse_string__ (enum segment_type string_type,
+                                struct segmenter *s,
+                                const char *input, size_t n,
+                                enum segment_type *type)
+{
+  if (n < 2)
+    return -1;
+  else if (input[1] == '\'' || input[1] == '"')
+    return segmenter_parse_string__ (string_type, 1, s, input, n, type);
+  else
+    return segmenter_parse_id__ (s, input, n, type);
+}
+
+static int
+segmenter_parse_mid_command__ (struct segmenter *s,
+                               const char *input, size_t n,
+                               enum segment_type *type)
+{
+  ucs4_t uc;
+  int mblen;
+  int ofs;
+
+  assert (s->state == S_GENERAL);
+  assert (!(s->substate & SS_START_OF_LINE));
+
+  mblen = segmenter_u8_to_uc__ (&uc, input, n);
+  if (mblen < 0)
+    return -1;
+
+  switch (uc)
+    {
+    case '\n':
+      s->substate |= SS_START_OF_LINE;
+      *type = SEG_NEWLINE;
+      return 1;
+
+    case '/':
+      if (n == 1)
+        return -1;
+      else if (input[1] == '*')
+        {
+          ofs = skip_comment (input, n, 2);
+          if (ofs < 0)
+            return -1;
+
+          *type = SEG_COMMENT;
+          return ofs;
+        }
+      else
+        {
+          s->substate = 0;
+          *type = SEG_PUNCT;
+          return 1;
+        }
+
+    case '(': case ')': case ',': case '=': case '-':
+    case '[': case ']': case '&': case '|': case '+':
+      *type = SEG_PUNCT;
+      s->substate = 0;
+      return 1;
+
+    case '*':
+      if (s->substate & SS_START_OF_COMMAND)
+        {
+          /* '*' at the beginning of a command begins a comment. */
+          s->state = S_COMMENT_1;
+          return segmenter_parse_comment_1__ (s, input, n, type);
+        }
+      else
+        return segmenter_parse_digraph__ ("*", s, input, n, type);
+
+    case '<':
+      return segmenter_parse_digraph__ ("=>", s, input, n, type);
+
+    case '>':
+      return segmenter_parse_digraph__ ("=", s, input, n, type);
+
+    case '~':
+      return segmenter_parse_digraph__ ("=", s, input, n, type);
+
+    case '.':
+      if (n < 2)
+        return -1;
+      else if (c_isdigit (input[1]))
+        return segmenter_parse_number__ (s, input, n, type);
+      else
+        {
+          int eol = at_end_of_line (input, n, 1);
+          if (eol < 0)
+            return -1;
+
+          if (eol)
+            {
+              *type = SEG_END_COMMAND;
+              s->substate = SS_START_OF_COMMAND;
+            }
+          else
+            *type = SEG_UNEXPECTED_DOT;
+          return 1;
+        }
+      NOT_REACHED ();
+
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      return segmenter_parse_number__ (s, input, n, type);
+
+    case 'u': case 'U':
+      return segmenter_maybe_parse_string__ (SEG_UNICODE_STRING,
+                                           s, input, n, type);
+
+    case 'x': case 'X':
+      return segmenter_maybe_parse_string__ (SEG_HEX_STRING,
+                                             s, input, n, type);
+
+    case '\'': case '"':
+      return segmenter_parse_string__ (SEG_QUOTED_STRING, 0,
+                                       s, input, n, type);
+
+    default:
+      if (lex_uc_is_space (uc))
+        {
+          ofs = skip_spaces (input, n, mblen);
+          if (ofs < 0)
+            return -1;
+
+          if (input[ofs - 1] == '\r' && input[ofs] == '\n')
+            {
+              if (ofs == 1)
+                {
+                  s->substate |= SS_START_OF_LINE;
+                  *type = SEG_NEWLINE;
+                  return 2;
+                }
+              else
+                ofs--;
+            }
+          *type = SEG_SPACES;
+          return ofs;
+        }
+      else if (lex_uc_is_id1 (uc))
+        return segmenter_parse_id__ (s, input, n, type);
+      else
+        {
+          *type = SEG_UNEXPECTED_CHAR;
+          s->substate = 0;
+          return mblen;
+        }
+    }
+}
+
+static int
+compare_commands (const void *a_, const void *b_)
+{
+  const char *const *ap = a_;
+  const char *const *bp = b_;
+  const char *a = *ap;
+  const char *b = *bp;
+
+  return c_strcasecmp (a, b);
+}
+
+static const char **
+segmenter_get_command_name_candidates (unsigned char first)
+{
+#define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) NAME,
+#define UNIMPL_CMD(NAME, DESCRIPTION) NAME,
+  static const char *commands[] =
+    {
+#include "language/command.def"
+      ""
+    };
+  static size_t n_commands = (sizeof commands / sizeof *commands) - 1;
+#undef DEF_CMD
+#undef UNIMPL_CMD
+
+  static bool inited;
+
+  static const char **cindex[UCHAR_MAX + 1];
+
+  if (!inited)
+    {
+      size_t i;
+
+      inited = true;
+
+      qsort (commands, n_commands, sizeof *commands, compare_commands);
+      for (i = 0; i < n_commands; i++)
+        {
+          unsigned char c = c_toupper (commands[i][0]);
+          if (cindex[c] == NULL)
+            cindex[c] = &commands[i];
+        }
+      for (i = 0; i <= UCHAR_MAX; i++)
+        if (cindex[i] == NULL)
+          cindex[i] = &commands[n_commands];
+    }
+
+  return cindex[c_toupper (first)];
+}
+
+static int
+segmenter_detect_command_name__ (const char *input, size_t n, int ofs)
+{
+  const char **commands;
+
+  input += ofs;
+  n -= ofs;
+  ofs = 0;
+  for (;;)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      if (ofs >= n)
+        return -1;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      if (uc == '\n'
+          || !(lex_uc_is_space (uc) || lex_uc_is_idn (uc) || uc == '-'))
+        break;
+
+      ofs += mblen;
+    }
+  if (input[ofs - 1] == '.')
+    ofs--;
+
+  for (commands = segmenter_get_command_name_candidates (input[0]);
+       c_toupper (input[0]) == c_toupper ((*commands)[0]);
+       commands++)
+    {
+      int missing_words;
+      bool exact;
+
+      if (command_match (ss_cstr (*commands), ss_buffer (input, ofs),
+                         &exact, &missing_words)
+          && missing_words <= 0)
+        return 1;
+    }
+
+  return 0;
+}
+
+static int
+is_start_of_string__ (const char *input, size_t n, int ofs)
+{
+  int c;
+
+  c = input[ofs];
+  if (c == 'x' || c == 'X' || c == 'u' || c == 'U')
+    {
+      if (ofs + 1 >= n)
+        return -1;
+
+      return input[ofs + 1] == '\'' || input[ofs + 1] == '"';
+    }
+  else
+    return c == '\'' || c == '"' || c == '\n';
+}
+
+static int
+segmenter_parse_start_of_line__ (struct segmenter *s,
+                                 const char *input, size_t n,
+                                 enum segment_type *type)
+{
+  ucs4_t uc;
+  int mblen;
+  int ofs;
+
+  assert (s->state == S_GENERAL);
+  assert (s->substate & SS_START_OF_LINE);
+
+  mblen = segmenter_u8_to_uc__ (&uc, input, n);
+  if (mblen < 0)
+    return -1;
+
+  switch (uc)
+    {
+    case '+':
+      ofs = skip_spaces_and_comments (input, n, 1);
+      if (ofs < 0)
+        return -1;
+      else
+        {
+          int is_string = is_start_of_string__ (input, n, ofs);
+          if (is_string < 0)
+            return -1;
+          else if (is_string)
+            {
+              /* This is punctuation that may separate pieces of a string. */
+              *type = SEG_PUNCT;
+              s->substate = 0;
+              return 1;
+            }
+        }
+      /* Fall through. */
+
+    case '-':
+    case '.':
+      *type = SEG_START_COMMAND;
+      s->substate = SS_START_OF_COMMAND;
+      return 1;
+
+    default:
+      if (lex_uc_is_space (uc))
+        {
+          int eol = at_end_of_line (input, n, 0);
+          if (eol < 0)
+            return -1;
+          else if (eol)
+            {
+              s->substate = SS_START_OF_COMMAND;
+              *type = SEG_SEPARATE_COMMANDS;
+              return 0;
+            }
+          break;
+        }
+
+      if (s->mode == SEG_MODE_INTERACTIVE || s->substate & SS_START_OF_COMMAND)
+        break;
+      else if (s->mode == SEG_MODE_AUTO)
+        {
+          int cmd = segmenter_detect_command_name__ (input, n, 0);
+          if (cmd < 0)
+            return -1;
+          else if (cmd == 0)
+            break;
+        }
+      else
+        assert (s->mode == SEG_MODE_BATCH);
+
+      s->substate = SS_START_OF_COMMAND;
+      *type = SEG_START_COMMAND;
+      return 0;
+    }
+
+  s->substate = SS_START_OF_COMMAND;
+  return segmenter_parse_mid_command__ (s, input, n, type);
+}
+
+static int
+segmenter_parse_file_label__ (struct segmenter *s,
+                              const char *input, size_t n,
+                              enum segment_type *type)
+{
+  struct segmenter sub;
+  int ofs;
+
+  sub = *s;
+  sub.state = S_GENERAL;
+  ofs = segmenter_push (&sub, input, n, type);
+
+  if (ofs < 0)
+    return -1;
+  else if (*type == SEG_IDENTIFIER)
+    {
+      int result;
+
+      assert (lex_id_match (ss_cstr ("LABEL"),
+                            ss_buffer ((char *) input, ofs)));
+      result = segmenter_unquoted (input, n, ofs);
+      if (result < 0)
+        return -1;
+      else
+        {
+          if (result)
+            s->state = S_TITLE_1;
+          else
+            *s = sub;
+          return ofs;
+        }
+    }
+  else
+    {
+      s->substate = sub.substate;
+      return ofs;
+    }
+}
+
+static int
+segmenter_subparse (struct segmenter *s,
+                    const char *input, size_t n, enum segment_type *type)
+{
+  struct segmenter sub;
+  int ofs;
+
+  sub.mode = s->mode;
+  sub.state = S_GENERAL;
+  sub.substate = s->substate;
+  ofs = segmenter_push (&sub, input, n, type);
+  s->substate = sub.substate;
+  return ofs;
+}
+
+static int
+segmenter_parse_do_repeat_1__ (struct segmenter *s,
+                               const char *input, size_t n,
+                               enum segment_type *type)
+{
+  int ofs = segmenter_subparse (s, input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  if (*type == SEG_START_COMMAND || *type == SEG_SEPARATE_COMMANDS)
+    s->state = S_DO_REPEAT_2;
+  else if (*type == SEG_END_COMMAND)
+    {
+      s->state = S_DO_REPEAT_3;
+      s->substate = 1;
+    }
+
+  return ofs;
+}
+
+static int
+segmenter_parse_do_repeat_2__ (struct segmenter *s,
+                               const char *input, size_t n,
+                               enum segment_type *type)
+{
+  int ofs = segmenter_subparse (s, input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  if (*type == SEG_NEWLINE)
+    {
+      s->state = S_DO_REPEAT_3;
+      s->substate = 1;
+    }
+
+  return ofs;
+}
+
+static bool
+check_repeat_command (struct segmenter *s,
+                      const char *input, size_t n)
+{
+  int direction;
+  char id[16];
+  int ofs;
+
+  ofs = 0;
+  if (input[ofs] == '+' || input[ofs] == '-')
+    ofs++;
+
+  ofs = next_id_in_command (s, input, n, ofs, id, sizeof id);
+  if (ofs < 0)
+    return false;
+  else if (lex_id_match (ss_cstr ("DO"), ss_cstr (id)))
+    direction = 1;
+  else if (lex_id_match (ss_cstr ("END"), ss_cstr (id)))
+    direction = -1;
+  else
+    return true;
+
+  ofs = next_id_in_command (s, input, n, ofs, id, sizeof id);
+  if (ofs < 0)
+    return false;
+
+  if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
+    s->substate += direction;
+  return true;
+}
+
+static int
+segmenter_parse_full_line__ (const char *input, size_t n,
+                             enum segment_type *type)
+{
+  const char *newline = memchr (input, '\n', n);
+
+  if (newline == NULL)
+    return -1;
+  else
+    {
+      int ofs = newline - input;
+      if (ofs == 0 || (ofs == 1 && input[0] == '\r'))
+        {
+          *type = SEG_NEWLINE;
+          return ofs + 1;
+        }
+      else
+        return ofs - (input[ofs - 1] == '\r');
+    }
+}
+
+static int
+segmenter_parse_do_repeat_3__ (struct segmenter *s,
+                               const char *input, size_t n,
+                               enum segment_type *type)
+{
+  int ofs;
+
+  ofs = segmenter_parse_full_line__ (input, n, type);
+  if (ofs < 0 || input[ofs - 1] == '\n')
+    return ofs;
+  else if (!check_repeat_command (s, input, n))
+    return -1;
+  else if (s->substate == 0)
+    {
+      s->state = S_GENERAL;
+      s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
+      return segmenter_push (s, input, n, type);
+    }
+  else
+    {
+      *type = SEG_DO_REPEAT_COMMAND;
+      return ofs;
+    }
+}
+
+static int
+segmenter_parse_begin_data_1__ (struct segmenter *s,
+                                const char *input, size_t n,
+                                enum segment_type *type)
+{
+  int ofs = segmenter_subparse (s, input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  if (*type == SEG_NEWLINE)
+    s->state = S_BEGIN_DATA_2;
+
+  return ofs;
+}
+
+static int
+segmenter_parse_begin_data_2__ (struct segmenter *s,
+                                const char *input, size_t n,
+                                enum segment_type *type)
+{
+  int ofs = segmenter_subparse (s, input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  if (*type == SEG_NEWLINE)
+    s->state = S_BEGIN_DATA_3;
+
+  return ofs;
+}
+
+static bool
+is_end_data (const char *input, size_t n)
+{
+  const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
+  bool endcmd;
+  ucs4_t uc;
+  int mblen;
+  int ofs;
+
+  if (n < 3 || c_strncasecmp (input, "END", 3))
+    return false;
+
+  ofs = 3;
+  mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
+  if (!lex_uc_is_space (uc))
+    return false;
+  ofs += mblen;
+
+  if (n - ofs < 4 || c_strncasecmp (input + ofs, "DATA", 4))
+    return false;
+  ofs += 4;
+
+  endcmd = false;
+  while (ofs < n)
+    {
+      mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
+      if (uc == '.')
+        {
+          if (endcmd)
+            return false;
+          endcmd = true;
+        }
+      else if (!lex_uc_is_space (uc))
+        return false;
+      ofs += mblen;
+    }
+
+  return true;
+}
+
+static int
+segmenter_parse_begin_data_3__ (struct segmenter *s,
+                                const char *input, size_t n,
+                                enum segment_type *type)
+{
+  int ofs;
+
+  ofs = segmenter_parse_full_line__ (input, n, type);
+  if (ofs < 0)
+    return -1;
+  else if (is_end_data (input, ofs))
+    {
+      s->state = S_GENERAL;
+      s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
+      return segmenter_push (s, input, n, type);
+    }
+  else
+    {
+      *type = SEG_INLINE_DATA;
+      s->state = S_BEGIN_DATA_4;
+      return input[ofs - 1] == '\n' ? 0 : ofs;
+    }
+}
+
+static int
+segmenter_parse_begin_data_4__ (struct segmenter *s,
+                                const char *input, size_t n,
+                                enum segment_type *type)
+{
+  int ofs;
+
+  ofs = segmenter_parse_newline__ (input, n, type);
+  if (ofs < 0)
+    return -1;
+
+  s->state = S_BEGIN_DATA_3;
+  return ofs;
+}
+
+static int
+segmenter_parse_title_1__ (struct segmenter *s,
+                           const char *input, size_t n,
+                           enum segment_type *type)
+{
+  int ofs;
+
+  ofs = skip_spaces (input, n, 0);
+  if (ofs < 0)
+    return -1;
+  s->state = S_TITLE_2;
+  *type = SEG_SPACES;
+  return ofs;
+}
+
+static int
+segmenter_parse_title_2__ (struct segmenter *s,
+                           const char *input, size_t n,
+                           enum segment_type *type)
+{
+  int endcmd;
+  int ofs;
+
+  endcmd = -1;
+  ofs = 0;
+  while (ofs < n)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      mblen = segmenter_u8_to_uc__ (&uc, input + ofs, n - ofs);
+      if (mblen < 0)
+        return -1;
+
+      switch (uc)
+        {
+        case '\n':
+          s->state = S_GENERAL;
+          s->substate = 0;
+          *type = SEG_UNQUOTED_STRING;
+          return endcmd >= 0 ? endcmd : ofs;
+
+        case '.':
+          endcmd = ofs;
+          break;
+
+        default:
+          if (!lex_uc_is_space (uc))
+            endcmd = -1;
+          break;
+        }
+
+      ofs += mblen;
+    }
+
+  return -1;
+}
+
+/* Returns the name of segment TYPE as a string.  The caller must not modify
+   or free the returned string.
+
+   This is useful only for debugging and testing. */
+const char *
+segment_type_to_string (enum segment_type type)
+{
+  switch (type)
+    {
+#define SEG_TYPE(NAME) case SEG_##NAME: return #NAME;
+      SEG_TYPES
+#undef SEG_TYPE
+    default:
+      return "unknown segment type";
+    }
+}
+
+/* Initializes S as a segmenter with the given syntax MODE.
+
+   A segmenter does not contain any external references, so nothing needs to be
+   done to destroy one.  For the same reason, segmenters may be copied with
+   plain struct assignment (or memcpy). */
+void
+segmenter_init (struct segmenter *s, enum segmenter_mode mode)
+{
+  s->state = S_SHBANG;
+  s->substate = 0;
+  s->mode = mode;
+}
+
+/* Returns the mode passed to segmenter_init() for S. */
+enum segmenter_mode
+segmenter_get_mode (const struct segmenter *s)
+{
+  return s->mode;
+}
+
+/* Attempts to label a prefix of S's remaining input with a segment type.  The
+   caller supplies the first N bytes of the remaining input as INPUT, which
+   must be a UTF-8 encoded string.  The end of the input stream must be
+   indicated by a null byte at the beginning of a line, that is, immediately
+   following a new-line (or as the first byte of the input stream).
+
+   The input may contain '\n' or '\r\n' line ends in any combination.
+
+   If successful, returns the number of bytes in the segment at the beginning
+   of INPUT (between 0 and N, inclusive) and stores the type of that segment
+   into *TYPE.  The next call to segmenter_push() should not include those
+   bytes as part of INPUT, because they have (figuratively) been consumed by
+   the segmenter.
+
+   Failure occurs only if the segment type of the N bytes in INPUT cannot yet
+   be determined.  In this case segmenter_push() returns -1.  The caller should
+   obtain more input and then call segmenter_push() again with a larger N and
+   repeat until the input is exhausted (which must be indicated as described
+   above) or until a valid segment is returned.  segmenter_push() will never
+   return -1 when the end of input is visible within INPUT.
+
+   The caller must not, in a sequence of calls, supply contradictory input.
+   That is, bytes provided as part of INPUT in one call, but not consumed, must
+   not be provided with *different* values on subsequent calls.  This is
+   because segmenter_push() must often make decisions based on looking ahead
+   beyond the bytes that it consumes. */
+int
+segmenter_push (struct segmenter *s, const char *input, size_t n,
+                enum segment_type *type)
+{
+  if (n == 0)
+    return -1;
+
+  if (input[0] == '\0')
+    {
+      *type = SEG_END;
+      return 1;
+    }
+
+  switch (s->state)
+    {
+    case S_SHBANG:
+      return segmenter_parse_shbang__ (s, input, n, type);
+
+    case S_GENERAL:
+      return (s->substate & SS_START_OF_LINE
+              ? segmenter_parse_start_of_line__ (s, input, n, type)
+              : segmenter_parse_mid_command__ (s, input, n, type));
+
+    case S_COMMENT_1:
+      return segmenter_parse_comment_1__ (s, input, n, type);
+    case S_COMMENT_2:
+      return segmenter_parse_comment_2__ (s, input, n, type);
+
+    case S_DOCUMENT_1:
+      return segmenter_parse_document_1__ (s, input, n, type);
+    case S_DOCUMENT_2:
+      return segmenter_parse_document_2__ (s, input, n, type);
+    case S_DOCUMENT_3:
+      return segmenter_parse_document_3__ (s, type);
+
+    case S_FILE_LABEL:
+      return segmenter_parse_file_label__ (s, input, n, type);
+
+    case S_DO_REPEAT_1:
+      return segmenter_parse_do_repeat_1__ (s, input, n, type);
+    case S_DO_REPEAT_2:
+      return segmenter_parse_do_repeat_2__ (s, input, n, type);
+    case S_DO_REPEAT_3:
+      return segmenter_parse_do_repeat_3__ (s, input, n, type);
+
+    case S_BEGIN_DATA_1:
+      return segmenter_parse_begin_data_1__ (s, input, n, type);
+    case S_BEGIN_DATA_2:
+      return segmenter_parse_begin_data_2__ (s, input, n, type);
+    case S_BEGIN_DATA_3:
+      return segmenter_parse_begin_data_3__ (s, input, n, type);
+    case S_BEGIN_DATA_4:
+      return segmenter_parse_begin_data_4__ (s, input, n, type);
+
+    case S_TITLE_1:
+      return segmenter_parse_title_1__ (s, input, n, type);
+    case S_TITLE_2:
+      return segmenter_parse_title_2__ (s, input, n, type);
+    }
+
+  NOT_REACHED ();
+}
+
+/* Returns the style of command prompt to display to an interactive user for
+   input in S.  The return value is most accurate in mode SEG_MODE_INTERACTIVE
+   and at the beginning of a line (that is, if segmenter_push() consumed as
+   much as possible of the input up to a new-line).  */
+enum prompt_style
+segmenter_get_prompt (const struct segmenter *s)
+{
+  switch (s->state)
+    {
+    case S_SHBANG:
+      return PROMPT_FIRST;
+
+    case S_GENERAL:
+      return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
+
+    case S_COMMENT_1:
+    case S_COMMENT_2:
+      return PROMPT_COMMENT;
+
+    case S_DOCUMENT_1:
+    case S_DOCUMENT_2:
+      return PROMPT_DOCUMENT;
+    case S_DOCUMENT_3:
+      return PROMPT_FIRST;
+
+    case S_FILE_LABEL:
+      return PROMPT_LATER;
+
+    case S_DO_REPEAT_1:
+    case S_DO_REPEAT_2:
+      return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
+    case S_DO_REPEAT_3:
+      return PROMPT_DO_REPEAT;
+
+    case S_BEGIN_DATA_1:
+      return PROMPT_FIRST;
+    case S_BEGIN_DATA_2:
+      return PROMPT_LATER;
+    case S_BEGIN_DATA_3:
+    case S_BEGIN_DATA_4:
+      return PROMPT_DATA;
+
+    case S_TITLE_1:
+    case S_TITLE_2:
+      return PROMPT_FIRST;
+    }
+
+  NOT_REACHED ();
+}
diff --git a/src/language/lexer/segment.h b/src/language/lexer/segment.h
new file mode 100644 (file)
index 0000000..686b471
--- /dev/null
@@ -0,0 +1,122 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 SEGMENT_H
+#define SEGMENT_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "libpspp/prompt.h"
+
+/* PSPP syntax segmentation.
+
+   PSPP divides traditional "lexical analysis" or "tokenization" into two
+   phases: a lower-level phase called "segmentation" and a higher-level phase
+   called "scanning".  This header file provides declarations for the
+   segmentation phase.  scan.h contains declarations for the scanning phase.
+
+   Segmentation accepts a stream of UTF-8 bytes as input.  It outputs a label
+   (a segment type) for each byte or contiguous sequence of bytes in the input.
+   It also, in a few corner cases, outputs zero-width segments that label the
+   boundary between a pair of bytes in the input.
+
+   Some segment types correspond directly to tokens; for example, an
+   "identifier" segment (SEG_IDENTIFIER) becomes an identifier token (T_ID)
+   later in lexical analysis.  Other segments contribute to tokens but do not
+   correspond diectly; for example, multiple quoted string segments
+   (SEG_QUOTED_STRING) separated by spaces (SEG_SPACES) and  "+" punctuators
+   (SEG_PUNCT) may be combined to form a single string token (T_STRING).
+   Still other segments are ignored (e.g. SEG_SPACES) or trigger special
+   behavior such as error messages later in tokenization
+   (e.g. SEG_EXPECTED_QUOTE).
+*/
+
+/* Segmentation mode.
+
+   This corresponds to the syntax mode for which a syntax file is intended.
+   This is the only configuration setting for a segmenter. */
+enum segmenter_mode
+  {
+    /* Try to interpret input correctly regardless of whether it is written
+       for interactive or batch mode. */
+    SEG_MODE_AUTO,
+
+    /* Interactive or batch syntax mode. */
+    SEG_MODE_INTERACTIVE,
+    SEG_MODE_BATCH
+  };
+
+#define SEG_TYPES                               \
+    SEG_TYPE(NUMBER)                            \
+    SEG_TYPE(QUOTED_STRING)                     \
+    SEG_TYPE(HEX_STRING)                        \
+    SEG_TYPE(UNICODE_STRING)                    \
+    SEG_TYPE(UNQUOTED_STRING)                   \
+    SEG_TYPE(RESERVED_WORD)                     \
+    SEG_TYPE(IDENTIFIER)                        \
+    SEG_TYPE(PUNCT)                             \
+                                                \
+    SEG_TYPE(SHBANG)                            \
+    SEG_TYPE(SPACES)                            \
+    SEG_TYPE(COMMENT)                           \
+    SEG_TYPE(NEWLINE)                           \
+                                                \
+    SEG_TYPE(COMMENT_COMMAND)                   \
+    SEG_TYPE(DO_REPEAT_COMMAND)                 \
+    SEG_TYPE(INLINE_DATA)                       \
+                                                \
+    SEG_TYPE(START_DOCUMENT)                    \
+    SEG_TYPE(DOCUMENT)                          \
+                                                \
+    SEG_TYPE(START_COMMAND)                     \
+    SEG_TYPE(SEPARATE_COMMANDS)                 \
+    SEG_TYPE(END_COMMAND)                       \
+    SEG_TYPE(END)                               \
+                                                \
+    SEG_TYPE(EXPECTED_QUOTE)                    \
+    SEG_TYPE(EXPECTED_EXPONENT)                 \
+    SEG_TYPE(UNEXPECTED_DOT)                    \
+    SEG_TYPE(UNEXPECTED_CHAR)
+
+/* Types of segments. */
+enum segment_type
+  {
+#define SEG_TYPE(NAME) SEG_##NAME,
+    SEG_TYPES
+#undef SEG_TYPE
+    SEG_N_TYPES
+  };
+
+const char *segment_type_to_string (enum segment_type);
+
+/* A segmenter.  Opaque. */
+struct segmenter
+  {
+    unsigned char state;
+    unsigned char substate;
+    unsigned char mode;
+  };
+
+void segmenter_init (struct segmenter *, enum segmenter_mode);
+
+enum segmenter_mode segmenter_get_mode (const struct segmenter *);
+
+int segmenter_push (struct segmenter *, const char *input, size_t n,
+                    enum segment_type *);
+
+enum prompt_style segmenter_get_prompt (const struct segmenter *);
+
+#endif /* segment.h */
diff --git a/src/language/lexer/token.c b/src/language/lexer/token.c
new file mode 100644 (file)
index 0000000..89a5cf0
--- /dev/null
@@ -0,0 +1,173 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/lexer/token.h"
+
+#include <math.h>
+#include <unictype.h>
+#include <unistr.h>
+
+#include "data/identifier.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+
+#include "gl/ftoastr.h"
+#include "gl/xalloc.h"
+
+/* Initializes TOKEN with an arbitrary type, number 0, and a null string. */
+void
+token_init (struct token *token)
+{
+  token->type = 0;
+  token->number = 0.0;
+  token->string = ss_empty ();
+}
+
+/* Frees the string that TOKEN contains. */
+void
+token_destroy (struct token *token)
+{
+  if (token != NULL)
+    ss_dealloc (&token->string);
+}
+
+static char *
+number_token_to_string (const struct token *token)
+{
+  char buffer[DBL_BUFSIZE_BOUND];
+
+  dtoastr (buffer, sizeof buffer, 0, 0, fabs (token->number));
+  return (token->type == T_POS_NUM
+          ? xstrdup (buffer)
+          : xasprintf ("-%s", buffer));
+}
+
+static char *
+quoted_string_representation (struct substring ss, size_t n_quotes)
+{
+  char *rep;
+  size_t i;
+  char *p;
+
+  p = rep = xmalloc (1 + ss.length + n_quotes + 1 + 1);
+  *p++ = '\'';
+  for (i = 0; i < ss.length; i++)
+    {
+      uint8_t c = ss.string[i];
+      if (c == '\'')
+        *p++ = c;
+      *p++ = c;
+    }
+  *p++ = '\'';
+  *p = '\0';
+
+  return rep;
+}
+
+static char *
+hex_string_representation (struct substring ss)
+{
+  char *rep;
+  size_t i;
+  char *p;
+
+  p = rep = xmalloc (2 + 2 * ss.length + 1 + 1);
+  *p++ = 'X';
+  *p++ = '\'';
+  for (i = 0; i < ss.length; i++)
+    {
+      static const char hex_digits[] = "0123456789abcdef";
+      uint8_t c = ss.string[i];
+      *p++ = hex_digits[c >> 4];
+      *p++ = hex_digits[c & 15];
+    }
+  *p++ = '\'';
+  *p = '\0';
+
+  return rep;
+}
+
+static char *
+string_representation (struct substring ss)
+{
+  size_t n_quotes;
+  size_t ofs;
+  int mblen;
+
+  n_quotes = 0;
+  for (ofs = 0; ofs < ss.length; ofs += mblen)
+    {
+      ucs4_t uc;
+
+      mblen = u8_mbtoucr (&uc,
+                          CHAR_CAST (const uint8_t *, ss.string + ofs),
+                          ss.length - ofs);
+      if (mblen < 0 || !uc_is_print (uc))
+        return hex_string_representation (ss);
+      else if (uc == '\'')
+        n_quotes++;
+    }
+  return quoted_string_representation (ss, n_quotes);
+}
+
+/* Returns a UTF-8 string that would yield TOKEN if it appeared in a syntax
+   file.  The caller should free the returned string, with free(), when it is
+   no longer needed.
+
+   The T_STOP token has no representation, so this function returns NULL. */
+char *
+token_to_string (const struct token *token)
+{
+  const char *name;
+
+  switch (token->type)
+    {
+    case T_POS_NUM:
+    case T_NEG_NUM:
+      return number_token_to_string (token);
+
+    case T_ID:
+      return ss_xstrdup (token->string);
+
+    case T_STRING:
+      return string_representation (token->string);
+
+    default:
+      name = token_type_to_name (token->type);
+      return name != NULL ? xstrdup (name) : NULL;
+    }
+}
+
+/* Prints TOKEN on STREAM, for debugging. */
+void
+token_print (const struct token *token, FILE *stream)
+{
+  fputs (token_type_to_name (token->type), stream);
+  if (token->type == T_POS_NUM || token->type == T_NEG_NUM
+      || token->number != 0.0)
+    {
+      char s[DBL_BUFSIZE_BOUND];
+
+      dtoastr (s, sizeof s, 0, 0, token->number);
+      fprintf (stream, "\t%s", s);
+    }
+  if (token->type == T_ID || token->type == T_STRING || token->string.length)
+    fprintf (stream, "\t\"%.*s\"",
+             (int) token->string.length, token->string.string);
+  putc ('\n', stream);
+}
diff --git a/src/language/lexer/token.h b/src/language/lexer/token.h
new file mode 100644 (file)
index 0000000..8feaf81
--- /dev/null
@@ -0,0 +1,45 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 TOKEN_H
+#define TOKEN_H 1
+
+#include <stdio.h>
+#include "libpspp/str.h"
+#include "data/identifier.h"
+
+/* A PSPP syntax token.
+
+   The 'type' member is used by the scanner (see scan.h) for SCAN_* values as
+   well, which is why it is not declared as type "enum token_type". */
+struct token
+  {
+    int type;                   /* Usually a "enum token_type" value. */
+    double number;
+    struct substring string;
+  };
+
+#define TOKEN_INITIALIZER(TYPE, NUMBER, STRING) \
+        { TYPE, NUMBER, SS_LITERAL_INITIALIZER (STRING) }
+
+void token_init (struct token *);
+void token_destroy (struct token *);
+
+char *token_to_string (const struct token *);
+
+void token_print (const struct token *, FILE *);
+
+#endif /* token.h */
index 269d24bca48d04b13da5c7a054b08fcdb281d4fd..74478cfa60ac7bce5249792e38fc6f77a0504062 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2009, 2010, 2011 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
@@ -25,6 +25,7 @@
 #include "data/value.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/cast.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
@@ -106,8 +107,7 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
 
       assert (fmt_get_category (*format) != FMT_CAT_STRING);
 
-      if (!data_in_msg (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE,
-                        *format, &v, 0, NULL))
+      if (!data_in_msg (lex_tokss (lexer), "UTF-8", *format, &v, 0, NULL))
         return false;
 
       lex_get (lexer);
@@ -129,21 +129,18 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
     }
 }
 
-/* Parses the current token from LEXER into value V, which must
-   already have been initialized with the specified WIDTH.
-   Returns true if successful, false otherwise. */
+/* Parses the current token from LEXER into value V, which must already have
+   been initialized with the specified VAR's WIDTH.  Returns true if
+   successful, false otherwise. */
 bool
-parse_value (struct lexer *lexer, union value *v, int width)
+parse_value (struct lexer *lexer, union value *v, const struct variable *var)
 {
+  int width = var_get_width (var);
   if (width == 0)
-    {
-      if (!lex_force_num (lexer))
-       return false;
-      v->f = lex_tokval (lexer);
-    }
+    return parse_number (lexer, &v->f, &var_get_print_format (var)->type);
   else if (lex_force_string (lexer))
     {
-      const char *s = ds_cstr (lex_tokstr (lexer));
+      const char *s = lex_tokcstr (lexer);
       value_copy_str_rpad (v, width, CHAR_CAST_BUG (const uint8_t *, s), ' ');
     }
   else
index 4f9004a361478efcbca80d2a41476706e5395cc7..94b2cdc142482a456bb7e277ae7f3ccce39b36f1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009, 2011 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
 
 struct lexer;
 enum fmt_type;
+struct variable;
 union value;
 bool parse_num_range (struct lexer *,
                       double *x, double *y, const enum fmt_type *fmt);
-bool parse_value (struct lexer *, union value *, int width);
+bool parse_value (struct lexer *, union value *, const struct variable *);
 
 #endif /* value-parser.h */
index b9d67523eeda711ed52501425d8ff9fa99ed0c54..49d6a5deb900a6e63e8363b1fd020c685116f16c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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/lexer/variable-parser.h"
 
 #include <ctype.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <stdlib.h>
 
+#include "data/dataset.h"
 #include "data/dictionary.h"
-#include "data/procedure.h"
 #include "data/variable.h"
 #include "language/lexer/lexer.h"
 #include "libpspp/assertion.h"
@@ -36,6 +37,7 @@
 #include "libpspp/str.h"
 #include "libpspp/stringi-set.h"
 
+#include "gl/c-ctype.h"
 #include "gl/xalloc.h"
 
 #include "gettext.h"
@@ -65,14 +67,14 @@ parse_vs_variable_idx (struct lexer *lexer, const struct var_set *vs,
       lex_error (lexer, _("expecting variable name"));
       return false;
     }
-  else if (var_set_lookup_var_idx (vs, lex_tokid (lexer), idx))
+  else if (var_set_lookup_var_idx (vs, lex_tokcstr (lexer), idx))
     {
       lex_get (lexer);
       return true;
     }
   else
     {
-      msg (SE, _("%s is not a variable name."), lex_tokid (lexer));
+      msg (SE, _("%s is not a variable name."), lex_tokcstr (lexer));
       return false;
     }
 }
@@ -336,10 +338,10 @@ parse_var_set_vars (struct lexer *lexer, const struct var_set *vs,
 
       if (pv_opts & PV_SINGLE)
         break;
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
   while (lex_token (lexer) == T_ALL
-         || (lex_token (lexer) == T_ID && var_set_lookup_var (vs, lex_tokid (lexer)) != NULL));
+         || (lex_token (lexer) == T_ID && var_set_lookup_var (vs, lex_tokcstr (lexer)) != NULL));
 
   if (*nv == 0)
     goto fail;
@@ -355,183 +357,206 @@ fail:
   return 0;
 }
 
-/* Extracts a numeric suffix from variable name S, copying it
-   into string R.  Sets *D to the length of R and *N to its
-   value. */
+/* Attempts to break UTF-8 encoded NAME into a root (whose contents are
+   arbitrary except that it does not end in a digit) followed by an integer
+   numeric suffix.  On success, stores the value of the suffix into *NUMBERP,
+   the number of digits in the suffix into *N_DIGITSP, and returns the number
+   of bytes in the root.  On failure, returns 0. */
 static int
-extract_num (char *s, char *r, int *n, int *d)
+extract_numeric_suffix (const char *name,
+                        unsigned long int *numberp, int *n_digitsp)
 {
-  char *cp;
-
-  /* Find first digit. */
-  cp = s + strlen (s) - 1;
-  while (isdigit ((unsigned char) *cp) && cp > s)
-    cp--;
-  cp++;
+  size_t root_len, n_digits;
+  size_t i;
 
-  /* Extract root. */
-  strncpy (r, s, cp - s);
-  r[cp - s] = 0;
+  /* Count length of root. */
+  root_len = 1;                 /* Valid identifier never starts with digit. */
+  for (i = 1; name[i] != '\0'; i++)
+    if (!c_isdigit (name[i]))
+      root_len = i + 1;
+  n_digits = i - root_len;
 
-  /* Count initial zeros. */
-  *n = *d = 0;
-  while (*cp == '0')
+  if (n_digits == 0)
     {
-      (*d)++;
-      cp++;
+      msg (SE, _("`%s' cannot be used with TO because it does not end in "
+                 "a digit."), name);
+      return 0;
     }
 
-  /* Extract value. */
-  while (isdigit ((unsigned char) *cp))
+  *numberp = strtoull (name + root_len, NULL, 10);
+  if (*numberp == ULONG_MAX)
     {
-      (*d)++;
-      *n = (*n * 10) + (*cp - '0');
-      cp++;
+      msg (SE, _("Numeric suffix on `%s' is larger than supported with TO."),
+           name);
+      return 0;
     }
+  *n_digitsp = n_digits;
+  return root_len;
+}
 
-  /* Sanity check. */
-  if (*n == 0 && *d == 0)
+static bool
+add_var_name (char *name,
+              char ***names, size_t *n_vars, size_t *allocated_vars,
+              struct stringi_set *set, int pv_opts)
+{
+  if (pv_opts & PV_NO_DUPLICATE && !stringi_set_insert (set, name))
     {
-      msg (SE, _("incorrect use of TO convention"));
-      return 0;
+      msg (SE, _("Variable %s appears twice in variable list."),
+           name);
+      return false;
     }
-  return 1;
+
+  if (*n_vars >= *allocated_vars)
+    *names = x2nrealloc (*names, allocated_vars, sizeof **names);
+  (*names)[(*n_vars)++] = name;
+  return true;
 }
 
 /* Parses a list of variable names according to the DATA LIST version
    of the TO convention.  */
 bool
-parse_DATA_LIST_vars (struct lexer *lexer, char ***names,
-                      size_t *nnames, int pv_opts)
+parse_DATA_LIST_vars (struct lexer *lexer, const struct dictionary *dict,
+                      char ***namesp, size_t *n_varsp, int pv_opts)
 {
-  int n1, n2;
-  int d1, d2;
-  int n;
-  size_t nvar, mvar;
-  char name1[VAR_NAME_LEN + 1], name2[VAR_NAME_LEN + 1];
-  char root1[VAR_NAME_LEN + 1], root2[VAR_NAME_LEN + 1];
+  char **names;
+  size_t n_vars;
+  size_t allocated_vars;
+
   struct stringi_set set;
-  int success = 0;
 
-  assert (names != NULL);
-  assert (nnames != NULL);
+  char *name1 = NULL;
+  char *name2 = NULL;
+  bool ok = false;
+
   assert ((pv_opts & ~(PV_APPEND | PV_SINGLE
                        | PV_NO_SCRATCH | PV_NO_DUPLICATE)) == 0);
   stringi_set_init (&set);
 
   if (pv_opts & PV_APPEND)
     {
-      nvar = mvar = *nnames;
+      n_vars = allocated_vars = *n_varsp;
+      names = *namesp;
 
       if (pv_opts & PV_NO_DUPLICATE)
         {
           size_t i;
 
-          for (i = 0; i < nvar; i++)
-            stringi_set_insert (&set, (*names)[i]);
+          for (i = 0; i < n_vars; i++)
+            stringi_set_insert (&set, names[i]);
         }
     }
   else
     {
-      nvar = mvar = 0;
-      *names = NULL;
+      n_vars = allocated_vars = 0;
+      names = NULL;
     }
 
   do
     {
-      if (lex_token (lexer) != T_ID)
+      if (lex_token (lexer) != T_ID
+          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
        {
          lex_error (lexer, "expecting variable name");
-         goto fail;
+         goto exit;
        }
-      if (dict_class_from_id (lex_tokid (lexer)) == DC_SCRATCH
+      if (dict_class_from_id (lex_tokcstr (lexer)) == DC_SCRATCH
           && (pv_opts & PV_NO_SCRATCH))
        {
          msg (SE, _("Scratch variables not allowed here."));
-         goto fail;
+         goto exit;
        }
-      strcpy (name1, lex_tokid (lexer));
+      name1 = xstrdup (lex_tokcstr (lexer));
       lex_get (lexer);
       if (lex_token (lexer) == T_TO)
        {
+          unsigned long int num1, num2;
+          int n_digits1, n_digits2;
+          int root_len1, root_len2;
+          unsigned long int number;
+
          lex_get (lexer);
-         if (lex_token (lexer) != T_ID)
+         if (lex_token (lexer) != T_ID
+              || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
            {
              lex_error (lexer, "expecting variable name");
-             goto fail;
+             goto exit;
            }
-         strcpy (name2, lex_tokid (lexer));
+          name2 = xstrdup (lex_tokcstr (lexer));
          lex_get (lexer);
 
-         if (!extract_num (name1, root1, &n1, &d1)
-             || !extract_num (name2, root2, &n2, &d2))
-           goto fail;
+          root_len1 = extract_numeric_suffix (name1, &num1, &n_digits1);
+          if (root_len1 == 0)
+            goto exit;
+
+          root_len2 = extract_numeric_suffix (name2, &num2, &n_digits2);
+          if (root_len2 == 0)
+           goto exit;
 
-         if (strcasecmp (root1, root2))
+         if (root_len1 != root_len2 || memcasecmp (name1, name2, root_len1))
            {
              msg (SE, _("Prefixes don't match in use of TO convention."));
-             goto fail;
+             goto exit;
            }
-         if (n1 > n2)
+         if (num1 > num2)
            {
              msg (SE, _("Bad bounds in use of TO convention."));
-             goto fail;
-           }
-         if (d2 > d1)
-           d2 = d1;
-
-         if (mvar < nvar + (n2 - n1 + 1))
-           {
-             mvar += ROUND_UP (n2 - n1 + 1, 16);
-             *names = xnrealloc (*names, mvar, sizeof **names);
+             goto exit;
            }
 
-         for (n = n1; n <= n2; n++)
+         for (number = num1; number <= num2; number++)
            {
-              char name[VAR_NAME_LEN + 1];
-             sprintf (name, "%s%0*d", root1, d1, n);
-
-              if (pv_opts & PV_NO_DUPLICATE && !stringi_set_insert (&set, name))
+              char *name = xasprintf ("%.*s%0*lu",
+                                      root_len1, name1,
+                                      n_digits1, number);
+              if (!add_var_name (name, &names, &n_vars, &allocated_vars,
+                                 &set, pv_opts))
                 {
-                  msg (SE, _("Variable %s appears twice in variable list."),
-                       name);
-                  goto fail;
+                  free (name);
+                  goto exit;
                 }
-             (*names)[nvar] = xstrdup (name);
-             nvar++;
            }
+
+          free (name1);
+          name1 = NULL;
+          free (name2);
+          name2 = NULL;
        }
       else
        {
-         if (nvar >= mvar)
-           {
-             mvar += 16;
-             *names = xnrealloc (*names, mvar, sizeof **names);
-           }
-         (*names)[nvar++] = xstrdup (name1);
+          if (!add_var_name (name1, &names, &n_vars, &allocated_vars,
+                             &set, pv_opts))
+            goto exit;
+          name1 = NULL;
        }
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
 
       if (pv_opts & PV_SINGLE)
        break;
     }
   while (lex_token (lexer) == T_ID);
-  success = 1;
+  ok = true;
 
-fail:
-  *nnames = nvar;
+exit:
   stringi_set_destroy (&set);
-  if (!success)
+  if (ok)
+    {
+      *namesp = names;
+      *n_varsp = n_vars;
+    }
+  else
     {
       int i;
-      for (i = 0; i < nvar; i++)
-       free ((*names)[i]);
-      free (*names);
-      *names = NULL;
-      *nnames = 0;
+      for (i = 0; i < n_vars; i++)
+       free (names[i]);
+      free (names);
+      *namesp = NULL;
+      *n_varsp = 0;
+
+      free (name1);
+      free (name2);
     }
-  return success;
+  return ok;
 }
 
 /* Registers each of the NAMES[0...NNAMES - 1] in POOL, as well
@@ -551,7 +576,8 @@ register_vars_pool (struct pool *pool, char **names, size_t nnames)
    parse_DATA_LIST_vars(), except that all allocations are taken
    from the given POOL. */
 bool
-parse_DATA_LIST_vars_pool (struct lexer *lexer, struct pool *pool,
+parse_DATA_LIST_vars_pool (struct lexer *lexer, const struct dictionary *dict,
+                           struct pool *pool,
                            char ***names, size_t *nnames, int pv_opts)
 {
   int retval;
@@ -562,7 +588,7 @@ parse_DATA_LIST_vars_pool (struct lexer *lexer, struct pool *pool,
      re-free it later. */
   assert (!(pv_opts & PV_APPEND));
 
-  retval = parse_DATA_LIST_vars (lexer, names, nnames, pv_opts);
+  retval = parse_DATA_LIST_vars (lexer, dict, names, nnames, pv_opts);
   if (retval)
     register_vars_pool (pool, *names, *nnames);
   return retval;
@@ -588,7 +614,7 @@ parse_mixed_vars (struct lexer *lexer, const struct dictionary *dict,
     }
   while (lex_token (lexer) == T_ID || lex_token (lexer) == T_ALL)
     {
-      if (lex_token (lexer) == T_ALL || dict_lookup_var (dict, lex_tokid (lexer)) != NULL)
+      if (lex_token (lexer) == T_ALL || dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL)
        {
          struct variable **v;
          size_t nv;
@@ -601,7 +627,7 @@ parse_mixed_vars (struct lexer *lexer, const struct dictionary *dict,
          free (v);
          *nnames += nv;
        }
-      else if (!parse_DATA_LIST_vars (lexer, names, nnames, PV_APPEND))
+      else if (!parse_DATA_LIST_vars (lexer, dict, names, nnames, PV_APPEND))
        goto fail;
     }
   return 1;
@@ -686,7 +712,6 @@ var_set_lookup_var_idx (const struct var_set *vs, const char *name,
 {
   assert (vs != NULL);
   assert (name != NULL);
-  assert (strlen (name) <= VAR_NAME_LEN);
 
   return vs->lookup_var_idx (vs, name, idx);
 }
index b0ab8c51920fc170acfc72fba19224da6cea7302..7abea0a14beade2d73626e24f16e77f300367a72 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 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
@@ -59,9 +59,11 @@ bool parse_variables_pool (struct lexer *, struct pool *, const struct dictionar
                           struct variable ***, size_t *, int opts);
 bool parse_var_set_vars (struct lexer *, const struct var_set *, struct variable ***, size_t *,
                         int opts);
-bool parse_DATA_LIST_vars (struct lexer *, char ***names, size_t *cnt, int opts);
-bool parse_DATA_LIST_vars_pool (struct lexer *, struct pool *,
-                               char ***names, size_t *cnt, int opts);
+bool parse_DATA_LIST_vars (struct lexer *, const struct dictionary *,
+                           char ***names, size_t *cnt, int opts);
+bool parse_DATA_LIST_vars_pool (struct lexer *, const struct dictionary *,
+                                struct pool *,
+                                char ***names, size_t *cnt, int opts);
 bool parse_mixed_vars (struct lexer *, const struct dictionary *dict,
                       char ***names, size_t *cnt, int opts);
 bool parse_mixed_vars_pool (struct lexer *, const struct dictionary *dict,
diff --git a/src/language/prompt.c b/src/language/prompt.c
deleted file mode 100644 (file)
index ede6a5e..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 <errno.h>
-#include <stdlib.h>
-
-#include "prompt.h"
-
-#include <data/file-name.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <libpspp/version.h>
-#include <output/tab.h>
-
-#include "xalloc.h"
-
-/* Current prompts in each style. */
-static char *prompts[PROMPT_CNT];
-
-/* Current prompting style. */
-static enum prompt_style current_style;
-
-/* Initializes prompts. */
-void
-prompt_init (void)
-{
-  prompts[PROMPT_FIRST] = xstrdup ("PSPP> ");
-  prompts[PROMPT_LATER] = xstrdup ("    > ");
-  prompts[PROMPT_DATA] = xstrdup ("data> ");
-  current_style = PROMPT_FIRST;
-}
-
-/* Frees prompts. */
-void
-prompt_done (void)
-{
-  int i;
-
-  for (i = 0; i < PROMPT_CNT; i++)
-    {
-      free (prompts[i]);
-      prompts[i] = NULL;
-    }
-}
-
-/* Gets the command prompt for the given STYLE. */
-const char *
-prompt_get (enum prompt_style style)
-{
-  assert (style < PROMPT_CNT);
-  return prompts[style];
-}
-
-/* Sets the given STYLE's prompt to STRING. */
-void
-prompt_set (enum prompt_style style, const char *string)
-{
-  assert (style < PROMPT_CNT);
-  free (prompts[style]);
-  prompts[style] = xstrdup (string);
-}
-
-/* Sets STYLE as the current prompt style. */
-void
-prompt_set_style (enum prompt_style style)
-{
-  assert (style < PROMPT_CNT);
-  current_style = style;
-}
-
-/* Returns the current prompt. */
-enum prompt_style
-prompt_get_style (void)
-{
-  return current_style;
-}
diff --git a/src/language/prompt.h b/src/language/prompt.h
deleted file mode 100644 (file)
index 648eb9d..0000000
+++ /dev/null
@@ -1,41 +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/>. */
-
-#ifndef PROMPT_H
-#define PROMPT_H 1
-
-#include <stdbool.h>
-
-enum prompt_style
-  {
-    PROMPT_FIRST,              /* First line of command. */
-    PROMPT_LATER,          /* Second or later line of command. */
-    PROMPT_DATA,               /* Between BEGIN DATA and END DATA. */
-    PROMPT_CNT
-  };
-
-
-void prompt_init (void);
-void prompt_done (void);
-
-enum prompt_style prompt_get_style (void);
-
-const char *prompt_get (enum prompt_style);
-void prompt_set (enum prompt_style, const char *);
-void prompt_set_style (enum prompt_style);
-
-
-#endif /* PROMPT_H */
index a8e3f6d71d267545b1d1d85ef60490433149c0f8..fed765692f9a65cc30d20c3b1d17ff2bef81843b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011 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 "language/stats/aggregate.h"
+
 #include <stdlib.h>
 
-#include <data/any-writer.h>
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/file-handle-def.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/subcase.h>
-#include <data/sys-file-writer.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/data-io/file-handle.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <language/stats/sort-criteria.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <math/moments.h>
-#include <math/sort.h>
-#include <math/statistic.h>
-#include <math/percentiles.h>
-
-#include "aggregate.h"
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/any-writer.h"
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "data/subcase.h"
+#include "data/sys-file-writer.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "language/stats/sort-criteria.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+#include "math/moments.h"
+#include "math/percentiles.h"
+#include "math/sort.h"
+#include "math/statistic.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -91,27 +92,27 @@ struct agr_var
 /* Attributes of aggregation functions. */
 const struct agr_func agr_func_tab[] =
   {
-    {"SUM",     N_("Sum of values"), AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
-    {"MEAN",   N_("Mean average"), AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
-    {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
-    {"SD",      N_("Standard deviation"), AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
-    {"MAX",     N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
-    {"MIN",     N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
-    {"PGT",     N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
-    {"PLT",     N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
-    {"PIN",     N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
-    {"POUT",    N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
-    {"FGT",     N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
-    {"FLT",     N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
-    {"FIN",     N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
-    {"FOUT",    N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
-    {"N",       N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
-    {"NU",      N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
-    {"NMISS",   N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"SUM",     N_("Sum of values"),                         AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
+    {"MEAN",   N_("Mean average"),                          AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
+    {"MEDIAN", N_("Median average"),                        AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
+    {"SD",      N_("Standard deviation"),                    AGR_SV_YES, 0, -1,          {FMT_F, 8, 2}},
+    {"MAX",     N_("Maximum value"),                         AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
+    {"MIN",     N_("Minimum value"),                         AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
+    {"PGT",     N_("Percentage greater than"),               AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"PLT",     N_("Percentage less than"),                  AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"PIN",     N_("Percentage included in range"),          AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"POUT",    N_("Percentage excluded from range"),        AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
+    {"FGT",     N_("Fraction greater than"),                 AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FLT",     N_("Fraction less than"),                    AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FIN",     N_("Fraction included in range"),            AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"FOUT",    N_("Fraction excluded from range"),          AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
+    {"N",       N_("Number of cases"),                       AGR_SV_NO,  0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NU",      N_("Number of cases (unweighted)"),          AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
+    {"NMISS",   N_("Number of missing values"),              AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
     {"NUMISS",  N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
-    {"FIRST",   N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
-    {"LAST",    N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
-    {NULL,      NULL, AGR_SV_NO, 0, -1,          {-1, -1, -1}},
+    {"FIRST",   N_("First non-missing value"),               AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
+    {"LAST",    N_("Last non-missing value"),                AGR_SV_YES, 0, VAL_STRING,  {-1, -1, -1}},
+    {NULL,      NULL,                                        AGR_SV_NO,  0, -1,          {-1, -1, -1}},
   };
 
 /* Missing value types. */
@@ -175,20 +176,20 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
   subcase_init_empty (&agr.sort);
 
   /* OUTFILE subcommand must be first. */
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   if (!lex_force_match_id (lexer, "OUTFILE"))
     goto error;
-  lex_match (lexer, '=');
-  if (!lex_match (lexer, '*'))
+  lex_match (lexer, T_EQUALS);
+  if (!lex_match (lexer, T_ASTERISK))
     {
-      out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
+      out_file = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
       if (out_file == NULL)
         goto error;
     }
 
   if (out_file == NULL && lex_match_id (lexer, "MODE"))
     {
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
       if (lex_match_id (lexer, "ADDVARIABLES"))
        {
          agr.add_variables = true;
@@ -207,7 +208,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
   if ( agr.add_variables )
     agr.dict = dict_clone (dict);
   else
-    agr.dict = dict_create ();    
+    agr.dict = dict_create (dict_get_encoding (dict));
 
   dict_set_label (agr.dict, dict_get_label (dict));
   dict_set_documents (agr.dict, dict_get_documents (dict));
@@ -215,11 +216,11 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
   /* Read most of the subcommands. */
   for (;;)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "MISSING"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (!lex_match_id (lexer, "COLUMNWISE"))
            {
              lex_error (lexer, _("expecting %s"), "COLUMNWISE");
@@ -235,7 +236,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
        {
           int i;
 
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
           if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
                                     &saw_direction))
             goto error;
@@ -258,7 +259,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
                "the same way as the input data."));
 
   /* Read in the aggregate functions. */
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   if (!parse_aggregate_functions (lexer, dict, &agr))
     goto error;
 
@@ -274,7 +275,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
 
   if (out_file == NULL)
     {
-      /* The active file will be replaced by the aggregated data,
+      /* The active dataset will be replaced by the aggregated data,
          so TEMPORARY is moot. */
       proc_cancel_temporary_transformations (ds);
       proc_discard_output (ds);
@@ -350,7 +351,8 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds)
       if (next_input == NULL)
         goto error;
 
-      proc_set_active_file (ds, next_input, agr.dict);
+      dataset_set_dict (ds, agr.dict);
+      dataset_set_source (ds, next_input);
       agr.dict = NULL;
     }
   else
@@ -412,11 +414,11 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
       ds_init_empty (&function_name);
 
       /* Parse the list of target variables. */
-      while (!lex_match (lexer, '='))
+      while (!lex_match (lexer, T_EQUALS))
        {
          size_t n_dest_prev = n_dest;
 
-         if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
+         if (!parse_DATA_LIST_vars (lexer, dict, &dest, &n_dest,
                                      (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
                                       | PV_NO_DUPLICATE)))
            goto error;
@@ -434,13 +436,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
 
          if (lex_is_string (lexer))
            {
-             struct string label;
-             ds_init_string (&label, lex_tokstr (lexer));
-
-             ds_truncate (&label, 255);
-             dest_label[n_dest - 1] = ds_xstrdup (&label);
+             dest_label[n_dest - 1] = xstrdup (lex_tokcstr (lexer));
              lex_get (lexer);
-             ds_destroy (&label);
            }
        }
 
@@ -451,8 +448,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
          goto error;
        }
 
-      ds_assign_string (&function_name, lex_tokstr (lexer));
-      exclude = ds_chomp (&function_name, '.') ? MV_SYSTEM : MV_ANY;
+      ds_assign_substring (&function_name, lex_tokss (lexer));
+      exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY;
 
       for (function = agr_func_tab; function->name; function++)
        if (!strcasecmp (function->name, ds_cstr (&function_name)))
@@ -468,11 +465,11 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
       lex_get (lexer);
 
       /* Check for leading lparen. */
-      if (!lex_match (lexer, '('))
+      if (!lex_match (lexer, T_LPAREN))
        {
          if (function->src_vars == AGR_SV_YES)
            {
-              lex_force_match (lexer, '(');
+              lex_force_match (lexer, T_LPAREN);
              goto error;
            }
        }
@@ -498,10 +495,12 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
              {
                int type;
 
-               lex_match (lexer, ',');
+               lex_match (lexer, T_COMMA);
                if (lex_is_string (lexer))
                  {
-                   arg[i].c = ds_xstrdup (lex_tokstr (lexer));
+                   arg[i].c = recode_string (dict_get_encoding (agr->dict),
+                                              "UTF-8", lex_tokcstr (lexer),
+                                              -1);
                    type = VAL_STRING;
                  }
                else if (lex_is_number (lexer))
@@ -528,7 +527,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
              }
 
          /* Trailing rparen. */
-         if (!lex_force_match (lexer, ')'))
+         if (!lex_force_match (lexer, T_RPAREN))
             goto error;
 
          /* Now check that the number of source variables match
@@ -639,7 +638,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
 
            free (dest[i]);
            if (dest_label[i])
-              var_set_label (destvar, dest_label[i]);
+              var_set_label (destvar, dest_label[i], true);
 
            v->dest = destvar;
          }
@@ -670,9 +669,9 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
       free (dest);
       free (dest_label);
 
-      if (!lex_match (lexer, '/'))
+      if (!lex_match (lexer, T_SLASH))
        {
-         if (lex_token (lexer) == '.')
+         if (lex_token (lexer) == T_ENDCMD)
            return true;
 
          lex_error (lexer, "expecting end of command");
@@ -810,6 +809,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
            iter->int1 = 1;
            break;
          case MAX | FSTRING:
+            /* Need to do some kind of Unicode collation thingy here */
            if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
              memcpy (iter->string, value_str (v, src_width), src_width);
            iter->int1 = 1;
index 1a50bbe4caea0a167b75e99a1b06bf8d790f14d3..8cddbcfa574120a20d326732079f3f849f070e34 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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
 #ifndef AGGREGATE_H
 #define AGGREGATE_H
 
-#include <data/format.h>
-#include <data/val-type.h>
-
 #include <stddef.h>
 
+#include "data/format.h"
+#include "data/val-type.h"
+
 enum agr_src_vars
   {
     AGR_SV_NO,
index fb191d0c274df1f57ceae16e2d1eaff2b3b9b644..7b2022f02e068c67bc9feb839451fb9549bb4232 100644 (file)
@@ -16,25 +16,33 @@ language_stats_sources = \
        src/language/stats/autorecode.c \
        src/language/stats/binomial.c \
        src/language/stats/binomial.h \
-       src/language/stats/chisquare.c \
+       src/language/stats/chisquare.c  \
        src/language/stats/chisquare.h \
+       src/language/stats/cochran.c \
+       src/language/stats/cochran.h \
        src/language/stats/correlations.c \
        src/language/stats/descriptives.c \
        src/language/stats/factor.c \
        src/language/stats/flip.c \
        src/language/stats/freq.c \
        src/language/stats/freq.h \
-       src/language/stats/glm.c \
+       src/language/stats/friedman.c \
+       src/language/stats/friedman.h \
        src/language/stats/kruskal-wallis.c \
        src/language/stats/kruskal-wallis.h \
-       src/language/stats/npar.c \
+       src/language/stats/mann-whitney.c \
+       src/language/stats/mann-whitney.h \
+       src/language/stats/npar.c  \
        src/language/stats/npar.h \
        src/language/stats/npar-summary.c \
        src/language/stats/npar-summary.h \
        src/language/stats/oneway.c \
+       src/language/stats/quick-cluster.c \
        src/language/stats/reliability.c \
        src/language/stats/roc.c \
        src/language/stats/roc.h \
+       src/language/stats/runs.h \
+       src/language/stats/runs.c \
        src/language/stats/sign.c \
        src/language/stats/sign.h \
        src/language/stats/sort-cases.c \
@@ -43,6 +51,8 @@ language_stats_sources = \
        src/language/stats/wilcoxon.c \
        src/language/stats/wilcoxon.h
 
+EXTRA_DIST += src/language/stats/glm.c
+
 all_q_sources += $(src_language_stats_built_sources:.c=.q)
 EXTRA_DIST += $(src_language_stats_built_sources:.c=.q)
 CLEANFILES += $(src_language_stats_built_sources)
index 2a72aaea82ecd266a1e6a81bbd5857fdecd52e54..a4d34ccf608e7c784334d6a23546da546df1f095 100644 (file)
 
 #include "data/case.h"
 #include "data/casereader.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
-#include "data/procedure.h"
 #include "data/transformations.h"
 #include "data/variable.h"
 #include "language/command.h"
 #include "language/lexer/lexer.h"
 #include "language/lexer/variable-parser.h"
 #include "libpspp/array.h"
-#include "libpspp/i18n.h"
 #include "libpspp/compiler.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/pool.h"
 #include "libpspp/str.h"
@@ -113,14 +113,15 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds)
 
   /* Parse variable lists. */
   lex_match_id (lexer, "VARIABLES");
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (!parse_variables_const (lexer, dict, &src_vars, &n_srcs,
                               PV_NO_DUPLICATE))
     goto error;
   if (!lex_force_match_id (lexer, "INTO"))
     goto error;
-  lex_match (lexer, '=');
-  if (!parse_DATA_LIST_vars (lexer, &dst_names, &n_dsts, PV_NO_DUPLICATE))
+  lex_match (lexer, T_EQUALS);
+  if (!parse_DATA_LIST_vars (lexer, dict, &dst_names, &n_dsts,
+                             PV_NO_DUPLICATE))
     goto error;
   if (n_dsts != n_srcs)
     {
@@ -143,7 +144,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds)
     }
 
   /* Parse options. */
-  while (lex_match (lexer, '/'))
+  while (lex_match (lexer, T_SLASH))
     {
       if (lex_match_id (lexer, "DESCENDING"))
        direction = DESCENDING;
@@ -156,7 +157,7 @@ cmd_autorecode (struct lexer *lexer, struct dataset *ds)
        }
     }
 
-  if (lex_token (lexer) != '.')
+  if (lex_token (lexer) != T_ENDCMD)
     {
       lex_error (lexer, _("expecting end of command"));
       goto error;
index 8126daf36c725d80652a6add4db7098c35dcdd72..94d0d9721e0b7f4c543d44a975ec8b8b9b7cbed0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011 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 <libpspp/compiler.h>
-#include <output/tab.h>
 
-#include <data/format.h>
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <data/value.h>
-#include <data/value-labels.h>
+#include "language/stats/binomial.h"
 
-#include <libpspp/message.h>
-#include <libpspp/assertion.h>
-
-#include "binomial.h"
-#include "freq.h"
+#include <gsl/gsl_cdf.h>
+#include <gsl/gsl_randist.h>
 
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "language/stats/freq.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "output/tab.h"
+
+#include "gl/xalloc.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include <libpspp/misc.h>
-
-#include <gsl/gsl_cdf.h>
-#include <gsl/gsl_randist.h>
-
-#include <minmax.h>
-
 static double calculate_binomial_internal (double n1, double n2,
                                           double p);
 
index 6218228690526da661921ec38b82d33c63b13a78..10d81132715552b7ccaad1d96ad2587cf20988ac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2009, 2010, 2011 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 <language/stats/chisquare.h>
+#include "language/stats/chisquare.h"
 
 #include <gsl/gsl_cdf.h>
 #include <math.h>
 #include <stdlib.h>
 
-#include "data/format.h"
 #include "data/case.h"
 #include "data/casereader.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
-#include "data/procedure.h"
+#include "data/format.h"
 #include "data/value-labels.h"
 #include "data/variable.h"
 #include "language/stats/freq.h"
index 182e092e14c7a52079f50fc4829ae0657c8e0e1b..da9329c0016e9a7730abe3dc3a317a05b6336a4b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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,7 +19,7 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <language/stats/npar.h>
+#include "language/stats/npar.h"
 
 struct chisquare_test
 {
diff --git a/src/language/stats/cochran.c b/src/language/stats/cochran.c
new file mode 100644 (file)
index 0000000..3ea8fd3
--- /dev/null
@@ -0,0 +1,243 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/stats/cochran.h"
+
+#include <gsl/gsl_cdf.h>
+#include <stdbool.h>
+
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "language/stats/npar.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "output/tab.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct cochran
+{
+  double success;
+  double failure;
+
+  double *hits;
+  double *misses;
+
+  const struct dictionary *dict;
+  double cc;
+  double df;
+  double q;
+};
+
+static void show_freqs_box (const struct one_sample_test *ost, const struct cochran *ch);
+static void show_sig_box (const struct cochran *ch);
+
+void
+cochran_execute (const struct dataset *ds,
+             struct casereader *input,
+             enum mv_class exclude,
+             const struct npar_test *test,
+             bool exact UNUSED, double timer UNUSED)
+{
+  struct one_sample_test *ct = UP_CAST (test, struct one_sample_test, parent);
+  int v;
+  struct cochran ch;
+  const struct dictionary *dict = dataset_dict (ds);
+  const struct variable *weight = dict_get_weight (dict);
+
+  struct ccase *c;
+  double rowsq = 0;
+  ch.cc = 0.0;
+  ch.dict = dict;
+  ch.success = SYSMIS;
+  ch.failure = SYSMIS;
+  ch.hits = xcalloc (ct->n_vars, sizeof *ch.hits);
+  ch.misses = xcalloc (ct->n_vars, sizeof *ch.misses);
+
+  for (; (c = casereader_read (input)); case_unref (c))
+    {
+      double case_hits = 0.0;
+      const double w = weight ? case_data (c, weight)->f: 1.0;
+      for (v = 0; v < ct->n_vars; ++v)
+       {
+         const struct variable *var = ct->vars[v];
+         const union value *val = case_data (c, var);
+
+         if ( var_is_value_missing (var, val, exclude))
+           continue;
+
+         if ( ch.success == SYSMIS)
+           {
+             ch.success = val->f;
+           }
+         else if (ch.failure == SYSMIS && val->f != ch.success)
+           {
+             ch.failure = val->f;
+           }
+         if ( ch.success == val->f)
+           {
+             ch.hits[v] += w;
+             case_hits += w;
+           }
+         else if ( ch.failure == val->f)
+           {
+             ch.misses[v] += w;
+           }
+         else
+           {
+             msg (MW, _("More than two values encountered.  Cochran Q test will not be run."));
+             goto finish;
+           }
+       }
+      ch.cc += w;
+      rowsq += pow2 (case_hits);
+    }
+  casereader_destroy (input);
+  
+  {
+    double c_l = 0;
+    double c_l2 = 0;
+    for (v = 0; v < ct->n_vars; ++v)
+      {
+       c_l += ch.hits[v];
+       c_l2 += pow2 (ch.hits[v]);
+      }
+
+    ch.q = ct->n_vars * c_l2;
+    ch.q -= pow2 (c_l);
+    ch.q *= ct->n_vars - 1;
+
+    ch.q /= ct->n_vars * c_l - rowsq;
+  
+    ch.df = ct->n_vars - 1;
+  }
+
+  show_freqs_box (ct, &ch);
+  show_sig_box (&ch);
+
+ finish:
+
+  free (ch.hits);
+  free (ch.misses);
+}
+
+static void
+show_freqs_box (const struct one_sample_test *ost, const struct cochran *ct)
+{
+  int i;
+  const struct variable *weight = dict_get_weight (ct->dict);
+  const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+  const int row_headers = 1;
+  const int column_headers = 2;
+  struct tab_table *table =
+    tab_create (row_headers + 2, column_headers + ost->n_vars);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Frequencies"));
+
+  /* Vertical lines inside the box */
+  tab_box (table, 1, 0, -1, TAL_1,
+          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  tab_joint_text (table, 1, 0, 2, 0,
+                 TAT_TITLE | TAB_CENTER, _("Value"));
+
+  tab_text_format (table, 1, 1, 0, _("Success (%g)"), ct->success);
+  tab_text_format (table, 2, 1, 0, _("Failure (%g)"), ct->failure);
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  for (i = 0 ; i < ost->n_vars ; ++i)
+    {
+      tab_text (table, 0, column_headers + i,
+               TAB_LEFT, var_to_string (ost->vars[i]));
+
+      tab_double (table, 1, column_headers + i, 0,
+                 ct->hits[i], wfmt);
+
+      tab_double (table, 2, column_headers + i, 0,
+                 ct->misses[i], wfmt);
+    }
+
+  tab_submit (table);
+}
+
+
+
+static void
+show_sig_box (const struct cochran *ch)
+{
+  const struct variable *weight = dict_get_weight (ch->dict);
+  const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+  const int row_headers = 1;
+  const int column_headers = 0;
+  struct tab_table *table =
+    tab_create (row_headers + 1, column_headers + 4);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Test Statistics"));
+
+  tab_text (table,  0, column_headers,
+           TAT_TITLE | TAB_LEFT , _("N"));
+
+  tab_text (table,  0, 1 + column_headers,
+           TAT_TITLE | TAB_LEFT , _("Cochran's Q"));
+
+  tab_text (table,  0, 2 + column_headers,
+           TAT_TITLE | TAB_LEFT, _("df"));
+
+  tab_text (table,  0, 3 + column_headers,
+           TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  tab_double (table, 1, column_headers, 
+             0, ch->cc, wfmt);
+
+  tab_double (table, 1, column_headers + 1, 
+             0, ch->q, 0);
+
+  tab_double (table, 1, column_headers + 2, 
+             0, ch->df, &F_8_0);
+
+  tab_double (table, 1, column_headers + 3, 
+             0, gsl_cdf_chisq_Q (ch->q, ch->df), 
+             0);
+
+  tab_submit (table);
+}
diff --git a/src/language/stats/cochran.h b/src/language/stats/cochran.h
new file mode 100644 (file)
index 0000000..db42cc3
--- /dev/null
@@ -0,0 +1,34 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 !cochran_h
+#define cochran_h 1
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "language/stats/npar.h"
+
+
+
+void cochran_execute (const struct dataset *ds,
+                     struct casereader *input,
+                     enum mv_class exclude,
+                     const struct npar_test *test,
+                     bool,
+                     double);
+
+
+#endif
index 6af8ba32ffd54cc32f8e84baa8f77ee0192eee1d..bc6508bd2f1863be967eec13fb3aed6a1c81a308 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <libpspp/assertion.h>
-#include <math/covariance.h>
-#include <math/correlation.h>
+#include <gsl/gsl_cdf.h>
 #include <gsl/gsl_matrix.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <output/tab.h>
-#include <libpspp/message.h>
-#include <data/format.h>
-#include <math/moments.h>
-
 #include <math.h>
-#include "xalloc.h"
-#include "minmax.h"
-#include <libpspp/misc.h>
-#include <gsl/gsl_cdf.h>
+
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "math/correlation.h"
+#include "math/covariance.h"
+#include "math/moments.h"
+#include "output/tab.h"
+
+#include "gl/xalloc.h"
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -278,7 +279,7 @@ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr
 {
   struct ccase *c;
   const gsl_matrix *var_matrix,  *samples_matrix, *mean_matrix;
-  const gsl_matrix *cov_matrix;
+  gsl_matrix *cov_matrix;
   gsl_matrix *corr_matrix;
   struct covariance *cov = covariance_2pass_create (corr->n_vars_total, corr->vars,
                                                    NULL,
@@ -315,6 +316,7 @@ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr
 
   covariance_destroy (cov);
   gsl_matrix_free (corr_matrix);
+  gsl_matrix_free (cov_matrix);
 }
 
 int
@@ -341,13 +343,13 @@ cmd_correlation (struct lexer *lexer, struct dataset *ds)
   opts.statistics = 0;
 
   /* Parse CORRELATIONS. */
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
       if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               if (lex_match_id (lexer, "PAIRWISE"))
                 opts.missing_type = CORR_PAIRWISE;
@@ -363,13 +365,13 @@ cmd_correlation (struct lexer *lexer, struct dataset *ds)
                   lex_error (lexer, NULL);
                   goto error;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
         }
       else if (lex_match_id (lexer, "PRINT"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if ( lex_match_id (lexer, "TWOTAIL"))
                opts.tails = 2;
@@ -385,13 +387,13 @@ cmd_correlation (struct lexer *lexer, struct dataset *ds)
                  goto error;
                }
 
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
            }
        }
       else if (lex_match_id (lexer, "STATISTICS"))
        {
-         lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+         lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if ( lex_match_id (lexer, "DESCRIPTIVES"))
                opts.statistics = STATS_DESCRIPTIVES;
@@ -408,14 +410,14 @@ cmd_correlation (struct lexer *lexer, struct dataset *ds)
                  goto error;
                }
 
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
            }
        }
       else
        {
          if (lex_match_id (lexer, "VARIABLES"))
            {
-             lex_match (lexer, '=');
+             lex_match (lexer, T_EQUALS);
            }
 
          corr = xrealloc (corr, sizeof (*corr) * (n_corrs + 1));
index 4f93d6f5abf8647a9f8ff88aafdc562b518d6a97..cf9473e87d378b097c0b62cc2dda6c6accbc9405 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 <stdlib.h>
 #include <stdio.h>
 
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/data-out.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash-functions.h>
-#include <libpspp/hmap.h>
-#include <libpspp/hmapx.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <output/tab.h>
-
-#include "minmax.h"
-#include "xalloc.h"
-#include "xsize.h"
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/data-out.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmap.h"
+#include "libpspp/hmapx.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xsize.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -198,6 +198,8 @@ struct crosstabs_proc
 
     /* STATISTICS. */
     unsigned int statistics;    /* Bit k is 1 if statistic k is requested. */
+
+    bool descending;            /* True if descending sort order is requested. */
   };
 
 static bool should_tabulate_case (const struct pivot_table *,
@@ -229,6 +231,7 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
   proc.n_variables = 0;
   proc.pivots = NULL;
   proc.n_pivots = 0;
+  proc.descending = false;
   proc.weight_format = wv ? *var_get_print_format (wv) : F_8_0;
 
   if (!parse_crosstabs (lexer, ds, &cmd, &proc))
@@ -239,6 +242,9 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 
   proc.mode = proc.n_variables ? INTEGER : GENERAL;
 
+
+  proc.descending = cmd.val == CRS_DVALUE;
+
   /* CELLS. */
   if (!cmd.sbc_cells)
     proc.cells = 1u << CRS_CL_COUNT;
@@ -375,10 +381,10 @@ crs_custom_tables (struct lexer *lexer, struct dataset *ds,
   /* Ensure that this is a TABLES subcommand. */
   if (!lex_match_id (lexer, "TABLES")
       && (lex_token (lexer) != T_ID ||
-         dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL)
+         dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) == NULL)
       && lex_token (lexer) != T_ALL)
     return 2;
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if (proc->variables != NULL)
     var_set = const_var_set_create_from_array (proc->variables,
@@ -467,7 +473,7 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds,
       return 0;
     }
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   for (;;)
     {
@@ -482,7 +488,7 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds,
                                    | PV_NO_DUPLICATE | PV_NO_SCRATCH)))
        return 0;
 
-      if (!lex_force_match (lexer, '('))
+      if (!lex_force_match (lexer, T_LPAREN))
          goto lossage;
 
       if (!lex_force_int (lexer))
@@ -490,7 +496,7 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds,
       min = lex_integer (lexer);
       lex_get (lexer);
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
 
       if (!lex_force_int (lexer))
        goto lossage;
@@ -503,7 +509,7 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds,
        }
       lex_get (lexer);
 
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         goto lossage;
 
       for (i = orig_nv; i < proc->n_variables; i++)
@@ -515,7 +521,7 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds,
           var_attach_aux (proc->variables[i], vr, var_dtor_free);
        }
 
-      if (lex_token (lexer) == '/')
+      if (lex_token (lexer) == T_SLASH)
        break;
     }
 
@@ -640,8 +646,11 @@ static int compare_table_entry_vars_3way (const struct table_entry *a,
                                           int idx0, int idx1);
 static int compare_table_entry_3way (const void *ap_, const void *bp_,
                                      const void *pt_);
+static int compare_table_entry_3way_inv (const void *ap_, const void *bp_,
+                                     const void *pt_);
+
 static void enum_var_values (const struct pivot_table *, int var_idx,
-                             union value **valuesp, int *n_values);
+                             union value **valuesp, int *n_values, bool descending);
 static void output_pivot_table (struct crosstabs_proc *,
                                 struct pivot_table *);
 static void make_pivot_table_subset (struct pivot_table *pt,
@@ -669,7 +678,8 @@ postcalc (struct crosstabs_proc *proc)
       hmap_destroy (&pt->data);
 
       sort (pt->entries, pt->n_entries, sizeof *pt->entries,
-            compare_table_entry_3way, pt);
+            proc->descending ? compare_table_entry_3way_inv : compare_table_entry_3way,
+           pt);
     }
 
   make_summary_table (proc);
@@ -779,6 +789,13 @@ compare_table_entry_3way (const void *ap_, const void *bp_, const void *pt_)
   return compare_table_entry_var_3way (a, b, pt, COL_VAR);
 }
 
+/* Inverted version of compare_table_entry_3way */
+static int
+compare_table_entry_3way_inv (const void *ap_, const void *bp_, const void *pt_)
+{
+  return -compare_table_entry_3way (ap_, bp_, pt_);
+}
+
 static int
 find_first_difference (const struct pivot_table *pt, size_t row)
 {
@@ -891,9 +908,7 @@ static void table_value_missing (struct crosstabs_proc *proc,
 static void delete_missing (struct pivot_table *);
 static void build_matrix (struct pivot_table *);
 
-/* Output pivot table beginning at PB and continuing until PE,
-   exclusive.  For efficiency, *MATP is a pointer to a matrix that can
-   hold *MAXROWS entries. */
+/* Output pivot table PT in the context of PROC. */
 static void
 output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
 {
@@ -905,7 +920,25 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
   struct tab_table *direct = NULL; /* Directional measures table. */
   size_t row0, row1;
 
-  enum_var_values (pt, COL_VAR, &pt->cols, &pt->n_cols);
+  enum_var_values (pt, COL_VAR, &pt->cols, &pt->n_cols, proc->descending);
+
+  if (pt->n_cols == 0)
+    {
+      struct string vars;
+      int i;
+
+      ds_init_cstr (&vars, var_get_name (pt->vars[0]));
+      for (i = 1; i < pt->n_vars; i++)
+        ds_put_format (&vars, " * %s", var_get_name (pt->vars[i]));
+
+      /* TRANSLATORS: The %s here describes a crosstabulation.  It takes the
+         form "var1 * var2 * var3 * ...".  */
+      msg (SW, _("Crosstabulation %s contained no non-missing cases."),
+           ds_cstr (&vars));
+
+      ds_destroy (&vars);
+      return;
+    }
 
   if (proc->cells)
     table = create_crosstab_table (proc, pt);
@@ -931,7 +964,7 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
       make_pivot_table_subset (pt, row0, row1, &x);
 
       /* Find all the row variable values. */
-      enum_var_values (&x, ROW_VAR, &x.rows, &x.n_rows);
+      enum_var_values (&x, ROW_VAR, &x.rows, &x.n_rows, proc->descending);
 
       if (size_overflow_p (xtimes (xtimes (x.n_rows, x.n_cols),
                                    sizeof (double))))
@@ -1156,20 +1189,15 @@ create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
   for (i = 0; i < pt->n_consts; i++)
     {
       const struct variable *var = pt->const_vars[i];
-      size_t ofs;
-      char *s = NULL;
+      char *s;
 
       ds_put_format (&title, ", %s=", var_get_name (var));
 
-      /* Insert the formatted value of the variable, then trim
-         leading spaces in what was just inserted. */
-      ofs = ds_length (&title);
+      /* Insert the formatted value of VAR without any leading spaces. */
       s = data_out (&pt->const_values[i], var_get_encoding (var),
                     var_get_print_format (var));
-      ds_put_cstr (&title, s);
+      ds_put_cstr (&title, s + strspn (s, " "));
       free (s);
-      ds_remove (&title, ofs, ss_cspan (ds_substr (&title, ofs, SIZE_MAX),
-                                        ss_cstr (" ")));
     }
 
   ds_put_cstr (&title, " [");
@@ -1377,6 +1405,14 @@ compare_value_3way (const void *a_, const void *b_, const void *width_)
   return value_compare_3way (a, b, *width);
 }
 
+/* Inverted version of the above */
+static int
+compare_value_3way_inv (const void *a_, const void *b_, const void *width_)
+{
+  return -compare_value_3way (a_, b_, width_);
+}
+
+
 /* Given an array of ENTRY_CNT table_entry structures starting at
    ENTRIES, creates a sorted list of the values that the variable
    with index VAR_IDX takes on.  The values are returned as a
@@ -1385,7 +1421,7 @@ compare_value_3way (const void *a_, const void *b_, const void *width_)
    */
 static void
 enum_var_values (const struct pivot_table *pt, int var_idx,
-                 union value **valuesp, int *n_values)
+                 union value **valuesp, int *n_values, bool descending)
 {
   const struct variable *var = pt->vars[var_idx];
   struct var_range *range = get_var_range (var);
@@ -1429,7 +1465,9 @@ enum_var_values (const struct pivot_table *pt, int var_idx,
         values[i++] = *iter;
       hmapx_destroy (&set);
 
-      sort (values, *n_values, sizeof *values, compare_value_3way, &width);
+      sort (values, *n_values, sizeof *values,
+           descending ? compare_value_3way_inv : compare_value_3way,
+           &width);
     }
 }
 
@@ -1454,7 +1492,7 @@ table_value_missing (struct crosstabs_proc *proc,
           free (s);
         }
       else
-        tab_value (table, c, r, opt, v, proc->dict, print);
+        tab_value (table, c, r, opt, v, var, print);
     }
 }
 
@@ -1713,7 +1751,7 @@ display_chisq (struct pivot_table *pt, struct tab_table *chisq,
 
   calc_chisq (pt, chisq_v, df, &fisher1, &fisher2);
 
-  tab_offset (chisq, pt->n_vars - 2, -1);
+  tab_offset (chisq, pt->n_consts + pt->n_vars - 2, -1);
 
   for (i = 0; i < N_CHISQ; i++)
     {
@@ -1790,7 +1828,7 @@ display_symmetric (struct crosstabs_proc *proc, struct pivot_table *pt,
                        somers_d_v, somers_d_ase, somers_d_t))
     return;
 
-  tab_offset (sym, pt->n_vars - 2, -1);
+  tab_offset (sym, pt->n_consts + pt->n_vars - 2, -1);
 
   for (i = 0; i < N_SYMMETRIC; i++)
     {
@@ -1835,7 +1873,7 @@ display_risk (struct pivot_table *pt, struct tab_table *risk)
   if (!calc_risk (pt, risk_v, upper, lower, c))
     return;
 
-  tab_offset (risk, pt->n_vars - 2, -1);
+  tab_offset (risk, pt->n_consts + pt->n_vars - 2, -1);
 
   for (i = 0; i < 3; i++)
     {
@@ -1960,7 +1998,7 @@ display_directional (struct crosstabs_proc *proc, struct pivot_table *pt,
   if (!calc_directional (proc, pt, direct_v, direct_ase, direct_t))
     return;
 
-  tab_offset (direct, pt->n_vars - 2, -1);
+  tab_offset (direct, pt->n_consts + pt->n_vars - 2, -1);
 
   for (i = 0; i < N_DIRECTIONAL; i++)
     {
index eb04bfa663889649855c771a944f98057e7381d8..017b78c277a175ad4feeacedb0306db6b98d57e0 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, 2011 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 <math.h>
 #include <stdlib.h>
 
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/assertion.h>
-#include <math/moments.h>
-#include <output/tab.h>
-
-#include "xalloc.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "math/moments.h"
+#include "output/tab.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -122,7 +123,7 @@ static const struct dsc_statistic_info dsc_info[DSC_N_STATS] =
 struct dsc_var
   {
     const struct variable *v;         /* Variable to calculate on. */
-    char z_name[VAR_NAME_LEN + 1]; /* Name for z-score variable. */
+    char *z_name;                     /* Name for z-score variable. */
     double valid, missing;     /* Valid, missing counts. */
     struct moments *moments;    /* Moments. */
     double min, max;            /* Maximum and mimimum values. */
@@ -168,9 +169,9 @@ static void free_dsc_proc (struct dsc_proc *);
 /* Z-score functions. */
 static bool try_name (const struct dictionary *dict,
                      struct dsc_proc *dsc, const char *name);
-static bool generate_z_varname (const struct dictionary *dict,
-                               struct dsc_proc *dsc, char *z_name,
-                               const char *name, int *z_cnt);
+static char *generate_z_varname (const struct dictionary *dict,
+                                 struct dsc_proc *dsc,
+                                 const char *name, int *z_cnt);
 static void dump_z_table (struct dsc_proc *);
 static void setup_z_trns (struct dsc_proc *, struct dataset *);
 
@@ -214,12 +215,12 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
   dsc->show_stats = dsc->calc_stats = DEFAULT_STATS;
 
   /* Parse DESCRIPTIVES. */
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
       if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               if (lex_match_id (lexer, "VARIABLE"))
                 dsc->missing_type = DSC_VARIABLE;
@@ -232,15 +233,15 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
                   lex_error (lexer, NULL);
                   goto error;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
         }
       else if (lex_match_id (lexer, "SAVE"))
         save_z_scores = 1;
       else if (lex_match_id (lexer, "FORMAT"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               if (lex_match_id (lexer, "LABELS"))
                 dsc->show_var_labels = 1;
@@ -259,14 +260,14 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
                   lex_error (lexer, NULL);
                   goto error;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
         }
       else if (lex_match_id (lexer, "STATISTICS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           dsc->show_stats = 0;
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               if (lex_match (lexer, T_ALL))
                 dsc->show_stats |= (1ul << DSC_N_STATS) - 1;
@@ -274,14 +275,14 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
                 dsc->show_stats |= DEFAULT_STATS;
               else
                dsc->show_stats |= 1ul << (match_statistic (lexer));
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
           if (dsc->show_stats == 0)
             dsc->show_stats = DEFAULT_STATS;
         }
       else if (lex_match_id (lexer, "SORT"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "NAME"))
             dsc->sort_by_stat = DSC_NAME;
           else
@@ -290,7 +291,7 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
              if (dsc->sort_by_stat == DSC_NONE )
                dsc->sort_by_stat = DSC_MEAN;
            }
-          if (lex_match (lexer, '('))
+          if (lex_match (lexer, T_LPAREN))
             {
               if (lex_match_id (lexer, "A"))
                 dsc->sort_ascending = 1;
@@ -298,18 +299,18 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
                 dsc->sort_ascending = 0;
               else
                 lex_error (lexer, NULL);
-              lex_force_match (lexer, ')');
+              lex_force_match (lexer, T_RPAREN);
             }
         }
       else if (var_cnt == 0)
         {
-          if (lex_look_ahead (lexer) == '=')
+          if (lex_next_token (lexer, 1) == T_EQUALS)
             {
               lex_match_id (lexer, "VARIABLES");
-              lex_match (lexer, '=');
+              lex_match (lexer, T_EQUALS);
             }
 
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               int i;
 
@@ -322,28 +323,29 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
                 {
                   struct dsc_var *dv = &dsc->vars[i];
                   dv->v = vars[i];
-                  dv->z_name[0] = '\0';
+                  dv->z_name = NULL;
                   dv->moments = NULL;
                 }
               dsc->var_cnt = var_cnt;
 
-              if (lex_match (lexer, '('))
+              if (lex_match (lexer, T_LPAREN))
                 {
                   if (lex_token (lexer) != T_ID)
                     {
                       lex_error (lexer, NULL);
                       goto error;
                     }
-                  if (try_name (dict, dsc, lex_tokid (lexer)))
+                  if (try_name (dict, dsc, lex_tokcstr (lexer)))
                     {
-                      strcpy (dsc->vars[dsc->var_cnt - 1].z_name, lex_tokid (lexer));
+                      struct dsc_var *dsc_var = &dsc->vars[dsc->var_cnt - 1];
+                      dsc_var->z_name = xstrdup (lex_tokcstr (lexer));
                       z_cnt++;
                     }
                   else
                     msg (SE, _("Z-score variable name %s would be"
-                               " a duplicate variable name."), lex_tokid (lexer));
+                               " a duplicate variable name."), lex_tokcstr (lexer));
                   lex_get (lexer);
-                  if (!lex_force_match (lexer, ')'))
+                  if (!lex_force_match (lexer, T_RPAREN))
                    goto error;
                 }
             }
@@ -354,7 +356,7 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
           goto error;
         }
 
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
     }
   if (var_cnt == 0)
     {
@@ -370,14 +372,19 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
           int gen_cnt = 0;
 
           for (i = 0; i < dsc->var_cnt; i++)
-            if (dsc->vars[i].z_name[0] == 0)
-              {
-                if (!generate_z_varname (dict, dsc, dsc->vars[i].z_name,
-                                         var_get_name (dsc->vars[i].v),
-                                         &gen_cnt))
-                  goto error;
-                z_cnt++;
-              }
+            {
+              struct dsc_var *dsc_var = &dsc->vars[i];
+              if (dsc_var->z_name == NULL)
+                {
+                  const char *name = var_get_name (dsc_var->v);
+                  dsc_var->z_name = generate_z_varname (dict, dsc, name,
+                                                        &gen_cnt);
+                  if (dsc_var->z_name == NULL)
+                    goto error;
+
+                  z_cnt++;
+                }
+            }
         }
       dump_z_table (dsc);
     }
@@ -463,7 +470,11 @@ free_dsc_proc (struct dsc_proc *dsc)
     return;
 
   for (i = 0; i < dsc->var_cnt; i++)
-    moments_destroy (dsc->vars[i].moments);
+    {
+      struct dsc_var *dsc_var = &dsc->vars[i];
+      free (dsc_var->z_name);
+      moments_destroy (dsc_var->moments);
+    }
   free (dsc->vars);
   free (dsc);
 }
@@ -481,33 +492,38 @@ try_name (const struct dictionary *dict, struct dsc_proc *dsc,
   if (dict_lookup_var (dict, name) != NULL)
     return false;
   for (i = 0; i < dsc->var_cnt; i++)
-    if (!strcasecmp (dsc->vars[i].z_name, name))
-      return false;
+    {
+      struct dsc_var *dsc_var = &dsc->vars[i];
+      if (dsc_var->z_name != NULL && !strcasecmp (dsc_var->z_name, name))
+        return false;
+    }
   return true;
 }
 
 /* Generates a name for a Z-score variable based on a variable
    named VAR_NAME, given that *Z_CNT generated variable names are
-   known to already exist.  If successful, returns true and
-   copies the new name into Z_NAME.  On failure, returns false. */
-static bool
-generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc, char *z_name,
+   known to already exist.  If successful, returns the new name
+   as a dynamically allocated string.  On failure, returns NULL. */
+static char *
+generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc,
                     const char *var_name, int *z_cnt)
 {
-  char name[VAR_NAME_LEN + 1];
+  char *z_name, *trunc_name;
 
   /* Try a name based on the original variable name. */
-  name[0] = 'Z';
-  str_copy_trunc (name + 1, sizeof name - 1, var_name);
-  if (try_name (dict, dsc, name))
-    {
-      strcpy (z_name, name);
-      return true;
-    }
+  z_name = xasprintf ("Z%s", var_name);
+  trunc_name = utf8_encoding_trunc (z_name, dict_get_encoding (dict),
+                                    ID_MAX_LEN);
+  free (z_name);
+  if (try_name (dict, dsc, trunc_name))
+    return trunc_name;
+  free (trunc_name);
 
   /* Generate a synthetic name. */
   for (;;)
     {
+      char name[8];
+
       (*z_cnt)++;
 
       if (*z_cnt <= 99)
@@ -523,14 +539,11 @@ generate_z_varname (const struct dictionary *dict, struct dsc_proc *dsc, char *z
          msg (SE, _("Ran out of generic names for Z-score variables.  "
                     "There are only 126 generic names: ZSC001-ZSC0999, "
                     "STDZ01-STDZ09, ZZZZ01-ZZZZ09, ZQZQ01-ZQZQ09."));
-         return false;
+         return NULL;
        }
 
       if (try_name (dict, dsc, name))
-       {
-         strcpy (z_name, name);
-         return true;
-       }
+        return xstrdup (name);
     }
   NOT_REACHED();
 }
@@ -547,7 +560,7 @@ dump_z_table (struct dsc_proc *dsc)
     size_t i;
 
     for (i = 0; i < dsc->var_cnt; i++)
-      if (dsc->vars[i].z_name[0] != '\0')
+      if (dsc->vars[i].z_name != NULL)
        cnt++;
   }
 
@@ -563,7 +576,7 @@ dump_z_table (struct dsc_proc *dsc)
     size_t i, y;
 
     for (i = 0, y = 1; i < dsc->var_cnt; i++)
-      if (dsc->vars[i].z_name[0] != '\0')
+      if (dsc->vars[i].z_name != NULL)
        {
          tab_text (t, 0, y, TAB_LEFT, var_get_name (dsc->vars[i].v));
          tab_text (t, 1, y++, TAB_LEFT, dsc->vars[i].z_name);
@@ -637,7 +650,7 @@ setup_z_trns (struct dsc_proc *dsc, struct dataset *ds)
   size_t cnt, i;
 
   for (cnt = i = 0; i < dsc->var_cnt; i++)
-    if (dsc->vars[i].z_name[0] != '\0')
+    if (dsc->vars[i].z_name != NULL)
       cnt++;
 
   t = xmalloc (sizeof *t);
@@ -661,14 +674,15 @@ setup_z_trns (struct dsc_proc *dsc, struct dataset *ds)
   for (cnt = i = 0; i < dsc->var_cnt; i++)
     {
       struct dsc_var *dv = &dsc->vars[i];
-      if (dv->z_name[0] != '\0')
+      if (dv->z_name != NULL)
        {
           struct dsc_z_score *z;
          struct variable *dst_var;
 
          dst_var = dict_create_var_assert (dataset_dict (ds), dv->z_name, 0);
-          var_set_label (dst_var, xasprintf (_("Z-score of %s"),
-                                             var_to_string (dv->v)));
+          var_set_label (dst_var,
+                         xasprintf (_("Z-score of %s"),var_to_string (dv->v)),
+                         false);
 
           z = &t->z_scores[cnt++];
           z->src_var = dv->v;
index e4239fda6adbbd45695b4350c93e64f7a51ade9b..e225f3343d4e5850afc43628d43f7add913aee89 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009, 2010, 2011 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 <gsl/gsl_cdf.h>
-#include <libpspp/message.h>
 #include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <math/sort.h>
-#include <math/order-stats.h>
-#include <math/percentiles.h>
-#include <math/tukey-hinges.h>
-#include <math/box-whisker.h>
-#include <math/trimmed-mean.h>
-#include <math/extrema.h>
-#include <math/np.h>
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/subcase.h>
-#include <data/value-labels.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/misc.h>
-#include <libpspp/str.h>
-#include <math/moments.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"
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/subcase.h"
+#include "data/value-labels.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/misc.h"
+#include "libpspp/str.h"
+#include "math/box-whisker.h"
+#include "math/extrema.h"
+#include "math/histogram.h"
+#include "math/moments.h"
+#include "math/np.h"
+#include "math/order-stats.h"
+#include "math/percentiles.h"
+#include "math/sort.h"
+#include "math/trimmed-mean.h"
+#include "math/tukey-hinges.h"
+#include "output/chart-item.h"
+#include "output/charts/boxplot.h"
+#include "output/charts/np-plot.h"
+#include "output/charts/plot-hist.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 /* (headers) */
-#include <output/charts/plot-hist.h>
-#include <math/histogram.h>
 
 /* (specification)
    "EXAMINE" (xmn_):
@@ -588,9 +587,9 @@ static int
 xmn_custom_percentiles (struct lexer *lexer, struct dataset *ds UNUSED,
                        struct cmd_examine *p UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
-  lex_match (lexer, '(');
+  lex_match (lexer, T_LPAREN);
 
   while ( lex_is_number (lexer) )
     {
@@ -598,11 +597,11 @@ xmn_custom_percentiles (struct lexer *lexer, struct dataset *ds UNUSED,
 
       lex_get (lexer);
 
-      lex_match (lexer, ',') ;
+      lex_match (lexer, T_COMMA) ;
     }
-  lex_match (lexer, ')');
+  lex_match (lexer, T_RPAREN);
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if ( lex_match_id (lexer, "HAVERAGE"))
     percentile_algorithm = PC_HAVERAGE;
@@ -674,9 +673,9 @@ xmn_custom_variables (struct lexer *lexer, struct dataset *ds,
                      void *aux UNUSED)
 {
   const struct dictionary *dict = dataset_dict (ds);
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
-  if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
+  if ( (lex_token (lexer) != T_ID || dict_lookup_var (dict, lex_tokcstr (lexer)) == NULL)
        && lex_token (lexer) != T_ALL)
     {
       return 2;
@@ -720,7 +719,7 @@ examine_parse_independent_vars (struct lexer *lexer,
   ll_init (&sf->result_list);
 
   if ( (lex_token (lexer) != T_ID ||
-       dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
+       dict_lookup_var (dict, lex_tokcstr (lexer)) == NULL)
        && lex_token (lexer) != T_ALL)
     {
       free ( sf ) ;
@@ -735,7 +734,7 @@ examine_parse_independent_vars (struct lexer *lexer,
       lex_match (lexer, T_BY);
 
       if ( (lex_token (lexer) != T_ID ||
-           dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
+           dict_lookup_var (dict, lex_tokcstr (lexer)) == NULL)
           && lex_token (lexer) != T_ALL)
        {
          free (sf);
@@ -749,9 +748,9 @@ examine_parse_independent_vars (struct lexer *lexer,
   else
     ll_push_tail (&factor_list, &sf->ll);
 
-  lex_match (lexer, ',');
+  lex_match (lexer, T_COMMA);
 
-  if ( lex_token (lexer) == '.' || lex_token (lexer) == '/' )
+  if ( lex_token (lexer) == T_ENDCMD || lex_token (lexer) == T_SLASH )
     return 1;
 
   success =  examine_parse_independent_vars (lexer, dict, cmd);
index 93358373df3eee57684e7d0abdcdefd7f050662c..a9c948e6369671ec6aa40f9a8103f91dbebb5ea4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -16,7 +16,6 @@
 
 #include <config.h>
 
-
 #include <gsl/gsl_vector.h>
 #include <gsl/gsl_linalg.h>
 #include <gsl/gsl_matrix.h>
 #include <gsl/gsl_blas.h> 
 #include <gsl/gsl_sort_vector.h>
 
-#include <math/covariance.h>
-
-#include <math/correlation.h>
-#include <math/moments.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 <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/subcase.h>
-
-#include <libpspp/misc.h>
-#include <libpspp/message.h>
-
-#include <output/tab.h>
-
-#include <output/charts/scree.h>
-#include <output/chart-item.h>
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.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/message.h"
+#include "libpspp/misc.h"
+#include "math/correlation.h"
+#include "math/covariance.h"
+#include "math/moments.h"
+#include "output/chart-item.h"
+#include "output/charts/scree.h"
+#include "output/tab.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -175,7 +169,7 @@ struct idata
   /* Intermediate values used in calculation */
 
   const gsl_matrix *corr ;  /* The correlation matrix */
-  const gsl_matrix *cov ;   /* The covariance matrix */
+  gsl_matrix *cov ;         /* The covariance matrix */
   const gsl_matrix *n ;     /* Matrix of number of samples */
 
   gsl_vector *eval ;  /* The eigenvalues */
@@ -206,6 +200,8 @@ idata_free (struct idata *id)
   gsl_vector_free (id->msr);
   gsl_vector_free (id->eval);
   gsl_matrix_free (id->evec);
+  if (id->cov != NULL)
+    gsl_matrix_free (id->cov);
 
   free (id);
 }
@@ -788,14 +784,14 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
 
   factor.wv = dict_get_weight (dict);
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "VARIABLES"))
     {
       goto error;
     }
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if (!parse_variables_const (lexer, dict, &factor.vars, &factor.n_vars,
                              PV_NO_DUPLICATE | PV_NUMERIC))
@@ -804,14 +800,14 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
   if (factor.n_vars < 2)
     msg (MW, _("Factor analysis on a single variable is not useful."));
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "PLOT"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "EIGEN"))
                {
@@ -831,8 +827,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "METHOD"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "COVARIANCE"))
                {
@@ -851,8 +847,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "ROTATION"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              /* VARIMAX and DEFAULT are defaults */
              if (lex_match_id (lexer, "VARIMAX") || lex_match_id (lexer, "DEFAULT"))
@@ -880,57 +876,57 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "CRITERIA"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "FACTORS"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_int (lexer);
                      factor.n_factors = lex_integer (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "MINEIGEN"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_num (lexer);
                      factor.min_eigen = lex_number (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "ECONVERGE"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_num (lexer);
                      factor.econverge = lex_number (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "RCONVERGE"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_num (lexer);
                      factor.rconverge = lex_number (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "ITERATE"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_int (lexer);
                      factor.iterations = lex_integer (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "DEFAULT"))
@@ -949,8 +945,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
       else if (lex_match_id (lexer, "EXTRACTION"))
        {
          extraction_seen = true;
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "PAF"))
                {
@@ -977,8 +973,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "FORMAT"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "SORT"))
                {
@@ -986,12 +982,12 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
                }
              else if (lex_match_id (lexer, "BLANK"))
                {
-                 if ( lex_force_match (lexer, '('))
+                 if ( lex_force_match (lexer, T_LPAREN))
                    {
                      lex_force_num (lexer);
                      factor.blank = lex_number (lexer);
                      lex_get (lexer);
-                     lex_force_match (lexer, ')');
+                     lex_force_match (lexer, T_RPAREN);
                    }
                }
              else if (lex_match_id (lexer, "DEFAULT"))
@@ -1009,8 +1005,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
       else if (lex_match_id (lexer, "PRINT"))
        {
          factor.print = 0;
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
               if (lex_match_id (lexer, "UNIVARIATE"))
                {
@@ -1083,8 +1079,8 @@ cmd_factor (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -1301,7 +1297,7 @@ show_factor_matrix (const struct cmd_factor *factor, struct idata *idata, const
     tab_title (t, _("Factor Matrix"));
   */
 
-  tab_title (t, title);
+  tab_title (t, "%s", title);
 
   tab_headers (t, heading_columns, 0, heading_rows, 0);
 
@@ -1494,7 +1490,7 @@ show_explained_variance (const struct cmd_factor * factor, struct idata *idata,
 
       c = 0;
 
-      tab_text_format (t, c++, i + heading_rows, TAB_LEFT | TAT_TITLE, _("%d"), i + 1);
+      tab_text_format (t, c++, i + heading_rows, TAB_LEFT | TAT_TITLE, _("%zu"), i + 1);
 
       i_cum += i_percent;
       e_cum += e_percent;
index 77881868b0c3fcc0fd3b8fa29ead25b117882b95..6049f1fa9c9acfbde0cd035c808e849ccd067c65 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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 <limits.h>
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casereader-provider.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/short-names.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <data/data-in.h>
-#include <data/data-out.h>
-#include "intprops.h"
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casereader-provider.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/short-names.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+#include "data/data-in.h"
+#include "data/data-out.h"
+
+#include "gl/intprops.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -109,23 +110,23 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   flip->error = false;
   flip->dict = dict;
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   if (lex_match_id (lexer, "VARIABLES"))
     {
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
       if (!parse_variables_const (lexer, dict, &vars, &flip->n_vars,
                                   PV_NO_DUPLICATE))
        goto error;
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
     }
   else
     dict_get_vars (dict, &vars, &flip->n_vars, DC_SYSTEM);
   pool_register (flip->pool, free, vars);
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   if (lex_match_id (lexer, "NEWNAMES"))
     {
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
       flip->new_names_var = parse_variable (lexer, dict);
       if (!flip->new_names_var)
         goto error;
@@ -157,7 +158,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
     var_names_add (flip->pool, &flip->old_names,
                    pool_strdup (flip->pool, var_get_name (vars[i])));
 
-  /* Read the active file into a flip_sink. */
+  /* Read the active dataset into a flip_sink. */
   proc_discard_output (ds);
 
   input = proc_open (ds);
@@ -197,7 +198,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   /* Flip the data we read. */
   if (!ok || !flip_file (flip))
     {
-      proc_discard_active_file (ds);
+      dataset_clear (ds);
       goto error;
     }
 
@@ -209,7 +210,7 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
       make_new_var (dict, flip->new_names.names[i]);
     else
       {
-        char s[VAR_NAME_LEN + 1];
+        char s[3 + INT_STRLEN_BOUND (i) + 1];
         sprintf (s, "VAR%03zu", i);
         dict_create_var_assert (dict, s, 0);
       }
@@ -218,8 +219,8 @@ cmd_flip (struct lexer *lexer, struct dataset *ds)
   reader = casereader_create_sequential (NULL, dict_get_proto (dict),
                                          flip->n_vars,
                                          &flip_casereader_class, flip);
-  proc_set_active_file_data (ds, reader);
-  return lex_end_of_command (lexer);
+  dataset_set_source (ds, reader);
+  return CMD_SUCCESS;
 
  error:
   destroy_flip_pgm (flip);
@@ -248,7 +249,7 @@ make_new_var (struct dictionary *dict, const char *name_)
     *--cp = '\0';
 
   /* Fix invalid characters. */
-  for (cp = name; *cp && cp < name + VAR_NAME_LEN; cp++)
+  for (cp = name; *cp && cp < name + ID_MAX_LEN; cp++)
     if (cp == name)
       {
         if (!lex_is_id1 (*cp) || *cp == '$')
@@ -269,8 +270,8 @@ make_new_var (struct dictionary *dict, const char *name_)
       int i;
       for (i = 1; ; i++)
         {
-          char n[VAR_NAME_LEN + 1];
-          int ofs = MIN (VAR_NAME_LEN - 1 - intlog10 (i), len);
+          char n[ID_MAX_LEN + 1];
+          int ofs = MIN (ID_MAX_LEN - 1 - intlog10 (i), len);
           strncpy (n, name, ofs);
           sprintf (&n[ofs], "%d", i);
 
index 723d26e8341c3f7c732f3ed394067dea0b4204c6..01247f518cdff07bea16ff1de5d24e14b1777a0b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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
@@ -23,9 +23,9 @@
 #include "data/case.h"
 #include "data/casegrouper.h"
 #include "data/casereader.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
 #include "data/format.h"
-#include "data/procedure.h"
 #include "data/settings.h"
 #include "data/value-labels.h"
 #include "data/variable.h"
@@ -188,7 +188,6 @@ struct var_freqs
 
     /* Variable attributes. */
     int width;
-    struct fmt_spec print;
   };
 
 struct frq_proc
@@ -618,10 +617,10 @@ frq_custom_variables (struct lexer *lexer, struct dataset *ds,
   size_t n_vars;
   size_t i;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_token (lexer) != T_ALL
       && (lex_token (lexer) != T_ID
-          || dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL))
+          || dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) == NULL))
     return 2;
 
   /* Get list of current variables, to avoid duplicates. */
@@ -646,7 +645,6 @@ frq_custom_variables (struct lexer *lexer, struct dataset *ds,
       vf->n_groups = 0;
       vf->groups = NULL;
       vf->width = var_get_width (var);
-      vf->print = *var_get_print_format (var);
     }
   frq->n_vars = n_vars;
 
@@ -662,8 +660,9 @@ frq_custom_grouped (struct lexer *lexer, struct dataset *ds, struct cmd_frequenc
 {
   struct frq_proc *frq = frq_;
 
-  lex_match (lexer, '=');
-  if ((lex_token (lexer) == T_ID && dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL)
+  lex_match (lexer, T_EQUALS);
+  if ((lex_token (lexer) == T_ID
+       && dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) != NULL)
       || lex_token (lexer) == T_ID)
     for (;;)
       {
@@ -680,7 +679,7 @@ frq_custom_grouped (struct lexer *lexer, struct dataset *ds, struct cmd_frequenc
        if (!parse_variables_const (lexer, dataset_dict (ds), &v, &n,
                               PV_NO_DUPLICATE | PV_NUMERIC))
          return 0;
-       if (lex_match (lexer, '('))
+       if (lex_match (lexer, T_LPAREN))
          {
            nl = ml = 0;
            dl = NULL;
@@ -693,11 +692,11 @@ frq_custom_grouped (struct lexer *lexer, struct dataset *ds, struct cmd_frequenc
                  }
                dl[nl++] = lex_tokval (lexer);
                lex_get (lexer);
-               lex_match (lexer, ',');
+               lex_match (lexer, T_COMMA);
              }
            /* Note that nl might still be 0 and dl might still be
               NULL.  That's okay. */
-           if (!lex_match (lexer, ')'))
+           if (!lex_match (lexer, T_RPAREN))
              {
                free (v);
                msg (SE, _("`)' expected after GROUPED interval list."));
@@ -737,14 +736,23 @@ frq_custom_grouped (struct lexer *lexer, struct dataset *ds, struct cmd_frequenc
           }
 
        free (v);
-       if (!lex_match (lexer, '/'))
-         break;
-       if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) != NULL)
-            && lex_token (lexer) != T_ALL)
-         {
-           lex_put_back (lexer, '/');
-           break;
-         }
+        if (lex_token (lexer) != T_SLASH)
+          break;
+
+        if ((lex_next_token (lexer, 1) == T_ID
+             && dict_lookup_var (dataset_dict (ds),
+                                 lex_next_tokcstr (lexer, 1)))
+            || lex_next_token (lexer, 1) == T_ALL)
+          {
+            /* The token after the slash is a variable name.  Keep parsing. */
+            lex_get (lexer);
+          }
+        else
+          {
+            /* The token after the slash must be the start of a new
+               subcommand.  Let the caller see the slash. */
+            break;
+          }
       }
 
   return 1;
@@ -840,7 +848,7 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
       if (label != NULL)
         tab_text (t, 0, r, TAB_LEFT, label);
 
-      tab_value (t, 1, r, TAB_NONE, &f->value, ft->dict, &vf->print);
+      tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
       tab_double (t, 2, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 3, r, TAB_NONE, percent, NULL);
       tab_double (t, 4, r, TAB_NONE, valid_percent, NULL);
@@ -857,7 +865,7 @@ dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
       if (label != NULL)
         tab_text (t, 0, r, TAB_LEFT, label);
 
-      tab_value (t, 1, r, TAB_NONE, &f->value, ft->dict, &vf->print);
+      tab_value (t, 1, r, TAB_NONE, &f->value, vf->var, NULL);
       tab_double (t, 2, r, TAB_NONE, f->count, wfmt);
       tab_double (t, 3, r, TAB_NONE,
                     f->count / ft->total_cases * 100.0, NULL);
@@ -921,8 +929,7 @@ calc_percentiles (const struct frq_proc *frq, const struct var_freqs *vf)
           if (rank <= tp)
             break;
 
-          if (f->count > 1
-              && (rank - (f->count - 1) > tp || f + 1 >= ft->missing))
+          if (tp + 1 < rank || f + 1 >= ft->missing)
             pc->value = f->value.f;
           else
             pc->value = calc_percentile (pc->p, W, f->value.f, f[1].value.f);
@@ -1038,7 +1045,7 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
   tab_double (t, 2, 0, TAB_NONE, ft->valid_cases, wfmt);
   tab_double (t, 2, 1, TAB_NONE, ft->total_cases - ft->valid_cases, wfmt);
 
-  for (i = 0; i < frq->n_percentiles; i++, r++)
+  for (i = 0; i < frq->n_percentiles; i++)
     {
       struct percentile *pc = &frq->percentiles[i];
 
@@ -1056,6 +1063,7 @@ dump_statistics (const struct frq_proc *frq, const struct var_freqs *vf,
         tab_fixed (t, 1, r, TAB_LEFT, pc->p * 100, 3, 0);
       tab_double (t, 2, r, TAB_NONE, pc->value,
                   var_get_print_format (vf->var));
+      r++;
     }
 
   tab_title (t, "%s", var_to_string (vf->var));
diff --git a/src/language/stats/friedman.c b/src/language/stats/friedman.c
new file mode 100644 (file)
index 0000000..5ef3083
--- /dev/null
@@ -0,0 +1,317 @@
+/* PSPP - a program for statistical analysis. -*-c-*-
+   Copyright (C) 2010, 2011 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 "language/stats/friedman.h"
+
+#include <gsl/gsl_cdf.h>
+#include <math.h>
+
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "output/tab.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+
+struct friedman
+{
+  double *rank_sum;
+  double cc;
+  double chi_sq;
+  double w;
+  const struct dictionary *dict;
+};
+
+static void show_ranks_box (const struct one_sample_test *ost, 
+                           const struct friedman *fr);
+
+static void show_sig_box (const struct one_sample_test *ost,
+                         const struct friedman *fr);
+
+struct datum
+{
+  long posn;
+  double x;
+};
+
+static int
+cmp_x (const void *a_, const void *b_)
+{
+  const struct datum *a = a_;
+  const struct datum *b = b_;
+
+  if (a->x < b->x)
+    return -1;
+  
+  return (a->x > b->x);
+}
+
+static int
+cmp_posn (const void *a_, const void *b_)
+{
+  const struct datum *a = a_;
+  const struct datum *b = b_;
+
+  if (a->posn < b->posn)
+    return -1;
+  
+  return (a->posn > b->posn);
+}
+
+void
+friedman_execute (const struct dataset *ds,
+                 struct casereader *input,
+                 enum mv_class exclude,
+                 const struct npar_test *test,
+                 bool exact UNUSED,
+                 double timer UNUSED)
+{
+  double numerator = 0.0;
+  double denominator = 0.0;
+  int v;
+  struct ccase *c;
+  const struct dictionary *dict = dataset_dict (ds);
+  const struct variable *weight = dict_get_weight (dict);
+
+  struct one_sample_test *ost = UP_CAST (test, struct one_sample_test, parent);
+  struct friedman_test *ft = UP_CAST (ost, struct friedman_test, parent);
+  bool warn = true;
+
+  double sigma_t = 0.0;        
+  struct datum *row = xcalloc (ost->n_vars, sizeof *row);
+  double rsq;
+  struct friedman fr;
+  fr.rank_sum = xcalloc (ost->n_vars, sizeof *fr.rank_sum);
+  fr.cc = 0.0;
+  fr.dict = dict;
+  for (v = 0; v < ost->n_vars; ++v)
+    {
+      row[v].posn = v;
+      fr.rank_sum[v] = 0.0;
+    }
+
+  input = casereader_create_filter_weight (input, dict, &warn, NULL);
+  input = casereader_create_filter_missing (input,
+                                           ost->vars, ost->n_vars,
+                                           exclude, 0, 0);
+
+  for (; (c = casereader_read (input)); case_unref (c))
+    {
+      double prev_x = SYSMIS;
+      int run_length = 0;
+
+      const double w = weight ? case_data (c, weight)->f: 1.0;
+
+      fr.cc += w;
+
+      for (v = 0; v < ost->n_vars; ++v)
+       {
+         const struct variable *var = ost->vars[v];
+         const union value *val = case_data (c, var);
+         row[v].x = val->f;
+       }
+
+      qsort (row, ost->n_vars, sizeof *row, cmp_x);
+      for (v = 0; v < ost->n_vars; ++v)
+       {
+         double x = row[v].x;
+         /* Replace value by the Rank */
+         if ( prev_x == x)
+           {
+             /* Deal with ties */
+             int i;
+             run_length++;
+             for (i = v - run_length; i < v; ++i)
+               {
+                 row[i].x *= run_length ;
+                 row[i].x += v + 1;
+                 row[i].x /= run_length + 1;
+               }
+             row[v].x = row[v-1].x;
+           }
+         else
+           {
+             row[v].x = v + 1;
+             if ( run_length > 0)
+               {
+                 double t = run_length + 1;
+                 sigma_t += w * (pow3 (t) - t);
+               }
+             run_length = 0;
+           }
+         prev_x = x;
+       }
+      if ( run_length > 0)
+       {
+         double t = run_length + 1;
+         sigma_t += w * (pow3 (t) - t );
+       }
+
+      qsort (row, ost->n_vars, sizeof *row, cmp_posn);
+
+      for (v = 0; v < ost->n_vars; ++v)
+       fr.rank_sum[v] += row[v].x * w;
+    }
+  casereader_destroy (input);
+  free (row);
+
+
+  for (v = 0; v < ost->n_vars; ++v)
+    {
+      numerator += pow2 (fr.rank_sum[v]);
+    }
+
+  rsq = numerator;
+
+  numerator *= 12.0 / (fr.cc * ost->n_vars * ( ost->n_vars + 1));
+  numerator -= 3 * fr.cc * ( ost->n_vars + 1);
+
+  denominator = 1 - sigma_t / ( fr.cc * ost->n_vars * ( pow2 (ost->n_vars) - 1));
+
+  fr.chi_sq = numerator / denominator;
+
+  if ( ft->kendalls_w)
+    {
+      fr.w = 12 * rsq ;
+      fr.w -= 3 * pow2 (fr.cc) *
+       ost->n_vars * pow2 (ost->n_vars + 1);
+
+      fr.w /= pow2 (fr.cc) * (pow3 (ost->n_vars) - ost->n_vars)
+       - fr.cc * sigma_t;
+    }
+  else
+    fr.w = SYSMIS;
+
+  show_ranks_box (ost, &fr);
+  show_sig_box (ost, &fr);
+
+  free (fr.rank_sum);
+}
+
+\f
+
+
+static void
+show_ranks_box (const struct one_sample_test *ost, const struct friedman *fr)
+{
+  int i;
+  const int row_headers = 1;
+  const int column_headers = 1;
+  struct tab_table *table =
+    tab_create (row_headers + 1, column_headers + ost->n_vars);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Ranks"));
+
+  /* Vertical lines inside the box */
+  tab_box (table, 1, 0, -1, TAL_1,
+          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+
+  tab_text (table, 1, 0, 0, _("Mean Rank"));
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) - 1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  for (i = 0 ; i < ost->n_vars ; ++i)
+    {
+      tab_text (table, 0, row_headers + i,
+               TAB_LEFT, var_to_string (ost->vars[i]));
+
+      tab_double (table, 1, row_headers + i,
+                 0, fr->rank_sum[i] / fr->cc, 0);
+    }
+
+  tab_submit (table);
+}
+
+
+static void
+show_sig_box (const struct one_sample_test *ost, const struct friedman *fr)
+{
+  const struct friedman_test *ft = UP_CAST (ost, const struct friedman_test, parent);
+  
+  int row = 0;
+  const struct variable *weight = dict_get_weight (fr->dict);
+  const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+  const int row_headers = 1;
+  const int column_headers = 0;
+  struct tab_table *table =
+    tab_create (row_headers + 1, column_headers + (ft->kendalls_w ? 5 : 4));
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Test Statistics"));
+
+  tab_text (table,  0, column_headers + row++,
+           TAT_TITLE | TAB_LEFT , _("N"));
+
+  if ( ft->kendalls_w)
+    tab_text (table,  0, column_headers + row++,
+             TAT_TITLE | TAB_LEFT , _("Kendall's W"));
+
+  tab_text (table,  0, column_headers + row++,
+           TAT_TITLE | TAB_LEFT , _("Chi-Square"));
+
+  tab_text (table,  0, column_headers + row++,
+           TAT_TITLE | TAB_LEFT, _("df"));
+
+  tab_text (table,  0, column_headers + row++,
+           TAT_TITLE | TAB_LEFT, _("Asymp. Sig."));
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  row = 0;
+  tab_double (table, 1, column_headers + row++, 
+             0, fr->cc, wfmt);
+
+  if (ft->kendalls_w)
+    tab_double (table, 1, column_headers + row++, 
+               0, fr->w, 0);
+
+  tab_double (table, 1, column_headers + row++, 
+             0, fr->chi_sq, 0);
+
+  tab_double (table, 1, column_headers + row++, 
+             0, ost->n_vars - 1, &F_8_0);
+
+  tab_double (table, 1, column_headers + row++, 
+             0, gsl_cdf_chisq_Q (fr->chi_sq, ost->n_vars - 1), 
+             0);
+
+  tab_submit (table);
+}
diff --git a/src/language/stats/friedman.h b/src/language/stats/friedman.h
new file mode 100644 (file)
index 0000000..d6cf003
--- /dev/null
@@ -0,0 +1,41 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 !friedman_h
+#define friedman_h 1
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "language/stats/npar.h"
+
+struct friedman_test
+{
+  struct one_sample_test parent;
+
+  /* Calculate and display the Kendall W statistic */
+  bool kendalls_w;
+};
+
+
+void friedman_execute (const struct dataset *ds,
+                      struct casereader *input,
+                      enum mv_class exclude,
+                      const struct npar_test *test,
+                      bool,
+                      double);
+
+
+#endif
index 1acf03ffb0a098655fd9a9ea2727a0a57a0cdf32..b8aa71cb4dae06e0ef2520e96a69799ab338d556 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-
-#include <math/covariance.h>
-#include <math/categoricals.h>
-#include <math/moments.h>
-#include <gsl/gsl_matrix.h>
-#include <linreg/sweep.h>
-
-#include <libpspp/ll.h>
-
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <language/lexer/value-parser.h>
-#include <language/command.h>
-
-#include <data/procedure.h>
-#include <data/value.h>
-#include <data/dictionary.h>
-
-#include <language/dictionary/split-file.h>
-#include <libpspp/taint.h>
-#include <libpspp/misc.h>
-
 #include <gsl/gsl_cdf.h>
+#include <gsl/gsl_matrix.h>
 #include <math.h>
-#include <data/format.h>
-
-#include <libpspp/message.h>
 
-#include <output/tab.h>
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/ll.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/taint.h"
+#include "linreg/sweep.h"
+#include "math/categoricals.h"
+#include "math/covariance.h"
+#include "math/moments.h"
+#include "output/tab.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -65,6 +58,13 @@ struct glm_spec
   /* The weight variable */
   const struct variable *wv;
 
+  /* 
+     Sums of squares due to different variables. Element 0 is the SSE
+     for the entire model. For i > 0, element i is the SS due to
+     variable i.
+   */
+  gsl_vector * ssq;
+
   bool intercept;
 };
 
@@ -74,8 +74,8 @@ struct glm_workspace
   struct moments *totals;
 };
 
-static void output_glm (const struct glm_spec *, const struct glm_workspace *ws);
-static void run_glm (const struct glm_spec *cmd, struct casereader *input, const struct dataset *ds);
+static void output_glm (struct glm_spec *, const struct glm_workspace *ws);
+static void run_glm (struct glm_spec *cmd, struct casereader *input, const struct dataset *ds);
 
 int
 cmd_glm (struct lexer *lexer, struct dataset *ds)
@@ -112,14 +112,14 @@ cmd_glm (struct lexer *lexer, struct dataset *ds)
   struct const_var_set *factors = const_var_set_create_from_array (glm.factor_vars, glm.n_factor_vars);
 
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -138,8 +138,8 @@ cmd_glm (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "INTERCEPT"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -160,7 +160,7 @@ cmd_glm (struct lexer *lexer, struct dataset *ds)
         {
          size_t n_des;
          const struct variable **des;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
          parse_const_var_set_vars (lexer, factors, &des, &n_des, 0);
        }
@@ -190,10 +190,86 @@ cmd_glm (struct lexer *lexer, struct dataset *ds)
   return CMD_FAILURE;
 }
 
+static void get_ssq (struct covariance *, gsl_vector *, struct glm_spec *);
+
+static bool
+not_dropped (size_t j, size_t * dropped, size_t n_dropped)
+{
+  size_t i;
+
+  for (i = 0; i < n_dropped; i++)
+    {
+      if (j == dropped [i])
+       return false;
+    }
+  return true;
+}
+
+static void
+get_ssq (struct covariance * cov, gsl_vector * ssq, struct glm_spec * cmd)
+{
+  const struct variable **vars;
+  gsl_matrix * small_cov = NULL;
+  gsl_matrix * cm = covariance_calculate_unnormalized (cov);
+  size_t i;
+  size_t j;
+  size_t k;
+  size_t n;
+  size_t m;
+  size_t * dropped;
+  size_t n_dropped;
+
+  dropped = xcalloc (covariance_dim (cov), sizeof (*dropped));
+  vars = xcalloc (covariance_dim (cov), sizeof (*vars));
+  covariance_get_var_indices (cov, vars);
+
+  for (k = 0; k < cmd->n_factor_vars; k++)
+    {
+      n_dropped = 0;
+      for (i = 1; i < covariance_dim (cov); i++)
+       {
+         if (vars [i] == cmd->factor_vars [k])
+           {
+             dropped [n_dropped++] = i;
+           }
+       }
+      small_cov = gsl_matrix_alloc (cm->size1 - n_dropped, cm->size2 - n_dropped);
+      gsl_matrix_set (small_cov, 0, 0, gsl_matrix_get (cm, 0, 0));
+      n = 0;
+      m = 0;
+      for (i = 0; i < cm->size1; i++)
+       {
+         if (not_dropped (i, dropped, n_dropped))
+           {
+             m = 0;
+             for (j = 0; j < cm->size2; j++)
+               {
+                 if (not_dropped (j, dropped, n_dropped))
+                   {
+                     gsl_matrix_set (small_cov, n, m, gsl_matrix_get (cm, i, j));
+                     m++;
+                   }
+               }
+             n++;
+           }
+       }
+      reg_sweep (small_cov, 0);
+      gsl_vector_set (ssq, k + 1, 
+                     gsl_matrix_get (small_cov, 0, 0)
+                     - gsl_vector_get (ssq, 0));
+      gsl_matrix_free (small_cov);
+    }
+
+  free (dropped);
+  free (vars);
+  gsl_matrix_free (cm);
+
+}
+
 static  void dump_matrix (const gsl_matrix *m);
 
 static void
-run_glm (const struct glm_spec *cmd, struct casereader *input, const struct dataset *ds)
+run_glm (struct glm_spec *cmd, struct casereader *input, const struct dataset *ds)
 {
   int v;
   struct taint *taint;
@@ -262,7 +338,17 @@ run_glm (const struct glm_spec *cmd, struct casereader *input, const struct data
 
     reg_sweep (cm, 0);
 
+    /*
+      Store the overall SSE.
+     */
+    cmd->ssq = gsl_vector_alloc (cm->size1);
+    gsl_vector_set (cmd->ssq, 0, gsl_matrix_get (cm, 0, 0));
+    get_ssq (cov, cmd->ssq, cmd);
+
+    gsl_vector_free (cmd->ssq);
     dump_matrix (cm);
+
+    gsl_matrix_free (cm);
   }
 
   if (!taint_has_tainted_successor (taint))
@@ -272,7 +358,7 @@ run_glm (const struct glm_spec *cmd, struct casereader *input, const struct data
 }
 
 static void
-output_glm (const struct glm_spec *cmd, const struct glm_workspace *ws)
+output_glm (struct glm_spec *cmd, const struct glm_workspace *ws)
 {
   const struct fmt_spec *wfmt = cmd->wv ? var_get_print_format (cmd->wv) : &F_8_0;
 
index ea8fe8ceebdf5c01c8de67a94dc7a1eb7fba5a3b..ecab0348d1ae16986f85e905ed19e0bd43fe4d50 100644 (file)
@@ -1,5 +1,5 @@
 /* Pspp - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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 <gsl/gsl_cdf.h>
 #include <math.h>
 
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/subcase.h>
-#include <data/variable.h>
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/hmap.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "math/sort.h"
+#include "output/tab.h"
 
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/hmap.h>
-#include <math/sort.h>
-
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 
 /* Returns true iff the independent variable lies in the range [nst->val1, nst->val2] */
@@ -224,7 +223,6 @@ kruskal_wallis_execute (const struct dataset *ds,
 }
 
 \f
-#include <output/tab.h>
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
index 6194759dd4a84757c5727c47df63ad96699f897a..b067d3fdb258a7225b2680655a67a7a24cee2aa3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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,9 +19,8 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <language/stats/npar.h>
-#include <data/case.h>
-
+#include "data/case.h"
+#include "language/stats/npar.h"
 
 struct kruskal_wallis_test
 {
diff --git a/src/language/stats/mann-whitney.c b/src/language/stats/mann-whitney.c
new file mode 100644 (file)
index 0000000..60f251b
--- /dev/null
@@ -0,0 +1,296 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "language/stats/mann-whitney.h"
+
+#include <gsl/gsl_cdf.h>
+
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "libpspp/cast.h"
+#include "libpspp/misc.h"
+#include "math/sort.h"
+#include "output/tab.h"
+
+/* Calculates the adjustment necessary for tie compensation */
+static void
+distinct_callback (double v UNUSED, casenumber t, double w UNUSED, void *aux)
+{
+  double *tiebreaker = aux;
+
+  *tiebreaker += (pow3 (t) - t) / 12.0;
+}
+
+struct mw
+{
+  double rank_sum[2];
+  double n[2];
+
+  double u;  /* The Mann-Whitney U statistic */
+  double w;  /* The Wilcoxon Rank Sum W statistic */
+  double z;  
+};
+
+static void show_ranks_box (const struct n_sample_test *nst, const struct mw *mw);
+static void show_statistics_box (const struct n_sample_test *nst, const struct mw *mw, bool exact);
+
+
+void
+mann_whitney_execute (const struct dataset *ds,
+                     struct casereader *input,
+                     enum mv_class exclude,
+                     const struct npar_test *test,
+                     bool exact,
+                     double timer UNUSED)
+{
+  int i;
+  const struct dictionary *dict = dataset_dict (ds);
+  const struct n_sample_test *nst = UP_CAST (test, const struct n_sample_test, parent);
+
+  const struct caseproto *proto = casereader_get_proto (input);
+  size_t rank_idx = caseproto_get_n_widths (proto);
+
+  struct mw *mw = xcalloc (nst->n_vars, sizeof *mw);
+
+  for (i = 0; i < nst->n_vars; ++i)
+    {
+      double tiebreaker = 0.0;
+      bool warn = true;
+      enum rank_error rerr = 0;
+      struct casereader *rr;
+      struct ccase *c;
+      const struct variable *var = nst->vars[i];
+      
+      struct casereader *reader =
+       sort_execute_1var (casereader_clone (input), var);
+
+      rr = casereader_create_append_rank (reader, var,
+                                         dict_get_weight (dict),
+                                         &rerr,
+                                         distinct_callback, &tiebreaker);
+
+      for (; (c = casereader_read (rr)); case_unref (c))
+       {
+         const union value *val = case_data (c, var);
+         const union value *group = case_data (c, nst->indep_var);
+         const size_t group_var_width = var_get_width (nst->indep_var);
+         const double rank = case_data_idx (c, rank_idx)->f;
+
+         if ( var_is_value_missing (var, val, exclude))
+           continue;
+
+         if ( value_equal (group, &nst->val1, group_var_width))
+           {
+             mw[i].rank_sum[0] += rank;
+             mw[i].n[0] += dict_get_case_weight (dict, c, &warn);
+           }
+         else if ( value_equal (group, &nst->val2, group_var_width))
+           {
+             mw[i].rank_sum[1] += rank;
+             mw[i].n[1] += dict_get_case_weight (dict, c, &warn);
+           }
+       }
+      casereader_destroy (rr);
+
+      {
+       double n;
+       double denominator;
+       struct mw *mwv = &mw[i];
+
+       mwv->u = mwv->n[0] * mwv->n[1] ;
+       mwv->u += mwv->n[0] * (mwv->n[0] + 1) / 2.0;
+       mwv->u -= mwv->rank_sum[0];
+
+       mwv->w = mwv->rank_sum[1];
+       if ( mwv->u > mwv->n[0] * mwv->n[1] / 2.0)
+         {
+           mwv->u =  mwv->n[0] * mwv->n[1] - mwv->u;
+           mwv->w = mwv->rank_sum[0];
+         }
+       mwv->z = mwv->u - mwv->n[0] * mwv->n[1] / 2.0;
+       n = mwv->n[0] + mwv->n[1];
+       denominator = pow3(n) - n;
+       denominator /= 12;
+       denominator -= tiebreaker;
+       denominator *= mwv->n[0] * mwv->n[1];
+       denominator /= n * (n - 1);
+      
+       mwv->z /= sqrt (denominator);
+      }
+    }
+  casereader_destroy (input);
+
+  show_ranks_box (nst, mw);
+  show_statistics_box (nst, mw, exact);
+
+  free (mw);
+}
+
+\f
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static void
+show_ranks_box (const struct n_sample_test *nst, const struct mw *mwv)
+{
+  int i;
+  const int row_headers = 1;
+  const int column_headers = 2;
+  struct tab_table *table =
+    tab_create (row_headers + 7, column_headers + nst->n_vars);
+
+  struct string g1str, g2str;;
+  ds_init_empty (&g1str);
+  var_append_value_name (nst->indep_var, &nst->val1, &g1str);
+
+  ds_init_empty (&g2str);
+  var_append_value_name (nst->indep_var, &nst->val2, &g2str);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Ranks"));
+
+  /* Vertical lines inside the box */
+  tab_box (table, 1, 0, -1, TAL_1,
+          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  tab_hline (table, TAL_1, row_headers, tab_nc (table) -1, 1);
+
+  tab_text (table, 1, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
+  tab_text (table, 2, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
+  tab_text (table, 3, 1, TAT_TITLE | TAB_CENTER, _("Total"));
+  tab_joint_text (table, 1, 0, 3, 0,
+                 TAT_TITLE | TAB_CENTER, _("N"));
+  tab_vline (table, TAL_2, 4, 0, tab_nr (table) - 1);
+
+  tab_text (table, 4, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
+  tab_text (table, 5, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
+  tab_joint_text (table, 4, 0, 5, 0,
+                 TAT_TITLE | TAB_CENTER, _("Mean Rank"));
+  tab_vline (table, TAL_2, 6, 0, tab_nr (table) - 1);
+
+  tab_text (table, 6, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g1str));
+  tab_text (table, 7, 1, TAT_TITLE | TAB_CENTER, ds_cstr (&g2str));
+  tab_joint_text (table, 6, 0, 7, 0,
+                 TAT_TITLE | TAB_CENTER, _("Sum of Ranks"));
+
+  ds_destroy (&g1str);
+  ds_destroy (&g2str);
+
+  for (i = 0 ; i < nst->n_vars ; ++i)
+    {
+      const struct mw *mw = &mwv[i];
+      tab_text (table, 0, column_headers + i, TAT_TITLE,
+               var_to_string (nst->vars[i]));
+
+      tab_double (table, 1, column_headers + i, 0,
+                 mw->n[0], 0);
+
+      tab_double (table, 2, column_headers + i, 0,
+                 mw->n[1], 0);
+
+      tab_double (table, 3, column_headers + i, 0,
+                 mw->n[1] + mw->n[0], 0);
+
+      /* Mean Ranks */
+      tab_double (table, 4, column_headers + i, 0,
+                 mw->rank_sum[0] / mw->n[0], 0);
+
+      tab_double (table, 5, column_headers + i, 0,
+                 mw->rank_sum[1] / mw->n[1], 0);
+
+      /* Sum of Ranks */
+      tab_double (table, 6, column_headers + i, 0,
+                 mw->rank_sum[0], 0);
+
+      tab_double (table, 7, column_headers + i, 0,
+                 mw->rank_sum[1], 0);
+    }
+
+  tab_submit (table);
+}
+
+static void
+show_statistics_box (const struct n_sample_test *nst, const struct mw *mwv, bool exact)
+{
+  int i;
+  const int row_headers = 1;
+  const int column_headers = 1;
+  struct tab_table *table =
+    tab_create (row_headers + (exact ? 6 : 4), column_headers + nst->n_vars);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Test Statistics"));
+
+  /* Vertical lines inside the box */
+  tab_box (table, 1, 0, -1, TAL_1,
+          row_headers, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  /* Box around the table */
+  tab_box (table, TAL_2, TAL_2, -1, -1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  tab_text (table, 1, 0, TAT_TITLE | TAB_CENTER, _("Mann-Whitney U"));
+  tab_text (table, 2, 0, TAT_TITLE | TAB_CENTER, _("Wilcoxon W"));
+  tab_text (table, 3, 0, TAT_TITLE | TAB_CENTER, _("Z"));
+  tab_text (table, 4, 0, TAT_TITLE | TAB_CENTER, _("Asymp. Sig. (2-tailed)"));
+
+  if (exact) 
+    {
+      tab_text (table, 5, 0, TAT_TITLE | TAB_CENTER, _("Exact Sig. (2-tailed)"));
+      tab_text (table, 6, 0, TAT_TITLE | TAB_CENTER, _("Point Probability"));
+    }
+
+  for (i = 0 ; i < nst->n_vars ; ++i)
+    {
+      const struct mw *mw = &mwv[i];
+
+      tab_text (table, 0, column_headers + i, TAT_TITLE,
+               var_to_string (nst->vars[i]));
+
+      tab_double (table, 1, column_headers + i, 0,
+                 mw->u, 0);
+
+      tab_double (table, 2, column_headers + i, 0,
+                 mw->w, 0);
+
+      tab_double (table, 3, column_headers + i, 0,
+                 mw->z, 0);
+
+      tab_double (table, 4, column_headers + i, 0,
+                 2.0 * gsl_cdf_ugaussian_P (mw->z), 0);
+    }
+
+  tab_submit (table);
+}
diff --git a/src/language/stats/mann-whitney.h b/src/language/stats/mann-whitney.h
new file mode 100644 (file)
index 0000000..aad691c
--- /dev/null
@@ -0,0 +1,41 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 !mann_whitney_h
+#define mann_whitney_h 1
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "language/stats/npar.h"
+
+
+struct mann_whitney_test
+{
+  struct two_sample_test parent;
+};
+
+struct casereader;
+struct dataset;
+
+void mann_whitney_execute (const struct dataset *ds,
+                      struct casereader *input,
+                      enum mv_class exclude,
+                      const struct npar_test *test,
+                      bool exact,
+                      double timer
+                      );
+
+#endif
index 2341761fd7df3e7e144da7c14b2311bd76a55440..e1870f62fd28f962979f79aff4498633feb13606 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011 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/format.h>
-#include <output/tab.h>
-#include <data/casereader.h>
-#include <data/variable.h>
-#include "npar-summary.h"
-#include <math/moments.h>
-#include <data/case.h>
-#include <data/dictionary.h>
+#include "language/stats/npar-summary.h"
+
 #include <math.h>
-#include <minmax.h>
+
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/variable.h"
+#include "math/moments.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index a8b12797c1c8b6667de481a41c5f05644a6a08d7..a78d1b7e2a22c7241f84b37d74b4fe85100b401d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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,8 @@
 #if !n_par_summary_h
 #define n_par_summary_h 1
 
+#include "data/missing-values.h"
+
 struct variable ;
 struct casereader ;
 struct dictionary;
index 5898535455bc9f4f3e70cf19c0014c09a40b226c..2bc42934a381b9798f18a0b1142524fd967445d3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis. -*-c-*-
-   Copyright (C) 2006, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2008, 2009, 2010, 2011 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 <language/stats/npar.h>
-#include "npar-summary.h"
+#include "language/stats/npar.h"
 
 #include <stdlib.h>
 #include <math.h>
 
-#include "xalloc.h"
-
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <libpspp/hmapx.h>
-#include <libpspp/hash-functions.h>
-#include <libpspp/message.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-#include <libpspp/taint.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <language/lexer/value-parser.h>
-#include <language/stats/binomial.h>
-#include <language/stats/chisquare.h>
-#include <language/stats/kruskal-wallis.h>
-#include <language/stats/wilcoxon.h>
-#include <language/stats/sign.h>
-#include <math/moments.h>
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "language/stats/binomial.h"
+#include "language/stats/chisquare.h"
+#include "language/stats/cochran.h"
+#include "language/stats/friedman.h"
+#include "language/stats/kruskal-wallis.h"
+#include "language/stats/mann-whitney.h"
+#include "language/stats/npar-summary.h"
+#include "language/stats/runs.h"
+#include "language/stats/sign.h"
+#include "language/stats/wilcoxon.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/hash-functions.h"
+#include "libpspp/hmapx.h"
+#include "libpspp/message.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+#include "libpspp/taint.h"
+#include "math/moments.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -75,10 +80,15 @@ struct cmd_npar_tests
     /* Count variables indicating how many
        of the subcommands have been given. */
     int chisquare;
+    int cochran;
     int binomial;
     int wilcoxon;
     int sign;
+    int runs;
+    int friedman;
+    int kendall;
     int kruskal_wallis;
+    int mann_whitney;
     int missing;
     int method;
     int statistics;
@@ -114,9 +124,14 @@ struct npar_specs
 /* Prototype for custom subcommands of NPAR TESTS. */
 static int npar_chisquare (struct lexer *, struct dataset *, struct npar_specs *);
 static int npar_binomial (struct lexer *, struct dataset *,  struct npar_specs *);
+static int npar_runs (struct lexer *, struct dataset *, struct npar_specs *);
+static int npar_friedman (struct lexer *, struct dataset *, struct npar_specs *);
+static int npar_kendall (struct lexer *, struct dataset *, struct npar_specs *);
+static int npar_cochran (struct lexer *, struct dataset *, struct npar_specs *);
 static int npar_wilcoxon (struct lexer *, struct dataset *, struct npar_specs *);
 static int npar_sign (struct lexer *, struct dataset *, struct npar_specs *);
 static int npar_kruskal_wallis (struct lexer *, struct dataset *, struct npar_specs *);
+static int npar_mann_whitney (struct lexer *, struct dataset *, struct npar_specs *);
 static int npar_method (struct lexer *, struct npar_specs *);
 
 /* Command parsing functions. */
@@ -127,10 +142,15 @@ static int
 parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests *npt,
                  struct npar_specs *nps)
 {
-  npt->chisquare = 0;
   npt->binomial = 0;
-  npt->wilcoxon = 0;
+  npt->chisquare = 0;
+  npt->cochran = 0;
+  npt->friedman = 0;
+  npt->kruskal_wallis = 0;
+  npt->mann_whitney = 0;
+  npt->runs = 0;
   npt->sign = 0;
+  npt->wilcoxon = 0;
   npt->missing = 0;
   npt->miss = MISS_ANALYSIS;
   npt->method = 0;
@@ -138,9 +158,73 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
   memset (npt->a_statistics, 0, sizeof npt->a_statistics);
   for (;;)
     {
-      if (lex_match_hyphenated_word (lexer, "CHISQUARE"))
+      if (lex_match_id (lexer, "COCHRAN"))
+       {
+          npt->cochran++;
+          switch (npar_cochran (lexer, ds, nps))
+            {
+            case 0:
+              goto lossage;
+            case 1:
+              break;
+            case 2:
+              lex_error (lexer, NULL);
+              goto lossage;
+            default:
+              NOT_REACHED ();
+            }
+       }
+      else if (lex_match_id (lexer, "FRIEDMAN"))
+       {
+          npt->friedman++;
+          switch (npar_friedman (lexer, ds, nps))
+            {
+            case 0:
+              goto lossage;
+            case 1:
+              break;
+            case 2:
+              lex_error (lexer, NULL);
+              goto lossage;
+            default:
+              NOT_REACHED ();
+            }
+       }
+      else if (lex_match_id (lexer, "KENDALL"))
+       {
+          npt->kendall++;
+          switch (npar_kendall (lexer, ds, nps))
+            {
+            case 0:
+              goto lossage;
+            case 1:
+              break;
+            case 2:
+              lex_error (lexer, NULL);
+              goto lossage;
+            default:
+              NOT_REACHED ();
+            }
+       }
+      else if (lex_match_id (lexer, "RUNS"))
+       {
+          npt->runs++;
+          switch (npar_runs (lexer, ds, nps))
+            {
+            case 0:
+              goto lossage;
+            case 1:
+              break;
+            case 2:
+              lex_error (lexer, NULL);
+              goto lossage;
+            default:
+              NOT_REACHED ();
+            }
+       }
+      else if (lex_match_id (lexer, "CHISQUARE"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->chisquare++;
           switch (npar_chisquare (lexer, ds, nps))
             {
@@ -151,13 +235,15 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
             case 2:
               lex_error (lexer, NULL);
               goto lossage;
+            case 3:
+              continue;
             default:
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "BINOMIAL"))
+      else if (lex_match_id (lexer, "BINOMIAL"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->binomial++;
           switch (npar_binomial (lexer, ds, nps))
             {
@@ -172,10 +258,10 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "K-W") ||
-              lex_match_hyphenated_word (lexer, "KRUSKAL-WALLIS"))
+      else if (lex_match_phrase (lexer, "K-W") ||
+              lex_match_phrase (lexer, "KRUSKAL-WALLIS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->kruskal_wallis++;
           switch (npar_kruskal_wallis (lexer, ds, nps))
             {
@@ -190,9 +276,27 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "WILCOXON"))
+      else if (lex_match_phrase (lexer, "M-W") ||
+              lex_match_phrase (lexer, "MANN-WHITNEY"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
+          npt->mann_whitney++;
+          switch (npar_mann_whitney (lexer, ds, nps))
+            {
+            case 0:
+              goto lossage;
+            case 1:
+              break;
+            case 2:
+              lex_error (lexer, NULL);
+              goto lossage;
+            default:
+              NOT_REACHED ();
+            }
+        }
+      else if (lex_match_id (lexer, "WILCOXON"))
+        {
+          lex_match (lexer, T_EQUALS);
           npt->wilcoxon++;
           switch (npar_wilcoxon (lexer, ds, nps))
             {
@@ -207,9 +311,9 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "SIGN"))
+      else if (lex_match_id (lexer, "SIGN"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->sign++;
           switch (npar_sign (lexer, ds, nps))
             {
@@ -224,36 +328,36 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "MISSING"))
+      else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->missing++;
           if (npt->missing > 1)
             {
               msg (SE, _("The %s subcommand may be given only once."), "MISSING");
               goto lossage;
             }
-          while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
+          while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
             {
-              if (lex_match_hyphenated_word (lexer, "ANALYSIS"))
+              if (lex_match_id (lexer, "ANALYSIS"))
                 npt->miss = MISS_ANALYSIS;
-              else if (lex_match_hyphenated_word (lexer, "LISTWISE"))
+              else if (lex_match_id (lexer, "LISTWISE"))
                 npt->miss = MISS_LISTWISE;
-              else if (lex_match_hyphenated_word (lexer, "INCLUDE"))
+              else if (lex_match_id (lexer, "INCLUDE"))
                 nps->filter = MV_SYSTEM;
-              else if (lex_match_hyphenated_word (lexer, "EXCLUDE"))
+              else if (lex_match_id (lexer, "EXCLUDE"))
                 nps->filter = MV_ANY;
               else
                 {
                   lex_error (lexer, NULL);
                   goto lossage;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "METHOD"))
+      else if (lex_match_id (lexer, "METHOD"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->method++;
           if (npt->method > 1)
             {
@@ -273,15 +377,15 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
               NOT_REACHED ();
             }
         }
-      else if (lex_match_hyphenated_word (lexer, "STATISTICS"))
+      else if (lex_match_id (lexer, "STATISTICS"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           npt->statistics++;
-          while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
+          while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
             {
-              if (lex_match_hyphenated_word (lexer, "DESCRIPTIVES"))
+              if (lex_match_id (lexer, "DESCRIPTIVES"))
                 npt->a_statistics[NPAR_ST_DESCRIPTIVES] = 1;
-              else if (lex_match_hyphenated_word (lexer, "QUARTILES"))
+              else if (lex_match_id (lexer, "QUARTILES"))
                 npt->a_statistics[NPAR_ST_QUARTILES] = 1;
               else if (lex_match (lexer, T_ALL))
                 npt->a_statistics[NPAR_ST_ALL] = 1;
@@ -290,22 +394,22 @@ parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests
                   lex_error (lexer, NULL);
                   goto lossage;
                 }
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
         }
       else if ( settings_get_syntax () != COMPATIBLE && lex_match_id (lexer, "ALGORITHM"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
           if (lex_match_id (lexer, "COMPATIBLE"))
             settings_set_cmd_algorithm (COMPATIBLE);
           else if (lex_match_id (lexer, "ENHANCED"))
             settings_set_cmd_algorithm (ENHANCED);
           }
-        if (!lex_match (lexer, '/'))
+        if (!lex_match (lexer, T_SLASH))
           break;
       }
 
-    if (lex_token (lexer) != '.')
+    if (lex_token (lexer) != T_ENDCMD)
       {
         lex_error (lexer, _("expecting end of command"));
         goto lossage;
@@ -408,8 +512,8 @@ cmd_npar_tests (struct lexer *lexer, struct dataset *ds)
       }
   }
 
-  qsort (npar_specs.vv, npar_specs.n_vars, sizeof (*npar_specs.vv), 
-        compare_var_ptrs_by_name);
+  sort (npar_specs.vv, npar_specs.n_vars, sizeof (*npar_specs.vv), 
+        compare_var_ptrs_by_name, NULL);
 
   if ( cmd.statistics )
     {
@@ -461,6 +565,156 @@ cmd_npar_tests (struct lexer *lexer, struct dataset *ds)
   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
+static int
+npar_runs (struct lexer *lexer, struct dataset *ds,
+          struct npar_specs *specs)
+{
+  struct runs_test *rt = pool_alloc (specs->pool, sizeof (*rt));
+  struct one_sample_test *tp = &rt->parent;
+  struct npar_test *nt = &tp->parent;
+
+  nt->execute = runs_execute;
+  nt->insert_variables = one_sample_insert_variables;
+
+  if ( lex_force_match (lexer, T_LPAREN) )
+    {
+      if ( lex_match_id (lexer, "MEAN"))
+       {
+         rt->cp_mode = CP_MEAN;
+       }
+      else if (lex_match_id (lexer, "MEDIAN"))
+       {
+         rt->cp_mode = CP_MEDIAN;
+       }
+      else if (lex_match_id (lexer, "MODE"))
+       {
+         rt->cp_mode = CP_MODE;
+       }
+      else if (lex_is_number (lexer))
+       {
+         rt->cutpoint = lex_number (lexer);
+         rt->cp_mode = CP_CUSTOM;
+         lex_get (lexer);
+       }
+      else
+       {
+         lex_error (lexer, _("Expecting MEAN, MEDIAN, MODE or number"));
+         return 0;
+       }
+                 
+      lex_force_match (lexer, T_RPAREN);
+      lex_force_match (lexer, T_EQUALS);
+      if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
+                                 &tp->vars, &tp->n_vars,
+                                 PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
+       {
+         return 2;
+       }
+    }
+
+  specs->n_tests++;
+  specs->test = pool_realloc (specs->pool,
+                             specs->test,
+                             sizeof (*specs->test) * specs->n_tests);
+
+  specs->test[specs->n_tests - 1] = nt;
+
+  return 1;
+}
+
+static int
+npar_friedman (struct lexer *lexer, struct dataset *ds,
+              struct npar_specs *specs)
+{
+  struct friedman_test *ft = pool_alloc (specs->pool, sizeof (*ft)); 
+  struct one_sample_test *ost = &ft->parent;
+  struct npar_test *nt = &ost->parent;
+
+  ft->kendalls_w = false;
+  nt->execute = friedman_execute;
+  nt->insert_variables = one_sample_insert_variables;
+
+  lex_match (lexer, T_EQUALS);
+
+  if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
+                                  &ost->vars, &ost->n_vars,
+                                  PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
+    {
+      return 2;
+    }
+
+  specs->n_tests++;
+  specs->test = pool_realloc (specs->pool,
+                             specs->test,
+                             sizeof (*specs->test) * specs->n_tests);
+
+  specs->test[specs->n_tests - 1] = nt;
+
+  return 1;
+}
+
+static int
+npar_kendall (struct lexer *lexer, struct dataset *ds,
+              struct npar_specs *specs)
+{
+  struct friedman_test *kt = pool_alloc (specs->pool, sizeof (*kt)); 
+  struct one_sample_test *ost = &kt->parent;
+  struct npar_test *nt = &ost->parent;
+
+  kt->kendalls_w = true;
+  nt->execute = friedman_execute;
+  nt->insert_variables = one_sample_insert_variables;
+
+  lex_match (lexer, T_EQUALS);
+
+  if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
+                                  &ost->vars, &ost->n_vars,
+                                  PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
+    {
+      return 2;
+    }
+
+  specs->n_tests++;
+  specs->test = pool_realloc (specs->pool,
+                             specs->test,
+                             sizeof (*specs->test) * specs->n_tests);
+
+  specs->test[specs->n_tests - 1] = nt;
+
+  return 1;
+}
+
+
+static int
+npar_cochran (struct lexer *lexer, struct dataset *ds,
+              struct npar_specs *specs)
+{
+  struct one_sample_test *ft = pool_alloc (specs->pool, sizeof (*ft)); 
+  struct npar_test *nt = &ft->parent;
+
+  nt->execute = cochran_execute;
+  nt->insert_variables = one_sample_insert_variables;
+
+  lex_match (lexer, T_EQUALS);
+
+  if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
+                                  &ft->vars, &ft->n_vars,
+                                  PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
+    {
+      return 2;
+    }
+
+  specs->n_tests++;
+  specs->test = pool_realloc (specs->pool,
+                             specs->test,
+                             sizeof (*specs->test) * specs->n_tests);
+
+  specs->test[specs->n_tests - 1] = nt;
+
+  return 1;
+}
+
+
 static int
 npar_chisquare (struct lexer *lexer, struct dataset *ds,
                struct npar_specs *specs)
@@ -468,6 +722,7 @@ npar_chisquare (struct lexer *lexer, struct dataset *ds,
   struct chisquare_test *cstp = pool_alloc (specs->pool, sizeof (*cstp));
   struct one_sample_test *tp = &cstp->parent;
   struct npar_test *nt = &tp->parent;
+  int retval = 1;
 
   nt->execute = chisquare_execute;
   nt->insert_variables = one_sample_insert_variables;
@@ -481,13 +736,13 @@ npar_chisquare (struct lexer *lexer, struct dataset *ds,
 
   cstp->ranged = false;
 
-  if ( lex_match (lexer, '('))
+  if ( lex_match (lexer, T_LPAREN))
     {
       cstp->ranged = true;
       if ( ! lex_force_num (lexer)) return 0;
       cstp->lo = lex_integer (lexer);
       lex_get (lexer);
-      lex_force_match (lexer, ',');
+      lex_force_match (lexer, T_COMMA);
       if (! lex_force_num (lexer) ) return 0;
       cstp->hi = lex_integer (lexer);
       if ( cstp->lo >= cstp->hi )
@@ -499,49 +754,44 @@ npar_chisquare (struct lexer *lexer, struct dataset *ds,
          return 0;
        }
       lex_get (lexer);
-      if (! lex_force_match (lexer, ')')) return 0;
+      if (! lex_force_match (lexer, T_RPAREN)) return 0;
     }
 
   cstp->n_expected = 0;
   cstp->expected = NULL;
-  if ( lex_match (lexer, '/') )
+  if (lex_match_phrase (lexer, "/EXPECTED"))
     {
-      if ( lex_match_id (lexer, "EXPECTED") )
-       {
-         lex_force_match (lexer, '=');
-         if ( ! lex_match_id (lexer, "EQUAL") )
-           {
-             double f;
-             int n;
-             while ( lex_is_number (lexer) )
-               {
-                 int i;
-                 n = 1;
-                 f = lex_number (lexer);
-                 lex_get (lexer);
-                 if ( lex_match (lexer, '*'))
-                   {
-                     n = f;
-                     f = lex_number (lexer);
-                     lex_get (lexer);
-                   }
-                 lex_match (lexer, ',');
-
-                 cstp->n_expected += n;
-                 cstp->expected = pool_realloc (specs->pool,
-                                                cstp->expected,
-                                                sizeof (double) *
-                                                cstp->n_expected);
-                 for ( i = cstp->n_expected - n ;
-                       i < cstp->n_expected;
-                       ++i )
-                   cstp->expected[i] = f;
+      lex_force_match (lexer, T_EQUALS);
+      if ( ! lex_match_id (lexer, "EQUAL") )
+        {
+          double f;
+          int n;
+          while ( lex_is_number (lexer) )
+            {
+              int i;
+              n = 1;
+              f = lex_number (lexer);
+              lex_get (lexer);
+              if ( lex_match (lexer, T_ASTERISK))
+                {
+                  n = f;
+                  f = lex_number (lexer);
+                  lex_get (lexer);
+                }
+              lex_match (lexer, T_COMMA);
+
+              cstp->n_expected += n;
+              cstp->expected = pool_realloc (specs->pool,
+                                             cstp->expected,
+                                             sizeof (double) *
+                                             cstp->n_expected);
+              for ( i = cstp->n_expected - n ;
+                    i < cstp->n_expected;
+                    ++i )
+                cstp->expected[i] = f;
 
-               }
-           }
-       }
-      else
-       lex_put_back (lexer, '/');
+            }
+        }
     }
 
   if ( cstp->ranged && cstp->n_expected > 0 &&
@@ -562,7 +812,7 @@ npar_chisquare (struct lexer *lexer, struct dataset *ds,
 
   specs->test[specs->n_tests - 1] = nt;
 
-  return 1;
+  return retval;
 }
 
 
@@ -573,6 +823,7 @@ npar_binomial (struct lexer *lexer, struct dataset *ds,
   struct binomial_test *btp = pool_alloc (specs->pool, sizeof (*btp));
   struct one_sample_test *tp = &btp->parent;
   struct npar_test *nt = &tp->parent;
+  bool equals = false;
 
   nt->execute = binomial_execute;
   nt->insert_variables = one_sample_insert_variables;
@@ -581,33 +832,33 @@ npar_binomial (struct lexer *lexer, struct dataset *ds,
 
   btp->p = 0.5;
 
-  if ( lex_match (lexer, '(') )
+  if ( lex_match (lexer, T_LPAREN) )
     {
+      equals = false;
       if ( lex_force_num (lexer) )
        {
          btp->p = lex_number (lexer);
          lex_get (lexer);
-         lex_force_match (lexer, ')');
+         lex_force_match (lexer, T_RPAREN);
        }
       else
        return 0;
     }
   else
-    /* Kludge: q2c swallows the '=' so put it back here  */
-     lex_put_back (lexer, '=');
+    equals = true;
 
-  if (lex_match (lexer, '=') )
+  if (equals || lex_match (lexer, T_EQUALS) )
     {
       if (parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
                                      &tp->vars, &tp->n_vars,
                                      PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
        {
-         if (lex_match (lexer, '('))
+         if (lex_match (lexer, T_LPAREN))
            {
              lex_force_num (lexer);
              btp->category1 = lex_number (lexer);
              lex_get (lexer);
-             if ( lex_match (lexer, ','))
+             if ( lex_match (lexer, T_COMMA))
                {
                  if ( ! lex_force_num (lexer) ) return 2;
                  btp->category2 = lex_number (lexer);
@@ -618,7 +869,7 @@ npar_binomial (struct lexer *lexer, struct dataset *ds,
                  btp->cutpoint = btp->category1;
                }
 
-             lex_force_match (lexer, ')');
+             lex_force_match (lexer, T_RPAREN);
            }
        }
       else
@@ -677,8 +928,8 @@ parse_two_sample_related_test (struct lexer *lexer,
                                        PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
        return false;
 
-      paired = (lex_match (lexer, '(') &&
-               lex_match_id (lexer, "PAIRED") && lex_match (lexer, ')'));
+      paired = (lex_match (lexer, T_LPAREN) &&
+               lex_match_id (lexer, "PAIRED") && lex_match (lexer, T_RPAREN));
     }
 
 
@@ -772,27 +1023,26 @@ parse_n_sample_related_test (struct lexer *lexer,
 
   nst->indep_var = parse_variable_const (lexer, dict);
 
-  if ( ! lex_force_match (lexer, '('))
+  if ( ! lex_force_match (lexer, T_LPAREN))
     return false;
 
   value_init (&nst->val1, var_get_width (nst->indep_var));
-  if ( ! parse_value (lexer, &nst->val1, var_get_width (nst->indep_var)))
+  if ( ! parse_value (lexer, &nst->val1, nst->indep_var))
     {
       value_destroy (&nst->val1, var_get_width (nst->indep_var));
       return false;
     }
 
-  if ( ! lex_force_match (lexer, ','))
-    return false;
+  lex_match (lexer, T_COMMA);
 
   value_init (&nst->val2, var_get_width (nst->indep_var));
-  if ( ! parse_value (lexer, &nst->val2, var_get_width (nst->indep_var)))
+  if ( ! parse_value (lexer, &nst->val2, nst->indep_var))
     {
       value_destroy (&nst->val2, var_get_width (nst->indep_var));
       return false;
     }
 
-  if ( ! lex_force_match (lexer, ')'))
+  if ( ! lex_force_match (lexer, T_RPAREN))
     return false;
 
   return true;
@@ -822,6 +1072,32 @@ npar_wilcoxon (struct lexer *lexer,
   return 1;
 }
 
+
+static int
+npar_mann_whitney (struct lexer *lexer,
+              struct dataset *ds,
+              struct npar_specs *specs )
+{
+  struct n_sample_test *tp = pool_alloc (specs->pool, sizeof (*tp));
+  struct npar_test *nt = &tp->parent;
+
+  nt->insert_variables = n_sample_insert_variables;
+  nt->execute = mann_whitney_execute;
+
+  if (!parse_n_sample_related_test (lexer, dataset_dict (ds),
+                                   tp, specs->pool) )
+    return 0;
+
+  specs->n_tests++;
+  specs->test = pool_realloc (specs->pool,
+                             specs->test,
+                             sizeof (*specs->test) * specs->n_tests);
+  specs->test[specs->n_tests - 1] = nt;
+
+  return 1;
+}
+
+
 static int
 npar_sign (struct lexer *lexer, struct dataset *ds,
           struct npar_specs *specs)
@@ -938,14 +1214,14 @@ npar_method (struct lexer *lexer,  struct npar_specs *specs)
        {
          specs->timer = 5.0;
 
-         if ( lex_match (lexer, '('))
+         if ( lex_match (lexer, T_LPAREN))
            {
              if ( lex_force_num (lexer) )
                {
                  specs->timer = lex_number (lexer);
                  lex_get (lexer);
                }
-             lex_force_match (lexer, ')');
+             lex_force_match (lexer, T_RPAREN);
            }
        }
     }
index af093ffb9993d4711387bc5542ac5a72c5b87d00..367cf65d3bb2a07ac6a97f3e9646120d11ed7171 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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,8 +19,8 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <data/missing-values.h>
-#include <data/value.h>
+#include "data/missing-values.h"
+#include "data/value.h"
 
 typedef const struct variable *variable_pair[2];
 
index 79b40cbd854a1be1d201ab50b8b150c5b740b3f7..a63d1a29e532876ebadb1fbf4d2f8100e0f83021 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/value.h>
-
-
-#include <math/covariance.h>
-#include <math/categoricals.h>
-#include <math/levene.h>
-#include <math/moments.h>
-#include <gsl/gsl_matrix.h>
-#include <linreg/sweep.h>
-
-#include <libpspp/ll.h>
-
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <language/lexer/value-parser.h>
-#include <language/command.h>
-
-
-#include <language/dictionary/split-file.h>
-#include <libpspp/taint.h>
-#include <libpspp/misc.h>
-
-#include <output/tab.h>
-
 #include <gsl/gsl_cdf.h>
+#include <gsl/gsl_matrix.h>
 #include <math.h>
-#include <data/format.h>
 
-#include <libpspp/message.h>
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/ll.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/taint.h"
+#include "linreg/sweep.h"
+#include "math/categoricals.h"
+#include "math/covariance.h"
+#include "math/levene.h"
+#include "math/moments.h"
+#include "output/tab.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -164,13 +156,13 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds)
   ll_init (&oneway.contrast_list);
 
   
-  if ( lex_match (lexer, '/'))
+  if ( lex_match (lexer, T_SLASH))
     {
       if (!lex_force_match_id (lexer, "VARIABLES"))
        {
          goto error;
        }
-      lex_match (lexer, '=');
+      lex_match (lexer, T_EQUALS);
     }
 
   if (!parse_variables_const (lexer, dict,
@@ -182,14 +174,14 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds)
 
   oneway.indep_var = parse_variable_const (lexer, dict);
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "STATISTICS"))
        {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "DESCRIPTIVES"))
                {
@@ -211,11 +203,11 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds)
          struct contrasts_node *cl = xzalloc (sizeof *cl);
 
          struct ll_list *coefficient_list = &cl->coefficient_list;
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
          ll_init (coefficient_list);
 
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if ( lex_is_number (lexer))
                {
@@ -236,8 +228,8 @@ cmd_oneway (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -392,11 +384,11 @@ run_oneway (const struct oneway_spec *cmd,
 
   for (v = 0; v < cmd->n_vars; ++v)
     {
-      ws.vws[v].cat = categoricals_create (&cmd->indep_var, 1,
-                                                      cmd->wv, cmd->exclude, 
-                                                      makeit,
-                                                      updateit,
-                                                      cmd->vars[v], ws.dd_total[v]);
+      ws.vws[v].cat = categoricals_create (&cmd->indep_var, 1, cmd->wv,
+                                           cmd->exclude, makeit, updateit,
+                                           CONST_CAST (struct variable *,
+                                                       cmd->vars[v]),
+                                           ws.dd_total[v]);
 
       ws.vws[v].cov = covariance_2pass_create (1, &cmd->vars[v],
                                               ws.vws[v].cat, 
@@ -495,11 +487,13 @@ run_oneway (const struct oneway_spec *cmd,
       pvw->n_groups = categoricals_total (cats);
 
       pvw->mse = (pvw->sst - pvw->ssa) / (n - pvw->n_groups);
+
+      gsl_matrix_free (cm);
     }
 
   for (v = 0; v < cmd->n_vars; ++v)
     {
-      struct categoricals *cats = covariance_get_categoricals (ws.vws[v].cov);
+      const struct categoricals *cats = covariance_get_categoricals (ws.vws[v].cov);
 
       categoricals_done (cats);
       
diff --git a/src/language/stats/quick-cluster.c b/src/language/stats/quick-cluster.c
new file mode 100644 (file)
index 0000000..014406f
--- /dev/null
@@ -0,0 +1,565 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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 <gsl/gsl_matrix.h>
+#include <gsl/gsl_permutation.h>
+#include <gsl/gsl_sort_vector.h>
+#include <gsl/gsl_statistics.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "math/random.h"
+#include "output/tab.h"
+#include "output/text-item.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+/* Holds all of the information for the functions.  int n, holds the number of
+   observation and its default value is -1.  We set it in
+   kmeans_recalculate_centers in first invocation. */
+struct Kmeans
+{
+  gsl_matrix *centers;         /* Centers for groups. */
+  gsl_vector_long *num_elements_groups;
+  int ngroups;                 /* Number of group. (Given by the user) */
+  casenumber n;                        /* Number of observations (default -1). */
+  int m;                       /* Number of variables. (Given by the user) */
+  int maxiter;                 /* Maximum iterations (Given by the user) */
+  int lastiter;                        /* Iteration where it found the solution. */
+  int trials;                  /* If not convergence, how many times has
+                                   clustering done. */
+  gsl_matrix *initial_centers; /* Initial random centers. */
+  const struct variable **variables;
+  gsl_permutation *group_order;        /* Group order for reporting. */
+  struct casereader *original_casereader;
+  struct caseproto *proto;
+  struct casereader *index_rdr;        /* Group ids for each case. */
+  const struct variable *wv;   /* Weighting variable. */
+};
+
+static struct Kmeans *kmeans_create (struct casereader *cs,
+                                    const struct variable **variables,
+                                    int m, int ngroups, int maxiter);
+
+static void kmeans_randomize_centers (struct Kmeans *kmeans);
+
+static int kmeans_get_nearest_group (struct Kmeans *kmeans, struct ccase *c);
+
+static void kmeans_recalculate_centers (struct Kmeans *kmeans);
+
+static int
+kmeans_calculate_indexes_and_check_convergence (struct Kmeans *kmeans);
+
+static void kmeans_order_groups (struct Kmeans *kmeans);
+
+static void kmeans_cluster (struct Kmeans *kmeans);
+
+static void quick_cluster_show_centers (struct Kmeans *kmeans, bool initial);
+
+static void quick_cluster_show_number_cases (struct Kmeans *kmeans);
+
+static void quick_cluster_show_results (struct Kmeans *kmeans);
+
+int cmd_quick_cluster (struct lexer *lexer, struct dataset *ds);
+
+static void kmeans_destroy (struct Kmeans *kmeans);
+
+/* Creates and returns a struct of Kmeans with given casereader 'cs', parsed
+   variables 'variables', number of cases 'n', number of variables 'm', number
+   of clusters and amount of maximum iterations. */
+static struct Kmeans *
+kmeans_create (struct casereader *cs, const struct variable **variables,
+              int m, int ngroups, int maxiter)
+{
+  struct Kmeans *kmeans = xmalloc (sizeof (struct Kmeans));
+  kmeans->centers = gsl_matrix_alloc (ngroups, m);
+  kmeans->num_elements_groups = gsl_vector_long_alloc (ngroups);
+  kmeans->ngroups = ngroups;
+  kmeans->n = 0;
+  kmeans->m = m;
+  kmeans->maxiter = maxiter;
+  kmeans->lastiter = 0;
+  kmeans->trials = 0;
+  kmeans->variables = variables;
+  kmeans->group_order = gsl_permutation_alloc (kmeans->centers->size1);
+  kmeans->original_casereader = cs;
+  kmeans->initial_centers = NULL;
+
+  kmeans->proto = caseproto_create ();
+  kmeans->proto = caseproto_add_width (kmeans->proto, 0);
+  kmeans->index_rdr = NULL;
+  return (kmeans);
+}
+
+static void
+kmeans_destroy (struct Kmeans *kmeans)
+{
+  gsl_matrix_free (kmeans->centers);
+  gsl_matrix_free (kmeans->initial_centers);
+
+  gsl_vector_long_free (kmeans->num_elements_groups);
+
+  gsl_permutation_free (kmeans->group_order);
+
+  caseproto_unref (kmeans->proto);
+
+  /*
+     These reader and writer were already destroyed.
+     free (kmeans->original_casereader);
+     free (kmeans->index_rdr);
+   */
+
+  free (kmeans);
+}
+
+/* Creates random centers using randomly selected cases from the data. */
+static void
+kmeans_randomize_centers (struct Kmeans *kmeans)
+{
+  int i, j;
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      for (j = 0; j < kmeans->m; j++)
+       {
+         if (i == j)
+           {
+             gsl_matrix_set (kmeans->centers, i, j, 1);
+           }
+         else
+           {
+             gsl_matrix_set (kmeans->centers, i, j, 0);
+           }
+       }
+    }
+  /* If it is the first iteration, the variable kmeans->initial_centers is NULL
+     and it is created once for reporting issues. In SPSS, initial centers are
+     shown in the reports but in PSPP it is not shown now. I am leaving it
+     here. */
+  if (!kmeans->initial_centers)
+    {
+      kmeans->initial_centers = gsl_matrix_alloc (kmeans->ngroups, kmeans->m);
+      gsl_matrix_memcpy (kmeans->initial_centers, kmeans->centers);
+    }
+}
+
+static int
+kmeans_get_nearest_group (struct Kmeans *kmeans, struct ccase *c)
+{
+  int result = -1;
+  double x;
+  int i, j;
+  double dist;
+  double mindist;
+  mindist = INFINITY;
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      dist = 0;
+      for (j = 0; j < kmeans->m; j++)
+       {
+         x = case_data (c, kmeans->variables[j])->f;
+         dist += pow2 (gsl_matrix_get (kmeans->centers, i, j) - x);
+       }
+      if (dist < mindist)
+       {
+         mindist = dist;
+         result = i;
+       }
+    }
+  return (result);
+}
+
+/* Re-calculate the cluster centers. */
+static void
+kmeans_recalculate_centers (struct Kmeans *kmeans)
+{
+  casenumber i;
+  int v, j;
+  double x, curval;
+  struct ccase *c;
+  struct ccase *c_index;
+  struct casereader *cs;
+  struct casereader *cs_index;
+  int index;
+  double weight;
+
+  i = 0;
+  cs = casereader_clone (kmeans->original_casereader);
+  cs_index = casereader_clone (kmeans->index_rdr);
+
+  gsl_matrix_set_all (kmeans->centers, 0.0);
+  for (; (c = casereader_read (cs)) != NULL; case_unref (c))
+    {
+      c_index = casereader_read (cs_index);
+      index = case_data_idx (c_index, 0)->f;
+      for (v = 0; v < kmeans->m; ++v)
+       {
+         if (kmeans->wv)
+           {
+             weight = case_data (c, kmeans->wv)->f;
+           }
+         else
+           {
+             weight = 1.0;
+           }
+         x = case_data (c, kmeans->variables[v])->f * weight;
+         curval = gsl_matrix_get (kmeans->centers, index, v);
+         gsl_matrix_set (kmeans->centers, index, v, curval + x);
+       }
+      i++;
+      case_unref (c_index);
+    }
+  casereader_destroy (cs);
+  casereader_destroy (cs_index);
+
+  /* Getting number of cases */
+  if (kmeans->n == 0)
+    kmeans->n = i;
+
+  /* We got sum of each center but we need averages.
+     We are dividing centers to numobs. This may be inefficient and
+     we should check it again. */
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      casenumber numobs = kmeans->num_elements_groups->data[i];
+      for (j = 0; j < kmeans->m; j++)
+       {
+         if (numobs > 0)
+           {
+             double *x = gsl_matrix_ptr (kmeans->centers, i, j);
+             *x /= numobs;
+           }
+         else
+           {
+             gsl_matrix_set (kmeans->centers, i, j, 0);
+           }
+       }
+    }
+}
+
+/* The variable index in struct Kmeans holds integer values that represents the
+   current groups of cases.  index[n]=a shows the nth case is belong to ath
+   cluster.  This function calculates these indexes and returns the number of
+   different cases of the new and old index variables.  If last two index
+   variables are equal, there is no any enhancement of clustering. */
+static int
+kmeans_calculate_indexes_and_check_convergence (struct Kmeans *kmeans)
+{
+  int totaldiff = 0;
+  double weight;
+  struct ccase *c;
+  struct casereader *cs = casereader_clone (kmeans->original_casereader);
+
+  /* A casewriter into which we will write the indexes. */
+  struct casewriter *index_wtr = autopaging_writer_create (kmeans->proto);
+
+  gsl_vector_long_set_all (kmeans->num_elements_groups, 0);
+
+  for (; (c = casereader_read (cs)) != NULL; case_unref (c))
+    {
+      /* A case to hold the new index. */
+      struct ccase *index_case_new = case_create (kmeans->proto);
+      int bestindex = kmeans_get_nearest_group (kmeans, c);
+      if (kmeans->wv)
+       {
+         weight = (casenumber) case_data (c, kmeans->wv)->f;
+       }
+      else
+       {
+         weight = 1.0;
+       }
+      kmeans->num_elements_groups->data[bestindex] += weight;
+      if (kmeans->index_rdr)
+       {
+         /* A case from which the old index will be read. */
+         struct ccase *index_case_old = NULL;
+
+         /* Read the case from the index casereader. */
+         index_case_old = casereader_read (kmeans->index_rdr);
+
+         /* Set totaldiff, using the old_index. */
+         totaldiff += abs (case_data_idx (index_case_old, 0)->f - bestindex);
+
+         /* We have no use for the old case anymore, so unref it. */
+         case_unref (index_case_old);
+       }
+      else
+       {
+         /* If this is the first run, then assume index is zero. */
+         totaldiff += bestindex;
+       }
+
+      /* Set the value of the new inde.x */
+      case_data_rw_idx (index_case_new, 0)->f = bestindex;
+
+      /* and write the new index to the casewriter */
+      casewriter_write (index_wtr, index_case_new);
+    }
+  casereader_destroy (cs);
+  /* We have now read through the entire index_rdr, so it's of no use
+     anymore. */
+  casereader_destroy (kmeans->index_rdr);
+
+  /* Convert the writer into a reader, ready for the next iteration to read */
+  kmeans->index_rdr = casewriter_make_reader (index_wtr);
+
+  return (totaldiff);
+}
+
+static void
+kmeans_order_groups (struct Kmeans *kmeans)
+{
+  gsl_vector *v = gsl_vector_alloc (kmeans->ngroups);
+  gsl_matrix_get_col (v, kmeans->centers, 0);
+  gsl_sort_vector_index (kmeans->group_order, v);
+}
+
+/* Main algorithm.
+   Does iterations, checks convergency. */
+static void
+kmeans_cluster (struct Kmeans *kmeans)
+{
+  int i;
+  bool redo;
+  int diffs;
+  bool show_warning1;
+
+  show_warning1 = true;
+cluster:
+  redo = false;
+  kmeans_randomize_centers (kmeans);
+  for (kmeans->lastiter = 0; kmeans->lastiter < kmeans->maxiter;
+       kmeans->lastiter++)
+    {
+      diffs = kmeans_calculate_indexes_and_check_convergence (kmeans);
+      kmeans_recalculate_centers (kmeans);
+      if (show_warning1 && kmeans->ngroups > kmeans->n)
+       {
+         msg (MW, _("Number of clusters may not be larger than the number "
+                     "of cases."));
+         show_warning1 = false;
+       }
+      if (diffs == 0)
+       break;
+    }
+
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      if (kmeans->num_elements_groups->data[i] == 0)
+       {
+         kmeans->trials++;
+         if (kmeans->trials >= 3)
+           break;
+         redo = true;
+         break;
+       }
+    }
+  if (redo)
+    goto cluster;
+
+}
+
+/* Reports centers of clusters.
+   Initial parameter is optional for future use.
+   If initial is true, initial cluster centers are reported.  Otherwise,
+   resulted centers are reported. */
+static void
+quick_cluster_show_centers (struct Kmeans *kmeans, bool initial)
+{
+  struct tab_table *t;
+  int nc, nr, heading_columns, currow;
+  int i, j;
+  nc = kmeans->ngroups + 1;
+  nr = kmeans->m + 4;
+  heading_columns = 1;
+  t = tab_create (nc, nr);
+  tab_headers (t, 0, nc - 1, 0, 1);
+  currow = 0;
+  if (!initial)
+    {
+      tab_title (t, _("Final Cluster Centers"));
+    }
+  else
+    {
+      tab_title (t, _("Initial Cluster Centers"));
+    }
+  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1);
+  tab_joint_text (t, 1, 0, nc - 1, 0, TAB_CENTER, _("Cluster"));
+  tab_hline (t, TAL_1, 1, nc - 1, 2);
+  currow += 2;
+
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      tab_text_format (t, (i + 1), currow, TAB_CENTER, "%d", (i + 1));
+    }
+  currow++;
+  tab_hline (t, TAL_1, 1, nc - 1, currow);
+  currow++;
+  for (i = 0; i < kmeans->m; i++)
+    {
+      tab_text (t, 0, currow + i, TAB_LEFT,
+               var_to_string (kmeans->variables[i]));
+    }
+
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      for (j = 0; j < kmeans->m; j++)
+       {
+         if (!initial)
+           {
+             tab_double (t, i + 1, j + 4, TAB_CENTER,
+                         gsl_matrix_get (kmeans->centers,
+                                         kmeans->group_order->data[i], j),
+                         var_get_print_format (kmeans->variables[j]));
+           }
+         else
+           {
+             tab_double (t, i + 1, j + 4, TAB_CENTER,
+                         gsl_matrix_get (kmeans->initial_centers,
+                                         kmeans->group_order->data[i], j),
+                         var_get_print_format (kmeans->variables[j]));
+           }
+       }
+    }
+  tab_submit (t);
+}
+
+/* Reports number of cases of each single cluster. */
+static void
+quick_cluster_show_number_cases (struct Kmeans *kmeans)
+{
+  struct tab_table *t;
+  int nc, nr;
+  int i, numelem;
+  long int total;
+  nc = 3;
+  nr = kmeans->ngroups + 1;
+  t = tab_create (nc, nr);
+  tab_headers (t, 0, nc - 1, 0, 0);
+  tab_title (t, _("Number of Cases in each Cluster"));
+  tab_box (t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, nc - 1, nr - 1);
+  tab_text (t, 0, 0, TAB_LEFT, _("Cluster"));
+
+  total = 0;
+  for (i = 0; i < kmeans->ngroups; i++)
+    {
+      tab_text_format (t, 1, i, TAB_CENTER, "%d", (i + 1));
+      numelem =
+       kmeans->num_elements_groups->data[kmeans->group_order->data[i]];
+      tab_text_format (t, 2, i, TAB_CENTER, "%d", numelem);
+      total += numelem;
+    }
+
+  tab_text (t, 0, kmeans->ngroups, TAB_LEFT, _("Valid"));
+  tab_text_format (t, 2, kmeans->ngroups, TAB_LEFT, "%ld", total);
+  tab_submit (t);
+}
+
+/* Reports. */
+static void
+quick_cluster_show_results (struct Kmeans *kmeans)
+{
+  kmeans_order_groups (kmeans);
+  /* Uncomment the line below for reporting initial centers. */
+  /* quick_cluster_show_centers (kmeans, true); */
+  quick_cluster_show_centers (kmeans, false);
+  quick_cluster_show_number_cases (kmeans);
+}
+
+int
+cmd_quick_cluster (struct lexer *lexer, struct dataset *ds)
+{
+  struct Kmeans *kmeans;
+  bool ok;
+  const struct dictionary *dict = dataset_dict (ds);
+  const struct variable **variables;
+  struct casereader *cs;
+  int groups = 2;
+  int maxiter = 2;
+  size_t p;
+
+  if (!parse_variables_const (lexer, dict, &variables, &p,
+                             PV_NO_DUPLICATE | PV_NUMERIC))
+    {
+      msg (ME, _("Variables cannot be parsed"));
+      return (CMD_FAILURE);
+    }
+
+  if (lex_match (lexer, T_SLASH))
+    {
+      if (lex_match_id (lexer, "CRITERIA"))
+       {
+         lex_match (lexer, T_EQUALS);
+         while (lex_token (lexer) != T_ENDCMD
+                && lex_token (lexer) != T_SLASH)
+           {
+             if (lex_match_id (lexer, "CLUSTERS"))
+               {
+                 if (lex_force_match (lexer, T_LPAREN))
+                   {
+                     lex_force_int (lexer);
+                     groups = lex_integer (lexer);
+                     lex_get (lexer);
+                     lex_force_match (lexer, T_RPAREN);
+                   }
+               }
+             else if (lex_match_id (lexer, "MXITER"))
+               {
+                 if (lex_force_match (lexer, T_LPAREN))
+                   {
+                     lex_force_int (lexer);
+                     maxiter = lex_integer (lexer);
+                     lex_get (lexer);
+                     lex_force_match (lexer, T_RPAREN);
+                   }
+               }
+             else
+                return CMD_FAILURE;
+           }
+       }
+    }
+
+  cs = proc_open (ds);
+
+  kmeans = kmeans_create (cs, variables, p, groups, maxiter);
+
+  kmeans->wv = dict_get_weight (dict);
+  kmeans_cluster (kmeans);
+  quick_cluster_show_results (kmeans);
+  ok = proc_commit (ds);
+
+  kmeans_destroy (kmeans);
+
+  return (ok);
+}
index ec3052c0acee616def219464aa7bf19edfec4550..2247354dcd337557f2127e0ddbbd84ec599917bf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011 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 <gsl/gsl_cdf.h>
 #include <limits.h>
 #include <math.h>
 
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/missing-values.h>
-#include <data/procedure.h>
-#include <data/short-names.h>
-#include <data/subcase.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/stats/sort-criteria.h>
-#include <libpspp/compiler.h>
-#include <libpspp/taint.h>
-#include <math/sort.h>
-#include <output/tab.h>
-
-#include <gsl/gsl_cdf.h>
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/short-names.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/stats/sort-criteria.h"
+#include "libpspp/compiler.h"
+#include "libpspp/taint.h"
+#include "math/sort.h"
+#include "output/tab.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -225,7 +224,7 @@ create_var_label (struct variable *dest_var,
     ds_put_format (&label, _("%s of %s"),
                    function_name[f], var_get_name (src_var));
 
-  var_set_label (dest_var, ds_cstr (&label));
+  var_set_label (dest_var, ds_cstr (&label), false);
 
   ds_destroy (&label);
 }
@@ -280,7 +279,7 @@ rank_cmd (struct dataset *ds, const struct subcase *sc,
         }
       ok = casegrouper_destroy (split_grouper);
       ok = proc_commit (ds) && ok;
-      ok = (proc_set_active_file_data (ds, casewriter_make_reader (output))
+      ok = (dataset_set_source (ds, casewriter_make_reader (output))
             && ok);
       if (!ok)
         break;
@@ -674,10 +673,12 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
       int v;
       for ( v = 0 ; v < n_src_vars ;  v ++ )
        {
+          struct dictionary *dict = dataset_dict (ds);
+
          if ( rank_specs[i].destvars[v] == NULL )
            {
              rank_specs[i].destvars[v] =
-               create_rank_variable (dataset_dict(ds), rank_specs[i].rfunc, src_vars[v], NULL);
+               create_rank_variable (dict, rank_specs[i].rfunc, src_vars[v], NULL);
            }
 
          create_var_label ( rank_specs[i].destvars[v],
@@ -769,7 +770,7 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
   /* Do the ranking */
   result = rank_cmd (ds, &sc, rank_specs, n_rank_specs);
 
-  /* Put the active file back in its original order.  Delete
+  /* Put the active dataset back in its original order.  Delete
      our sort key, which we don't need anymore.  */
   {
     struct casereader *sorted;
@@ -781,7 +782,7 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
     result = proc_commit (ds) && result;
 
     dict_delete_var (dataset_dict (ds), order);
-    result = proc_set_active_file_data (ds, sorted) && result;
+    result = dataset_set_source (ds, sorted) && result;
   }
 
   rank_cleanup();
@@ -796,9 +797,9 @@ cmd_rank (struct lexer *lexer, struct dataset *ds)
 static int
 rank_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_rank *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
-  if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL)
+  if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) == NULL)
       && lex_token (lexer) != T_ALL)
       return 2;
 
@@ -808,7 +809,7 @@ rank_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_rank
 
   if ( lex_match (lexer, T_BY)  )
     {
-      if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL))
+      if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer)) == NULL))
        {
          return 2;
        }
@@ -847,9 +848,9 @@ parse_rank_function (struct lexer *lexer, struct dictionary *dict, struct cmd_ra
       while( lex_token (lexer) == T_ID )
        {
 
-         if ( dict_lookup_var (dict, lex_tokid (lexer)) != NULL )
+         if ( dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL )
            {
-             msg(SE, _("Variable %s already exists."), lex_tokid (lexer));
+             msg(SE, _("Variable %s already exists."), lex_tokcstr (lexer));
              return 0;
            }
          if ( var_count >= subcase_get_n_fields (&sc) )
@@ -858,7 +859,7 @@ parse_rank_function (struct lexer *lexer, struct dictionary *dict, struct cmd_ra
              return 0;
            }
 
-         destvar = create_rank_variable (dict, f, src_vars[var_count], lex_tokid (lexer));
+         destvar = create_rank_variable (dict, f, src_vars[var_count], lex_tokcstr (lexer));
          rank_specs[n_rank_specs - 1].destvars[var_count] = destvar ;
 
          lex_get (lexer);
@@ -932,13 +933,13 @@ rank_custom_ntiles (struct lexer *lexer, struct dataset *ds, struct cmd_rank *cm
 {
   struct dictionary *dict = dataset_dict (ds);
 
-  if ( lex_force_match (lexer, '(') )
+  if ( lex_force_match (lexer, T_LPAREN) )
     {
       if ( lex_force_int (lexer) )
        {
          k_ntiles = lex_integer (lexer);
          lex_get (lexer);
-         lex_force_match (lexer, ')');
+         lex_force_match (lexer, T_RPAREN);
        }
       else
        return 0;
index 8f9979ae73306476c8eec5a6c42105a01a951d7a..c41f9e7895e7e05595331b767994a725cf417914 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009, 2010, 2011 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 <gsl/gsl_vector.h>
 #include <math.h>
 #include <stdlib.h>
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/missing-values.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/data-io/file-handle.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/taint.h>
-#include <math/covariance.h>
-#include <math/linreg.h>
-#include <math/moments.h>
-#include <output/tab.h>
-
-#include "xalloc.h"
+
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/missing-values.h"
+#include "data/transformations.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/taint.h"
+#include "math/covariance.h"
+#include "math/linreg.h"
+#include "math/moments.h"
+#include "output/tab.h"
+
+#include "gl/intprops.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -206,7 +208,7 @@ reg_stats_coeff (linreg * c, void *aux_)
   tab_double (t, 4, 1, 0, 0.0, NULL);
   t_stat = linreg_intercept (c) / std_err;
   tab_double (t, 5, 1, 0, t_stat, NULL);
-  pval = 2 * gsl_cdf_tdist_Q (fabs (t_stat), 1.0);
+  pval = 2 * gsl_cdf_tdist_Q (fabs (t_stat), (double) (linreg_n_obs (c) - linreg_n_coeffs (c)));
   tab_double (t, 6, 1, 0, pval, NULL);
   for (j = 0; j < linreg_n_coeffs (c); j++)
     {
@@ -602,29 +604,19 @@ regression_trns_resid_proc (void *t_, struct ccase **c,
   return TRNS_CONTINUE;
 }
 
-/*
-   Returns false if NAME is a duplicate of any existing variable name.
-*/
-static bool
-try_name (const struct dictionary *dict, const char *name)
+static char *
+reg_get_name (const struct dictionary *dict, const char *prefix)
 {
-  if (dict_lookup_var (dict, name) != NULL)
-    return false;
-
-  return true;
-}
-
-static void
-reg_get_name (const struct dictionary *dict, char name[VAR_NAME_LEN],
-             const char prefix[VAR_NAME_LEN])
-{
-  int i = 1;
+  char *name;
+  int i;
 
-  snprintf (name, VAR_NAME_LEN, "%s%d", prefix, i);
-  while (!try_name (dict, name))
+  /* XXX handle too-long prefixes */
+  name = xmalloc (strlen (prefix) + INT_BUFSIZE_BOUND (i) + 1);
+  for (i = 1; ; i++)
     {
-      i++;
-      snprintf (name, VAR_NAME_LEN, "%s%d", prefix, i);
+      sprintf (name, "%s%d", prefix, i);
+      if (dict_lookup_var (dict, name) == NULL)
+        return name;
     }
 }
 
@@ -634,7 +626,7 @@ reg_save_var (struct dataset *ds, const char *prefix, trns_proc_func * f,
 {
   struct dictionary *dict = dataset_dict (ds);
   static int trns_index = 1;
-  char name[VAR_NAME_LEN];
+  char *name;
   struct variable *new_var;
   struct reg_trns *t = NULL;
 
@@ -642,9 +634,11 @@ reg_save_var (struct dataset *ds, const char *prefix, trns_proc_func * f,
   t->trns_id = trns_index;
   t->n_trns = n_trns;
   t->c = c;
-  reg_get_name (dict, name, prefix);
-  new_var = dict_create_var (dict, name, 0);
-  assert (new_var != NULL);
+
+  name = reg_get_name (dict, prefix);
+  new_var = dict_create_var_assert (dict, name, 0);
+  free (name);
+
   *v = new_var;
   add_transformation (ds, f, regression_trns_free, t);
   trns_index++;
@@ -752,10 +746,10 @@ regression_custom_variables (struct lexer *lexer, struct dataset *ds,
 {
   const struct dictionary *dict = dataset_dict (ds);
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if ((lex_token (lexer) != T_ID
-       || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
+       || dict_lookup_var (dict, lex_tokcstr (lexer)) == NULL)
       && lex_token (lexer) != T_ALL)
     return 2;
 
@@ -810,7 +804,7 @@ fill_covariance (gsl_matrix *cov, struct covariance *all_cov,
   size_t dep_subscript;
   size_t *rows;
   const gsl_matrix *ssizes;
-  const gsl_matrix *cm;
+  gsl_matrix *cm;
   const gsl_matrix *mean_matrix;
   const gsl_matrix *ssize_matrix;
   double result = 0.0;
index c73790713cebaceedf0bdc42a87e594eaa5cc43f..1c1212e3303d3ee3db98bec3c4142cb2a9a4d636 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <math.h>
 
-#include <libpspp/misc.h>
-
-#include <libpspp/str.h>
-#include <libpspp/message.h>
-
-
-#include <data/procedure.h>
-#include <data/missing-values.h>
-#include <data/casereader.h>
-#include <data/casegrouper.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-
-#include <language/lexer/variable-parser.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-
-#include <math/moments.h>
-#include <output/tab.h>
-#include <output/text-item.h>
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "math/moments.h"
+#include "output/tab.h"
+#include "output/text-item.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -129,21 +124,21 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
 
   reliability.total_start = 0;
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "VARIABLES"))
     {
       goto error;
     }
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if (!parse_variables_const (lexer, dict, &reliability.variables, &reliability.n_variables,
                              PV_NO_DUPLICATE | PV_NUMERIC))
     goto error;
 
   if (reliability.n_variables < 2)
-    msg (MW, _("Reliabilty on a single variable is not useful."));
+    msg (MW, _("Reliability on a single variable is not useful."));
 
 
     {
@@ -166,27 +161,27 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
 
 
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "SCALE"))
        {
          struct const_var_set *vs;
-         if ( ! lex_force_match (lexer, '('))
+         if ( ! lex_force_match (lexer, T_LPAREN))
            goto error;
 
          if ( ! lex_force_string (lexer) ) 
            goto error;
 
-         ds_init_string (&reliability.scale_name, lex_tokstr (lexer));
+         ds_init_substring (&reliability.scale_name, lex_tokss (lexer));
 
          lex_get (lexer);
 
-         if ( ! lex_force_match (lexer, ')'))
+         if ( ! lex_force_match (lexer, T_RPAREN))
            goto error;
 
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
          vs = const_var_set_create_from_array (reliability.variables, reliability.n_variables);
 
@@ -201,7 +196,7 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MODEL"))
        {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "ALPHA"))
            {
              reliability.model = MODEL_ALPHA;
@@ -211,12 +206,12 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
              reliability.model = MODEL_SPLIT;
              reliability.split_point = -1;
 
-             if ( lex_match (lexer, '('))
+             if ( lex_match (lexer, T_LPAREN))
                {
                  lex_force_num (lexer);
                  reliability.split_point = lex_number (lexer);
                  lex_get (lexer);
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
            }
          else
@@ -224,7 +219,7 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "SUMMARY"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "TOTAL"))
            {
              reliability.summary |= SUMMARY_TOTAL;
@@ -238,8 +233,8 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
index dd2093674b16c34ecb8db3702687b6b38cd5245e..471b946ee817b17124836b4f601d9358fbd833cf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <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 <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 "language/stats/roc.h"
 
 #include <gsl/gsl_cdf.h>
 
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.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 "gettext.h"
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
@@ -95,7 +95,7 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
   roc.dict = dataset_dict (ds);
   roc.state_var = NULL;
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
   if (!parse_variables_const (lexer, dict, &roc.vars, &roc.n_vars,
                              PV_APPEND | PV_NO_DUPLICATE | PV_NUMERIC))
     goto error;
@@ -107,28 +107,28 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
 
   roc.state_var = parse_variable (lexer, dict);
 
-  if ( !lex_force_match (lexer, '('))
+  if ( !lex_force_match (lexer, T_LPAREN))
     {
       goto error;
     }
 
   value_init (&roc.state_value, var_get_width (roc.state_var));
-  parse_value (lexer, &roc.state_value, var_get_width (roc.state_var));
+  parse_value (lexer, &roc.state_value, roc.state_var);
 
 
-  if ( !lex_force_match (lexer, ')'))
+  if ( !lex_force_match (lexer, T_RPAREN))
     {
       goto error;
     }
 
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
       if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -147,15 +147,15 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "PLOT"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "CURVE"))
            {
              roc.curve = true;
-             if (lex_match (lexer, '('))
+             if (lex_match (lexer, T_LPAREN))
                {
                  roc.reference = true;
                  lex_force_match_id (lexer, "REFERENCE");
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
            }
          else if (lex_match_id (lexer, "NONE"))
@@ -170,8 +170,8 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "PRINT"))
        {
-         lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+         lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "SE"))
                {
@@ -190,12 +190,12 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "CRITERIA"))
        {
-         lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+         lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
            {
              if (lex_match_id (lexer, "CUTOFF"))
                {
-                 lex_force_match (lexer, '(');
+                 lex_force_match (lexer, T_LPAREN);
                  if (lex_match_id (lexer, "INCLUDE"))
                    {
                      roc.exclude = MV_SYSTEM;
@@ -209,11 +209,11 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
                      lex_error (lexer, NULL);
                      goto error;
                    }
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
              else if (lex_match_id (lexer, "TESTPOS"))
                {
-                 lex_force_match (lexer, '(');
+                 lex_force_match (lexer, T_LPAREN);
                  if (lex_match_id (lexer, "LARGE"))
                    {
                      roc.invert = false;
@@ -227,19 +227,19 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
                      lex_error (lexer, NULL);
                      goto error;
                    }
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
              else if (lex_match_id (lexer, "CI"))
                {
-                 lex_force_match (lexer, '(');
+                 lex_force_match (lexer, T_LPAREN);
                  lex_force_num (lexer);
                  roc.ci = lex_number (lexer);
                  lex_get (lexer);
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
              else if (lex_match_id (lexer, "DISTRIBUTION"))
                {
-                 lex_force_match (lexer, '(');
+                 lex_force_match (lexer, T_LPAREN);
                  if (lex_match_id (lexer, "FREE"))
                    {
                      roc.bi_neg_exp = false;
@@ -253,7 +253,7 @@ cmd_roc (struct lexer *lexer, struct dataset *ds)
                      lex_error (lexer, NULL);
                      goto error;
                    }
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
              else
                {
diff --git a/src/language/stats/runs.c b/src/language/stats/runs.c
new file mode 100644 (file)
index 0000000..9fc571c
--- /dev/null
@@ -0,0 +1,404 @@
+/* PSPP - a program for statistical analysis. -*-c-*-
+   Copyright (C) 2010, 2011 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 "language/stats/runs.h"
+
+#include <gsl/gsl_cdf.h>
+#include <math.h>
+
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "math/percentiles.h"
+#include "math/sort.h"
+#include "output/tab.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+
+struct run_state
+{
+  /* The value used to dichotimise the data */
+  double cutpoint;
+
+  /* The number of cases not less than cutpoint */
+  double np;
+
+  /* The number of cases less than cutpoint */
+  double nn;
+
+  /* The sum of np and nn */
+  double n;
+
+  /* The number of runs */
+  long runs;
+
+  /* The sign of the last case seen */
+  short last_sign;
+};
+
+
+
+/* Return the Z statistic representing the assympototic
+   distribution of the the number of runs */
+static double
+runs_statistic (const struct run_state *rs)
+{
+  double z;
+  double sigma;
+  double mu  = 2 * rs->np * rs->nn;
+  mu /= rs->np + rs->nn;
+  mu += 1.0;
+
+  z = rs->runs - mu;
+
+  if ( rs->n < 50)
+    {
+      if (z <= -0.5)
+       z += 0.5;
+      else if (z >= 0.5)
+       z -= 0.5;
+      else
+       return 0;
+    }
+
+  sigma = 2 * rs->np * rs->nn;
+  sigma *= 2 * rs->np * rs->nn - rs->nn - rs->np;
+  sigma /= pow2 (rs->np + rs->nn);
+  sigma /= rs->np + rs->nn - 1.0;
+  sigma = sqrt (sigma);
+
+  z /= sigma;
+
+  return z;
+}
+
+static void show_runs_result (const struct runs_test *, const struct run_state *, const struct dictionary *);
+
+void 
+runs_execute (const struct dataset *ds,
+             struct casereader *input,
+             enum mv_class exclude,
+             const struct npar_test *test,
+             bool exact UNUSED,
+             double timer UNUSED)
+{
+  int v;
+  struct ccase *c;
+  const struct dictionary *dict = dataset_dict (ds);
+  const struct variable *weight = dict_get_weight (dict);
+
+  struct one_sample_test *otp = UP_CAST (test, struct one_sample_test, parent);
+  struct runs_test *rt = UP_CAST (otp, struct runs_test, parent);
+  struct run_state *rs = xcalloc (otp->n_vars, sizeof (*rs));
+
+  switch  ( rt->cp_mode)
+    {
+    case CP_MODE:
+      {
+       for (v = 0; v < otp->n_vars; ++v)
+         {
+           bool multimodal = false;
+           struct run_state *run = &rs[v];
+           double last_cc;
+           struct casereader *group = NULL;
+           struct casegrouper *grouper;
+           struct casereader *reader = casereader_clone (input);
+           const struct variable *var = otp->vars[v];
+
+           reader = sort_execute_1var (reader, var);
+           
+           grouper = casegrouper_create_vars (reader, &var, 1);
+           last_cc = SYSMIS;
+           while (casegrouper_get_next_group (grouper, &group))
+             {
+               double x = SYSMIS;
+               double cc = 0.0;
+               struct ccase *c;
+               for (; (c = casereader_read (group)); case_unref (c))
+                 {
+                   const double w = weight ? case_data (c, weight)->f: 1.0;
+                   const union value *val = case_data (c, var);
+                   if ( var_is_value_missing (var, val, exclude))
+                     continue;
+                   x = val->f;
+                   cc += w;
+                 }
+
+               if ( cc > last_cc)
+                 {
+                   run->cutpoint = x;
+                 }
+               else if ( cc == last_cc)
+                 {
+                   multimodal = true;
+                   if ( x > run->cutpoint)
+                     run->cutpoint = x;
+                 }
+               last_cc = cc;
+               casereader_destroy (group);
+             }
+           casegrouper_destroy (grouper);
+           if (multimodal)
+             msg (MW, _("Multiple modes exist for varible `%s'.  Using %g as the threshold value."),
+                  var_get_name (var), run->cutpoint);
+         }
+      }
+      break;
+    case CP_MEDIAN:
+      {
+       for (v = 0; v < otp->n_vars; ++v)
+         {
+           double cc = 0.0;
+           struct ccase *c;
+           struct run_state *run = &rs[v];
+           struct casereader *reader = casereader_clone (input);
+           const struct variable *var = otp->vars[v];
+           struct casewriter *writer;
+           struct percentile *median;
+           struct order_stats *os;
+           struct subcase sc;
+           subcase_init_var (&sc, var, SC_ASCEND);
+           writer = sort_create_writer (&sc, casereader_get_proto (reader));
+
+           for (; (c = casereader_read (reader)); )
+             {
+               const union value *val = case_data (c, var);
+               const double w = weight ? case_data (c, weight)->f: 1.0;
+               if ( var_is_value_missing (var, val, exclude))
+                 {
+                   case_unref (c);
+                   continue;
+                 }
+
+               cc += w;
+               casewriter_write (writer, c);
+             }
+           subcase_destroy (&sc);
+           casereader_destroy (reader);
+           reader = casewriter_make_reader (writer);
+
+           median = percentile_create (0.5, cc);
+           os = &median->parent;
+           
+           order_stats_accumulate (&os, 1,
+                                   reader,
+                                   weight,
+                                   var,
+                                   exclude);
+
+           run->cutpoint = percentile_calculate (median, PC_HAVERAGE);
+           statistic_destroy (&median->parent.parent);
+         }
+      }
+      break;
+    case CP_MEAN:
+      {
+       struct casereader *reader = casereader_clone (input);
+       for (; (c = casereader_read (reader)); case_unref (c))
+         {
+           const double w = weight ? case_data (c, weight)->f: 1.0;
+           for (v = 0; v < otp->n_vars; ++v)
+             {
+               const struct variable *var = otp->vars[v];
+               const union value *val = case_data (c, var);
+               const double x = val->f;
+               struct run_state *run = &rs[v];
+
+               if ( var_is_value_missing (var, val, exclude))
+                 continue;
+
+               run->cutpoint += x * w;
+               run->n += w;
+             }
+         }
+       casereader_destroy (reader);
+       for (v = 0; v < otp->n_vars; ++v)
+         {
+           struct run_state *run = &rs[v];
+           run->cutpoint /= run->n;
+         }
+      }
+      break;
+    case CP_CUSTOM:
+      {
+      for (v = 0; v < otp->n_vars; ++v)
+       {
+         struct run_state *run = &rs[v];
+         run->cutpoint = rt->cutpoint;
+       }
+      }
+      break;
+    }
+
+  for (; (c = casereader_read (input)); case_unref (c))
+    {
+      const double w = weight ? case_data (c, weight)->f: 1.0;
+
+      for (v = 0; v < otp->n_vars; ++v)
+       {
+         struct run_state *run = &rs[v];
+         const struct variable *var = otp->vars[v];
+         const union value *val = case_data (c, var);
+         double x = val->f;
+         double d = x - run->cutpoint;
+         short sign = 0;
+
+         if ( var_is_value_missing (var, val, exclude))
+           continue;
+
+         if (d >= 0)
+           {
+             sign = +1;
+             run->np += w;
+           }
+         else
+           {
+             sign = -1;
+             run->nn += w;
+           }
+
+         if (sign != run->last_sign)
+           run->runs++;
+
+         run->last_sign = sign;
+       }
+    }
+  casereader_destroy (input);
+
+  for (v = 0; v < otp->n_vars; ++v)
+    {
+      struct run_state *run = &rs[v];
+      run->n = run->np + run->nn;
+    }
+
+  show_runs_result (rt, rs, dict);
+
+  free (rs);
+}
+
+\f
+
+static void
+show_runs_result (const struct runs_test *rt, const struct run_state *rs, const struct dictionary *dict)
+{
+  const struct variable *weight = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = weight ? var_get_print_format (weight) : &F_8_0;
+
+  const struct one_sample_test *otp = &rt->parent;
+
+  int i;
+  const int row_headers = 1;
+  const int column_headers = 1;
+  struct tab_table *table =
+    tab_create (row_headers + otp->n_vars, column_headers + 7);
+
+  tab_headers (table, row_headers, 0, column_headers, 0);
+
+  tab_title (table, _("Runs Test"));
+
+  /* Box around the table and vertical lines inside*/
+  tab_box (table, TAL_2, TAL_2, -1, TAL_1,
+          0,  0, tab_nc (table) - 1, tab_nr (table) - 1 );
+
+  tab_hline (table, TAL_2, 0, tab_nc (table) -1, column_headers);
+  tab_vline (table, TAL_2, row_headers, 0, tab_nr (table) - 1);
+
+  for (i = 0 ; i < otp->n_vars; ++i)
+    {
+      const struct run_state *run = &rs[i];
+
+      double z = runs_statistic (run);
+
+      tab_text (table,  row_headers + i, 0, 
+               TAT_TITLE | TAB_CENTER ,
+               var_to_string (otp->vars[i]));
+
+      tab_double (table, row_headers +i, 1, 0,
+                 run->cutpoint, 0);
+
+      tab_double (table, row_headers +i, 2, 0,
+                 run->nn, wfmt);
+                 
+      tab_double (table, row_headers +i, 3, 0,
+                 run->np, wfmt);
+
+      tab_double (table, row_headers +i, 4, 0,
+                 run->n, wfmt);
+
+      tab_double (table, row_headers +i, 5, 0,
+                 run->runs, &F_8_0);
+
+      tab_double (table, row_headers +i, 6, 0,
+                 z, 0);
+
+      tab_double (table, row_headers +i, 7, 0,
+                 2.0 * gsl_cdf_ugaussian_P (z), 0);
+    }
+
+  switch  ( rt->cp_mode)
+    {
+    case CP_CUSTOM:
+      tab_text (table,  0, column_headers ,
+               TAT_TITLE | TAB_LEFT , _("Test Value"));
+      break;
+    case CP_MODE:
+      tab_text (table,  0, column_headers ,
+               TAT_TITLE | TAB_LEFT , _("Test Value (mode)"));
+      break;
+    case CP_MEAN:
+      tab_text (table,  0, column_headers ,
+               TAT_TITLE | TAB_LEFT , _("Test Value (mean)"));
+      break;
+    case CP_MEDIAN:
+      tab_text (table,  0, column_headers ,
+               TAT_TITLE | TAB_LEFT , _("Test Value (median)"));
+      break;
+    }
+
+  tab_text (table,  0, column_headers + 1,
+           TAT_TITLE | TAB_LEFT , _("Cases < Test Value"));
+
+  tab_text (table,  0, column_headers + 2,
+           TAT_TITLE | TAB_LEFT , _("Cases >= Test Value"));
+
+  tab_text (table,  0, column_headers + 3,
+           TAT_TITLE | TAB_LEFT , _("Total Cases"));
+
+  tab_text (table,  0, column_headers + 4,
+           TAT_TITLE | TAB_LEFT , _("Number of Runs"));
+
+  tab_text (table,  0, column_headers + 5,
+           TAT_TITLE | TAB_LEFT , _("Z"));
+
+  tab_text (table,  0, column_headers + 6,
+           TAT_TITLE | TAB_LEFT , _("Asymp. Sig. (2-tailed)"));
+
+  tab_submit (table);
+}
+
+
diff --git a/src/language/stats/runs.h b/src/language/stats/runs.h
new file mode 100644 (file)
index 0000000..8dbce96
--- /dev/null
@@ -0,0 +1,51 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2006, 2011 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 !runs_h
+#define runs_h 1
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "language/stats/npar.h"
+
+enum cp_mode
+  {
+    CP_MEAN,
+    CP_MEDIAN,
+    CP_MODE,
+    CP_CUSTOM
+  };
+
+
+struct runs_test
+{
+  struct one_sample_test parent;
+
+  double cutpoint;
+
+  enum cp_mode cp_mode;
+};
+
+
+void runs_execute (const struct dataset *ds,
+                       struct casereader *input,
+                        enum mv_class exclude,
+                       const struct npar_test *test,
+                       bool,
+                  double);
+
+
+#endif
index 3848911313ed62721eff29b20d6fd9bdf14ca6e9..0048eb3e5a810ee867cc485008ab5b9151fb3111 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 "sign.h"
 
-#include <data/variable.h>
-#include <libpspp/str.h>
-#include <output/tab.h>
+#include "language/stats/sign.h"
+
 #include <gsl/gsl_cdf.h>
 #include <gsl/gsl_randist.h>
-#include "npar.h"
-#include <data/procedure.h>
-#include <data/missing-values.h>
-#include <data/dictionary.h>
-#include <data/casereader.h>
-#include <data/format.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "data/variable.h"
+#include "language/stats/npar.h"
+#include "libpspp/str.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 1404e00685da0e8acecb2ccf8818f1cd7cfa0879..d23b8351aef999885ea83e7138513a8153b1da9d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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,7 +19,7 @@
 
 
 #include <stdbool.h>
-#include <data/missing-values.h>
+#include "data/missing-values.h"
 
 struct casereader;
 struct dataset;
index deb8b5cbc97b00f1ee4cd7da54bbff8701260ffa..cb60901fe64ed3dc8ca03a6df004dedc8608d079 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, 2011 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 <assert.h>
-#include <stdlib.h>
 #include <limits.h>
-
-#include "sort-criteria.h"
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <data/subcase.h>
-#include <math/sort.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/settings.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/stats/sort-criteria.h"
+#include "libpspp/message.h"
+#include "math/sort.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -52,9 +52,9 @@ cmd_sort_cases (struct lexer *lexer, struct dataset *ds)
   if (!parse_sort_criteria (lexer, dataset_dict (ds), &ordering, NULL, NULL))
     return CMD_CASCADING_FAILURE;
 
-  if (settings_get_testing_mode () && lex_match (lexer, '/'))
+  if (settings_get_testing_mode () && lex_match (lexer, T_SLASH))
     {
-      if (!lex_force_match_id (lexer, "BUFFERS") || !lex_match (lexer, '=')
+      if (!lex_force_match_id (lexer, "BUFFERS") || !lex_match (lexer, T_EQUALS)
           || !lex_force_int (lexer))
         goto done;
 
@@ -69,15 +69,15 @@ cmd_sort_cases (struct lexer *lexer, struct dataset *ds)
     }
 
   proc_discard_output (ds);
-  output = sort_execute (proc_open (ds), &ordering);
+  output = sort_execute (proc_open_filtering (ds, false), &ordering);
   ok = proc_commit (ds);
-  ok = proc_set_active_file_data (ds, output) && ok;
+  ok = dataset_set_source (ds, output) && ok;
 
  done:
   min_buffers = 64;
   max_buffers = INT_MAX;
 
   subcase_destroy (&ordering);
-  return ok ? lex_end_of_command (lexer) : CMD_CASCADING_FAILURE;
+  return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
 
index 9ae299ee6c9e67da5513784eb266c56405e0da20..b8bdbd06f85b658808e7cfd6126a9350b845ab00 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, 2011 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 <language/stats/sort-criteria.h>
+#include "language/stats/sort-criteria.h"
 
 #include <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/subcase.h>
-#include <data/variable.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
+#include "data/dictionary.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -63,7 +63,7 @@ parse_sort_criteria (struct lexer *lexer, const struct dictionary *dict,
         goto error;
 
       /* Sort direction. */
-      if (lex_match (lexer, '('))
+      if (lex_match (lexer, T_LPAREN))
        {
          if (lex_match_id (lexer, "D") || lex_match_id (lexer, "DOWN"))
            direction = SC_DESCEND;
@@ -74,7 +74,7 @@ parse_sort_criteria (struct lexer *lexer, const struct dictionary *dict,
              msg (SE, _("`A' or `D' expected inside parentheses."));
               goto error;
            }
-         if (!lex_match (lexer, ')'))
+         if (!lex_match (lexer, T_RPAREN))
            {
              msg (SE, _("`)' expected."));
               goto error;
@@ -94,7 +94,7 @@ parse_sort_criteria (struct lexer *lexer, const struct dictionary *dict,
         }
     }
   while (lex_token (lexer) == T_ID
-         && dict_lookup_var (dict, lex_tokid (lexer)) != NULL);
+         && dict_lookup_var (dict, lex_tokcstr (lexer)) != NULL);
 
   free (local_vars);
   return true;
index 9eb2c471356b2daa7a6e94f7a7174aac1c7cb65f..d26fc8a4cffe6385cab26340e656698cab237d02 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/casegrouper.h>
-#include <data/casereader.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/value-labels.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/dictionary/split-file.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/value-parser.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-#include <libpspp/taint.h>
-#include <math/group-proc.h>
-#include <math/levene.h>
-#include <math/correlation.h>
-#include <output/tab.h>
-#include <data/format.h>
-
-#include "minmax.h"
-#include "xalloc.h"
-#include "xmemdup0.h"
+#include "data/case.h"
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/value-labels.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/dictionary/split-file.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hash.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "libpspp/taint.h"
+#include "math/correlation.h"
+#include "math/group-proc.h"
+#include "math/levene.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -164,6 +164,8 @@ static int compare_group_binary (const struct group_statistics *a,
 static unsigned hash_group_binary (const struct group_statistics *g,
                                   const struct t_test_proc *p);
 
+static void t_test_proc_destroy (struct t_test_proc *proc);
+
 int
 cmd_t_test (struct lexer *lexer, struct dataset *ds)
 {
@@ -189,7 +191,7 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds)
     {
       msg (SE, _("Exactly one of TESTVAL, GROUPS and PAIRS subcommands "
                  "must be specified."));
-      goto done;
+      goto error;
     }
 
   proc.mode = (cmd.sbc_testval ? T_1_SAMPLE
@@ -209,7 +211,7 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds)
       if (cmd.sbc_variables)
        {
          msg (SE, _("VARIABLES subcommand may not be used with PAIRS."));
-          goto done;
+          goto error;
        }
 
       /* Fill proc.vars with the unique variables from pairs. */
@@ -228,7 +230,7 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds)
       if (!cmd.n_variables)
         {
           msg (SE, _("One or more VARIABLES must be specified."));
-          goto done;
+          goto error;
         }
       proc.n_vars = cmd.n_variables;
       proc.vars = cmd.v_variables;
@@ -240,31 +242,33 @@ cmd_t_test (struct lexer *lexer, struct dataset *ds)
   while (casegrouper_get_next_group (grouper, &group))
     calculate (&proc, group, ds);
   ok = casegrouper_destroy (grouper);
+
+  /* Free 'proc' then commit the procedure.  Must happen in this order because
+     if proc->indep_var was created by a temporary transformation then
+     committing will destroy it.  */
+  t_test_proc_destroy (&proc);
   ok = proc_commit (ds) && ok;
 
-  if (proc.mode == T_IND_SAMPLES)
-    {
-      int v;
-      /* Destroy any group statistics we created */
-      for (v = 0; v < proc.n_vars; v++)
-       {
-         struct group_proc *grpp = group_proc_get (proc.vars[v]);
-         hsh_destroy (grpp->group_hash);
-       }
-    }
+  return ok ? CMD_SUCCESS : CMD_FAILURE;
 
-done:
+error:
   free_t_test (&cmd);
 parse_failed:
-  if (proc.indep_var != NULL)
+  t_test_proc_destroy (&proc);
+  return CMD_FAILURE;
+}
+
+static void
+t_test_proc_destroy (struct t_test_proc *proc)
+{
+  if (proc->indep_var != NULL)
     {
-      int width = var_get_width (proc.indep_var);
-      value_destroy (&proc.g_value[0], width);
-      value_destroy (&proc.g_value[1], width);
+      int width = var_get_width (proc->indep_var);
+      value_destroy (&proc->g_value[0], width);
+      value_destroy (&proc->g_value[1], width);
     }
-  free (proc.vars);
-  free (proc.pairs);
-  return ok ? CMD_SUCCESS : CMD_FAILURE;
+  free (proc->vars);
+  free (proc->pairs);
 }
 
 static int
@@ -275,7 +279,7 @@ tts_custom_groups (struct lexer *lexer, struct dataset *ds,
   int n_values;
   int width;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   proc->indep_var = parse_variable (lexer, dataset_dict (ds));
   if (proc->indep_var == NULL)
@@ -287,19 +291,19 @@ tts_custom_groups (struct lexer *lexer, struct dataset *ds,
   value_init (&proc->g_value[0], width);
   value_init (&proc->g_value[1], width);
 
-  if (!lex_match (lexer, '('))
+  if (!lex_match (lexer, T_LPAREN))
     n_values = 0;
   else
     {
-      if (!parse_value (lexer, &proc->g_value[0], width))
+      if (!parse_value (lexer, &proc->g_value[0], proc->indep_var))
         return 0;
-      lex_match (lexer, ',');
-      if (lex_match (lexer, ')'))
+      lex_match (lexer, T_COMMA);
+      if (lex_match (lexer, T_RPAREN))
         n_values = 1;
       else
         {
-          if (!parse_value (lexer, &proc->g_value[1], width)
-              || !lex_force_match (lexer, ')'))
+          if (!parse_value (lexer, &proc->g_value[1], proc->indep_var)
+              || !lex_force_match (lexer, T_RPAREN))
             return 0;
           n_values = 2;
         }
@@ -355,7 +359,7 @@ tts_custom_pairs (struct lexer *lexer, struct dataset *ds,
   size_t n_total_pairs;
   size_t i, j;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if (!parse_variables_const (lexer, dataset_dict (ds), &vars1, &n_vars1,
                               PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH))
@@ -370,9 +374,9 @@ tts_custom_pairs (struct lexer *lexer, struct dataset *ds,
           return 0;
         }
 
-      if (lex_match (lexer, '(')
+      if (lex_match (lexer, T_LPAREN)
           && lex_match_id (lexer, "PAIRED")
-          && lex_match (lexer, ')'))
+          && lex_match (lexer, T_RPAREN))
         {
           paired = true;
           if (n_vars1 != n_vars2)
index 268296d7e6ee404f2a6657d7970ec385628ff05e..ed6225df6cee329ab33be3f737829e5ab9bf3f1d 100644 (file)
@@ -1,5 +1,5 @@
 /* Pspp - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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 "wilcoxon.h"
+#include "language/stats/wilcoxon.h"
 
 #include <gsl/gsl_cdf.h>
 #include <math.h>
 
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/subcase.h>
-#include <data/variable.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <math/sort.h>
-#include <math/wilcoxon-sig.h>
-#include <output/tab.h>
-
-#include "minmax.h"
-#include "xalloc.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/subcase.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "math/sort.h"
+#include "math/wilcoxon-sig.h"
+#include "output/tab.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 static double
 append_difference (const struct ccase *c, casenumber n UNUSED, void *aux)
index b0f86a2c9062abe99bff257db2f74f36859ef33f..1650badd00aef45f97c513f6d3c9a5c2a99ceeec 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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,9 +19,9 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <language/stats/npar.h>
-#include <data/case.h>
 
+#include "data/case.h"
+#include "language/stats/npar.h"
 
 struct rank_sum
 {
diff --git a/src/language/syntax-file.c b/src/language/syntax-file.c
deleted file mode 100644 (file)
index 83bd07b..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 "syntax-file.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <data/file-name.h>
-#include <data/settings.h>
-#include <data/variable.h>
-#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/version.h>
-#include <output/tab.h>
-
-#include <libpspp/ll.h>
-
-#include "prompt.h"
-
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-#include <libpspp/getl.h>
-
-
-struct syntax_file_source
-  {
-    struct getl_interface parent ;
-
-    FILE *syntax_file;
-
-    /* Current location. */
-    char *fn;                          /* File name. */
-    int ln;                            /* Line number. */
-  };
-
-static const char *
-name (const struct getl_interface *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 = UP_CAST (s, struct syntax_file_source,
-                                                  parent);
-  return sfs->ln;
-}
-
-
-/* Reads a line from syntax file source S into LINE.
-   Returns true if successful, false at end of file. */
-static bool
-read_syntax_file (struct getl_interface *s,
-                  struct string *line)
-{
-  struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
-                                            parent);
-
-  if (sfs->syntax_file == NULL)
-    return false;
-
-  /* Read line from file and remove new-line.
-     Skip initial "#! /usr/bin/pspp" line. */
-  do
-    {
-      sfs->ln++;
-      ds_clear (line);
-      if (!ds_read_line (line, sfs->syntax_file, SIZE_MAX))
-        {
-          if (ferror (sfs->syntax_file))
-            msg (ME, _("Reading `%s': %s."), sfs->fn, strerror (errno));
-          return false;
-        }
-      ds_chomp (line, '\n');
-    }
-  while (sfs->ln == 1 && !memcmp (ds_cstr (line), "#!", 2));
-
-  return true;
-}
-
-static void
-syntax_close (struct getl_interface *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));
-  free (sfs->fn);
-  free (sfs);
-}
-
-static bool
-always_false (const struct getl_interface *s UNUSED)
-{
-  return false;
-}
-
-
-/* Creates a syntax file source with file name FN. */
-struct getl_interface *
-create_syntax_file_source (const char *fn)
-{
-  struct syntax_file_source *ss = xzalloc (sizeof (*ss));
-
-  ss->fn = xstrdup (fn);
-  ss->syntax_file = fn_open (ss->fn, "r");
-  if (ss->syntax_file == NULL)
-    msg (ME, _("Opening `%s': %s."), ss->fn, strerror (errno));
-
-  ss->parent.interactive = always_false;
-  ss->parent.read = read_syntax_file ;
-  ss->parent.filter = NULL;
-  ss->parent.close = syntax_close ;
-  ss->parent.name = name ;
-  ss->parent.location = line_number;
-
-  return &ss->parent;
-}
-
diff --git a/src/language/syntax-file.h b/src/language/syntax-file.h
deleted file mode 100644 (file)
index 8044f3c..0000000
+++ /dev/null
@@ -1,25 +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/>. */
-
-#if !SYNTAX_FILE
-#define SYNTAX_FILE 1
-
-struct getl_interface;
-
-/* Creates a syntax file source with file name FN. */
-struct getl_interface * create_syntax_file_source (const char *) ;
-
-#endif
diff --git a/src/language/syntax-string-source.c b/src/language/syntax-string-source.c
deleted file mode 100644 (file)
index 4f3c1c1..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/* PSPPIRE - a graphical interface for PSPP.
-   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
-   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/cast.h>
-#include <libpspp/getl.h>
-#include <libpspp/compiler.h>
-#include <libpspp/str.h>
-
-#include <stdlib.h>
-
-#include "syntax-string-source.h"
-
-#include "xalloc.h"
-
-struct syntax_string_source
-  {
-    struct getl_interface parent;
-    struct string buffer;
-    size_t posn;
-  };
-
-
-static bool
-always_false (const struct getl_interface *i UNUSED)
-{
-  return false;
-}
-
-/* Returns the name of the source */
-static const char *
-name (const struct getl_interface *i UNUSED)
-{
-  return NULL;
-}
-
-
-/* Returns the location within the source */
-static int
-location (const struct getl_interface *i UNUSED)
-{
-  return 0;
-}
-
-
-static void
-do_close (struct getl_interface *i )
-{
-  struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
-                                              parent);
-
-  ds_destroy (&sss->buffer);
-
-  free (sss);
-}
-
-
-
-static bool
-read_single_line (struct getl_interface *i,
-                 struct string *line)
-{
-  struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
-                                              parent);
-
-  size_t next;
-
-  if ( sss->posn == -1)
-    return false;
-
-  next = ss_find_char (ds_substr (&sss->buffer,
-                                 sss->posn, -1), '\n');
-
-  ds_assign_substring (line,
-                      ds_substr (&sss->buffer,
-                                 sss->posn,
-                                 next)
-                      );
-
-  if ( next != -1 )
-    sss->posn += next + 1; /* + 1 to skip newline */
-  else
-    sss->posn = -1; /* End of file encountered */
-
-  return true;
-}
-
-static struct syntax_string_source *
-create_syntax_string_source__ (void)
-{
-  struct syntax_string_source *sss = xzalloc (sizeof *sss);
-
-  sss->posn = 0;
-
-  sss->parent.interactive = always_false;
-  sss->parent.close = do_close;
-  sss->parent.read = read_single_line;
-
-  sss->parent.name = name;
-  sss->parent.location = location;
-
-  return sss;
-}
-
-struct getl_interface *
-create_syntax_string_source (const char *s)
-{
-  struct syntax_string_source *sss = create_syntax_string_source__ ();
-  ds_init_cstr (&sss->buffer, s);
-  return &sss->parent;
-}
-
-struct getl_interface *
-create_syntax_format_source (const char *format, ...)
-{
-  struct syntax_string_source *sss;
-  va_list args;
-
-  sss = create_syntax_string_source__ ();
-
-  ds_init_empty (&sss->buffer);
-
-  va_start (args, format);
-  ds_put_vformat (&sss->buffer, format, args);
-  va_end (args);
-
-  return &sss->parent;
-}
-
-/* Return the syntax currently contained in S.
-   Primarily usefull for debugging */
-const char *
-syntax_string_source_get_syntax (const struct syntax_string_source *s)
-{
-  return ds_cstr (&s->buffer);
-}
diff --git a/src/language/syntax-string-source.h b/src/language/syntax-string-source.h
deleted file mode 100644 (file)
index d2e1a9b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* PSPPIRE - a graphical interface for PSPP.
-   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
-   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 SYNTAX_STRING_SOURCE_H
-#define SYNTAX_STRING_SOURCE_H
-
-#include "libpspp/compiler.h"
-
-struct getl_interface;
-
-struct syntax_string_source;
-
-struct getl_interface *create_syntax_string_source (const char *);
-struct getl_interface *create_syntax_format_source (const char *, ...)
-  PRINTF_FORMAT (1, 2);
-
-const char * syntax_string_source_get_syntax (const struct syntax_string_source *s);
-
-
-#endif
index b2d5a1663f0808a8a6b9a6f09a3527eea61c3b24..b7a428b10478c294ec438e60e0c9f5485b40b9a4 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
 
 #include <config.h>
 
-#include <libpspp/float-format.h>
+#include "libpspp/float-format.h"
 
-#include "gettext.h"
 #include <inttypes.h>
+#include <limits.h>
+#include <unistr.h>
 
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-
-#define _(msgid) gettext (msgid)
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 /* Maximum supported size of a floating-point number, in bytes. */
 #define FP_MAX_SIZE 32
@@ -93,6 +93,32 @@ get_float_format_name (enum float_format format)
   NOT_REACHED ();
 }
 
+/* Returns the integer value of (hex) digit C. */
+static int
+digit_value (int c)
+{
+  switch (c)
+    {
+    case '0': return 0;
+    case '1': return 1;
+    case '2': return 2;
+    case '3': return 3;
+    case '4': return 4;
+    case '5': return 5;
+    case '6': return 6;
+    case '7': return 7;
+    case '8': return 8;
+    case '9': return 9;
+    case 'a': case 'A': return 10;
+    case 'b': case 'B': return 11;
+    case 'c': case 'C': return 12;
+    case 'd': case 'D': return 13;
+    case 'e': case 'E': return 14;
+    case 'f': case 'F': return 15;
+    default: return INT_MAX;
+    }
+}
+
 /* Parses a number in the form FORMAT(STRING), where FORMAT is
    the name of the format and STRING gives the number's
    representation.  Also supports ordinary floating-point numbers
@@ -100,6 +126,7 @@ get_float_format_name (enum float_format format)
 static bool
 parse_fp (struct lexer *lexer, struct fp *fp)
 {
+  memset (fp, 0, sizeof *fp);
   if (lex_is_number (lexer))
     {
       double number = lex_number (lexer);
@@ -109,38 +136,51 @@ parse_fp (struct lexer *lexer, struct fp *fp)
     }
   else if (lex_token (lexer) == T_ID)
     {
-      size_t length;
+      struct substring s;
 
       if (!parse_float_format (lexer, &fp->format)
-          || !lex_force_match (lexer, '(')
+          || !lex_force_match (lexer, T_LPAREN)
           || !lex_force_string (lexer))
         return false;
 
-      length = ds_length (lex_tokstr (lexer));
+      s = lex_tokss (lexer);
       if (fp->format != FLOAT_HEX)
         {
-          if (length != float_get_size (fp->format))
+          size_t i;
+
+          if (s.length != float_get_size (fp->format) * 2)
             {
-              msg (SE, _("%zu-byte string needed but %zu-byte string "
-                         "supplied."),
-                   float_get_size (fp->format), length);
+              msg (SE, "%zu-byte string needed but %zu-byte string "
+                   "supplied.", float_get_size (fp->format), s.length);
               return false;
             }
-          assert (length <= sizeof fp->data);
-          memcpy (fp->data, ds_data (lex_tokstr (lexer)), length);
+          assert (s.length / 2 <= sizeof fp->data);
+          for (i = 0; i < s.length / 2; i++)
+            {
+              int hi = digit_value (s.string[i * 2]);
+              int lo = digit_value (s.string[i * 2 + 1]);
+
+              if (hi >= 16 || lo >= 16)
+                {
+                  msg (SE, "Invalid hex digit in string.");
+                  return false;
+                }
+
+              fp->data[i] = hi * 16 + lo;
+            }
         }
       else
         {
-          if (length >= sizeof fp->data)
+          if (s.length >= sizeof fp->data)
             {
-              msg (SE, _("Hexadecimal floating constant too long."));
+              msg (SE, "Hexadecimal floating constant too long.");
               return false;
             }
-          strncpy (CHAR_CAST_BUG (char *,fp->data), ds_cstr (lex_tokstr (lexer)), sizeof fp->data);
+          memcpy (fp->data, s.string, s.length);
         }
 
       lex_get (lexer);
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         return false;
     }
   else
@@ -197,9 +237,8 @@ mismatch (const struct fp *from, const struct fp *to, char *result,
       make_printable (to->format, to->data, to_size, expected,
                       sizeof expected);
       make_printable (to->format, result, to_size, actual, sizeof actual);
-      msg (SE,
-           _("%s conversion of %s from %s to %s should have produced %s "
-             "but actually produced %s."),
+      msg (SE, "%s conversion of %s from %s to %s should have produced %s "
+           "but actually produced %s.",
            conversion_type,
            original, get_float_format_name (from->format),
            get_float_format_name (to->format), expected,
@@ -244,20 +283,20 @@ cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
     {
       if (fp_cnt >= sizeof fp / sizeof *fp)
         {
-          msg (SE, _("Too many values in single command."));
+          msg (SE, "Too many values in single command.");
           return CMD_FAILURE;
         }
       if (!parse_fp (lexer, &fp[fp_cnt++]))
         return CMD_FAILURE;
 
-      if (lex_token (lexer) == '.' && fp_cnt > 1)
+      if (lex_token (lexer) == T_ENDCMD && fp_cnt > 1)
         break;
-      else if (!lex_force_match (lexer, '='))
+      else if (!lex_force_match (lexer, T_EQUALS))
         return CMD_FAILURE;
 
       if (fp_cnt == 1)
         {
-          if (lex_match (lexer, '='))
+          if (lex_match (lexer, T_EQUALS))
             bijective = true;
           else if (lex_match (lexer, T_GT))
             bijective = false;
@@ -269,7 +308,7 @@ cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
         }
       else
         {
-          if ((bijective && !lex_force_match (lexer, '='))
+          if ((bijective && !lex_force_match (lexer, T_EQUALS))
               || (!bijective && !lex_force_match (lexer, T_GT)))
             return CMD_FAILURE;
         }
index 6285fc042c04a07cac583e68a38c814921ab4022..cd7ca52475591aed781542582ef6de17c55aa3fa 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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 <data/format.h>
-#include <data/format-guesser.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
+#include "data/format.h"
+#include "data/format-guesser.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
 
 /* Executes the DEBUG FORMAT GUESSER command. */
 int
@@ -35,8 +35,8 @@ cmd_debug_format_guesser (struct lexer *lexer, struct dataset *ds UNUSED)
   g = fmt_guesser_create ();
   while (lex_is_string (lexer))
     {
-      fprintf (stderr, "\"%s\" ", ds_cstr (lex_tokstr (lexer)));
-      fmt_guesser_add (g, ds_ss (lex_tokstr (lexer)));
+      fprintf (stderr, "\"%s\" ", lex_tokcstr (lexer));
+      fmt_guesser_add (g, lex_tokss (lexer));
       lex_get (lexer);
     }
 
@@ -53,5 +53,5 @@ cmd_debug_format_guesser (struct lexer *lexer, struct dataset *ds UNUSED)
   msg_enable ();
   putc ('\n', stderr);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index 795c7297431a98fc806e57c4ff2b5312c865b21f..af328928abddbff93e5cb6ac59ef955ef4367e0f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011 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 <stdio.h>
-#include "gettext.h"
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <math/moments.h>
+
 #include <math.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include "xalloc.h"
-#include <libpspp/compiler.h>
 
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "math/moments.h"
+
+#include "gl/xalloc.h"
+
+#include "gettext.h"
 #define _(msgid) gettext (msgid)
 
 static bool
@@ -40,7 +43,7 @@ read_values (struct lexer *lexer, double **values, double **weights, size_t *cnt
       double value = lex_tokval (lexer);
       double weight = 1.;
       lex_get (lexer);
-      if (lex_match (lexer, '*'))
+      if (lex_match (lexer, T_ASTERISK))
         {
           if (!lex_is_number (lexer))
             {
@@ -79,9 +82,9 @@ cmd_debug_moments (struct lexer *lexer, struct dataset *ds UNUSED)
 
   if (lex_match_id (lexer, "ONEPASS"))
     two_pass = 0;
-  if (lex_token (lexer) != '/')
+  if (lex_token (lexer) != T_SLASH)
     {
-      lex_force_match (lexer, '/');
+      lex_force_match (lexer, T_SLASH);
       goto done;
     }
   lex_get (lexer);
@@ -132,7 +135,7 @@ cmd_debug_moments (struct lexer *lexer, struct dataset *ds UNUSED)
     }
   fprintf (stderr, "\n");
 
-  retval = lex_end_of_command (lexer);
+  retval = CMD_SUCCESS;
 
  done:
   free (values);
index 5aea2c334f34f5157a7dbcd77d4fa0f4a478f6b7..0322f5728b80209a165a55693afdc42da4364e63 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2010, 2011 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 <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/string-map.h>
-#include <output/measure.h>
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/string-map.h"
+#include "output/measure.h"
 
 /* Executes the DEBUG PAPER SIZE command. */
 int
@@ -33,7 +33,7 @@ cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
 
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
-  paper_size = ds_cstr (lex_tokstr (lexer));
+  paper_size = lex_tokcstr (lexer);
 
   printf ("\"%s\" => ", paper_size);
   if (measure_paper (paper_size, &h, &v))
@@ -44,5 +44,5 @@ cmd_debug_paper_size (struct lexer *lexer, struct dataset *ds UNUSED)
     printf ("error\n");
   lex_get (lexer);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index df91f1ae70aa19271239e97711e16cf658fcaf3a..9bfcad0001560c55f9aa5e8abaff448188722e96 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2011 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 <libpspp/pool.h>
-#include <language/command.h>
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
+#include "libpspp/pool.h"
+#include "language/command.h"
+
 #define N_ITERATIONS 8192
 #define N_FILES 16
 
index 3a3e16d50af4ab1176215e9246ff9a868ef24751..46fe09c4518eb9c4bc06b3e308f10c979e1be819 100644 (file)
@@ -5,6 +5,7 @@ src_language_utilities_built_sources = \
        src/language/utilities/set.c
 
 language_utilities_sources = \
+       src/language/utilities/cache.c \
        src/language/utilities/cd.c \
        src/language/utilities/date.c \
        src/language/utilities/echo.c \
diff --git a/src/language/utilities/cache.c b/src/language/utilities/cache.c
new file mode 100644 (file)
index 0000000..dda055d
--- /dev/null
@@ -0,0 +1,34 @@
+/* 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 <errno.h>
+#include <unistd.h>
+
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Parses the CACHE command. */
+int
+cmd_cache (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
+{
+  return CMD_SUCCESS;
+}
+
index 38211e7661f8e6b0ac1978b56e6808150f794fbb..d28c0a30aa126d4a6b894e2e511a0d3607f21f47 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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 <language/command.h>
-#include <libpspp/message.h>
+
+#include "language/command.h"
+
 #include <errno.h>
-#include <language/lexer/lexer.h>
 #include <unistd.h>
 
+#include "language/lexer/lexer.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
@@ -33,7 +37,7 @@ cmd_cd (struct lexer *lexer, struct dataset *ds UNUSED)
   if ( ! lex_force_string (lexer))
     goto error;
 
-  path = ds_xstrdup (lex_tokstr (lexer));
+  path = utf8_to_filename (lex_tokcstr (lexer));
 
   if ( -1 == chdir (path) )
     {
@@ -44,6 +48,7 @@ cmd_cd (struct lexer *lexer, struct dataset *ds UNUSED)
     }
 
   free (path);
+  lex_get (lexer);
 
   return CMD_SUCCESS;
 
index f465eb37b5a4d8028ffa6e0abff62fa9926b4ee5..3b754b4980efa902ce155bc4708ce93c7358242f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2010, 2011 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 <language/command.h>
-#include <libpspp/message.h>
-#include <language/lexer/lexer.h>
+
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -27,7 +28,7 @@ int
 cmd_use (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   if (lex_match (lexer, T_ALL))
-    return lex_end_of_command (lexer);
+    return CMD_SUCCESS;
 
   msg (SW, _("Only USE ALL is currently implemented."));
   return CMD_FAILURE;
index b27b40017a367c397901acfb932bb1e81166ad2e..88ece636ad1e1ba1054c45d2fe16b3c6de187cf1 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <language/lexer/lexer.h>
-#include <language/command.h>
-#include <output/tab.h>
 
-#include "xalloc.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "output/text-item.h"
+
+#include "gl/xalloc.h"
 
 /* Echos a string to the output stream */
 int
 cmd_echo (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  struct tab_table *tab;
-
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
 
-  tab = tab_create(1, 1);
-
-  tab_text(tab, 0, 0, 0, ds_cstr (lex_tokstr (lexer)));
-
-  tab_submit(tab);
+  text_item_submit (text_item_create (TEXT_ITEM_ECHO, lex_tokcstr (lexer)));
+  lex_get (lexer);
 
   return CMD_SUCCESS;
 }
index ac09145451609c52d7236849631a38a0138bd34f..fbc9d208be7a08a1b4c518894f0e317d1413be5b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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/lexer/lexer.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/localcharset.h"
 #include "gl/xalloc.h"
 #include "gl/xmalloca.h"
 
@@ -129,35 +131,41 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
       return CMD_FAILURE;
     }
 
-  if (lex_token (lexer) == '.')
+  if (lex_token (lexer) == T_ENDCMD)
     return shell () ? CMD_SUCCESS : CMD_FAILURE;
   else if (lex_match_id (lexer, "COMMAND"))
     {
       struct string command;
+      char *locale_command;
       bool ok;
 
-      lex_match (lexer, '=');
-      if (!lex_force_match (lexer, '['))
+      lex_match (lexer, T_EQUALS);
+      if (!lex_force_match (lexer, T_LBRACK))
         return CMD_FAILURE;
 
       ds_init_empty (&command);
       while (lex_is_string (lexer))
         {
           if (!ds_is_empty (&command))
-            ds_put_char (&command, '\n');
-          ds_put_substring (&command, ds_ss (lex_tokstr (lexer)));
+            ds_put_byte (&command, '\n');
+          ds_put_substring (&command, lex_tokss (lexer));
           lex_get (lexer);
         }
-      if (!lex_force_match (lexer, ']'))
+      if (!lex_force_match (lexer, T_RBRACK))
         {
           ds_destroy (&command);
           return CMD_FAILURE;
         }
 
-      ok = run_command (ds_cstr (&command));
+      locale_command = recode_string (locale_charset (), "UTF-8",
+                                      ds_cstr (&command),
+                                      ds_length (&command));
       ds_destroy (&command);
 
-      return ok ? lex_end_of_command (lexer) : CMD_FAILURE;
+      ok = run_command (locale_command);
+      free (locale_command);
+
+      return ok ? CMD_SUCCESS : CMD_FAILURE;
     }
   else
     {
index 52d0e09c91dec5b559e8c86104917f08cad2b5dd..bcee162c6a04f56e44a01164d0c7af87662cba62 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, 2010, 2011 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 <data/file-name.h>
-#include <language/command.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/dataset.h"
+#include "data/file-name.h"
+#include "data/session.h"
+#include "language/command.h"
+#include "language/lexer/include-path.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "dirname.h"
-#include "xalloc.h"
+#include "gl/dirname.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static int parse_insert (struct lexer *lexer, char **filename);
+enum variant
+  {
+    INSERT,
+    INCLUDE
+  };
 
-
-int
-cmd_include (struct lexer *lexer, struct dataset *ds UNUSED)
+static int
+do_insert (struct lexer *lexer, struct dataset *ds, enum variant variant)
 {
-  char *filename = NULL;
-  int status = parse_insert (lexer, &filename);
-
-  if ( CMD_SUCCESS != status)
-    return status;
+  enum lex_syntax_mode syntax_mode;
+  enum lex_error_mode error_mode;
+  char *relative_name;
+  char *filename;
+  char *encoding;
+  int status;
+  bool cd;
 
-  lex_get (lexer);
-
-  status = lex_end_of_command (lexer);
+  /* Skip optional FILE=. */
+  if (lex_match_id (lexer, "FILE"))
+    lex_match (lexer, T_EQUALS);
 
-  if ( status == CMD_SUCCESS)
+  /* File name can be identifier or string. */
+  if (lex_token (lexer) != T_ID && !lex_is_string (lexer))
     {
-      struct source_stream *ss = lex_get_source_stream (lexer);
-
-      assert (filename);
-      getl_include_source (ss, create_syntax_file_source (filename),
-                          GETL_BATCH, ERRMODE_STOP);
-      free (filename);
+      lex_error (lexer, _("expecting file name"));
+      return CMD_FAILURE;
     }
 
-  return status;
-}
-
-
-int
-cmd_insert (struct lexer *lexer, struct dataset *ds UNUSED)
-{
-  enum syntax_mode syntax_mode = GETL_INTERACTIVE;
-  enum error_mode error_mode = ERRMODE_CONTINUE;
-  char *filename = NULL;
-  int status = parse_insert (lexer, &filename);
-  bool cd = false;
-
-  if ( CMD_SUCCESS != status)
-    return status;
+  relative_name = utf8_to_filename (lex_tokcstr (lexer)); 
+  filename = include_path_search (relative_name);
+  free (relative_name);
 
+  if ( ! filename)
+    {
+      msg (SE, _("Can't find `%s' in include file search path."),
+           lex_tokcstr (lexer));
+      return CMD_FAILURE;
+    }
   lex_get (lexer);
 
-  while ( '.' != lex_token (lexer))
+  syntax_mode = LEX_SYNTAX_INTERACTIVE;
+  error_mode = LEX_ERROR_CONTINUE;
+  cd = false;
+  status = CMD_FAILURE;
+  encoding = xstrdup (session_get_default_syntax_encoding (
+                        dataset_session (ds)));
+  while ( T_ENDCMD != lex_token (lexer))
     {
-      if (lex_match_id (lexer, "SYNTAX"))
+      if (lex_match_id (lexer, "ENCODING"))
+        {
+          lex_match (lexer, T_EQUALS);
+          if (!lex_force_string (lexer))
+            goto exit;
+
+          free (encoding);
+          encoding = xstrdup (lex_tokcstr (lexer));
+        }
+      else if (variant == INSERT && lex_match_id (lexer, "SYNTAX"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if ( lex_match_id (lexer, "INTERACTIVE") )
-           syntax_mode = GETL_INTERACTIVE;
+           syntax_mode = LEX_SYNTAX_INTERACTIVE;
          else if ( lex_match_id (lexer, "BATCH"))
-           syntax_mode = GETL_BATCH;
+           syntax_mode = LEX_SYNTAX_BATCH;
+         else if ( lex_match_id (lexer, "AUTO"))
+           syntax_mode = LEX_SYNTAX_AUTO;
          else
            {
-             lex_error (lexer, _("expecting %s or %s after %s"),
-                         "BATCH", "INTERACTIVE", "SYNTAX");
-             return CMD_FAILURE;
+             lex_error (lexer, _("expecting %s, %s, or %s after %s"),
+                         "BATCH", "INTERACTIVE", "AUTO", "SYNTAX");
+             goto exit;
            }
        }
-      else if (lex_match_id (lexer, "CD"))
+      else if (variant == INSERT && lex_match_id (lexer, "CD"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if ( lex_match_id (lexer, "YES") )
            {
              cd = true;
@@ -111,100 +126,71 @@ cmd_insert (struct lexer *lexer, struct dataset *ds UNUSED)
            {
              lex_error (lexer, _("expecting %s or %s after %s"),
                          "YES", "NO", "CD");
-             return CMD_FAILURE;
+             goto exit;
            }
        }
-      else if (lex_match_id (lexer, "ERROR"))
+      else if (variant == INSERT && lex_match_id (lexer, "ERROR"))
        {
-         lex_match (lexer, '=');
+         lex_match (lexer, T_EQUALS);
          if ( lex_match_id (lexer, "CONTINUE") )
            {
-             error_mode = ERRMODE_CONTINUE;
+             error_mode = LEX_ERROR_CONTINUE;
            }
          else if ( lex_match_id (lexer, "STOP"))
            {
-             error_mode = ERRMODE_STOP;
+             error_mode = LEX_ERROR_STOP;
            }
          else
            {
              lex_error (lexer, _("expecting %s or %s after %s"),
                          "CONTINUE", "STOP", "ERROR");
-             return CMD_FAILURE;
+             goto exit;
            }
        }
 
       else
        {
-         lex_error (lexer, _("Unexpected token: `%s'."),
-                    lex_token_representation (lexer));
-
-         return CMD_FAILURE;
+         lex_error (lexer, NULL);
+         goto exit;
        }
     }
-
   status = lex_end_of_command (lexer);
 
   if ( status == CMD_SUCCESS)
     {
-      struct source_stream *ss = lex_get_source_stream (lexer);
-
-      assert (filename);
-      getl_include_source (ss, create_syntax_file_source (filename),
-                          syntax_mode,
-                          error_mode);
-
-      if ( cd )
-       {
-         char *directory = dir_name (filename);
-         chdir (directory);
-         free (directory);
-       }
-
-      free (filename);
+      struct lex_reader *reader;
+
+      reader = lex_reader_for_file (filename, encoding,
+                                    syntax_mode, error_mode);
+      if (reader != NULL)
+        {
+          lex_discard_rest_of_command (lexer);
+          lex_include (lexer, reader);
+
+          if ( cd )
+            {
+              char *directory = dir_name (filename);
+              chdir (directory);
+              free (directory);
+            }
+        }
     }
 
+exit:
+  free (encoding);
+  free (filename);
   return status;
 }
 
-
-static int
-parse_insert (struct lexer *lexer, char **filename)
+int
+cmd_include (struct lexer *lexer, struct dataset *ds)
 {
-  char *target_fn;
-  char *relative_filename;
-
-  /* Skip optional FILE=. */
-  if (lex_match_id (lexer, "FILE"))
-    lex_match (lexer, '=');
-
-  /* File name can be identifier or string. */
-  if (lex_token (lexer) != T_ID && !lex_is_string (lexer))
-    {
-      lex_error (lexer, _("expecting file name"));
-      return CMD_FAILURE;
-    }
-
-  target_fn = ds_cstr (lex_tokstr (lexer));
-
-  relative_filename =
-    fn_search_path (target_fn,
-                   getl_include_path (lex_get_source_stream (lexer)));
-
-  if ( ! relative_filename)
-    {
-      msg (SE, _("Can't find `%s' in include file search path."),
-        target_fn);
-      return CMD_FAILURE;
-    }
-
-  *filename = relative_filename;
-  if (*filename == NULL) 
-    {
-      msg (SE, _("Unable to open `%s': %s."),
-           relative_filename, strerror (errno));
-      free (relative_filename);
-      return CMD_FAILURE;
-    }
+  return do_insert (lexer, ds, INCLUDE);
+}
 
-  return CMD_SUCCESS;
+int
+cmd_insert (struct lexer *lexer, struct dataset *ds)
+{
+  return do_insert (lexer, ds, INSERT);
 }
+
index 967b1bd2a1c314cca681dd78516084fd30921994..8b0e3f0c31926862e1135464460a30fccee3ca50 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2010, 2011 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 <libpspp/message.h>
+
+#include <errno.h>
 #include <stdlib.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include <errno.h>
-#include <data/settings.h>
-#include <language/command.h>
-#include <libpspp/message.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
+
+#include "data/settings.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -42,24 +44,24 @@ cmd_permissions (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   char  *fn = 0;
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
   if (lex_match_id (lexer, "FILE"))
-    lex_match (lexer, '=');
+    lex_match (lexer, T_EQUALS);
 
   if (!lex_force_string (lexer))
     return CMD_FAILURE;
 
-  fn = ds_xstrdup (lex_tokstr (lexer));
+  fn = ss_xstrdup (lex_tokss (lexer));
   lex_force_match (lexer, T_STRING);
 
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
   if ( ! lex_match_id (lexer, "PERMISSIONS"))
     goto error;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if ( lex_match_id (lexer, "READONLY"))
     {
@@ -93,20 +95,23 @@ cmd_permissions (struct lexer *lexer, struct dataset *ds UNUSED)
 int
 change_permissions (const char *file_name, enum PER per)
 {
+  char *locale_file_name;
   struct stat buf;
   mode_t mode;
 
   if (settings_get_safer_mode ())
     {
       msg (SE, _("This command not allowed when the SAFER option is set."));
-      return CMD_FAILURE;
+      return 0;
     }
 
 
-  if ( -1 == stat(file_name, &buf) )
+  locale_file_name = utf8_to_filename (file_name);
+  if ( -1 == stat(locale_file_name, &buf) )
     {
       const int errnum = errno;
       msg (SE, _("Cannot stat %s: %s"), file_name, strerror(errnum));
+      free (locale_file_name);
       return 0;
     }
 
@@ -115,13 +120,16 @@ change_permissions (const char *file_name, enum PER per)
   else
     mode = buf.st_mode & ~0222;
 
-  if ( -1 == chmod(file_name, mode))
+  if ( -1 == chmod(locale_file_name, mode))
 
     {
       const int errnum = errno;
       msg (SE, _("Cannot change mode of %s: %s"), file_name, strerror(errnum));
+      free (locale_file_name);
       return 0;
     }
 
+  free (locale_file_name);
+
   return 1;
 }
index 79fe9216b51f715a1e51f60240f60a2d54e8f51a..ce358ae8a4a7e1a21ee4f1246addd1012dbeb7c8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 <stdlib.h>
 #include <time.h>
 
-#include <data/data-in.h>
-#include <data/data-out.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/settings.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/prompt.h>
-#include <libpspp/compiler.h>
-#include <libpspp/copyleft.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/message.h>
-#include <libpspp/i18n.h>
-#include <math/random.h>
-#include <output/driver.h>
-#include <output/journal.h>
+#include "data/data-in.h"
+#include "data/data-out.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/copyleft.h"
+#include "libpspp/float-format.h"
+#include "libpspp/i18n.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
+#include "math/random.h"
+#include "output/driver.h"
+#include "output/journal.h"
 
 #if HAVE_LIBTERMCAP
 #if HAVE_TERMCAP_H
@@ -70,10 +69,7 @@ int tgetnum (const char *);
      cce=string;
      compression=compress:on/off;
      cpi=integer "x>0" "%s must be greater than 0";
-     cprompt=string;
      decimal=dec:dot/comma;
-     dprompt=string;
-     endcmd=string "x==1" "one character long";
      epoch=custom;
      errors=custom;
      format=custom;
@@ -97,9 +93,7 @@ int tgetnum (const char *);
      mxloops=integer "x >=1" "%s must be at least 1";
      mxmemory=integer;
      mxwarns=integer;
-     nulline=null:on/off;
      printback=custom;
-     prompt=string;
      results=custom;
      rib=rib:msbfirst/lsbfirst/vax/native;
      rrb=rrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
@@ -148,26 +142,15 @@ cmd_set (struct lexer *lexer, struct dataset *ds)
   if (cmd.sbc_cce)
     settings_set_cc ( cmd.s_cce, FMT_CCE);
 
-  if (cmd.sbc_prompt)
-    prompt_set (PROMPT_FIRST, cmd.s_prompt);
-  if (cmd.sbc_cprompt)
-    prompt_set (PROMPT_LATER, cmd.s_cprompt);
-  if (cmd.sbc_dprompt)
-    prompt_set (PROMPT_DATA, cmd.s_dprompt);
-
   if (cmd.sbc_decimal)
     settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ',');
 
-  if (cmd.sbc_endcmd)
-    settings_set_endcmd (cmd.s_endcmd[0]);
   if (cmd.sbc_include)
     settings_set_include (cmd.inc == STC_ON);
   if (cmd.sbc_mxerrs)
     settings_set_max_messages (MSG_S_ERROR, cmd.n_mxerrs[0]);
   if (cmd.sbc_mxwarns)
     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)
     settings_set_input_integer_format (stc_to_integer_format (cmd.rib));
   if (cmd.sbc_rrb)
@@ -271,7 +254,7 @@ set_output_routing (struct lexer *lexer, enum settings_output_type type)
 {
   enum settings_output_devices devices;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   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"))
@@ -299,7 +282,7 @@ stc_custom_blanks (struct lexer *lexer,
                   struct dataset *ds UNUSED,
                   struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "SYSMIS"))
     {
       lex_get (lexer);
@@ -322,7 +305,7 @@ stc_custom_epoch (struct lexer *lexer,
                  struct dataset *ds UNUSED,
                  struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "AUTOMATIC"))
     settings_set_epoch (-1);
   else if (lex_is_integer (lexer))
@@ -357,7 +340,7 @@ stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_se
 {
   int page_length;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "NONE"))
     page_length = -1;
   else
@@ -383,27 +366,26 @@ static int
 stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED,
                   struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  const struct string *s;
+  const char *s;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if ( !lex_force_string (lexer))
     return 0;
 
-  s = lex_tokstr (lexer);
+  s = lex_tokcstr (lexer);
 
   /* First try this string as an encoding name */
-  if ( valid_encoding (ds_cstr (s)))
-    set_default_encoding (ds_cstr (s));
+  if ( valid_encoding (s))
+    set_default_encoding (s);
 
   /* Now try as a locale name (or alias) */
-  else if (set_encoding_from_locale (ds_cstr (s)))
+  else if (set_encoding_from_locale (s))
     {
     }
   else
     {
-      msg (ME, _("%s is not a recognised encoding or locale name"),
-          ds_cstr (s));
+      msg (ME, _("%s is not a recognized encoding or locale name"), s);
       return 0;
     }
 
@@ -436,7 +418,7 @@ stc_custom_results (struct lexer *lexer, struct dataset *ds UNUSED,
 static int
 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "RANDOM"))
     set_rng (time (0));
   else
@@ -453,7 +435,7 @@ stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set
 static int
 stc_custom_width (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "NARROW"))
     settings_set_viewwidth (79);
   else if (lex_match_id (lexer, "WIDE"))
@@ -481,7 +463,7 @@ stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_se
 {
   struct fmt_spec fmt;
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (!parse_format_specifier (lexer, &fmt))
     return 0;
 
@@ -504,14 +486,17 @@ stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_se
 static int
 stc_custom_journal (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
   if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES"))
     journal_enable ();
   else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO"))
     journal_disable ();
   else if (lex_is_string (lexer) || lex_token (lexer) == T_ID)
     {
-      journal_set_file_name (ds_cstr (lex_tokstr (lexer)));
+      char *filename = utf8_to_filename (lex_tokcstr (lexer));
+      journal_set_file_name (filename);
+      free (filename);
+
       lex_get (lexer);
     }
   else
@@ -554,16 +539,16 @@ show_blanks (const struct dataset *ds UNUSED)
 }
 
 static void
-format_cc (struct string *out, struct substring in, char grouping)
+format_cc (struct string *out, const char *in, char grouping)
 {
-  while (!ss_is_empty (in))
+  while (*in != '\0')
     {
-      char c = ss_get_char (&in);
+      char c = *in++;
       if (c == grouping || c == '\'')
-        ds_put_char (out, '\'');
+        ds_put_byte (out, '\'');
       else if (c == '"')
-        ds_put_char (out, '"');
-      ds_put_char (out, c);
+        ds_put_byte (out, '"');
+      ds_put_byte (out, c);
     }
 }
 
@@ -574,13 +559,13 @@ show_cc (enum fmt_type type)
   struct string out;
 
   ds_init_empty (&out);
-  format_cc (&out, cc->neg_prefix, cc->grouping);
-  ds_put_char (&out, cc->grouping);
-  format_cc (&out, cc->prefix, cc->grouping);
-  ds_put_char (&out, cc->grouping);
-  format_cc (&out, cc->suffix, cc->grouping);
-  ds_put_char (&out, cc->grouping);
-  format_cc (&out, cc->neg_suffix, cc->grouping);
+  format_cc (&out, cc->neg_prefix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->prefix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->suffix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->neg_suffix.s, cc->grouping);
 
   return ds_cstr (&out);
 }
@@ -621,12 +606,6 @@ show_decimals (const struct dataset *ds UNUSED)
   return xasprintf ("`%c'", settings_get_decimal_char (FMT_F));
 }
 
-static char *
-show_endcmd (const struct dataset *ds UNUSED)
-{
-  return xasprintf ("`%c'", settings_get_endcmd ());
-}
-
 static char *
 show_errors (const struct dataset *ds UNUSED)
 {
@@ -811,7 +790,6 @@ const struct show_sbc show_table[] =
     {"CCD", show_ccd},
     {"CCE", show_cce},
     {"DECIMALS", show_decimals},
-    {"ENDCMD", show_endcmd},
     {"ERRORS", show_errors},
     {"FORMAT", show_format},
     {"LENGTH", show_length},
@@ -877,7 +855,7 @@ show_copying (const struct dataset *ds UNUSED)
 int
 cmd_show (struct lexer *lexer, struct dataset *ds)
 {
-  if (lex_token (lexer) == '.')
+  if (lex_token (lexer) == T_ENDCMD)
     {
       show_all (ds);
       return CMD_SUCCESS;
@@ -917,9 +895,9 @@ cmd_show (struct lexer *lexer, struct dataset *ds)
           return CMD_FAILURE;
         }
 
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
     }
-  while (lex_token (lexer) != '.');
+  while (lex_token (lexer) != T_ENDCMD);
 
   return CMD_SUCCESS;
 }
@@ -930,12 +908,12 @@ static struct settings *saved_settings[MAX_SAVED_SETTINGS];
 static int n_saved_settings;
 
 int
-cmd_preserve (struct lexer *lexer, struct dataset *ds UNUSED)
+cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
   if (n_saved_settings < MAX_SAVED_SETTINGS)
     {
       saved_settings[n_saved_settings++] = settings_get ();
-      return lex_end_of_command (lexer);
+      return CMD_SUCCESS;
     }
   else
     {
@@ -947,14 +925,14 @@ cmd_preserve (struct lexer *lexer, struct dataset *ds UNUSED)
 }
 
 int
-cmd_restore (struct lexer *lexer, struct dataset *ds UNUSED)
+cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
   if (n_saved_settings > 0)
     {
       struct settings *s = saved_settings[--n_saved_settings];
       settings_set (s);
       settings_destroy (s);
-      return lex_end_of_command (lexer);
+      return CMD_SUCCESS;
     }
   else
     {
index fe826db155dadb8ad1b5cd97d2df7709399171ba..cc5314c4e3dab6b69c36328e9f574d9d37332597 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, 2010, 2011 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 <ctype.h>
 #include <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/start-date.h>
-#include <libpspp/version.h>
-#include <output/text-item.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/start-date.h"
+#include "libpspp/version.h"
+#include "output/text-item.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -52,23 +52,10 @@ cmd_subtitle (struct lexer *lexer, struct dataset *ds UNUSED)
 static int
 parse_title (struct lexer *lexer, enum text_item_type type)
 {
-  int c;
-
-  c = lex_look_ahead (lexer);
-  if (c == '"' || c == '\'')
-    {
-      lex_get (lexer);
-      if (!lex_force_string (lexer))
-       return CMD_FAILURE;
-      set_title (ds_cstr (lex_tokstr (lexer)), type);
-      lex_get (lexer);
-      return lex_end_of_command (lexer);
-    }
-  else
-    {
-      set_title (lex_rest_of_line (lexer), type);
-      lex_discard_line (lexer);
-    }
+  if (!lex_force_string (lexer))
+    return CMD_FAILURE;
+  set_title (lex_tokcstr (lexer), type);
+  lex_get (lexer);
   return CMD_SUCCESS;
 }
 
@@ -82,81 +69,49 @@ set_title (const char *title, enum text_item_type type)
 int
 cmd_file_label (struct lexer *lexer, struct dataset *ds)
 {
-  const char *label;
-
-  label = lex_rest_of_line (lexer);
-  lex_discard_line (lexer);
-  while (isspace ((unsigned char) *label))
-    label++;
+  if (!lex_force_string (lexer))
+    return CMD_FAILURE;
 
-  dict_set_label (dataset_dict (ds), label);
+  dict_set_label (dataset_dict (ds), lex_tokcstr (lexer));
+  lex_get (lexer);
 
   return CMD_SUCCESS;
 }
 
-/* Add entry date line to DICT's documents. */
-static void
-add_document_trailer (struct dictionary *dict)
-{
-  char buf[64];
-
-  sprintf (buf, _("   (Entered %s)"), get_start_date ());
-  dict_add_document_line (dict, buf);
-}
-
 /* Performs the DOCUMENT command. */
 int
 cmd_document (struct lexer *lexer, struct dataset *ds)
 {
   struct dictionary *dict = dataset_dict (ds);
-  struct string line = DS_EMPTY_INITIALIZER;
-  bool end_dot;
+  char *trailer;
 
-  do
+  if (!lex_force_string (lexer))
+    return CMD_FAILURE;
+
+  while (lex_is_string (lexer))
     {
-      end_dot = lex_end_dot (lexer);
-      ds_assign_string (&line, lex_entire_line_ds (lexer));
-      if (end_dot)
-        ds_put_char (&line, '.');
-      dict_add_document_line (dict, ds_cstr (&line));
-
-      lex_discard_line (lexer);
-      lex_get_line (lexer);
+      dict_add_document_line (dict, lex_tokcstr (lexer), true);
+      lex_get (lexer);
     }
-  while (!end_dot);
 
-  add_document_trailer (dict);
-  ds_destroy (&line);
+  trailer = xasprintf (_("   (Entered %s)"), get_start_date ());
+  dict_add_document_line (dict, trailer, true);
+  free (trailer);
 
   return CMD_SUCCESS;
 }
 
-/* Performs the DROP DOCUMENTS command. */
+/* Performs the ADD DOCUMENTS command. */
 int
-cmd_drop_documents (struct lexer *lexer, struct dataset *ds)
+cmd_add_documents (struct lexer *lexer, struct dataset *ds)
 {
-  dict_clear_documents (dataset_dict (ds));
-
-  return lex_end_of_command (lexer);
+  return cmd_document (lexer, ds);
 }
 
-
-/* Performs the ADD DOCUMENTS command. */
+/* Performs the DROP DOCUMENTS command. */
 int
-cmd_add_documents (struct lexer *lexer, struct dataset *ds)
+cmd_drop_documents (struct lexer *lexer UNUSED, struct dataset *ds)
 {
-  struct dictionary *dict = dataset_dict (ds);
-
-  if ( ! lex_force_string (lexer) )
-    return CMD_FAILURE;
-
-  while ( lex_is_string (lexer))
-    {
-      dict_add_document_line (dict, ds_cstr (lex_tokstr (lexer)));
-      lex_get (lexer);
-    }
-
-  add_document_trailer (dict);
-
-  return lex_end_of_command (lexer) ;
+  dict_clear_documents (dataset_dict (ds));
+  return CMD_SUCCESS;
 }
index a508933c68cb7686d2690ec0d75048662b3b4e18..0ab4e3a4bb5ac44cdc6aeaf5a0251b4df2914833 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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 <stdint.h>
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <data/vector.h>
-#include <language/command.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "data/vector.h"
+#include "language/command.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -90,7 +90,7 @@ cmd_compute (struct lexer *lexer, struct dataset *ds)
   if (lvalue == NULL)
     goto fail;
 
-  if (!lex_force_match (lexer, '='))
+  if (!lex_force_match (lexer, T_EQUALS))
     goto fail;
   compute->rvalue = parse_rvalue (lexer, lvalue, ds);
   if (compute->rvalue == NULL)
@@ -100,7 +100,7 @@ cmd_compute (struct lexer *lexer, struct dataset *ds)
 
   lvalue_finalize (lvalue, compute, dict);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
  fail:
   lvalue_destroy (lvalue, dict);
@@ -246,7 +246,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds)
     goto fail;
 
   /* Rvalue expression. */
-  if (!lex_force_match (lexer, '='))
+  if (!lex_force_match (lexer, T_EQUALS))
     goto fail;
   compute->rvalue = parse_rvalue (lexer, lvalue, ds);
   if (compute->rvalue == NULL)
@@ -256,7 +256,7 @@ cmd_if (struct lexer *lexer, struct dataset *ds)
 
   lvalue_finalize (lvalue, compute, dict);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
  fail:
   lvalue_destroy (lvalue, dict);
@@ -346,30 +346,30 @@ lvalue_parse (struct lexer *lexer, struct dataset *ds)
   if (!lex_force_id (lexer))
     goto lossage;
 
-  if (lex_look_ahead (lexer) == '(')
+  if (lex_next_token (lexer, 1) == T_LPAREN)
     {
       /* Vector. */
-      lvalue->vector = dict_lookup_vector (dict, lex_tokid (lexer));
+      lvalue->vector = dict_lookup_vector (dict, lex_tokcstr (lexer));
       if (lvalue->vector == NULL)
        {
-         msg (SE, _("There is no vector named %s."), lex_tokid (lexer));
+         msg (SE, _("There is no vector named %s."), lex_tokcstr (lexer));
           goto lossage;
        }
 
       /* Vector element. */
       lex_get (lexer);
-      if (!lex_force_match (lexer, '('))
+      if (!lex_force_match (lexer, T_LPAREN))
        goto lossage;
       lvalue->element = expr_parse (lexer, ds, EXPR_NUMBER);
       if (lvalue->element == NULL)
         goto lossage;
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         goto lossage;
     }
   else
     {
       /* Variable name. */
-      const char *var_name = lex_tokid (lexer);
+      const char *var_name = lex_tokcstr (lexer);
       lvalue->variable = dict_lookup_var (dict, var_name);
       if (lvalue->variable == NULL)
         {
index 4fb889b17717ae3a0dec8bc98ee5a81ea6e219b9..c42bdc34cf01bedba7d5aa86756cdefca797ee4b 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/dictionary.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/value-parser.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/value-parser.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -92,7 +92,9 @@ static trns_proc_func count_trns_proc;
 static trns_free_func count_trns_free;
 
 static bool parse_numeric_criteria (struct lexer *, struct pool *, struct criteria *);
-static bool parse_string_criteria (struct lexer *, struct pool *, struct criteria *);
+static bool parse_string_criteria (struct lexer *, struct pool *,
+                                   struct criteria *,
+                                   const char *dict_encoding);
 \f
 int
 cmd_count (struct lexer *lexer, struct dataset *ds)
@@ -115,7 +117,7 @@ cmd_count (struct lexer *lexer, struct dataset *ds)
       /* Get destination variable, or at least its name. */
       if (!lex_force_id (lexer))
        goto fail;
-      dv->var = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer));
+      dv->var = dict_lookup_var (dataset_dict (ds), lex_tokcstr (lexer));
       if (dv->var != NULL)
         {
           if (var_is_alpha (dv->var))
@@ -125,46 +127,48 @@ cmd_count (struct lexer *lexer, struct dataset *ds)
             }
         }
       else
-        dv->name = pool_strdup (trns->pool, lex_tokid (lexer));
+        dv->name = pool_strdup (trns->pool, lex_tokcstr (lexer));
 
       lex_get (lexer);
-      if (!lex_force_match (lexer, '='))
+      if (!lex_force_match (lexer, T_EQUALS))
        goto fail;
 
       crit = dv->crit = pool_alloc (trns->pool, sizeof *crit);
       for (;;)
        {
+          struct dictionary *dict = dataset_dict (ds);
           bool ok;
 
          crit->next = NULL;
          crit->vars = NULL;
-         if (!parse_variables_const (lexer, dataset_dict (ds), &crit->vars,
+         if (!parse_variables_const (lexer, dict, &crit->vars,
                                      &crit->var_cnt,
-                                PV_DUPLICATE | PV_SAME_TYPE))
+                                      PV_DUPLICATE | PV_SAME_TYPE))
            goto fail;
           pool_register (trns->pool, free, crit->vars);
 
-         if (!lex_force_match (lexer, '('))
+         if (!lex_force_match (lexer, T_LPAREN))
            goto fail;
 
           crit->value_cnt = 0;
           if (var_is_numeric (crit->vars[0]))
             ok = parse_numeric_criteria (lexer, trns->pool, crit);
           else
-            ok = parse_string_criteria (lexer, trns->pool, crit);
+            ok = parse_string_criteria (lexer, trns->pool, crit,
+                                        dict_get_encoding (dict));
          if (!ok)
            goto fail;
 
-         if (lex_token (lexer) == '/' || lex_token (lexer) == '.')
+         if (lex_token (lexer) == T_SLASH || lex_token (lexer) == T_ENDCMD)
            break;
 
          crit = crit->next = pool_alloc (trns->pool, sizeof *crit);
        }
 
-      if (lex_token (lexer) == '.')
+      if (lex_token (lexer) == T_ENDCMD)
        break;
 
-      if (!lex_force_match (lexer, '/'))
+      if (!lex_force_match (lexer, T_SLASH))
        goto fail;
       dv = dv->next = pool_alloc (trns->pool, sizeof *dv);
     }
@@ -222,8 +226,8 @@ parse_numeric_criteria (struct lexer *lexer, struct pool *pool, struct criteria
       else
         return false;
 
-      lex_match (lexer, ',');
-      if (lex_match (lexer, ')'))
+      lex_match (lexer, T_COMMA);
+      if (lex_match (lexer, T_RPAREN))
        break;
     }
   return true;
@@ -231,7 +235,8 @@ parse_numeric_criteria (struct lexer *lexer, struct pool *pool, struct criteria
 
 /* Parses a set of string criteria values.  Returns success. */
 static bool
-parse_string_criteria (struct lexer *lexer, struct pool *pool, struct criteria *crit)
+parse_string_criteria (struct lexer *lexer, struct pool *pool,
+                       struct criteria *crit, const char *dict_encoding)
 {
   int len = 0;
   size_t allocated = 0;
@@ -245,6 +250,8 @@ parse_string_criteria (struct lexer *lexer, struct pool *pool, struct criteria *
   for (;;)
     {
       char **cur;
+      char *s;
+
       if (crit->value_cnt >= allocated)
         crit->values.str = pool_2nrealloc (pool, crit->values.str,
                                            &allocated,
@@ -252,13 +259,19 @@ parse_string_criteria (struct lexer *lexer, struct pool *pool, struct criteria *
 
       if (!lex_force_string (lexer))
        return false;
+
+      s = recode_string (dict_encoding, "UTF-8", lex_tokcstr (lexer),
+                         ss_length (lex_tokss (lexer)));
+
       cur = &crit->values.str[crit->value_cnt++];
       *cur = pool_alloc (pool, len + 1);
-      str_copy_rpad (*cur, len + 1, ds_cstr (lex_tokstr (lexer)));
+      str_copy_rpad (*cur, len + 1, s);
       lex_get (lexer);
 
-      lex_match (lexer, ',');
-      if (lex_match (lexer, ')'))
+      free (s);
+
+      lex_match (lexer, T_COMMA);
+      if (lex_match (lexer, T_RPAREN))
        break;
     }
 
index d1cfabf6676478deb66baca38b371431c5ddd1d6..f23fcec3f1fc79c6b8511e34f54b9e60a56ecaf1 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, 2011 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 <stdlib.h>
 
-#include <data/case.h>
-#include <data/procedure.h>
-#include <data/transformations.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/transformations.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
 
 static int trns_fail (void *x, struct ccase **c, casenumber n);
-
-
 \f
 /* A transformation which is guaranteed to fail. */
 
@@ -34,15 +33,13 @@ static int
 trns_fail (void *x UNUSED, struct ccase **c UNUSED,
           casenumber n UNUSED)
 {
+  msg (SE, "DEBUG XFORM FAIL transformation executed");
   return TRNS_ERROR;
 }
 
-
 int
-cmd_debug_xform_fail (struct lexer *lexer, struct dataset *ds)
+cmd_debug_xform_fail (struct lexer *lexer UNUSED, struct dataset *ds)
 {
-
   add_transformation (ds, trns_fail, NULL, NULL);
-
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index 5cfad0ed766ec2376429c32b3dc1bbb83e212271..44e5b8513326e32a844ba9bee618d94ce74ba777 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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,9 +22,9 @@
 
 #include "data/case.h"
 #include "data/data-in.h"
+#include "data/dataset.h"
 #include "data/dictionary.h"
 #include "data/format.h"
-#include "data/procedure.h"
 #include "data/transformations.h"
 #include "data/variable.h"
 #include "language/command.h"
@@ -34,6 +34,7 @@
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/pool.h"
 #include "libpspp/str.h"
@@ -84,8 +85,6 @@ struct recode_trns
   {
     struct pool *pool;
 
-
-
     /* Variable types, for convenience. */
     enum val_type src_type;     /* src_vars[*] type. */
     enum val_type dst_type;     /* dst_vars[*] type. */
@@ -105,23 +104,26 @@ struct recode_trns
   };
 
 static bool parse_src_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
-static bool parse_mappings (struct lexer *, struct recode_trns *);
+static bool parse_mappings (struct lexer *, struct recode_trns *,
+                            const char *dict_encoding);
 static bool parse_dst_vars (struct lexer *, struct recode_trns *, const struct dictionary *dict);
 
 static void add_mapping (struct recode_trns *,
                          size_t *map_allocated, const struct map_in *);
 
 static bool parse_map_in (struct lexer *lexer, struct map_in *, struct pool *,
-                          enum val_type src_type, size_t max_src_width);
+                          enum val_type src_type, size_t max_src_width,
+                          const char *dict_encoding);
 static void set_map_in_generic (struct map_in *, enum map_in_type);
 static void set_map_in_num (struct map_in *, enum map_in_type, double, double);
 static void set_map_in_str (struct map_in *, struct pool *,
-                            const struct string *, size_t width);
+                            struct substring, size_t width,
+                            const char *dict_encoding);
 
 static bool parse_map_out (struct lexer *lexer, struct pool *, struct map_out *);
 static void set_map_out_num (struct map_out *, double);
 static void set_map_out_str (struct map_out *, struct pool *,
-                             const struct string *);
+                             struct substring);
 
 static void enlarge_dst_widths (struct recode_trns *);
 static void create_dst_vars (struct recode_trns *, struct dictionary *);
@@ -137,15 +139,16 @@ cmd_recode (struct lexer *lexer, struct dataset *ds)
 {
   do
     {
+      struct dictionary *dict = dataset_dict (ds);
       struct recode_trns *trns
         = pool_create_container (struct recode_trns, pool);
 
       /* Parse source variable names,
          then input to output mappings,
          then destintation variable names. */
-      if (!parse_src_vars (lexer, trns, dataset_dict (ds) )
-          || !parse_mappings (lexer, trns)
-          || !parse_dst_vars (lexer, trns, dataset_dict (ds)))
+      if (!parse_src_vars (lexer, trns, dict)
+          || !parse_mappings (lexer, trns, dict_get_encoding (dict))
+          || !parse_dst_vars (lexer, trns, dict))
         {
           recode_trns_free (trns);
           return CMD_FAILURE;
@@ -159,17 +162,17 @@ cmd_recode (struct lexer *lexer, struct dataset *ds)
       /* Create destination variables, if needed.
          This must be the final step; otherwise we'd have to
          delete destination variables on failure. */
-      trns->dst_dict = dataset_dict (ds);
+      trns->dst_dict = dict;
       if (trns->src_vars != trns->dst_vars)
-       create_dst_vars (trns, dataset_dict (ds));
+       create_dst_vars (trns, dict);
 
       /* Done. */
       add_transformation (ds,
                          recode_trns_proc, recode_trns_free, trns);
     }
-  while (lex_match (lexer, '/'));
+  while (lex_match (lexer, T_SLASH));
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Parses a set of variables to recode into TRNS->src_vars and
@@ -191,7 +194,8 @@ parse_src_vars (struct lexer *lexer,
    into TRNS->mappings and TRNS->map_cnt.  Sets TRNS->dst_type.
    Returns true if successful, false on parse error. */
 static bool
-parse_mappings (struct lexer *lexer, struct recode_trns *trns)
+parse_mappings (struct lexer *lexer, struct recode_trns *trns,
+                const char *dict_encoding)
 {
   size_t map_allocated;
   bool have_dst_type;
@@ -211,7 +215,7 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns)
   trns->map_cnt = 0;
   map_allocated = 0;
   have_dst_type = false;
-  if (!lex_force_match (lexer, '('))
+  if (!lex_force_match (lexer, T_LPAREN))
     return false;
   do
     {
@@ -231,12 +235,13 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns)
               struct map_in in;
 
               if (!parse_map_in (lexer, &in, trns->pool,
-                                 trns->src_type, trns->max_src_width))
+                                 trns->src_type, trns->max_src_width,
+                                 dict_encoding))
                 return false;
               add_mapping (trns, &map_allocated, &in);
-              lex_match (lexer, ',');
+              lex_match (lexer, T_COMMA);
             }
-          while (!lex_match (lexer, '='));
+          while (!lex_match (lexer, T_EQUALS));
 
           if (!parse_map_out (lexer, trns->pool, &out))
             return false;
@@ -276,10 +281,10 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns)
       trns->dst_type = dst_type;
       have_dst_type = true;
 
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         return false;
     }
-  while (lex_match (lexer, '('));
+  while (lex_match (lexer, T_LPAREN));
 
   return true;
 }
@@ -291,7 +296,8 @@ parse_mappings (struct lexer *lexer, struct recode_trns *trns)
    false on parse error. */
 static bool
 parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
-              enum val_type src_type, size_t max_src_width)
+              enum val_type src_type, size_t max_src_width,
+              const char *dict_encoding)
 {
 
   if (lex_match_id (lexer, "ELSE"))
@@ -318,10 +324,11 @@ parse_map_in (struct lexer *lexer, struct map_in *in, struct pool *pool,
         return false;
       else 
        {
-         set_map_in_str (in, pool, lex_tokstr (lexer), max_src_width);
+         set_map_in_str (in, pool, lex_tokss (lexer), max_src_width,
+                          dict_encoding);
          lex_get (lexer);
          if (lex_token (lexer) == T_ID
-             && lex_id_match (ss_cstr ("THRU"), ss_cstr (lex_tokid (lexer))))
+             && lex_id_match (ss_cstr ("THRU"), lex_tokss (lexer)))
            {
              msg (SE, _("THRU is not allowed with string variables."));
              return false;
@@ -370,13 +377,16 @@ set_map_in_num (struct map_in *in, enum map_in_type type, double x, double y)
    right to WIDTH characters long. */
 static void
 set_map_in_str (struct map_in *in, struct pool *pool,
-                const struct string *string, size_t width)
+                struct substring string, size_t width,
+                const char *dict_encoding)
 {
+  char *s = recode_string (dict_encoding, "UTF-8",
+                           ss_data (string), ss_length (string));
   in->type = MAP_SINGLE;
   value_init_pool (pool, &in->x, width);
   value_copy_buf_rpad (&in->x, width,
-                       CHAR_CAST_BUG (uint8_t *, ds_data (string)),
-                       ds_length (string), ' ');
+                       CHAR_CAST (uint8_t *, s), strlen (s), ' ');
+  free (s);
 }
 
 /* Parses a mapping output value into OUT, allocating memory from
@@ -393,7 +403,7 @@ parse_map_out (struct lexer *lexer, struct pool *pool, struct map_out *out)
     set_map_out_num (out, SYSMIS);
   else if (lex_is_string (lexer))
     {
-      set_map_out_str (out, pool, lex_tokstr (lexer));
+      set_map_out_str (out, pool, lex_tokss (lexer));
       lex_get (lexer);
     }
   else if (lex_match_id (lexer, "COPY")) 
@@ -421,10 +431,10 @@ set_map_out_num (struct map_out *out, double value)
 /* Sets OUT as a string mapping output with the given VALUE. */
 static void
 set_map_out_str (struct map_out *out, struct pool *pool,
-                 const struct string *value)
+                 const struct substring value)
 {
-  const char *string = ds_data (value);
-  size_t length = ds_length (value);
+  const char *string = ss_data (value);
+  size_t length = ss_length (value);
 
   if (length == 0)
     {
@@ -632,7 +642,7 @@ find_src_string (struct recode_trns *trns, const uint8_t *value,
             char *error;
 
             error = data_in (ss_buffer (CHAR_CAST_BUG (char *, value), width),
-                             LEGACY_NATIVE, FMT_F, &uv, 0, encoding);
+                             C_ENCODING, FMT_F, &uv, 0, encoding);
             match = error == NULL;
             free (error);
 
index 6fbc758c2e1329f41d57d626daa9eb8ca75b495a..260841a6029b541ddd97dc3ca811391dfee68471 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-2011 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 <math.h>
 
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/compiler.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-#include <math/random.h>
+#include "data/dataset.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+#include "math/random.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -111,7 +111,7 @@ cmd_sample (struct lexer *lexer, struct dataset *ds)
   trns->frac = frac;
   add_transformation (ds, sample_trns_proc, sample_trns_free, trns);
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
 
 /* Executes a SAMPLE transformation. */
index 85f616d536fb3ad39e670f517f9f892488a9a8b8..4110f9089b2f3d19bc94b73343ec16c5f709ea3b 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, 2011 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 <stdlib.h>
 
-#include <data/dictionary.h>
-#include <data/transformations.h>
-#include <data/procedure.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/expressions/public.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/transformations.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/expressions/public.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -54,7 +54,7 @@ cmd_select_if (struct lexer *lexer, struct dataset *ds)
   if (!e)
     return CMD_CASCADING_FAILURE;
 
-  if (lex_token (lexer) != '.')
+  if (lex_token (lexer) != T_ENDCMD)
     {
       expr_free (e);
       lex_error (lexer, _("expecting end of command"));
@@ -95,7 +95,7 @@ cmd_filter (struct lexer *lexer, struct dataset *ds)
   struct dictionary *dict = dataset_dict (ds);
   if (lex_match_id (lexer, "OFF"))
     dict_set_filter (dict, NULL);
-  else if (lex_token (lexer) == '.')
+  else if (lex_token (lexer) == T_ENDCMD)
     {
       msg (SW, _("Syntax error expecting OFF or BY.  "
                  "Turning off case filtering."));
@@ -125,5 +125,5 @@ cmd_filter (struct lexer *lexer, struct dataset *ds)
       dict_set_filter (dict, v);
     }
 
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 }
index b776612922f2579b290f3a3657f12adb8efee0fe..c06047b4abdbb8e128910a17049f972893abd295 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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>
 #endif
 
-#include <libpspp/abt.h>
-#include <libpspp/cast.h>
+#include "libpspp/abt.h"
 
 #include <stdbool.h>
 
-#include <libpspp/assertion.h>
+#include "libpspp/cast.h"
+#include "libpspp/assertion.h"
 
 static struct abt_node **down_link (struct abt *, struct abt_node *);
 static struct abt_node *skew (struct abt *, struct abt_node *);
index 24d7268a2d6543a383361c50914d796e52e7b6c1..fa9d0dc87d6b7112a856cbe6666046a6013a9077 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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>
+#include "libpspp/cast.h"
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
index ecf1ab23c74264ba4331ba413e5b14edd4836125..c72c250394864091bb8bcd3458cb8bfae413c2c1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <libpspp/argv-parser.h>
+#include "libpspp/argv-parser.h"
 
 #include <limits.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/str.h>
+#include "libpspp/assertion.h"
+#include "libpspp/str.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 struct argv_option_plus
   {
@@ -128,11 +128,11 @@ argv_parser_run (struct argv_parser *ap, int argc, char **argv)
           if (shortopt_ptrs[c] == NULL)
             {
               shortopt_ptrs[c] = aop;
-              ds_put_char (&shortopts, aop->base.short_name);
+              ds_put_byte (&shortopts, aop->base.short_name);
               if (aop->base.has_arg != no_argument)
-                ds_put_char (&shortopts, ':');
+                ds_put_byte (&shortopts, ':');
               if (aop->base.has_arg == optional_argument)
-                ds_put_char (&shortopts, ':');
+                ds_put_byte (&shortopts, ':');
             }
           else
             {
index b1b4ee524562e4335b275ddbbb0072b1e4312667..a0ac943af66bc8fceffce5ca8babcd7d3d5dbfe6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011 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
    <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
+
 #include "array.h"
+
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
-#include <libpspp/assertion.h>
+#include "libpspp/assertion.h"
 
-#include "xalloc.h"
-#include "minmax.h"
+#include "gl/xalloc.h"
+#include "gl/minmax.h"
 \f
 /* Finds an element in ARRAY, which contains COUNT elements of
    SIZE bytes each, using COMPARE for comparisons.  Returns the
index de7912bb08cd81f7f9bbb8bda8dc8819c72eba9f..e4948406d034bde5762a55288766d5e0fb4d7eaf 100644 (file)
@@ -20,14 +20,14 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/copyleft.h \
        src/libpspp/deque.c \
        src/libpspp/deque.h \
+       src/libpspp/encoding-guesser.c \
+       src/libpspp/encoding-guesser.h \
        src/libpspp/ext-array.c \
        src/libpspp/ext-array.h \
        src/libpspp/float-format.c \
        src/libpspp/float-format.h \
        src/libpspp/freaderror.c \
        src/libpspp/freaderror.h \
-       src/libpspp/getl.c \
-       src/libpspp/getl.h \
        src/libpspp/hash-functions.c \
        src/libpspp/hash-functions.h \
        src/libpspp/hash.c \
@@ -44,8 +44,6 @@ src_libpspp_libpspp_la_SOURCES = \
        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 \
        src/libpspp/ll.h \
        src/libpspp/llx.c \
@@ -56,10 +54,10 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/misc.h \
        src/libpspp/model-checker.c \
        src/libpspp/model-checker.h \
-       src/libpspp/msg-locator.c \
-       src/libpspp/msg-locator.h \
        src/libpspp/pool.c \
        src/libpspp/pool.h \
+       src/libpspp/prompt.c \
+       src/libpspp/prompt.h \
        src/libpspp/range-map.c \
        src/libpspp/range-map.h \
        src/libpspp/range-set.c \
@@ -88,6 +86,8 @@ src_libpspp_libpspp_la_SOURCES = \
        src/libpspp/temp-file.h \
        src/libpspp/tower.c \
        src/libpspp/tower.h \
+       src/libpspp/u8-istream.c \
+       src/libpspp/u8-istream.h \
        src/libpspp/version.h \
        src/libpspp/zip-writer.c \
        src/libpspp/zip-writer.h
index 997083b1a08fb64271098f1342a126b9ebd0fe6b..4178d1475af769810a3f193d3af3d1afb5c48797 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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>
 #endif
 
-#include <libpspp/bt.h>
+#include "libpspp/bt.h"
 
 #include <limits.h>
 #include <stdbool.h>
 #include <stdint.h>
 
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 static void rebalance_subtree (struct bt *, struct bt_node *, size_t);
 
index 0ee29898e8263eeb434d8987192157c771fbb19a..41fc5d44b0a3bc27ee23277ea2fc5abb27764398 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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
@@ -25,7 +25,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/cast.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
index d34d6c625a8791bcbaf1213018c6215e3c847ff2..732f09da82d371735340580e79b39bf216793a2c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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 <libpspp/deque.h>
+#include "libpspp/deque.h"
+
 #include <string.h>
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 /* Initializes DEQUE as an empty deque with an initial capacity
    of zero. */
index cdb6abd32628b73f53781ad480485423c2e8044d..151308013cf560a72cd31f670f144d1a97f53297 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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
@@ -66,7 +66,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 
-#include <libpspp/assertion.h>
+#include "libpspp/assertion.h"
 
 /* A deque implemented as a circular buffer. */
 struct deque
diff --git a/src/libpspp/encoding-guesser.c b/src/libpspp/encoding-guesser.c
new file mode 100644 (file)
index 0000000..7d10015
--- /dev/null
@@ -0,0 +1,312 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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/encoding-guesser.h"
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistr.h>
+
+#include "libpspp/cast.h"
+#include "libpspp/i18n.h"
+
+#include "gl/localcharset.h"
+#include "gl/c-strcase.h"
+
+/* http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info is a useful source
+   of information about encoding detection.
+*/
+
+/* Parses and returns the fallback encoding from ENCODING, which must be in one
+   of the forms described at the top of encoding-guesser.h.  The returned
+   string might be ENCODING itself or a suffix of it, or it might be a
+   statically allocated string. */
+const char *
+encoding_guess_parse_encoding (const char *encoding)
+{
+  if (encoding == NULL
+      || !c_strcasecmp (encoding, "auto")
+      || !c_strcasecmp (encoding, "auto,locale")
+      || !c_strcasecmp (encoding, "locale"))
+    return locale_charset ();
+  else if (!c_strncasecmp (encoding, "auto,", 5))
+    return encoding + 5;
+  else
+    return encoding;
+}
+
+/* Returns true if ENCODING, which must be in one of the forms described at the
+   top of encoding-guesser.h, is one that performs encoding autodetection,
+   false otherwise. */
+bool
+encoding_guess_encoding_is_auto (const char *encoding)
+{
+  return (encoding == NULL
+          || (!c_strncasecmp (encoding, "auto", 4)
+              && (encoding[4] == ',' || encoding[4] == '\0')));
+}
+
+static uint16_t
+get_be16 (const uint8_t *data)
+{
+  return (data[0] << 8) | data[1];
+}
+
+static uint16_t
+get_le16 (const uint8_t *data)
+{
+  return (data[1] << 8) | data[0];
+}
+
+static uint32_t
+get_be32 (const uint8_t *data)
+{
+  return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+
+}
+
+static uint32_t
+get_le32 (const uint8_t *data)
+{
+  return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
+
+}
+
+static const char *
+guess_utf16 (const uint8_t *data, size_t n)
+{
+  size_t even_nulls, odd_nulls;
+
+  if (n < ENCODING_GUESS_MIN && n % 2 != 0)
+    return NULL;
+
+  even_nulls = odd_nulls = 0;
+  while (n >= 2)
+    {
+      even_nulls += data[0] == 0;
+      odd_nulls += data[1] == 0;
+      if (data[0] == 0 && data[1] == 0)
+        return NULL;
+
+      data += 2;
+      n -= 2;
+    }
+
+  if (odd_nulls > even_nulls)
+    return "UTF-16LE";
+  else if (even_nulls > 0)
+    return "UTF-16BE";
+  else
+    return NULL;
+}
+
+static bool
+is_utf32 (const uint8_t *data, size_t n, uint32_t (*get_u32) (const uint8_t *))
+{
+  if (n < ENCODING_GUESS_MIN && n % 4 != 0)
+    return false;
+
+  while (n >= 4)
+    {
+      uint32_t uc = get_u32 (data);
+
+      if (uc < 0x09 || uc > 0x10ffff)
+        return false;
+
+      data += 4;
+      n -= 4;
+    }
+
+  return true;
+}
+
+/* Counts and returns the number of bytes, but no more than N, starting at S
+   that are ASCII text characters. */
+size_t
+encoding_guess_count_ascii (const void *s_, size_t n)
+{
+  const uint8_t *s = s_;
+  size_t ofs;
+
+  for (ofs = 0; ofs < n; ofs++)
+    if (!encoding_guess_is_ascii_text (s[ofs]))
+      break;
+  return ofs;
+}
+
+static bool
+is_all_utf8_text (const void *s_, size_t n)
+{
+  const uint8_t *s = s_;
+  size_t ofs;
+
+  ofs = 0;
+  while (ofs < n)
+    {
+      uint8_t c = s[ofs];
+      if (c < 0x80)
+        {
+          if (!encoding_guess_is_ascii_text (c))
+            return false;
+          ofs++;
+        }
+      else
+        {
+          ucs4_t uc;
+          int mblen;
+
+          mblen = u8_mbtoucr (&uc, s + ofs, n - ofs);
+          if (mblen < 0)
+            return mblen == -2;
+
+          ofs += mblen;
+        }
+    }
+  return true;
+}
+
+/* Attempts to guess the encoding of a text file based on ENCODING, an encoding
+   name in one of the forms described at the top of encoding-guesser.h, and
+   DATA, which contains the first N bytes of the file.  Returns the guessed
+   encoding, which might be ENCODING itself or a suffix of it or a statically
+   allocated string.
+
+   Encoding autodetection only takes place if ENCODING actually specifies
+   autodetection.  See encoding-guesser.h for details.
+
+   UTF-8 cannot be distinguished from other ASCII-based encodings until a
+   non-ASCII text character is encountered.  If ENCODING specifies
+   autodetection and this function returns "ASCII", then the client should
+   process the input until it encounters an non-ASCII character (as returned by
+   encoding_guess_is_ascii_text()) and then use encoding_guess_tail_encoding()
+   to make a final encoding guess.  See encoding-guesser.h for details.
+
+   N must be at least ENCODING_GUESS_MIN, unless the file is shorter than
+   that. */
+const char *
+encoding_guess_head_encoding (const char *encoding,
+                              const void *data_, size_t n)
+{
+  const uint8_t *data = data_;
+  const char *fallback_encoding;
+  const char *guess;
+
+  fallback_encoding = encoding_guess_parse_encoding (encoding);
+  if (!encoding_guess_encoding_is_auto (encoding))
+    return fallback_encoding;
+
+  if (n == 0)
+    return fallback_encoding;
+
+  if ((n >= ENCODING_GUESS_MIN || n % 4 == 0)
+      && (get_be32 (data) == 0xfeff || get_le32 (data) == 0xfeff))
+    return "UTF-32";
+
+  if (n >= 4)
+    {
+      uint32_t x = get_be32 (data);
+      if (x == 0x84319533)
+        return "GB-18030";
+      else if (x == 0xdd736673)
+        return "UTF-EBCDIC";
+    }
+
+  if ((n >= ENCODING_GUESS_MIN || n % 2 == 0)
+      && (get_be16 (data) == 0xfeff || get_le16 (data) == 0xfeff))
+    return "UTF-16";
+
+  if (n >= 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf)
+    return "UTF-8";
+
+  guess = guess_utf16 (data, n);
+  if (guess != NULL)
+    return guess;
+
+  if (is_utf32 (data, n, get_be32))
+    return "UTF-32BE";
+  if (is_utf32 (data, n, get_le32))
+    return "UTF-32LE";
+
+  if (!is_encoding_ascii_compatible (fallback_encoding)
+      || !encoding_guess_tail_is_utf8 (data, n))
+    return fallback_encoding;
+
+  return "ASCII";
+}
+
+/* Returns an encoding guess based on ENCODING and the N bytes of text starting
+   at DATA.  DATA should start with the first non-ASCII text character (as
+   determined by encoding_guess_is_ascii_text()) found in the input.
+
+   The return value will either be "UTF-8" or the fallback encoding for
+   ENCODING.
+
+   See encoding-guesser.h for intended use of this function.
+
+   N must be at least ENCODING_GUESS_MIN, unless the file has fewer bytes than
+   that starting with the first non-ASCII text character. */
+const char *
+encoding_guess_tail_encoding (const char *encoding,
+                              const void *data, size_t n)
+{
+  return (encoding_guess_tail_is_utf8 (data, n)
+          ? "UTF-8"
+          : encoding_guess_parse_encoding (encoding));
+}
+
+/* Same as encoding_guess_tail_encoding() but returns true for UTF-8 or false
+   for the fallback encoding. */
+bool
+encoding_guess_tail_is_utf8 (const void *data, size_t n)
+{
+  return (n < ENCODING_GUESS_MIN
+          ? u8_check (data, n) == NULL
+          : is_all_utf8_text (data, n));
+}
+
+/* Attempts to guess the encoding of a text file based on ENCODING, an encoding
+   name in one of the forms described at the top of encoding-guesser.h, and the
+   SIZE byts in DATA, which contains the entire contents of the file.  Returns
+   the guessed encoding, which might be ENCODING itself or a suffix of it or a
+   statically allocated string.
+
+   Encoding autodetection only takes place if ENCODING actually specifies
+   autodetection.  See encoding-guesser.h for details. */
+const char *
+encoding_guess_whole_file (const char *encoding, const void *text, size_t size)
+{
+  const char *guess;
+
+  guess = encoding_guess_head_encoding (encoding, text, size);
+  if (!strcmp (guess, "ASCII") && encoding_guess_encoding_is_auto (encoding))
+    {
+      size_t ofs = encoding_guess_count_ascii (text, size);
+      if (ofs < size)
+        return encoding_guess_tail_encoding (encoding,
+                                             (const char *) text + ofs,
+                                             size - ofs);
+      else
+        return encoding_guess_parse_encoding (encoding);
+    }
+  else
+    return guess;
+}
diff --git a/src/libpspp/encoding-guesser.h b/src/libpspp/encoding-guesser.h
new file mode 100644 (file)
index 0000000..0a7d1f9
--- /dev/null
@@ -0,0 +1,130 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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_ENCODING_GUESSER_H
+#define LIBPSPP_ENCODING_GUESSER_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* A library for autodetecting the encoding of a text file.
+
+   Naming Encodings
+   ----------------
+
+   The encoding guesser starts with an encoding name in one of various
+   different forms.  Some of the forms do not actually do any autodetection.
+   The encoding guesser will return the specified encoding without looking at
+   any file data:
+
+     - A valid IANA or system encoding name: These are returned as-is.
+
+     - "Locale": Translated to the encoding used by the system locale, as
+       returned by locale_charset().
+
+   The remaining forms that do perform autodetection are:
+
+     - "Auto," followed by a valid IANA or system encoding name (the "fallback
+       encoding"): Requests detection whether the input is encoded in UTF-8,
+       UTF-16, UTF-32, or a few other easily identifiable charsets.  When a
+       particular character set cannot be recognized, the guesser falls back to
+       the encoding following the comma.  UTF-8 detection works only for
+       ASCII-compatible character sets.
+
+     - NULL or "Auto": As above, with the encoding used by the system locale as
+       the fallback encoding.
+
+   The above are suggested capitalizations but encoding names are not
+   case-sensitive.
+
+   The encoding_guess_parse_encoding() and encoding_guess_encoding_is_auto()
+   functions work with encoding names in these forms.
+
+   Usage
+   -----
+
+   1. Call encoding_guess_head_encoding() with several bytes from the start of
+      the text file.  Feed in at least ENCODING_GUESS_MIN bytes, unless the
+      file is shorter than that, but as many more as are conveniently
+      available.  ENCODING_GUESS_SUGGESTED is a reasonable amount.
+
+      encoding_guess_head_encoding() returns its best guess at the file's
+      encoding.  Ordinarily it returns a final guess that the client can use to
+      interpret the file, and you're all done.  However, if it returns "ASCII"
+      and the original encoding name requests autodetection (which you can find
+      out by calling encoding_guess_encoding_is_auto()), then proceed to the
+      next step.
+
+   2. The encoding guesser is confident that the stream uses an ASCII
+      compatible encoding, either UTF-8 or the fallback encoding.  The client
+      may safely read and process the stream up to the first non-ASCII
+      character.  If the stream continues to be ASCII all the way to its end,
+      then we're done.
+
+      The encoding guesser provides a pair of functions to detect non-ASCII
+      characters: encoding_guess_is_ascii_text() for single characters and
+      encoding_guess_count_ascii() as a convenient wrapper for whole buffers.
+
+   3. Otherwise, the stream contains some non-ASCII data at some point.  Now
+      the client should gather several bytes starting at this point, at least
+      ENCODING_GUESS_MIN, unless the file ends before that, but as many more as
+      are conveniently available.  ENCODING_GUESS_SUGGESTED is a reasonable
+      amount.
+
+      The client should pass these bytes to encoding_guess_tail_encoding(),
+      which returns a best and final guess at the file's encoding, which is
+      either UTF-8 or the fallback encoding.  Another alternative is
+      encoding_guess_tail_is_utf8(), which guesses the same way but has a
+      different form of return value.
+*/
+
+/* Minimum number of bytes for use in autodetection.
+   You should only pass fewer bytes to the autodetection routines if the file
+   is actually shorter than this. */
+#define ENCODING_GUESS_MIN              16
+
+/* Suggested minimum buffer size to use for autodetection. */
+#define ENCODING_GUESS_SUGGESTED        1024
+
+/* Parsing encoding names. */
+const char *encoding_guess_parse_encoding (const char *encoding);
+bool encoding_guess_encoding_is_auto (const char *encoding);
+
+/* Making an initial coding guess based on the start of a file. */
+const char *encoding_guess_head_encoding (const char *encoding,
+                                          const void *, size_t);
+
+/* Refining an initial ASCII coding guess using later non-ASCII bytes. */
+static inline bool encoding_guess_is_ascii_text (uint8_t c);
+size_t encoding_guess_count_ascii (const void *, size_t);
+bool encoding_guess_tail_is_utf8 (const void *, size_t);
+const char *encoding_guess_tail_encoding (const char *encoding,
+                                          const void *, size_t);
+
+/* Guessing from entire file contents. */
+const char *encoding_guess_whole_file (const char *encoding,
+                                       const void *, size_t);
+
+/* Returns true if C is a byte that might appear in an ASCII text file,
+   false otherwise. */
+static inline bool
+encoding_guess_is_ascii_text (uint8_t c)
+{
+  return (c >= 0x20 && c < 0x7f) || (c >= 0x09 && c < 0x0e);
+}
+
+#endif /* libpspp/encoding-guesser.h */
index b1eded3a3f4d41e658dd2c5aad57d4991e251bc7..68bbe954f38768d80d48a9c1f90ae71873daf086 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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,6 +30,7 @@
 #include "libpspp/temp-file.h"
 
 #include "gl/error.h"
+#include "gl/unlocked-io.h"
 #include "gl/xalloc.h"
 
 #include "gettext.h"
index 0450dbeacc1d2573f35230b611a93db12b6ea7bd..4ba4c9375b6efd410f5362b6e48209838e7688ab 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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 <libpspp/float-format.h>
+#include "libpspp/float-format.h"
 
+#include <byteswap.h>
 #include <ctype.h>
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/integer-format.h>
+#include "libpspp/assertion.h"
+#include "libpspp/integer-format.h"
 
-#include "error.h"
-#include <byteswap.h>
+#include "gl/error.h"
 \f
 /* Neutral intermediate representation for binary floating-point numbers. */
 struct fp
index b2af548f3986c0004b4ea34e7621639447e4bd40..9cabf9bf2e228c0db8be76526096bc3c1694e4ba 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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,7 +19,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/compiler.h>
+#include "libpspp/compiler.h"
 
 /* A floating-point format. */
 enum float_format
diff --git a/src/libpspp/getl.c b/src/libpspp/getl.c
deleted file mode 100644 (file)
index 9db6c3a..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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/getl.h"
-
-#include <stdlib.h>
-
-#include "libpspp/ll.h"
-#include "libpspp/str.h"
-#include "libpspp/string-array.h"
-
-#include "gl/configmake.h"
-#include "gl/relocatable.h"
-#include "gl/xalloc.h"
-
-struct getl_source
-  {
-    struct getl_source *included_from; /* File that this is nested inside. */
-    struct getl_source *includes;      /* File nested inside this file. */
-
-    struct ll  ll;   /* Element in the sources list */
-
-    struct getl_interface *interface;
-    enum syntax_mode syntax_mode;
-    enum error_mode error_mode;
-  };
-
-struct source_stream
-  {
-    struct ll_list sources ;  /* List of source files. */
-    struct string_array include_path;
-  };
-
-char **
-getl_include_path (const struct source_stream *ss_)
-{
-  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 *
-current_source (const struct source_stream *ss)
-{
-  const struct ll *ll = ll_head (&ss->sources);
-  return ll_data (ll, struct getl_source, ll );
-}
-
-enum syntax_mode
-source_stream_current_syntax_mode (const struct source_stream *ss)
-{
-  struct getl_source *cs = current_source (ss);
-
-  return cs->syntax_mode;
-}
-
-
-
-enum error_mode
-source_stream_current_error_mode (const struct source_stream *ss)
-{
-  struct getl_source *cs = current_source (ss);
-
-  return cs->error_mode;
-}
-
-
-
-/* Initialize getl. */
-struct source_stream *
-create_source_stream (void)
-{
-  struct source_stream *ss;
-
-  ss = xzalloc (sizeof (*ss));
-  ll_init (&ss->sources);
-
-  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;
-}
-
-/* Delete everything from the include path. */
-void
-getl_clear_include_path (struct source_stream *ss)
-{
-  string_array_clear (&ss->include_path);
-}
-
-/* Add to the include path. */
-void
-getl_add_include_dir (struct source_stream *ss, const char *path)
-{
-  string_array_append (&ss->include_path, path);
-}
-
-/* Appends source S to the list of source files. */
-void
-getl_append_source (struct source_stream *ss,
-                   struct getl_interface *i,
-                   enum syntax_mode syntax_mode,
-                   enum error_mode err_mode)
-{
-  struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
-
-  s->interface = i ;
-  s->syntax_mode = syntax_mode;
-  s->error_mode = err_mode;
-
-  ll_push_tail (&ss->sources, &s->ll);
-}
-
-/* Nests source S within the current source file. */
-void
-getl_include_source (struct source_stream *ss,
-                    struct getl_interface *i,
-                    enum syntax_mode syntax_mode,
-                    enum error_mode err_mode)
-{
-  struct getl_source *current = current_source (ss);
-  struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
-
-  s->interface = i;
-
-  s->included_from = current ;
-  s->includes  = NULL;
-  s->syntax_mode  = syntax_mode;
-  s->error_mode = err_mode;
-  current->includes = s;
-
-  ll_push_head (&ss->sources, &s->ll);
-}
-
-/* Closes the current source, and move  the current source to the
-   next file in the chain. */
-static void
-close_source (struct source_stream *ss)
-{
-  struct getl_source *s = current_source (ss);
-
-  if ( s->interface->close )
-    s->interface->close (s->interface);
-
-  ll_pop_head (&ss->sources);
-
-  if (s->included_from != NULL)
-    current_source (ss)->includes = NULL;
-
-  free (s);
-}
-
-/* Closes all sources until an interactive source is
-   encountered. */
-void
-getl_abort_noninteractive (struct source_stream *ss)
-{
-  while ( ! ll_is_empty (&ss->sources))
-    {
-      const struct getl_source *s = current_source (ss);
-
-      if ( !s->interface->interactive (s->interface) )
-       close_source (ss);
-    }
-}
-
-/* Returns true if the current source is interactive,
-   false otherwise. */
-bool
-getl_is_interactive (const struct source_stream *ss)
-{
-  const struct getl_source *s = current_source (ss);
-
-  if (ll_is_empty (&ss->sources) )
-    return false;
-
-  return s->interface->interactive (s->interface);
-}
-
-/* Returns the name of the current source, or NULL if there is no
-   current source */
-const char *
-getl_source_name (const struct source_stream *ss)
-{
-  const struct getl_source *s = current_source (ss);
-
-  if ( ll_is_empty (&ss->sources) )
-    return NULL;
-
-  if ( ! s->interface->name )
-    return NULL;
-
-  return s->interface->name (s->interface);
-}
-
-/* Returns the line number within the current source, or 0 if there is no
-   current source. */
-int
-getl_source_location (const struct source_stream *ss)
-{
-  const struct getl_source *s = current_source (ss);
-
-  if ( ll_is_empty (&ss->sources) )
-    return 0;
-
-  if ( !s->interface->location )
-    return 0;
-
-  return s->interface->location (s->interface);
-}
-
-
-/* Close getl. */
-void
-destroy_source_stream (struct source_stream *ss)
-{
-  while ( !ll_is_empty (&ss->sources))
-    close_source (ss);
-  string_array_destroy (&ss->include_path);
-
-  free (ss);
-}
-
-
-/* Reads a single line into LINE.
-   Returns true when a line has been read, false at end of input.
-*/
-bool
-getl_read_line (struct source_stream *ss, struct string *line)
-{
-  assert (ss != NULL);
-  while (!ll_is_empty (&ss->sources))
-    {
-      struct getl_source *s = current_source (ss);
-
-      ds_clear (line);
-      if (s->interface->read (s->interface, line))
-        {
-          while (s)
-           {
-             if (s->interface->filter)
-               s->interface->filter (s->interface, line);
-             s = s->included_from;
-           }
-
-          return true;
-        }
-      close_source (ss);
-    }
-
-  return false;
-}
diff --git a/src/libpspp/getl.h b/src/libpspp/getl.h
deleted file mode 100644 (file)
index 47dea27..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 GETL_H
-#define GETL_H 1
-
-#include <stdbool.h>
-#include <libpspp/ll.h>
-
-struct string;
-
-struct getl_source;
-
-/* Syntax rules that apply to a given source line. */
-enum syntax_mode
-  {
-    /* Each line that begins in column 1 starts a new command.  A
-       `+' or `-' in column 1 is ignored to allow visual
-       indentation of new commands.  Continuation lines must be
-       indented from the left margin.  A period at the end of a
-       line does end a command, but it is optional. */
-    GETL_BATCH,
-
-    /* Each command must end in a period or in a blank line. */
-    GETL_INTERACTIVE
-  };
-
-enum error_mode
-  {
-    /* When errors are encountered, report the error and continue to
-       the next command. */
-    ERRMODE_CONTINUE,
-
-    /* When errors are encountered, abort the current stream. */
-    ERRMODE_STOP
-  };
-
-/* An abstract base class for objects which act as line buffers for the
-   PSPP.  Ie anything which might contain content for the lexer */
-struct getl_interface
-  {
-    /* Returns true if the interface is interactive, that is, if
-       it prompts a human user.  This property is independent of
-       the syntax mode returned by the read member function. */
-    bool  (*interactive) (const struct getl_interface *);
-
-    /* Read a line the intended syntax mode from the interface.
-       Returns true if succesful, false on failure or at end of
-       input. */
-    bool  (*read)  (struct getl_interface *,
-                    struct string *);
-
-    /* Close and destroy the interface */
-    void  (*close) (struct getl_interface *);
-
-    /* Filter for current and all included sources, which may
-       modify the line.  Usually null.  */
-    void  (*filter) (struct getl_interface *,
-                     struct string *line);
-
-    /* Returns the name of the source */
-    const char * (*name) (const struct getl_interface *);
-
-    /* Returns the current location within the source */
-    int (*location) (const struct getl_interface *);
-  };
-
-struct source_stream;
-
-struct source_stream *create_source_stream (void);
-
-enum syntax_mode source_stream_current_syntax_mode
-   (const struct source_stream *);
-
-
-enum error_mode source_stream_current_error_mode
-   (const struct source_stream *);
-
-
-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 *);
-char **getl_include_path (const struct source_stream *);
-
-void getl_abort_noninteractive (struct source_stream *);
-bool getl_is_interactive (const struct source_stream *);
-
-bool getl_read_line (struct source_stream *, struct string *);
-
-void getl_append_source (struct source_stream *, struct getl_interface *s,
-                        enum syntax_mode, enum error_mode) ;
-
-void getl_include_source (struct source_stream *, struct getl_interface *s,
-                         enum syntax_mode, enum error_mode) ;
-
-const char * getl_source_name (const struct source_stream *);
-int getl_source_location (const struct source_stream *);
-
-#endif /* line-buffer.h */
index a72ee06e185e8171efe4f50270215af4ac340943..c43017313a789666ca83bb8373351bc59972a3b0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2008, 2009, 2010, 2011 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,7 +15,9 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <libpspp/hash-functions.h>
+
+#include "libpspp/hash-functions.h"
+
 #include <assert.h>
 #include <ctype.h>
 #include <math.h>
@@ -100,13 +102,12 @@ hash_string (const char *s, unsigned int basis)
   return hash_bytes (s, strlen (s), basis);
 }
 
-/* Returns a hash value for null-terminated string S, with
-   lowercase and uppercase letters treated as equal, starting
-   from BASIS. */
+/* Returns a hash value for the N bytes at S, with lowercase and uppercase
+   letters treated as equal, starting from BASIS. */
 unsigned int
-hash_case_string (const char *s, unsigned int basis)
+hash_case_bytes (const void *s_, size_t n, unsigned int basis)
 {
-  size_t n = strlen (s);
+  const char *s = s_;
   uint32_t a, b, c;
   uint32_t tmp[3];
   int i;
@@ -139,6 +140,15 @@ hash_case_string (const char *s, unsigned int basis)
   return c;
 }
 
+/* Returns a hash value for null-terminated string S, with
+   lowercase and uppercase letters treated as equal, starting
+   from BASIS. */
+unsigned int
+hash_case_string (const char *s, unsigned int basis)
+{
+  return hash_case_bytes (s, strlen (s), basis);
+}
+
 /* Returns a hash value for integer X, starting from BASIS. */
 unsigned int
 hash_int (int x, unsigned int basis)
@@ -157,20 +167,21 @@ hash_int (int x, unsigned int basis)
 unsigned int
 hash_double (double d, unsigned int basis)
 {
-#if SIZEOF_DOUBLE == 8
-  uint32_t tmp[2];
-  uint32_t a, b, c;
+  if (sizeof (double) == 8)
+    {
+      uint32_t tmp[2];
+      uint32_t a, b, c;
 
-  a = b = c = 0xdeadbeef + 8 + basis;
+      a = b = c = 0xdeadbeef + 8 + basis;
 
-  memcpy (tmp, &d, 8);
-  a += tmp[0];
-  b += tmp[1];
-  HASH_FINAL (a, b, c);
-  return c;
-#else /* SIZEOF_DOUBLE != 8 */
-  return hash_bytes (&d, sizeof d, basis);
-#endif /* SIZEOF_DOUBLE != 8 */
+      memcpy (tmp, &d, 8);
+      a += tmp[0];
+      b += tmp[1];
+      HASH_FINAL (a, b, c);
+      return c;
+    }
+  else
+    return hash_bytes (&d, sizeof d, basis);
 }
 
 /* Returns a hash value for pointer P, starting from BASIS. */
index bdf3da31ab7578fa464b693fe059b91382957ee3..86414fb1c22dc870e6b0a5ac53ba2f1b3a7805d1 100644 (file)
@@ -21,6 +21,7 @@
 
 unsigned int hash_bytes (const void *, size_t, unsigned int basis);
 unsigned int hash_string (const char *, unsigned int basis);
+unsigned int hash_case_bytes (const void *, size_t, unsigned int basis);
 unsigned int hash_case_string (const char *, unsigned int basis);
 unsigned int hash_int (int, unsigned int basis);
 unsigned int hash_double (double, unsigned int basis);
index 9101d1f19eea6574e6a659c94b19b6b4780f9158..f2d99e3a8f31204d9a93d48cc1208695bff78713 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include <stdbool.h>
-#include "hash.h"
-#include "message.h"
+
 #include <assert.h>
 #include <limits.h>
 #include <stdbool.h>
 #include <stdlib.h>
+
 #include "array.h"
 #include "compiler.h"
+#include "hash.h"
 #include "misc.h"
-#include "str.h"
 #include "pool.h"
+#include "str.h"
 
 #include "xalloc.h"
 
index e586bcc0c18d1ae79242dc5a6ba42068db5b1f63..3281c0e273b0eabac518f71ed66ca4ddc9d2578b 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, 2011 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,7 +19,7 @@
 
 #include <stddef.h>
 #include <stdbool.h>
-#include <libpspp/hash-functions.h>
+#include "libpspp/hash-functions.h"
 
 typedef int hsh_compare_func (const void *, const void *, const void *aux);
 typedef unsigned hsh_hash_func (const void *, const void *aux);
index 30abcdc46d7fe5e7f960f98a9d14f507d9394c44..ace8e4c1ce7565c24661e4bd3e9dfaf7bb3a7f82 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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>
 #endif
 
-#include <libpspp/heap.h>
-#include <libpspp/pool.h>
-#include <libpspp/assertion.h>
+#include "libpspp/heap.h"
+#include "libpspp/pool.h"
+#include "libpspp/assertion.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* A heap. */
 struct heap
index 3a3c516a03485ab7e4a5ecac923719c3425c4ee0..c24c763277d53fde92c03f3e8360fc90e509f61d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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,7 +70,7 @@
 #ifndef LIBPSPP_HEAP_H
 #define LIBPSPP_HEAP_H 1
 
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 #include <stdbool.h>
 #include <stddef.h>
 
index 9050cc08f5571a6f2e8908201444d834a96a6398..4436f8dfca1375f89ced27f907a2cdeeb2b52111 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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>
 #endif
 
-#include <libpspp/hmap.h>
+#include "libpspp/hmap.h"
+
 #include <assert.h>
 #include <stdlib.h>
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 static size_t capacity_to_mask (size_t capacity);
 
index 095edf104674ba0af56b2a2da7d0bb4687807c0d..2776c6c8b0c840f1649a5c7f891caff8bd8d334d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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>
+#include "libpspp/cast.h"
 
 /* Returns the data structure corresponding to the given NODE,
    assuming that NODE is embedded as the given MEMBER name in
index 2fe7f9f770b21c7224182270dc87609ed7a0a104..345836192a2195e682343f3eb1b3c5127743f35d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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/hmap.h>
+#include "libpspp/hmap.h"
 #include <stdlib.h>
 
 /* Hash table node. */
index 4934617121c786f5b19c6db88cc20e6f2033f116..a3dc08a1ff26982171e8b9cf9c15543e74a2d506 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011 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,6 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unigbrk.h>
 
 #include "libpspp/assertion.h"
 #include "libpspp/hmapx.h"
@@ -35,6 +36,7 @@
 #include "libpspp/str.h"
 #include "libpspp/version.h"
 
+#include "gl/c-strcase.h"
 #include "gl/localcharset.h"
 #include "gl/xalloc.h"
 #include "gl/relocatable.h"
@@ -45,14 +47,15 @@ struct converter
     char *tocode;
     char *fromcode;
     iconv_t conv;
+    int error;
   };
 
 static char *default_encoding;
 static struct hmapx map;
 
 /* A wrapper around iconv_open */
-static iconv_t
-create_iconv (const char* tocode, const char* fromcode)
+static struct converter *
+create_iconv__ (const char* tocode, const char* fromcode)
 {
   size_t hash;
   struct hmapx_node *node;
@@ -63,28 +66,53 @@ create_iconv (const char* tocode, const char* fromcode)
   HMAPX_FOR_EACH_WITH_HASH (converter, node, hash, &map)
     if (!strcmp (tocode, converter->tocode)
         && !strcmp (fromcode, converter->fromcode))
-      return converter->conv;
+      return converter;
 
   converter = xmalloc (sizeof *converter);
   converter->tocode = xstrdup (tocode);
   converter->fromcode = xstrdup (fromcode);
   converter->conv = iconv_open (tocode, fromcode);
+  converter->error = converter->conv == (iconv_t) -1 ? errno : 0;
   hmapx_insert (&map, converter, hash);
 
+  return converter;
+}
+
+static iconv_t
+create_iconv (const char* tocode, const char* fromcode)
+{
+  struct converter *converter;
+
+  converter = create_iconv__ (tocode, fromcode);
+
   /* I don't think it's safe to translate this string or to use messaging
      as the converters have not yet been set up */
-  if ( (iconv_t) -1 == converter->conv && 0 != strcmp (tocode, fromcode))
+  if (converter->error && strcmp (tocode, fromcode))
     {
-      const int err = errno;
       fprintf (stderr,
                "Warning: "
                "cannot create a converter for `%s' to `%s': %s\n",
-               fromcode, tocode, strerror (err));
+               fromcode, tocode, strerror (converter->error));
+      converter->error = 0;
     }
 
   return converter->conv;
 }
 
+/* Converts the single byte C from encoding FROM to TO, returning the first
+   byte of the result.
+
+   This function probably shouldn't be used at all, but some code still does
+   use it. */
+char
+recode_byte (const char *to, const char *from, char c)
+{
+  char x;
+  char *s = recode_string (to, from, &c, 1);
+  x = s[0];
+  free (s);
+  return x;
+}
 
 /* Similar to recode_string_pool, but allocates the returned value on the heap
    instead of in a pool.  It is the caller's responsibility to free the
@@ -96,6 +124,17 @@ recode_string (const char *to, const char *from,
   return recode_string_pool (to, from, text, length, NULL);
 }
 
+/* Returns the length, in bytes, of the string that a similar recode_string()
+   call would return. */
+size_t
+recode_string_len (const char *to, const char *from,
+                   const char *text, int length)
+{
+  char *s = recode_string (to, from, text, length);
+  size_t len = strlen (s);
+  free (s);
+  return len;
+}
 
 /* Uses CONV to convert the INBYTES starting at IP into the OUTBYTES starting
    at OP, and appends a null terminator to the output.
@@ -180,6 +219,279 @@ recode_string_pool (const char *to, const char *from,
   return out.string;
 }
 
+/* Returns the name of the encoding that should be used for file names.
+
+   This is meant to be the same encoding used by g_filename_from_uri() and
+   g_filename_to_uri() in GLib. */
+static const char *
+filename_encoding (void)
+{
+#if defined _WIN32 || defined __WIN32__
+  return "UTF-8";
+#else
+  return locale_charset ();
+#endif
+}
+
+static char *
+xconcat2 (const char *a, size_t a_len,
+          const char *b, size_t b_len)
+{
+  char *s = xmalloc (a_len + b_len + 1);
+  memcpy (s, a, a_len);
+  memcpy (s + a_len, b, b_len);
+  s[a_len + b_len] = '\0';
+  return s;
+}
+
+/* Conceptually, this function concatenates HEAD_LEN-byte string HEAD and
+   TAIL_LEN-byte string TAIL, both encoded in UTF-8, then converts them to
+   ENCODING.  If the re-encoded result is no more than MAX_LEN bytes long, then
+   it returns HEAD_LEN.  Otherwise, it drops one character[*] from the end of
+   HEAD and tries again, repeating as necessary until the concatenated result
+   fits or until HEAD_LEN reaches 0.
+
+   [*] Actually this function drops grapheme clusters instead of characters, so
+       that, e.g. a Unicode character followed by a combining accent character
+       is either completely included or completely excluded from HEAD_LEN.  See
+       UAX #29 at http://unicode.org/reports/tr29/ for more information on
+       grapheme clusters.
+
+   A null ENCODING is treated as UTF-8.
+
+   Sometimes this function has to actually construct the concatenated string to
+   measure its length.  When this happens, it sets *RESULTP to that
+   null-terminated string, allocated with malloc(), for the caller to use if it
+   needs it.  Otherwise, it sets *RESULTP to NULL.
+
+   Simple examples for encoding="UTF-8", max_len=6:
+
+       head="abc",  tail="xyz"     => 3
+       head="abcd", tail="xyz"     => 3 ("d" dropped).
+       head="abc",  tail="uvwxyz"  => 0 ("abc" dropped).
+       head="abc",  tail="tuvwxyz" => 0 ("abc" dropped).
+
+   Examples for encoding="ISO-8859-1", max_len=6:
+
+       head="éèä",  tail="xyz"     => 6
+         (each letter in head is only 1 byte in ISO-8859-1 even though they
+          each take 2 bytes in UTF-8 encoding)
+*/
+static size_t
+utf8_encoding_concat__ (const char *head, size_t head_len,
+                        const char *tail, size_t tail_len,
+                        const char *encoding, size_t max_len,
+                        char **resultp)
+{
+  *resultp = NULL;
+  if (head_len == 0)
+    return 0;
+  else if (encoding == NULL || !c_strcasecmp (encoding, "UTF-8"))
+    {
+      if (head_len + tail_len <= max_len)
+        return head_len;
+      else if (tail_len >= max_len)
+        return 0;
+      else
+        {
+          size_t copy_len;
+          ucs4_t prev;
+          size_t ofs;
+          int mblen;
+
+          copy_len = 0;
+          for (ofs = u8_mbtouc (&prev, CHAR_CAST (const uint8_t *, head),
+                                head_len);
+               ofs <= max_len - tail_len;
+               ofs += mblen)
+            {
+              ucs4_t next;
+
+              mblen = u8_mbtouc (&next,
+                                 CHAR_CAST (const uint8_t *, head + ofs),
+                                 head_len - ofs);
+              if (uc_is_grapheme_break (prev, next))
+                copy_len = ofs;
+
+              prev = next;
+            }
+
+          return copy_len;
+        }
+    }
+  else
+    {
+      char *result;
+
+      result = (tail_len > 0
+                ? xconcat2 (head, head_len, tail, tail_len)
+                : CONST_CAST (char *, head));
+      if (recode_string_len (encoding, "UTF-8", result,
+                             head_len + tail_len) <= max_len)
+        {
+          *resultp = result != head ? result : NULL;
+          return head_len;
+        }
+      else
+        {
+          bool correct_result = false;
+          size_t copy_len;
+          ucs4_t prev;
+          size_t ofs;
+          int mblen;
+
+          copy_len = 0;
+          for (ofs = u8_mbtouc (&prev, CHAR_CAST (const uint8_t *, head),
+                                head_len);
+               ofs <= head_len;
+               ofs += mblen)
+            {
+              ucs4_t next;
+
+              mblen = u8_mbtouc (&next,
+                                 CHAR_CAST (const uint8_t *, head + ofs),
+                                 head_len - ofs);
+              if (uc_is_grapheme_break (prev, next))
+                {
+                  if (result != head)
+                    {
+                      memcpy (result, head, ofs);
+                      memcpy (result + ofs, tail, tail_len);
+                      result[ofs + tail_len] = '\0';
+                    }
+
+                  if (recode_string_len (encoding, "UTF-8", result,
+                                         ofs + tail_len) <= max_len)
+                    {
+                      correct_result = true;
+                      copy_len = ofs;
+                    }
+                  else
+                    correct_result = false;
+                }
+
+              prev = next;
+            }
+
+          if (result != head)
+            {
+              if (correct_result)
+                *resultp = result;
+              else
+                free (result);
+            }
+
+          return copy_len;
+        }
+    }
+}
+
+/* Concatenates a prefix of HEAD with all of TAIL and returns the result as a
+   null-terminated string owned by the caller.  HEAD, TAIL, and the returned
+   string are all encoded in UTF-8.  As many characters[*] from the beginning
+   of HEAD are included as will fit within MAX_LEN bytes supposing that the
+   resulting string were to be re-encoded in ENCODING.  All of TAIL is always
+   included, even if TAIL by itself is longer than MAX_LEN in ENCODING.
+
+   [*] Actually this function drops grapheme clusters instead of characters, so
+       that, e.g. a Unicode character followed by a combining accent character
+       is either completely included or completely excluded from the returned
+       string.  See UAX #29 at http://unicode.org/reports/tr29/ for more
+       information on grapheme clusters.
+
+   A null ENCODING is treated as UTF-8.
+
+   Simple examples for encoding="UTF-8", max_len=6:
+
+       head="abc",  tail="xyz"     => "abcxyz"
+       head="abcd", tail="xyz"     => "abcxyz"
+       head="abc",  tail="uvwxyz"  => "uvwxyz"
+       head="abc",  tail="tuvwxyz" => "tuvwxyz"
+
+   Examples for encoding="ISO-8859-1", max_len=6:
+
+       head="éèä",  tail="xyz"    => "éèäxyz"
+         (each letter in HEAD is only 1 byte in ISO-8859-1 even though they
+          each take 2 bytes in UTF-8 encoding)
+*/
+char *
+utf8_encoding_concat (const char *head, const char *tail,
+                      const char *encoding, size_t max_len)
+{
+  size_t tail_len = strlen (tail);
+  size_t prefix_len;
+  char *result;
+
+  prefix_len = utf8_encoding_concat__ (head, strlen (head), tail, tail_len,
+                                       encoding, max_len, &result);
+  return (result != NULL
+          ? result
+          : xconcat2 (head, prefix_len, tail, tail_len));
+}
+
+/* Returns the length, in bytes, of the string that would be returned by
+   utf8_encoding_concat() if passed the same arguments, but the implementation
+   is often more efficient. */
+size_t
+utf8_encoding_concat_len (const char *head, const char *tail,
+                          const char *encoding, size_t max_len)
+{
+  size_t tail_len = strlen (tail);
+  size_t prefix_len;
+  char *result;
+
+  prefix_len = utf8_encoding_concat__ (head, strlen (head), tail, tail_len,
+                                       encoding, max_len, &result);
+  free (result);
+  return prefix_len + tail_len;
+}
+
+/* Returns an allocated, null-terminated string, owned by the caller,
+   containing as many characters[*] from the beginning of S that would fit
+   within MAX_LEN bytes if the returned string were to be re-encoded in
+   ENCODING.  Both S and the returned string are encoded in UTF-8.
+
+   [*] Actually this function drops grapheme clusters instead of characters, so
+       that, e.g. a Unicode character followed by a combining accent character
+       is either completely included or completely excluded from the returned
+       string.  See UAX #29 at http://unicode.org/reports/tr29/ for more
+       information on grapheme clusters.
+
+   A null ENCODING is treated as UTF-8.
+*/
+char *
+utf8_encoding_trunc (const char *s, const char *encoding, size_t max_len)
+{
+  return utf8_encoding_concat (s, "", encoding, max_len);
+}
+
+/* Returns the length, in bytes, of the string that would be returned by
+   utf8_encoding_trunc() if passed the same arguments, but the implementation
+   is often more efficient. */
+size_t
+utf8_encoding_trunc_len (const char *s, const char *encoding, size_t max_len)
+{
+  return utf8_encoding_concat_len (s, "", encoding, max_len);
+}
+
+/* Returns FILENAME converted from UTF-8 to the filename encoding.
+   On Windows the filename encoding is UTF-8; elsewhere it is based on the
+   current locale. */
+char *
+utf8_to_filename (const char *filename)
+{
+  return recode_string (filename_encoding (), "UTF-8", filename, -1);
+}
+
+/* Returns FILENAME converted from the filename encoding to UTF-8.
+   On Windows the filename encoding is UTF-8; elsewhere it is based on the
+   current locale. */
+char *
+filename_to_utf8 (const char *filename)
+{
+  return recode_string ("UTF-8", filename_encoding (), filename, -1);
+}
+
 /* Converts the string TEXT, which should be encoded in FROM-encoding, to a
    dynamically allocated string in TO-encoding.  Any characters which cannot be
    converted will be represented by '?'.
@@ -208,7 +520,7 @@ recode_substring_pool (const char *to, const char *from,
   if ( (iconv_t) -1 == conv )
     {
       struct substring out;
-      ss_alloc_substring (&out, text);
+      ss_alloc_substring_pool (&out, text, pool);
       return out;
     }
 
@@ -229,17 +541,13 @@ recode_substring_pool (const char *to, const char *from,
 void
 i18n_init (void)
 {
-#if ENABLE_NLS
   setlocale (LC_CTYPE, "");
-#ifdef LC_MESSAGES
   setlocale (LC_MESSAGES, "");
-#endif
 #if HAVE_LC_PAPER
   setlocale (LC_PAPER, "");
 #endif
   bindtextdomain (PACKAGE, relocate(locale_dir));
   textdomain (PACKAGE);
-#endif /* ENABLE_NLS */
 
   assert (default_encoding == NULL);
   default_encoding = xstrdup (locale_charset ());
@@ -247,7 +555,6 @@ i18n_init (void)
   hmapx_init (&map);
 }
 
-
 const char *
 get_default_encoding (void)
 {
@@ -314,7 +621,8 @@ i18n_done (void)
     {
       free (cvtr->tocode);
       free (cvtr->fromcode);
-      iconv_close (cvtr->conv);
+      if (cvtr->conv != (iconv_t) -1)
+        iconv_close (cvtr->conv);
       free (cvtr);
     }
 
@@ -367,3 +675,70 @@ get_system_decimal (void)
   return radix_char;
 }
 
+const char *
+uc_name (ucs4_t uc, char buffer[16])
+{
+  if (uc >= 0x20 && uc < 0x7f)
+    snprintf (buffer, 16, "`%c'", uc);
+  else
+    snprintf (buffer, 16, "U+%04X", uc);
+  return buffer;
+}
+\f
+bool
+get_encoding_info (struct encoding_info *e, const char *name)
+{
+  const struct substring in = SS_LITERAL_INITIALIZER (
+    "\t\n\v\f\r "
+    "!\"#$%&'()*+,-./0123456789:;<=>?@"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
+    "abcdefghijklmnopqrstuvwxyz{|}~");
+
+  struct substring out, cr, lf;
+  bool ok;
+
+  memset (e, 0, sizeof *e);
+
+  cr = recode_substring_pool (name, "UTF-8", ss_cstr ("\r"), NULL);
+  lf = recode_substring_pool (name, "UTF-8", ss_cstr ("\n"), NULL);
+  ok = cr.length >= 1 && cr.length <= MAX_UNIT && cr.length == lf.length;
+  if (!ok)
+    {
+      fprintf (stderr, "warning: encoding `%s' is not supported.\n", name);
+      ss_dealloc (&cr);
+      ss_dealloc (&lf);
+      ss_alloc_substring (&cr, ss_cstr ("\r"));
+      ss_alloc_substring (&lf, ss_cstr ("\n"));
+    }
+
+  e->unit = cr.length;
+  memcpy (e->cr, cr.string, e->unit);
+  memcpy (e->lf, lf.string, e->unit);
+
+  ss_dealloc (&cr);
+  ss_dealloc (&lf);
+
+  out = recode_substring_pool ("UTF-8", name, in, NULL);
+  e->is_ascii_compatible = ss_equals (in, out);
+  ss_dealloc (&out);
+
+  return ok;
+}
+
+bool
+is_encoding_ascii_compatible (const char *encoding)
+{
+  struct encoding_info e;
+
+  get_encoding_info (&e, encoding);
+  return e.is_ascii_compatible;
+}
+
+/* Returns true if iconv can convert ENCODING to and from UTF-8,
+   otherwise false. */
+bool
+is_encoding_supported (const char *encoding)
+{
+  return (create_iconv__ ("UTF-8", encoding)->conv != (iconv_t) -1
+          && create_iconv__ (encoding, "UTF-8")->conv != (iconv_t) -1);
+}
index 37bd94406564e13a9282a8fd4d8e76a5e319a3bf..fc3a64935e4e903b4abf1dc3abe6861d46bd5b8b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011 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 I18N_H
 
 #include <stdbool.h>
+#include <unistr.h>
 
 void  i18n_done (void);
 void  i18n_init (void);
 
 #define UTF8 "UTF-8"
 
+/* The encoding of literal strings in PSPP source code, as seen at execution
+   time.  In fact this is likely to be some extended ASCII encoding, such as
+   UTF-8 or ISO-8859-1, but ASCII is adequate for our purposes. */
+#define C_ENCODING "ASCII"
+
 struct pool;
 
+char recode_byte (const char *to, const char *from, char);
+
 char *recode_string (const char *to, const char *from,
                      const char *text, int len);
 char *recode_string_pool (const char *to, const char *from,
@@ -33,6 +41,22 @@ char *recode_string_pool (const char *to, const char *from,
 struct substring recode_substring_pool (const char *to, const char *from,
                                         struct substring text, struct pool *);
 
+size_t recode_string_len (const char *to, const char *from,
+                          const char *text, int len);
+
+char *utf8_encoding_trunc (const char *, const char *encoding,
+                           size_t max_len);
+size_t utf8_encoding_trunc_len (const char *, const char *encoding,
+                                size_t max_len);
+
+char *utf8_encoding_concat (const char *head, const char *tail,
+                            const char *encoding, size_t max_len);
+size_t utf8_encoding_concat_len (const char *head, const char *tail,
+                                 const char *encoding, size_t max_len);
+
+char *utf8_to_filename (const char *filename);
+char *filename_to_utf8 (const char *filename);
+
 bool valid_encoding (const char *enc);
 
 char get_system_decimal (void);
@@ -42,5 +66,74 @@ void set_default_encoding (const char *enc);
 
 bool set_encoding_from_locale (const char *loc);
 
+const char *uc_name (ucs4_t uc, char buffer[16]);
+\f
+/* Information about character encodings. */
+
+/* ISO C defines a set of characters that a C implementation must support at
+   runtime, called the C basic execution character set, which consists of the
+   following characters:
+
+       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
+       n o p q r s t u v w x y z
+       0 1 2 3 4 5 6 7 8 9
+       ! " # % & ' ( ) * + , - . / :
+       ; < = > ? [ \ ] ^ _ { | } ~
+       space \a \b \r \n \t \v \f \0
+
+   The following is true of every member of the C basic execution character
+   set in all "reasonable" encodings:
+
+       1. Every member of the C basic character set is encoded.
+
+       2. Every member of the C basic character set has the same width in
+          bytes, called the "unit width".  Most encodings have a unit width of
+          1 byte, but UCS-2 and UTF-16 have a unit width of 2 bytes and UCS-4
+          and UTF-32 have a unit width of 4 bytes.
+
+       3. In a stateful encoding, the encoding of members of the C basic
+          character set does not vary with shift state.
+
+       4. When a string is read unit-by-unit, a unit that has the encoded value
+          of a member of the C basic character set, EXCEPT FOR THE DECIMAL
+          DIGITS, always represents that member.  That is, if the encoding has
+          multi-unit characters, the units that encode the C basic character
+          set are never part of a multi-unit character.
+
+          The exception for decimal digits is due to GB18030, which uses
+          decimal digits as part of multi-byte encodings.
+
+   All 8-bit and wider encodings that I have been able to find follow these
+   rules.  7-bit and narrower encodings (e.g. UTF-7) do not.  I'm not too
+   concerned about that. */
+
+#include <stdbool.h>
+
+/* Maximum width of a unit, in bytes.  UTF-32 with 4-byte units is the widest
+   that I am aware of. */
+#define MAX_UNIT 4
+
+/* Information about an encoding. */
+struct encoding_info
+  {
+    /* Encoding name.  IANA says character set names may be up to 40 US-ASCII
+       characters. */
+    char name[41];
+
+    /* True if this encoding has a unit width of 1 byte, and every character
+       used in ASCII text files has the same value in this encoding. */
+    bool is_ascii_compatible;
+
+    /* Character information. */
+    int unit;                   /* Unit width, in bytes. */
+    char cr[MAX_UNIT];          /* \r in encoding, 'unit' bytes long. */
+    char lf[MAX_UNIT];          /* \n in encoding, 'unit' bytes long. */
+  };
+
+bool get_encoding_info (struct encoding_info *, const char *name);
+bool is_encoding_ascii_compatible (const char *encoding);
+bool is_encoding_supported (const char *encoding);
 
 #endif /* i18n.h */
index 2d8a72efe68569d015e67a62b3a851e19c7a8121..c248e0ff042b8c765ebe5724d3aa82d7e278a76c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <libpspp/integer-format.h>
+#include "libpspp/integer-format.h"
 
 #include <assert.h>
 
index 8649bf0c390f3f80982fd628a46a0807130d5681..e888292f27d0214ab19fc746c7650777f882067a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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,7 +20,7 @@
 #include <byteswap.h>
 #include <stdint.h>
 
-#include <libpspp/str.h>
+#include "libpspp/str.h"
 
 /* An integer format. */
 enum integer_format
index 0bb9277dc9172ae3aad1b801df4fba36cc606dac..fc31acf0b439fec19c339296abe3e5fe8f5ce314 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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 <string.h>
 
 #include "libpspp/assertion.h"
+#include "libpspp/cast.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
 
@@ -32,20 +33,22 @@ struct interned_string
   {
     struct hmap_node node;      /* Node in hash table. */
     size_t ref_cnt;             /* Reference count. */
+    size_t length;              /* strlen(string).  */
     char string[1];             /* Null-terminated string. */
   };
 
 /* All interned strings. */
 static struct hmap interns = HMAP_INITIALIZER (interns);
 
-/* Searches the table of interned string for  */
+/* Searches the table of interned strings for one equal to S, which has length
+   LENGTH and hash value HASH. */
 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))
+    if (is->length == length && !memcmp (s, is->string, length))
       return is;
 
   return NULL;
@@ -68,16 +71,17 @@ intern_new (const char *s)
       is = xmalloc (length + sizeof *is);
       hmap_insert (&interns, &is->node, hash);
       is->ref_cnt = 1;
+      is->length = length;
       memcpy (is->string, s, length + 1);
     }
   return is->string;
 }
 
 static struct interned_string *
-interned_string_from_string (const char *s)
+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);
+  char (*s)[1] = (char (*)[1]) s_;
+  struct interned_string *is = UP_CAST (s, struct interned_string, string);
   assert (is->ref_cnt > 0);
   return is;
 }
@@ -119,3 +123,11 @@ is_interned_string (const char *s)
   unsigned int hash = hash_bytes (s, length, 0);
   return intern_lookup__ (s, length, hash) != NULL;
 }
+
+/* Returns the length of S, which must be an interned string returned by
+   intern_new(). */
+size_t
+intern_strlen (const char *s)
+{
+  return interned_string_from_string (s)->length;
+}
index 147a69a8bced253be9c747f70f4e0a94e1ae95f2..2f07a9ef77808b17f19e85adc2ffc9dc8d024262 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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
    See http://en.wikipedia.org/wiki/String_interning for more information. */
 
 #include <stdbool.h>
+#include <stddef.h>
 
 const char *intern_new (const char *);
 const char *intern_ref (const char *);
 void intern_unref (const char *);
 
+size_t intern_strlen (const char *);
+
 bool is_interned_string (const char *);
 
 #endif /* libpspp/intern.h */
diff --git a/src/libpspp/legacy-encoding.c b/src/libpspp/legacy-encoding.c
deleted file mode 100644 (file)
index 18a6219..0000000
+++ /dev/null
@@ -1,41 +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 <libpspp/legacy-encoding.h>
-#include <libpspp/i18n.h>
-#include <stdlib.h>
-
-char
-legacy_to_native (const char *from, char c)
-{
-  char x;
-  char *s = recode_string (LEGACY_NATIVE, from, &c, 1);
-  x = s[0];
-  free (s);
-  return x;
-}
-
-char
-legacy_from_native (const char *to, char c)
-{
-  char x;
-  char *s = recode_string (to, LEGACY_NATIVE, &c, 1);
-  x = s[0];
-  free (s);
-  return x;
-}
diff --git a/src/libpspp/legacy-encoding.h b/src/libpspp/legacy-encoding.h
deleted file mode 100644 (file)
index c6ae0ab..0000000
+++ /dev/null
@@ -1,34 +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 LIBPSPP_LEGACY_ENCODING
-#define LIBPSPP_LEGACY_ENCODING 1
-
-#include <libpspp/compiler.h>
-
-#if 'A' == 0x41
-#define  LEGACY_NATIVE "ASCII"
-#elif 'A' == 0xc1
-#define  LEGACY_NATIVE "EBCDIC-US"
-#else
-#error Cannot detect native character set.
-#endif
-
-char legacy_to_native (const char *from, char) PURE_FUNCTION;
-char legacy_from_native (const char *to, char) PURE_FUNCTION;
-
-
-#endif /* libpspp/legacy-encoding.h */
index e6533f2cd25fccf5beb2cbf9a4da31c279022027..21f8dd8870a2fc96b48ccfd49c228aeb7bc3db21 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2011 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
@@ -28,7 +28,8 @@
 #include <config.h>
 #endif
 
-#include <libpspp/ll.h>
+#include "libpspp/ll.h"
+
 #include <assert.h>
 
 /* Returns the number of nodes in LIST (not counting the null
index bf871f6b0f842a0a42726de48364aad08ea4d3ea..9e6e35f04ad72ee4af7264883cf080bc49359ad0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2011 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,9 +50,7 @@
 #include <assert.h>
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/cast.h>
-
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 /* Embedded, circular doubly linked list.
 
index 905850bc41c13ec74be83289e0571c0972f464dc..3a0cbf60fce154cc7c5c88e390741236ae38cc80 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2011 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
@@ -28,8 +28,8 @@
 #include <config.h>
 #endif
 
-#include <libpspp/llx.h>
-#include "compiler.h"
+#include "libpspp/llx.h"
+#include "libpspp/compiler.h"
 #include <assert.h>
 #include <stdlib.h>
 
index 2aa18e7ba5694bced71cbe32a3feb69700e23f9b..80a8a838063e3c2a3e05963c11030f4d141f5803 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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
@@ -49,7 +49,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <libpspp/ll.h>
+#include "libpspp/ll.h"
 
 /* External, circular doubly linked list.
 
index ed6d6e7a9b0cc9b3b10df864ddbc30f57a49d926..4d95ba43acb61e522c84ec2e2b775ba430ab9146 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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
@@ -16,8 +16,7 @@
 
 #include <config.h>
 
-#include "message.h"
-#include "msg-locator.h"
+#include "libpspp/message.h"
 
 #include <assert.h>
 #include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <libpspp/str.h>
-#include <libpspp/version.h>
-#include <data/settings.h>
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
+#include "data/settings.h"
 
+#include "gl/minmax.h"
 #include "gl/progname.h"
 #include "gl/xalloc.h"
 #include "gl/xvasprintf.h"
@@ -37,8 +38,9 @@
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Message handler as set by msg_init(). */
-static void (*msg_handler)  (const struct msg *);
+/* Message handler as set by msg_set_handler(). */
+static void (*msg_handler)  (const struct msg *, void *aux);
+static void *msg_aux;
 
 /* Disables emitting messages if positive. */
 static int messages_disabled;
@@ -57,30 +59,37 @@ msg (enum msg_class class, const char *format, ...)
   m.severity = msg_class_to_severity (class);
   va_start (args, format);
   m.text = xvasprintf (format, args);
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = 0;
-  m.where.last_column = 0;
+  m.file_name = NULL;
+  m.first_line = m.last_line = 0;
+  m.first_column = m.last_column = 0;
   va_end (args);
 
   msg_emit (&m);
 }
 
-static struct source_stream *s_stream;
-
 void
-msg_init (struct source_stream *ss,  void (*handler) (const struct msg *) )
+msg_set_handler (void (*handler) (const struct msg *, void *aux), void *aux)
 {
-  s_stream = ss;
   msg_handler = handler;
+  msg_aux = aux;
 }
+\f
+/* Working with messages. */
 
-void
-msg_done (void)
+const char *
+msg_severity_to_string (enum msg_severity severity)
 {
+  switch (severity)
+    {
+    case MSG_S_ERROR:
+      return _("error");
+    case MSG_S_WARNING:
+      return _("warning");
+    case MSG_S_NOTE:
+    default:
+      return _("note");
+    }
 }
-\f
-/* Working with messages. */
 
 /* Duplicate a message */
 struct msg *
@@ -89,8 +98,8 @@ msg_dup (const struct msg *m)
   struct msg *new_msg;
 
   new_msg = xmemdup (m, sizeof *m);
-  if (m->where.file_name != NULL)
-    new_msg->where.file_name = xstrdup (m->where.file_name);
+  if (m->file_name != NULL)
+    new_msg->file_name = xstrdup (m->file_name);
   new_msg->text = xstrdup (m->text);
 
   return new_msg;
@@ -98,13 +107,13 @@ msg_dup (const struct msg *m)
 
 /* Frees a message created by msg_dup().
 
-   (Messages not created by msg_dup(), as well as their where.file_name
+   (Messages not created by msg_dup(), as well as their file_name
    members, are typically not dynamically allocated, so this function should
    not be used to destroy them.) */
 void
 msg_destroy (struct msg *m)
 {
-  free (m->where.file_name);
+  free (m->file_name);
   free (m->text);
   free (m);
 }
@@ -112,47 +121,66 @@ msg_destroy (struct msg *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 > 0
-          || m->where.first_column > 0))
+      && (m->file_name || m->first_line > 0 || m->first_column > 0))
     {
-      if (m->where.file_name)
-        ds_put_format (&s, "%s", m->where.file_name);
-      if (m->where.line_number > 0)
+      int l1 = m->first_line;
+      int l2 = MAX (m->first_line, m->last_line - 1);
+      int c1 = m->first_column;
+      int c2 = MAX (m->first_column, m->last_column - 1);
+
+      if (m->file_name)
+        ds_put_format (&s, "%s", m->file_name);
+
+      if (l1 > 0)
         {
           if (!ds_is_empty (&s))
-            ds_put_char (&s, ':');
-          ds_put_format (&s, "%d", m->where.line_number);
+            ds_put_byte (&s, ':');
+
+          if (l2 > l1)
+            {
+              if (c1 > 0)
+                ds_put_format (&s, "%d.%d-%d.%d", l1, c1, l2, c2);
+              else
+                ds_put_format (&s, "%d-%d", l1, l2);
+            }
+          else
+            {
+              if (c1 > 0)
+                {
+                  if (c2 > c1)
+                    {
+                      /* The GNU coding standards say to use
+                         LINENO-1.COLUMN-1-COLUMN-2 for this case, but GNU
+                         Emacs interprets COLUMN-2 as LINENO-2 if I do that.
+                         I've submitted an Emacs bug report:
+                         http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7725.
+
+                         For now, let's be compatible. */
+                      ds_put_format (&s, "%d.%d-%d.%d", l1, c1, l1, c2);
+                    }
+                  else
+                    ds_put_format (&s, "%d.%d", l1, c1);
+                }
+              else
+                ds_put_format (&s, "%d", l1);
+            }
         }
-      if (m->where.first_column > 0)
+      else if (c1 > 0)
         {
-          ds_put_format (&s, ".%d", m->where.first_column);
-          if (m->where.last_column > m->where.first_column + 1)
-            ds_put_format (&s, "-%d", m->where.last_column - 1);
+          if (c2 > c1)
+            ds_put_format (&s, ".%d-%d", c1, c2);
+          else
+            ds_put_format (&s, ".%d", c1);
         }
       ds_put_cstr (&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);
+  ds_put_format (&s, "%s: ", msg_severity_to_string (m->severity));
 
   if (m->category == MSG_C_SYNTAX && command_name != NULL)
     ds_put_format (&s, "%s: ", command_name);
@@ -214,12 +242,13 @@ submit_note (char *s)
 
   m.category = MSG_C_GENERAL;
   m.severity = MSG_S_NOTE;
-  m.where.file_name = NULL;
-  m.where.line_number = 0;
-  m.where.first_column = 0;
-  m.where.last_column = 0;
+  m.file_name = NULL;
+  m.first_line = 0;
+  m.last_line = 0;
+  m.first_column = 0;
+  m.last_column = 0;
   m.text = s;
-  msg_handler (&m);
+  msg_handler (&m, msg_aux);
   free (s);
 }
 
@@ -236,7 +265,7 @@ process_msg (const struct msg *m)
       || (warnings_off && m->severity == MSG_S_WARNING) )
     return;
 
-  msg_handler (m);
+  msg_handler (m, msg_aux);
 
   counts[m->severity]++;
   max_msgs = settings_get_max_messages (m->severity);
@@ -271,20 +300,6 @@ process_msg (const struct msg *m)
 void
 msg_emit (struct msg *m)
 {
-  if ( s_stream && m->where.file_name == NULL )
-    {
-      struct msg_locator loc;
-
-      get_msg_location (s_stream, &loc);
-      m->where.file_name = loc.file_name;
-      m->where.line_number = loc.line_number;
-    }
-  else
-    {
-      m->where.file_name = NULL;
-      m->where.line_number = 0;
-    }
-
   if (!messages_disabled)
      process_msg (m);
 
index fad7816f19b0c57804248010203fbbda35feb512..3856ee5b812a895420886e87f7c41ce5a2f7af3e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 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,7 +19,7 @@
 
 #include <stdarg.h>
 #include <stdbool.h>
-#include <libpspp/compiler.h>
+#include "libpspp/compiler.h"
 
 /* What kind of message is this? */
 enum msg_category
@@ -39,6 +39,8 @@ enum msg_severity
     MSG_N_SEVERITIES
   };
 
+const char *msg_severity_to_string (enum msg_severity);
+
 /* Combination of a category and a severity for convenience. */
 enum msg_class
   {
@@ -67,30 +69,22 @@ msg_class_from_category_and_severity (enum msg_category category,
   return category * 3 + severity;
 }
 
-/* A file location.  */
-struct msg_locator
-  {
-    char *file_name;           /* File name (NULL if none). */
-    int line_number;           /* Line number (0 if none). */
-    int first_column;          /* 1-based column number (0 if none). */
-    int last_column;           /* 1-based exclusive last column (0 if none). */
-  };
-
 /* A message. */
 struct msg
   {
     enum msg_category category; /* Message category. */
     enum msg_severity severity; /* Message severity. */
-    struct msg_locator where;  /* File location, or (NULL, -1). */
+    char *file_name;            /* Name of file containing error, or NULL. */
+    int first_line;             /* 1-based line number, or 0 if none. */
+    int last_line;             /* 1-based exclusive last line (0=none). */
+    int first_column;           /* 1-based first column, or 0 if none. */
+    int last_column;            /* 1-based exclusive last column (0=none). */
     char *text;                 /* Error text. */
   };
 
-struct source_stream ;
-
 /* Initialization. */
-void msg_init (struct source_stream *, void (*handler) (const struct msg *) );
-
-void msg_done (void);
+void msg_set_handler (void (*handler) (const struct msg *, void *lexer),
+                      void *aux);
 
 /* Working with messages. */
 struct msg *msg_dup (const struct msg *);
@@ -107,9 +101,6 @@ void msg_enable (void);
 void msg_disable (void);
 
 /* Error context. */
-void msg_push_msg_locator (const struct msg_locator *);
-void msg_pop_msg_locator (const struct msg_locator *);
-
 bool msg_ui_too_many_errors (void);
 void msg_ui_reset_counts (void);
 bool msg_ui_any_errors (void);
index 940f89aa73495cf80fc4b8e3663cdac15c87273f..e0a0f71a62706891145c01966d4dacff94530d53 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, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <libpspp/model-checker.h>
+#include "libpspp/model-checker.h"
 
 #include <limits.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/time.h>
 
-#include <libpspp/argv-parser.h>
-#include <libpspp/bit-vector.h>
-#include <libpspp/compiler.h>
-#include <libpspp/deque.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
+#include "libpspp/argv-parser.h"
+#include "libpspp/bit-vector.h"
+#include "libpspp/compiler.h"
+#include "libpspp/deque.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
 
-#include "error.h"
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 \f
 /* Initializes PATH as an empty path. */
 void
@@ -120,7 +120,7 @@ mc_path_to_string (const struct mc_path *path, struct string *string)
   for (i = 0; i < mc_path_get_length (path); i++)
     {
       if (i > 0)
-        ds_put_char (string, ' ');
+        ds_put_byte (string, ' ');
       ds_put_format (string, "%d", mc_path_get_operation (path, i));
     }
 }
index a7372f8d3faf6066435064372c3279eedc970031..be97d389bcc7219c8dd325e02900f829b2082077 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 <sys/time.h>
 
-#include <libpspp/compiler.h>
+#include "libpspp/compiler.h"
 
 /* An active model checking run. */
 struct mc;
diff --git a/src/libpspp/msg-locator.c b/src/libpspp/msg-locator.c
deleted file mode 100644 (file)
index fb8082e..0000000
+++ /dev/null
@@ -1,84 +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 <stdlib.h>
-#include "msg-locator.h"
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <libpspp/message.h>
-#include "getl.h"
-
-#include "xalloc.h"
-
-/* File locator stack. */
-static const struct msg_locator **file_loc;
-
-static int nfile_loc, mfile_loc;
-
-void
-msg_locator_done (void)
-{
-  free(file_loc);
-  file_loc = NULL;
-  nfile_loc = mfile_loc = 0;
-}
-
-
-/* File locator stack functions. */
-
-/* Pushes F onto the stack of file locations. */
-void
-msg_push_msg_locator (const struct msg_locator *loc)
-{
-  if (nfile_loc >= mfile_loc)
-    {
-      if (mfile_loc == 0)
-       mfile_loc = 8;
-      else
-       mfile_loc *= 2;
-
-      file_loc = xnrealloc (file_loc, mfile_loc, sizeof *file_loc);
-    }
-
-  file_loc[nfile_loc++] = loc;
-}
-
-/* Pops F off the stack of file locations.
-   Argument F is only used for verification that that is actually the
-   item on top of the stack. */
-void
-msg_pop_msg_locator (const struct msg_locator *loc)
-{
-  assert (nfile_loc >= 0 && file_loc[nfile_loc - 1] == loc);
-  nfile_loc--;
-}
-
-/* Puts the current file and line number into LOC, or NULL and -1 if
-   none. */
-void
-get_msg_location (const struct source_stream *ss, struct msg_locator *loc)
-{
-  if (nfile_loc)
-    {
-      *loc = *file_loc[nfile_loc - 1];
-    }
-  else
-    {
-      loc->file_name = CONST_CAST (char *, getl_source_name (ss));
-      loc->line_number = getl_source_location (ss);
-    }
-}
diff --git a/src/libpspp/msg-locator.h b/src/libpspp/msg-locator.h
deleted file mode 100644 (file)
index 1dfc883..0000000
+++ /dev/null
@@ -1,34 +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/>. */
-
-struct msg_locator ;
-
-void msg_locator_done (void);
-
-/* File locator stack functions. */
-
-/* Pushes F onto the stack of file locations. */
-void msg_push_msg_locator (const struct msg_locator *loc);
-
-/* Pops F off the stack of file locations.
-   Argument F is only used for verification that that is actually the
-   item on top of the stack. */
-void msg_pop_msg_locator (const struct msg_locator *loc);
-
-struct source_stream ;
-/* Puts the current file and line number into LOC, or NULL and -1 if
-   none. */
-void get_msg_location (const struct source_stream *ss, struct msg_locator *loc);
index 7a8a591da58a7e84ebaf6952f784cec17f7571d0..7f3175d477bde1d758f5f358378fa448b30a60ab 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2010, 2011 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
@@ -299,7 +299,8 @@ pool_alloc (struct pool *pool, size_t amt)
 void *
 pool_alloc_unaligned (struct pool *pool, size_t amt)
 {
-  assert (pool != NULL);
+  if (pool == NULL)
+    return xmalloc (amt);
 
 #ifndef DISCRETE_BLOCKS
   /* Strings need not be aligned on any boundary, but some
diff --git a/src/libpspp/prompt.c b/src/libpspp/prompt.c
new file mode 100644 (file)
index 0000000..0722c3b
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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/prompt.h"
+
+const char *
+prompt_style_to_string (enum prompt_style style)
+{
+  switch (style)
+    {
+    case PROMPT_FIRST:
+      return "first";
+    case PROMPT_LATER:
+      return "later";
+    case PROMPT_DATA:
+      return "data";
+    case PROMPT_COMMENT:
+      return "COMMENT";
+    case PROMPT_DOCUMENT:
+      return "DOCUMENT";
+    case PROMPT_DO_REPEAT:
+      return "DO REPEAT";
+    default:
+      return "unknown prompt";
+    }
+}
+
diff --git a/src/libpspp/prompt.h b/src/libpspp/prompt.h
new file mode 100644 (file)
index 0000000..14e820b
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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 PROMPT_H
+#define PROMPT_H 1
+
+enum prompt_style
+  {
+    PROMPT_FIRST,              /* First line of command. */
+    PROMPT_LATER,               /* Second or later line of command. */
+    PROMPT_DATA,               /* Between BEGIN DATA and END DATA. */
+    PROMPT_COMMENT,             /* COMMENT or * command. */
+    PROMPT_DOCUMENT,            /* DOCUMENT command. */
+    PROMPT_DO_REPEAT            /* DO REPEAT command. */
+  };
+
+const char *prompt_style_to_string (enum prompt_style);
+
+#endif /* prompt.h */
index 0d6ce8263078674b321898ac4a38e6533a54d77a..2af9405a869393e2ca7a7ab852348a98e2d5ab7d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2011 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 <libpspp/range-map.h>
+#include "libpspp/range-map.h"
 
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
 
 static struct range_map_node *bt_to_range_map_node (const struct bt_node *);
 static int compare_range_map_nodes (const struct bt_node *,
index 024fe93790e507a052e14e4990152b9b17c7ea91..2d4b5ade334fcdad52a00f1b46b6aa37f9e7b6ec 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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,8 +32,8 @@
 
 #include <stdbool.h>
 
-#include <libpspp/bt.h>
-#include <libpspp/cast.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
index cd17fe02a4e2130544d5d37687cf46210ff2de39..ed7b3f5edb6a50f4220b8a3d9c372cdd05bdc373 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 <libpspp/range-set.h>
+#include "libpspp/range-set.h"
 
 #include <limits.h>
 #include <stdlib.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/pool.h>
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/pool.h"
 
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 static int compare_range_set_nodes (const struct bt_node *,
                                     const struct bt_node *,
index ee7dac23137d3c39b392b13cb11c7d560c71fc79..9e665e994efae8d079cc0166129568779c9bdfb2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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
@@ -25,8 +25,8 @@
 #define LIBPSPP_RANGE_SET_H
 
 #include <stdbool.h>
-#include <libpspp/bt.h>
-#include <libpspp/cast.h>
+#include "libpspp/bt.h"
+#include "libpspp/cast.h"
 
 /* A set of ranges. */
 struct range_set
index 298f2caf9eb9ae09108aa247fc6db7b000183de1..65a4612259f7e0510feb8cb55bbd7e619ce3e1d5 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, 2011 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 <libpspp/sparse-array.h>
+#include "libpspp/sparse-array.h"
 
 #include <limits.h>
 #include <string.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
 
-#include "count-one-bits.h"
-#include "minmax.h"
+#include "gl/count-one-bits.h"
+#include "gl/minmax.h"
 
 /* Sparse array data structure.
 
@@ -534,7 +534,9 @@ scan_in_use_reverse (struct leaf_node *leaf, unsigned int idx)
   for (;;)
     {
       int ofs = idx % LONG_BITS;
-      unsigned long int in_use = leaf->in_use[idx / LONG_BITS] << (31 - ofs);
+      unsigned long int in_use;
+
+      in_use = leaf->in_use[idx / LONG_BITS] << (LONG_BITS - 1 - ofs);
       if (in_use)
         return idx - count_leading_zeros (in_use);
       if (idx < LONG_BITS)
index 69c2ef28a7e3c5f83e60f4c864b35bf3b351ae7f..f839b0f2a8c6581c13f9a61feda56c0deb9263e8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2010, 2011 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 <libpspp/sparse-xarray.h>
+#include "libpspp/sparse-xarray.h"
 
 #include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/ext-array.h>
-#include <libpspp/misc.h>
-#include <libpspp/range-set.h>
-#include <libpspp/sparse-array.h>
+#include "libpspp/assertion.h"
+#include "libpspp/ext-array.h"
+#include "libpspp/misc.h"
+#include "libpspp/range-set.h"
+#include "libpspp/sparse-array.h"
 
-#include "md4.h"
-#include "minmax.h"
-#include "xalloc.h"
+#include "gl/md4.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 /* A sparse array of arrays of bytes. */
 struct sparse_xarray
index 9f0cb6e31463ab5caf319114e43fed26f640ae2b..7e722c17e6b92602798725e3bdd618327a46691f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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 <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <unistr.h>
 
-#include <libpspp/cast.h>
-#include <libpspp/message.h>
-#include <libpspp/pool.h>
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/pool.h"
 
-#include <relocatable.h>
-#include "minmax.h"
-#include "xalloc.h"
-#include "xmemdup0.h"
-#include "xsize.h"
+#include "gl/relocatable.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
+#include "gl/xsize.h"
 \f
 /* Reverses the order of NBYTES bytes at address P, thus converting
    between little- and big-endian byte orders.  */
@@ -50,19 +51,6 @@ buf_reverse (char *p, size_t nbytes)
     }
 }
 
-/* Finds the last NEEDLE of length NEEDLE_LEN in a HAYSTACK of length
-   HAYSTACK_LEN.  Returns a pointer to the needle found. */
-char *
-buf_find_reverse (const char *haystack, size_t haystack_len,
-                 const char *needle, size_t needle_len)
-{
-  int i;
-  for (i = haystack_len - needle_len; i >= 0; i--)
-    if (!memcmp (needle, &haystack[i], needle_len))
-      return (char *) &haystack[i];
-  return 0;
-}
-
 /* Compares the SIZE bytes in A to those in B, disregarding case,
    and returns a strcmp()-type result. */
 int
@@ -194,8 +182,8 @@ buf_copy_rpad (char *dst, size_t dst_size,
 
 /* Copies string SRC to string DST, which is in a buffer DST_SIZE
    bytes long.
-   Truncates DST to DST_SIZE - 1 characters or right-pads with
-   spaces to DST_SIZE - 1 characters if necessary. */
+   Truncates DST to DST_SIZE - 1 bytes or right-pads with
+   spaces to DST_SIZE - 1 bytes if necessary. */
 void
 str_copy_rpad (char *dst, size_t dst_size, const char *src)
 {
@@ -214,7 +202,7 @@ str_copy_rpad (char *dst, size_t dst_size, const char *src)
 }
 
 /* Copies SRC to DST, which is in a buffer DST_SIZE bytes long.
-   Truncates DST to DST_SIZE - 1 characters, if necessary. */
+   Truncates DST to DST_SIZE - 1 bytes, if necessary. */
 void
 str_copy_trunc (char *dst, size_t dst_size, const char *src)
 {
@@ -231,7 +219,7 @@ str_copy_trunc (char *dst, size_t dst_size, const char *src)
 
 /* Copies buffer SRC, of SRC_LEN bytes,
    to DST, which is in a buffer DST_SIZE bytes long.
-   Truncates DST to DST_SIZE - 1 characters, if necessary. */
+   Truncates DST to DST_SIZE - 1 bytes, if necessary. */
 void
 str_copy_buf_trunc (char *dst, size_t dst_size,
                     const char *src, size_t src_size)
@@ -244,7 +232,7 @@ str_copy_buf_trunc (char *dst, size_t dst_size,
   dst[dst_len] = '\0';
 }
 
-/* Converts each character in S to uppercase. */
+/* Converts each byte in S to uppercase. */
 void
 str_uppercase (char *s)
 {
@@ -252,7 +240,7 @@ str_uppercase (char *s)
     *s = toupper ((unsigned char) *s);
 }
 
-/* Converts each character in S to lowercase. */
+/* Converts each byte in S to lowercase. */
 void
 str_lowercase (char *s)
 {
@@ -282,32 +270,22 @@ str_format_26adic (unsigned long int number, char buffer[], size_t size)
   while (number-- > 0)
     {
       if (length >= size)
-        return false;
+        goto overflow;
       buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26];
       number /= 26;
     }
 
   if (length >= size)
-    return false;
+    goto overflow;
   buffer[length] = '\0';
 
   buf_reverse (buffer, length);
   return true;
-}
-
-/* Formats FORMAT into DST, as with sprintf(), and returns the
-   address of the terminating null written to DST. */
-char *
-spprintf (char *dst, const char *format, ...)
-{
-  va_list args;
-  int count;
 
-  va_start (args, format);
-  count = vsprintf (dst, format, args);
-  va_end (args);
-
-  return dst + count;
+overflow:
+  if (length > 0)
+    buffer[0] = '\0';
+  return false;
 }
 
 /* Sets the SIZE bytes starting at BLOCK to C,
@@ -321,36 +299,7 @@ mempset (void *block, int c, size_t size)
 \f
 /* Substrings. */
 
-/* Returns an empty substring. */
-struct substring
-ss_empty (void)
-{
-  struct substring ss;
-  ss.string = NULL;
-  ss.length = 0;
-  return ss;
-}
-
-/* Returns a substring whose contents are the given C-style
-   string CSTR. */
-struct substring
-ss_cstr (const char *cstr)
-{
-  return ss_buffer (cstr, strlen (cstr));
-}
-
-/* Returns a substring whose contents are the CNT characters in
-   BUFFER. */
-struct substring
-ss_buffer (const char *buffer, size_t cnt)
-{
-  struct substring ss;
-  ss.string = (char *) buffer;
-  ss.length = cnt;
-  return ss;
-}
-
-/* Returns a substring whose contents are the CNT characters
+/* Returns a substring whose contents are the CNT bytes
    starting at the (0-based) position START in SS. */
 struct substring
 ss_substr (struct substring ss, size_t start, size_t cnt)
@@ -362,14 +311,14 @@ ss_substr (struct substring ss, size_t start, size_t cnt)
 }
 
 /* Returns a substring whose contents are the first CNT
-   characters in SS. */
+   bytes in SS. */
 struct substring
 ss_head (struct substring ss, size_t cnt)
 {
   return ss_buffer (ss.string, MIN (cnt, ss.length));
 }
 
-/* Returns a substring whose contents are the last CNT characters
+/* Returns a substring whose contents are the last CNT bytes
    in SS. */
 struct substring
 ss_tail (struct substring ss, size_t cnt)
@@ -389,7 +338,7 @@ ss_alloc_substring (struct substring *new, struct substring old)
   new->length = old.length;
 }
 
-/* Allocates room for a CNT-character string in NEW. */
+/* Allocates room for a CNT-byte string in NEW. */
 void
 ss_alloc_uninit (struct substring *new, size_t cnt)
 {
@@ -397,18 +346,25 @@ ss_alloc_uninit (struct substring *new, size_t cnt)
   new->length = cnt;
 }
 
-/* Makes a pool_alloc_unaligned()'d copy of the contents of OLD
-   in POOL, and stores it in NEW. */
+void
+ss_realloc (struct substring *ss, size_t size)
+{
+  ss->string = xrealloc (ss->string, size);
+}
+
+/* Makes a pool_alloc_unaligned()'d, null-terminated copy of the contents of
+   OLD in POOL, and stores it in NEW. */
 void
 ss_alloc_substring_pool (struct substring *new, struct substring old,
                          struct pool *pool)
 {
-  new->string = pool_alloc_unaligned (pool, old.length);
+  new->string = pool_alloc_unaligned (pool, old.length + 1);
   new->length = old.length;
   memcpy (new->string, old.string, old.length);
+  new->string[old.length] = '\0';
 }
 
-/* Allocates room for a CNT-character string in NEW in POOL. */
+/* Allocates room for a CNT-byte string in NEW in POOL. */
 void
 ss_alloc_uninit_pool (struct substring *new, size_t cnt, struct pool *pool)
 {
@@ -423,7 +379,7 @@ ss_dealloc (struct substring *ss)
   free (ss->string);
 }
 
-/* Truncates SS to at most CNT characters in length. */
+/* Truncates SS to at most CNT bytes in length. */
 void
 ss_truncate (struct substring *ss, size_t cnt)
 {
@@ -431,22 +387,22 @@ ss_truncate (struct substring *ss, size_t cnt)
     ss->length = cnt;
 }
 
-/* Removes trailing characters in TRIM_SET from SS.
-   Returns number of characters removed. */
+/* Removes trailing bytes in TRIM_SET from SS.
+   Returns number of bytes removed. */
 size_t
 ss_rtrim (struct substring *ss, struct substring trim_set)
 {
   size_t cnt = 0;
   while (cnt < ss->length
-         && ss_find_char (trim_set,
+         && ss_find_byte (trim_set,
                           ss->string[ss->length - cnt - 1]) != SIZE_MAX)
     cnt++;
   ss->length -= cnt;
   return cnt;
 }
 
-/* Removes leading characters in TRIM_SET from SS.
-   Returns number of characters removed. */
+/* Removes leading bytes in TRIM_SET from SS.
+   Returns number of bytes removed. */
 size_t
 ss_ltrim (struct substring *ss, struct substring trim_set)
 {
@@ -455,7 +411,7 @@ ss_ltrim (struct substring *ss, struct substring trim_set)
   return cnt;
 }
 
-/* Trims leading and trailing characters in TRIM_SET from SS. */
+/* Trims leading and trailing bytes in TRIM_SET from SS. */
 void
 ss_trim (struct substring *ss, struct substring trim_set)
 {
@@ -463,10 +419,10 @@ ss_trim (struct substring *ss, struct substring trim_set)
   ss_rtrim (ss, trim_set);
 }
 
-/* If the last character in SS is C, removes it and returns true.
+/* If the last byte in SS is C, removes it and returns true.
    Otherwise, returns false without changing the string. */
 bool
-ss_chomp (struct substring *ss, char c)
+ss_chomp_byte (struct substring *ss, char c)
 {
   if (ss_last (*ss) == c)
     {
@@ -477,6 +433,20 @@ ss_chomp (struct substring *ss, char c)
     return false;
 }
 
+/* If SS ends with SUFFIX, removes it and returns true.
+   Otherwise, returns false without changing the string. */
+bool
+ss_chomp (struct substring *ss, struct substring suffix)
+{
+  if (ss_ends_with (*ss, suffix))
+    {
+      ss->length -= suffix.length;
+      return true;
+    }
+  else
+    return false;
+}
+
 /* Divides SS into tokens separated by any of the DELIMITERS.
    Each call replaces TOKEN by the next token in SS, or by an
    empty string if no tokens remain.  Returns true if a token was
@@ -523,12 +493,12 @@ ss_tokenize (struct substring ss, struct substring delimiters,
 {
   ss_advance (&ss, *save_idx);
   *save_idx += ss_ltrim (&ss, delimiters);
-  ss_get_chars (&ss, ss_cspan (ss, delimiters), token);
+  ss_get_bytes (&ss, ss_cspan (ss, delimiters), token);
   *save_idx += ss_length (*token) + 1;
   return ss_length (*token) > 0;
 }
 
-/* Removes the first CNT characters from SS. */
+/* Removes the first CNT bytes from SS. */
 void
 ss_advance (struct substring *ss, size_t cnt)
 {
@@ -538,10 +508,10 @@ ss_advance (struct substring *ss, size_t cnt)
   ss->length -= cnt;
 }
 
-/* If the first character in SS is C, removes it and returns true.
+/* If the first byte in SS is C, removes it and returns true.
    Otherwise, returns false without changing the string. */
 bool
-ss_match_char (struct substring *ss, char c)
+ss_match_byte (struct substring *ss, char c)
 {
   if (ss_first (*ss) == c)
     {
@@ -553,11 +523,11 @@ ss_match_char (struct substring *ss, char c)
     return false;
 }
 
-/* If the first character in SS is in MATCH, removes it and
-   returns the character that was removed.
+/* If the first byte in SS is in MATCH, removes it and
+   returns the byte that was removed.
    Otherwise, returns EOF without changing the string. */
 int
-ss_match_char_in (struct substring *ss, struct substring match)
+ss_match_byte_in (struct substring *ss, struct substring match)
 {
   int c = EOF;
   if (ss->length > 0
@@ -585,10 +555,10 @@ ss_match_string (struct substring *ss, const struct substring target)
     return false;
 }
 
-/* Removes the first character from SS and returns it.
+/* Removes the first byte from SS and returns it.
    If SS is empty, returns EOF without modifying SS. */
 int
-ss_get_char (struct substring *ss)
+ss_get_byte (struct substring *ss)
 {
   int c = ss_first (*ss);
   if (c != EOF)
@@ -600,21 +570,21 @@ ss_get_char (struct substring *ss)
 }
 
 /* Stores the prefix of SS up to the first DELIMITER in OUT (if
-   any).  Trims those same characters from SS.  DELIMITER is
+   any).  Trims those same bytes from SS.  DELIMITER is
    removed from SS but not made part of OUT.  Returns true if
    DELIMITER was found (and removed), false otherwise. */
 bool
 ss_get_until (struct substring *ss, char delimiter, struct substring *out)
 {
-  ss_get_chars (ss, ss_cspan (*ss, ss_buffer (&delimiter, 1)), out);
-  return ss_match_char (ss, delimiter);
+  ss_get_bytes (ss, ss_cspan (*ss, ss_buffer (&delimiter, 1)), out);
+  return ss_match_byte (ss, delimiter);
 }
 
-/* Stores the first CNT characters in SS in OUT (or fewer, if SS
-   is shorter than CNT characters).  Trims the same characters
+/* Stores the first CNT bytes in SS in OUT (or fewer, if SS
+   is shorter than CNT bytes).  Trims the same bytes
    from the beginning of SS.  Returns CNT. */
 size_t
-ss_get_chars (struct substring *ss, size_t cnt, struct substring *out)
+ss_get_bytes (struct substring *ss, size_t cnt, struct substring *out)
 {
   *out = ss_head (*ss, cnt);
   ss_advance (ss, cnt);
@@ -623,7 +593,7 @@ ss_get_chars (struct substring *ss, size_t cnt, struct substring *out)
 
 /* Parses and removes an optionally signed decimal integer from
    the beginning of SS.  Returns 0 if an error occurred,
-   otherwise the number of characters removed from SS.  Stores
+   otherwise the number of bytes removed from SS.  Stores
    the integer's value into *VALUE. */
 size_t
 ss_get_long (struct substring *ss, long *value)
@@ -651,7 +621,7 @@ ss_get_long (struct substring *ss, long *value)
   return 0;
 }
 
-/* Returns true if SS is empty (contains no characters),
+/* Returns true if SS is empty (has length 0 bytes),
    false otherwise. */
 bool
 ss_is_empty (struct substring ss)
@@ -659,28 +629,28 @@ ss_is_empty (struct substring ss)
   return ss.length == 0;
 }
 
-/* Returns the number of characters in SS. */
+/* Returns the number of bytes in SS. */
 size_t
 ss_length (struct substring ss)
 {
   return ss.length;
 }
 
-/* Returns a pointer to the characters in SS. */
+/* Returns a pointer to the bytes in SS. */
 char *
 ss_data (struct substring ss)
 {
   return ss.string;
 }
 
-/* Returns a pointer just past the last character in SS. */
+/* Returns a pointer just past the last byte in SS. */
 char *
 ss_end (struct substring ss)
 {
   return ss.string + ss.length;
 }
 
-/* Returns the character in position IDX in SS, as a value in the
+/* Returns the byte in position IDX in SS, as a value in the
    range of unsigned char.  Returns EOF if IDX is out of the
    range of indexes for SS. */
 int
@@ -689,7 +659,7 @@ ss_at (struct substring ss, size_t idx)
   return idx < ss.length ? (unsigned char) ss.string[idx] : EOF;
 }
 
-/* Returns the first character in SS as a value in the range of
+/* Returns the first byte in SS as a value in the range of
    unsigned char.  Returns EOF if SS is the empty string. */
 int
 ss_first (struct substring ss)
@@ -697,7 +667,7 @@ ss_first (struct substring ss)
   return ss_at (ss, 0);
 }
 
-/* Returns the last character in SS as a value in the range of
+/* Returns the last byte in SS as a value in the range of
    unsigned char.  Returns EOF if SS is the empty string. */
 int
 ss_last (struct substring ss)
@@ -705,26 +675,35 @@ ss_last (struct substring ss)
   return ss.length > 0 ? (unsigned char) ss.string[ss.length - 1] : EOF;
 }
 
-/* Returns the number of contiguous characters at the beginning
+/* Returns true if SS ends with SUFFIX, false otherwise. */
+bool
+ss_ends_with (struct substring ss, struct substring suffix)
+{
+  return (ss.length >= suffix.length
+          && !memcmp (&ss.string[ss.length - suffix.length], suffix.string,
+                      suffix.length));
+}
+
+/* Returns the number of contiguous bytes at the beginning
    of SS that are in SKIP_SET. */
 size_t
 ss_span (struct substring ss, struct substring skip_set)
 {
   size_t i;
   for (i = 0; i < ss.length; i++)
-    if (ss_find_char (skip_set, ss.string[i]) == SIZE_MAX)
+    if (ss_find_byte (skip_set, ss.string[i]) == SIZE_MAX)
       break;
   return i;
 }
 
-/* Returns the number of contiguous characters at the beginning
+/* Returns the number of contiguous bytes at the beginning
    of SS that are not in SKIP_SET. */
 size_t
 ss_cspan (struct substring ss, struct substring stop_set)
 {
   size_t i;
   for (i = 0; i < ss.length; i++)
-    if (ss_find_char (stop_set, ss.string[i]) != SIZE_MAX)
+    if (ss_find_byte (stop_set, ss.string[i]) != SIZE_MAX)
       break;
   return i;
 }
@@ -732,7 +711,7 @@ ss_cspan (struct substring ss, struct substring stop_set)
 /* Returns the offset in SS of the first instance of C,
    or SIZE_MAX if C does not occur in SS. */
 size_t
-ss_find_char (struct substring ss, char c)
+ss_find_byte (struct substring ss, char c)
 {
   const char *p = memchr (ss.string, c, ss.length);
   return p != NULL ? p - ss.string : SIZE_MAX;
@@ -777,7 +756,7 @@ ss_equals_case (struct substring a, struct substring b)
   return a.length == b.length && !memcasecmp (a.string, b.string, a.length);
 }
 
-/* Returns the position in SS that the character at P occupies.
+/* Returns the position in SS that the byte at P occupies.
    P must point within SS or one past its end. */
 size_t
 ss_pointer_to_position (struct substring ss, const char *p)
@@ -797,6 +776,81 @@ ss_xstrdup (struct substring ss)
   s[ss.length] = '\0';
   return s;
 }
+/* UTF-8. */
+
+/* Returns the character represented by the UTF-8 sequence at the start of S.
+   The return value is either a Unicode code point in the range 0 to 0x10ffff,
+   or UINT32_MAX if S is empty. */
+ucs4_t
+ss_first_mb (struct substring s)
+{
+  return ss_at_mb (s, 0);
+}
+
+/* Returns the number of bytes in the UTF-8 character at the beginning of S.
+
+   The return value is 0 if S is empty, otherwise between 1 and 4. */
+int
+ss_first_mblen (struct substring s)
+{
+  return ss_at_mblen (s, 0);
+}
+
+/* Advances S past the UTF-8 character at its beginning.  Returns the Unicode
+   code point that was skipped (in the range 0 to 0x10ffff), or UINT32_MAX if S
+   was not modified because it was initially empty. */
+ucs4_t
+ss_get_mb (struct substring *s)
+{
+  if (s->length > 0)
+    {
+      ucs4_t uc;
+      int n;
+
+      n = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, s->string), s->length);
+      s->string += n;
+      s->length -= n;
+      return uc;
+    }
+  else
+    return UINT32_MAX;
+}
+
+/* Returns the character represented by the UTF-8 sequence starting OFS bytes
+   into S.  The return value is either a Unicode code point in the range 0 to
+   0x10ffff, or UINT32_MAX if OFS is past the last byte in S.
+
+   (Returns 0xfffd if OFS points into the middle, not the beginning, of a UTF-8
+   sequence.)  */
+ucs4_t
+ss_at_mb (struct substring s, size_t ofs)
+{
+  if (s.length > ofs)
+    {
+      ucs4_t uc;
+      u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, s.string + ofs),
+                 s.length - ofs);
+      return uc;
+    }
+  else
+    return UINT32_MAX;
+}
+
+/* Returns the number of bytes represented by the UTF-8 sequence starting OFS
+   bytes into S.  The return value is 0 if OFS is past the last byte in S,
+   otherwise between 1 and 4. */
+int
+ss_at_mblen (struct substring s, size_t ofs)
+{
+  if (s.length > ofs)
+    {
+      ucs4_t uc;
+      return u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, s.string + ofs),
+                        s.length - ofs);
+    }
+  else
+    return 0;
+}
 \f
 /* Initializes ST as an empty string. */
 void
@@ -916,20 +970,20 @@ ds_ss (const struct string *st)
   return st->ss;
 }
 
-/* Returns a substring that contains CNT characters from ST
+/* Returns a substring that contains CNT bytes from ST
    starting at position START.
 
    If START is greater than or equal to the length of ST, then
    the substring will be the empty string.  If START + CNT
    exceeds the length of ST, then the substring will only be
-   ds_length(ST) - START characters long. */
+   ds_length(ST) - START bytes long. */
 struct substring
 ds_substr (const struct string *st, size_t start, size_t cnt)
 {
   return ss_substr (ds_ss (st), start, cnt);
 }
 
-/* Returns a substring that contains the first CNT characters in
+/* Returns a substring that contains the first CNT bytes in
    ST.  If CNT exceeds the length of ST, then the substring will
    contain all of ST. */
 struct substring
@@ -938,7 +992,7 @@ ds_head (const struct string *st, size_t cnt)
   return ss_head (ds_ss (st), cnt);
 }
 
-/* Returns a substring that contains the last CNT characters in
+/* Returns a substring that contains the last CNT bytes in
    ST.  If CNT exceeds the length of ST, then the substring will
    contain all of ST. */
 struct substring
@@ -947,7 +1001,7 @@ ds_tail (const struct string *st, size_t cnt)
   return ss_tail (ds_ss (st), cnt);
 }
 
-/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
+/* Ensures that ST can hold at least MIN_CAPACITY bytes plus a null
    terminator. */
 void
 ds_extend (struct string *st, size_t min_capacity)
@@ -973,23 +1027,23 @@ ds_shrink (struct string *st)
     }
 }
 
-/* Truncates ST to at most LENGTH characters long. */
+/* Truncates ST to at most LENGTH bytes long. */
 void
 ds_truncate (struct string *st, size_t length)
 {
   ss_truncate (&st->ss, length);
 }
 
-/* Removes trailing characters in TRIM_SET from ST.
-   Returns number of characters removed. */
+/* Removes trailing bytes in TRIM_SET from ST.
+   Returns number of bytes removed. */
 size_t
 ds_rtrim (struct string *st, struct substring trim_set)
 {
   return ss_rtrim (&st->ss, trim_set);
 }
 
-/* Removes leading characters in TRIM_SET from ST.
-   Returns number of characters removed. */
+/* Removes leading bytes in TRIM_SET from ST.
+   Returns number of bytes removed. */
 size_t
 ds_ltrim (struct string *st, struct substring trim_set)
 {
@@ -999,8 +1053,8 @@ ds_ltrim (struct string *st, struct substring trim_set)
   return cnt;
 }
 
-/* Trims leading and trailing characters in TRIM_SET from ST.
-   Returns number of charactesr removed. */
+/* Trims leading and trailing bytes in TRIM_SET from ST.
+   Returns number of bytes removed. */
 size_t
 ds_trim (struct string *st, struct substring trim_set)
 {
@@ -1008,12 +1062,20 @@ ds_trim (struct string *st, struct substring trim_set)
   return cnt + ds_ltrim (st, trim_set);
 }
 
-/* If the last character in ST is C, removes it and returns true.
+/* If the last byte in ST is C, removes it and returns true.
+   Otherwise, returns false without modifying ST. */
+bool
+ds_chomp_byte (struct string *st, char c)
+{
+  return ss_chomp_byte (&st->ss, c);
+}
+
+/* If ST ends with SUFFIX, removes it and returns true.
    Otherwise, returns false without modifying ST. */
 bool
-ds_chomp (struct string *st, char c)
+ds_chomp (struct string *st, struct substring suffix)
 {
-  return ss_chomp (&st->ss, c);
+  return ss_chomp (&st->ss, suffix);
 }
 
 /* Divides ST into tokens separated by any of the DELIMITERS.
@@ -1051,17 +1113,17 @@ ds_tokenize (const struct string *st, struct substring delimiters,
 }
 
 /* Pad ST on the right with copies of PAD until ST is at least
-   LENGTH characters in size.  If ST is initially LENGTH
-   characters or longer, this is a no-op. */
+   LENGTH bytes in size.  If ST is initially LENGTH
+   bytes or longer, this is a no-op. */
 void
 ds_rpad (struct string *st, size_t length, char pad)
 {
   if (length > st->ss.length)
-    ds_put_char_multiple (st, pad, length - st->ss.length);
+    ds_put_byte_multiple (st, pad, length - st->ss.length);
 }
 
 /* Sets the length of ST to exactly NEW_LENGTH,
-   either by truncating characters from the end,
+   either by truncating bytes from the end,
    or by padding on the right with PAD. */
 void
 ds_set_length (struct string *st, size_t new_length, char pad)
@@ -1072,7 +1134,7 @@ ds_set_length (struct string *st, size_t new_length, char pad)
     st->ss.length = new_length;
 }
 
-/* Removes N characters from ST starting at offset START. */
+/* Removes N bytes from ST starting at offset START. */
 void
 ds_remove (struct string *st, size_t start, size_t n)
 {
@@ -1080,12 +1142,12 @@ ds_remove (struct string *st, size_t start, size_t n)
     {
       if (st->ss.length - start <= n)
         {
-          /* All characters at or beyond START are deleted. */
+          /* All bytes at or beyond START are deleted. */
           st->ss.length = start;
         }
       else
         {
-          /* Some characters remain and must be shifted into
+          /* Some bytes remain and must be shifted into
              position. */
           memmove (st->ss.string + st->ss.length,
                    st->ss.string + st->ss.length + n,
@@ -1095,7 +1157,7 @@ ds_remove (struct string *st, size_t start, size_t n)
     }
   else
     {
-      /* There are no characters to delete or no characters at or
+      /* There are no bytes to delete or no bytes at or
          beyond START, hence deletion is a no-op. */
     }
 }
@@ -1122,7 +1184,7 @@ ds_data (const struct string *st)
 }
 
 /* Returns a pointer to the null terminator ST.
-   This might not be an actual null character unless ds_c_str() has
+   This might not be an actual null byte unless ds_c_str() has
    been called since the last modification to ST. */
 char *
 ds_end (const struct string *st)
@@ -1130,7 +1192,7 @@ ds_end (const struct string *st)
   return ss_end (ds_ss (st));
 }
 
-/* Returns the character in position IDX in ST, as a value in the
+/* Returns the byte in position IDX in ST, as a value in the
    range of unsigned char.  Returns EOF if IDX is out of the
    range of indexes for ST. */
 int
@@ -1139,7 +1201,7 @@ ds_at (const struct string *st, size_t idx)
   return ss_at (ds_ss (st), idx);
 }
 
-/* Returns the first character in ST as a value in the range of
+/* Returns the first byte in ST as a value in the range of
    unsigned char.  Returns EOF if ST is the empty string. */
 int
 ds_first (const struct string *st)
@@ -1147,7 +1209,7 @@ ds_first (const struct string *st)
   return ss_first (ds_ss (st));
 }
 
-/* Returns the last character in ST as a value in the range of
+/* Returns the last byte in ST as a value in the range of
    unsigned char.  Returns EOF if ST is the empty string. */
 int
 ds_last (const struct string *st)
@@ -1155,7 +1217,14 @@ ds_last (const struct string *st)
   return ss_last (ds_ss (st));
 }
 
-/* Returns the number of consecutive characters at the beginning
+/* Returns true if ST ends with SUFFIX, false otherwise. */
+bool
+ds_ends_with (const struct string *st, struct substring suffix)
+{
+  return ss_ends_with (st->ss, suffix);
+}
+
+/* Returns the number of consecutive bytes at the beginning
    of ST that are in SKIP_SET. */
 size_t
 ds_span (const struct string *st, struct substring skip_set)
@@ -1163,7 +1232,7 @@ ds_span (const struct string *st, struct substring skip_set)
   return ss_span (ds_ss (st), skip_set);
 }
 
-/* Returns the number of consecutive characters at the beginning
+/* Returns the number of consecutive bytes at the beginning
    of ST that are not in STOP_SET.  */
 size_t
 ds_cspan (const struct string *st, struct substring stop_set)
@@ -1171,13 +1240,13 @@ ds_cspan (const struct string *st, struct substring stop_set)
   return ss_cspan (ds_ss (st), stop_set);
 }
 
-/* Returns the position of the first occurrence of character C in
+/* Returns the position of the first occurrence of byte C in
    ST at or after position OFS, or SIZE_MAX if there is no such
    occurrence. */
 size_t
-ds_find_char (const struct string *st, char c)
+ds_find_byte (const struct string *st, char c)
 {
-  return ss_find_char (ds_ss (st), c);
+  return ss_find_byte (ds_ss (st), c);
 }
 
 /* Compares A and B and returns a strcmp()-type comparison
@@ -1188,7 +1257,7 @@ ds_compare (const struct string *a, const struct string *b)
   return ss_compare (ds_ss (a), ds_ss (b));
 }
 
-/* Returns the position in ST that the character at P occupies.
+/* Returns the position in ST that the byte at P occupies.
    P must point within ST or one past its end. */
 size_t
 ds_pointer_to_position (const struct string *st, const char *p)
@@ -1233,16 +1302,15 @@ ds_steal_cstr (struct string *st)
   return s;
 }
 
-/* Reads characters from STREAM and appends them to ST, stopping
-   after MAX_LENGTH characters, after appending a newline, or
+/* Reads bytes from STREAM and appends them to ST, stopping
+   after MAX_LENGTH bytes, after appending a newline, or
    after an I/O error or end of file was encountered, whichever
-   comes first.  Returns true if at least one character was added
-   to ST, false if no characters were read before an I/O error or
+   comes first.  Returns true if at least one byte was added
+   to ST, false if no bytes were read before an I/O error or
    end of file (or if MAX_LENGTH was 0).
 
    This function treats LF and CR LF sequences as new-line,
-   translating each of them to a single '\n' new-line character
-   in ST. */
+   translating each of them to a single '\n' in ST. */
 bool
 ds_read_line (struct string *st, FILE *stream, size_t max_length)
 {
@@ -1257,7 +1325,7 @@ ds_read_line (struct string *st, FILE *stream, size_t max_length)
           return length > 0;
 
         case '\n':
-          ds_put_char (st, c);
+          ds_put_byte (st, c);
           return true;
 
         case '\r':
@@ -1265,13 +1333,13 @@ ds_read_line (struct string *st, FILE *stream, size_t max_length)
           if (c == '\n')
             {
               /* CR followed by LF is special: translate to \n. */
-              ds_put_char (st, '\n');
+              ds_put_byte (st, '\n');
               return true;
             }
           else
             {
               /* CR followed by anything else is just CR. */
-              ds_put_char (st, '\r');
+              ds_put_byte (st, '\r');
               if (c == EOF)
                 return true;
               ungetc (c, stream);
@@ -1279,7 +1347,7 @@ ds_read_line (struct string *st, FILE *stream, size_t max_length)
           break;
 
         default:
-          ds_put_char (st, c);
+          ds_put_byte (st, c);
         }
     }
 
@@ -1334,7 +1402,7 @@ ds_read_config_line (struct string *st, int *line_number, FILE *stream)
       (*line_number)++;
       ds_rtrim (st, ss_cstr (CC_SPACES));
     }
-  while (ds_chomp (st, '\\'));
+  while (ds_chomp_byte (st, '\\'));
 
   remove_comment (st);
   return true;
@@ -1392,6 +1460,30 @@ ds_put_uninit (struct string *st, size_t incr)
   return end;
 }
 
+/* Moves the bytes in ST following offset OFS + OLD_LEN in ST to offset OFS +
+   NEW_LEN and returns the byte at offset OFS.  The first min(OLD_LEN, NEW_LEN)
+   bytes at the returned position are unchanged; if NEW_LEN > OLD_LEN then the
+   following NEW_LEN - OLD_LEN bytes are initially indeterminate.
+
+   The intention is that the caller should write NEW_LEN bytes at the returned
+   position, to effectively replace the OLD_LEN bytes previously at that
+   position. */
+char *
+ds_splice_uninit (struct string *st,
+                  size_t ofs, size_t old_len, size_t new_len)
+{
+  if (new_len != old_len)
+    {
+      if (new_len > old_len)
+        ds_extend (st, ds_length (st) + (new_len - old_len));
+      memmove (ds_data (st) + (ofs + new_len),
+               ds_data (st) + (ofs + old_len),
+               ds_length (st) - (ofs + old_len));
+      st->ss.length += new_len - old_len;
+    }
+  return ds_data (st) + ofs;
+}
+
 /* Formats FORMAT as a printf string and appends the result to ST. */
 void
 ds_put_format (struct string *st, const char *format, ...)
@@ -1438,16 +1530,16 @@ ds_put_vformat (struct string *st, const char *format, va_list args_)
     }
 }
 
-/* Appends character CH to ST. */
+/* Appends byte CH to ST. */
 void
-ds_put_char (struct string *st, int ch)
+ds_put_byte (struct string *st, int ch)
 {
   ds_put_uninit (st, 1)[0] = ch;
 }
 
-/* Appends CNT copies of character CH to ST. */
+/* Appends CNT copies of byte CH to ST. */
 void
-ds_put_char_multiple (struct string *st, int ch, size_t cnt)
+ds_put_byte_multiple (struct string *st, int ch, size_t cnt)
 {
   memset (ds_put_uninit (st, cnt), ch, cnt);
 }
index 0b57f7364e07816400b0d90f80e12376f219b821..7c3ef3d5f9ed5ffd89ff4c339e49e66fa9464073 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, 2011 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
@@ -23,6 +23,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include <unitypes.h>
 
 #include "compiler.h"
 #include "memcasecmp.h"
@@ -32,7 +33,6 @@
 /* Miscellaneous. */
 
 void buf_reverse (char *, size_t);
-char *buf_find_reverse (const char *, size_t, const char *, size_t);
 int buf_compare_case (const char *, const char *, size_t);
 int buf_compare_rpad (const char *, size_t, const char *, size_t);
 void buf_copy_lpad (char *, size_t, const char *, size_t, char pad);
@@ -49,8 +49,6 @@ void str_lowercase (char *);
 
 bool str_format_26adic (unsigned long int number, char buffer[], size_t);
 
-char *spprintf (char *dst, const char *format, ...);
-
 void *mempset (void *, int, size_t);
 \f
 /* Common character classes for use with substring and string functions. */
@@ -75,9 +73,9 @@ struct substring
 /* Constructors.
    These functions do not allocate any memory, so the substrings
    they create should not normally be destroyed. */
-struct substring ss_empty (void);
-struct substring ss_cstr (const char *);
-struct substring ss_buffer (const char *, size_t);
+static inline struct substring ss_empty (void);
+static inline struct substring ss_cstr (const char *);
+static inline struct substring ss_buffer (const char *, size_t);
 struct substring ss_substr (struct substring, size_t start, size_t);
 struct substring ss_head (struct substring, size_t);
 struct substring ss_tail (struct substring, size_t);
@@ -87,6 +85,7 @@ struct substring ss_tail (struct substring, size_t);
 struct pool;
 void ss_alloc_substring (struct substring *, struct substring);
 void ss_alloc_uninit (struct substring *, size_t);
+void ss_realloc (struct substring *, size_t);
 void ss_alloc_substring_pool (struct substring *, struct substring,
                               struct pool *);
 void ss_alloc_uninit_pool (struct substring *, size_t, struct pool *);
@@ -99,17 +98,18 @@ void ss_truncate (struct substring *, size_t);
 size_t ss_rtrim (struct substring *, struct substring trim_set);
 size_t ss_ltrim (struct substring *, struct substring trim_set);
 void ss_trim (struct substring *, struct substring trim_set);
-bool ss_chomp (struct substring *, char);
+bool ss_chomp_byte (struct substring *, char);
+bool ss_chomp (struct substring *, struct substring);
 bool ss_separate (struct substring src, struct substring delimiters,
                   size_t *save_idx, struct substring *token);
 bool ss_tokenize (struct substring src, struct substring delimiters,
                   size_t *save_idx, struct substring *token);
 void ss_advance (struct substring *, size_t);
-bool ss_match_char (struct substring *, char);
-int ss_match_char_in (struct substring *, struct substring);
+bool ss_match_byte (struct substring *, char);
+int ss_match_byte_in (struct substring *, struct substring);
 bool ss_match_string (struct substring *, const struct substring);
-int ss_get_char (struct substring *);
-size_t ss_get_chars (struct substring *, size_t cnt, struct substring *);
+int ss_get_byte (struct substring *);
+size_t ss_get_bytes (struct substring *, size_t cnt, struct substring *);
 bool ss_get_until (struct substring *, char delimiter, struct substring *);
 size_t ss_get_long (struct substring *, long *);
 
@@ -121,15 +121,23 @@ char *ss_end (struct substring);
 int ss_at (struct substring, size_t idx);
 int ss_first (struct substring);
 int ss_last (struct substring);
+bool ss_ends_with (struct substring, struct substring suffix);
 size_t ss_span (struct substring, struct substring skip_set);
 size_t ss_cspan (struct substring, struct substring stop_set);
-size_t ss_find_char (struct substring, char);
+size_t ss_find_byte (struct substring, char);
 int ss_compare (struct substring, struct substring);
 int ss_compare_case (struct substring, struct substring);
 int ss_equals (struct substring, struct substring);
 int ss_equals_case (struct substring, struct substring);
 size_t ss_pointer_to_position (struct substring, const char *);
 char *ss_xstrdup (struct substring);
+
+/* UTF-8. */
+ucs4_t ss_first_mb (struct substring);
+int ss_first_mblen (struct substring);
+ucs4_t ss_get_mb (struct substring *);
+ucs4_t ss_at_mb (struct substring, size_t ofs);
+int ss_at_mblen (struct substring, size_t ofs);
 \f
 /* Variable length strings. */
 
@@ -171,7 +179,8 @@ void ds_truncate (struct string *, size_t);
 size_t ds_rtrim (struct string *, struct substring trim_set);
 size_t ds_ltrim (struct string *, struct substring trim_set);
 size_t ds_trim (struct string *, struct substring trim_set);
-bool ds_chomp (struct string *, char);
+bool ds_chomp_byte (struct string *, char);
+bool ds_chomp (struct string *, struct substring);
 bool ds_separate (const struct string *src, struct substring delimiters,
                   size_t *save_idx, struct substring *token);
 bool ds_tokenize (const struct string *src, struct substring delimiters,
@@ -194,9 +203,10 @@ char *ds_end (const struct string *);
 int ds_at (const struct string *, size_t idx);
 int ds_first (const struct string *);
 int ds_last (const struct string *);
+bool ds_ends_with (const struct string *, struct substring suffix);
 size_t ds_span (const struct string *, struct substring skip_set);
 size_t ds_cspan (const struct string *, struct substring stop_set);
-size_t ds_find_char (const struct string *, char);
+size_t ds_find_byte (const struct string *, char);
 int ds_compare (const struct string *, const struct string *);
 size_t ds_pointer_to_position (const struct string *, const char *);
 char *ds_xstrdup (const struct string *);
@@ -211,8 +221,8 @@ bool ds_read_config_line (struct string *, int *line_number, FILE *);
 bool ds_read_stream (struct string *, size_t size, size_t cnt, FILE *stream);
 
 /* Append. */
-void ds_put_char (struct string *, int ch);
-void ds_put_char_multiple (struct string *, int ch, size_t);
+void ds_put_byte (struct string *, int ch);
+void ds_put_byte_multiple (struct string *, int ch, size_t);
 void ds_put_cstr (struct string *, const char *);
 void ds_put_substring (struct string *, struct substring);
 void ds_put_vformat (struct string *st, const char *, va_list)
@@ -221,6 +231,9 @@ void ds_put_format (struct string *, const char *, ...)
      PRINTF_FORMAT (2, 3);
 char *ds_put_uninit (struct string *st, size_t incr);
 
+char *ds_splice_uninit (struct string *, size_t ofs, size_t old_len,
+                        size_t new_len);
+
 /* Other */
 /* calls relocate from gnulib on ST */
 void ds_relocate (struct string *st);
@@ -229,6 +242,33 @@ void ds_relocate (struct string *st);
 void u8_buf_copy_rpad (uint8_t *dst, size_t dst_size,
                       const uint8_t *src, size_t src_size,
                       char pad);
-
+\f
+struct substring
+ss_empty (void)
+{
+  struct substring ss;
+  ss.string = NULL;
+  ss.length = 0;
+  return ss;
+}
+
+/* Returns a substring whose contents are the given C-style
+   string CSTR. */
+static inline struct substring
+ss_cstr (const char *cstr)
+{
+  return ss_buffer (cstr, strlen (cstr));
+}
+
+/* Returns a substring whose contents are the CNT characters in
+   BUFFER. */
+static inline struct substring
+ss_buffer (const char *buffer, size_t cnt)
+{
+  struct substring ss;
+  ss.string = (char *) buffer;
+  ss.length = cnt;
+  return ss;
+}
 
 #endif /* str_h */
index 48124797ba570af9cdd70b61230295dc160749ce..e67ed470283d6ee7e34e14257ed86656863af460 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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 <libpspp/string-map.h>
+#include "libpspp/string-map.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/hash-functions.h>
-#include <libpspp/string-set.h>
+#include "libpspp/hash-functions.h"
+#include "libpspp/string-set.h"
 
 #include "gl/xalloc.h"
 
index f8ffabcffc1250bfdbdc428c511601937bdc6353..c29551bb1ff62b709eb7e876313faab45abd40c7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -23,7 +23,7 @@
    key-value pairs. */
 
 #include <stdbool.h>
-#include <libpspp/hmap.h>
+#include "libpspp/hmap.h"
 
 struct string_set;
 
index 3fd370db93877900504f6c4b693efe308af46044..d6a8012749652b40e4b675bcae623e9c3e536111 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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 <libpspp/string-set.h>
+#include "libpspp/string-set.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <libpspp/hash-functions.h>
+#include "libpspp/hash-functions.h"
 
 #include "gl/xalloc.h"
 
index a604e1513efe9179ff931a2f4bf0b2d8edf746d2..aad8cdb01d63d4408a6686d3bc33b706407d2d1d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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,7 +22,7 @@
    This is a convenient wrapper around a "struct hmap" for storing strings. */
 
 #include <stdbool.h>
-#include <libpspp/hmap.h>
+#include "libpspp/hmap.h"
 
 /* A node in the string set. */
 struct string_set_node
index bc01e721cd92a735a7c06ff2a61e1f8bf699605c..1c4894b411bb8a8cae193635572756ccabf27e09 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -23,7 +23,7 @@
    key-value pairs. */
 
 #include <stdbool.h>
-#include <libpspp/hmap.h>
+#include "libpspp/hmap.h"
 
 struct string_set;
 struct stringi_set;
index f438d048e3661555923a15cf6ad1c71e2c1efc86..2a000889ec1fa9a686a519dbb859a3355131f01b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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,7 +22,7 @@
    This is a convenient wrapper around a "struct hmap" for storing strings. */
 
 #include <stdbool.h>
-#include <libpspp/hmap.h>
+#include "libpspp/hmap.h"
 
 /* A node in the string set. */
 struct stringi_set_node
index 4c1cecb97cdbbdbcdd2302e91f2741e7a68a8bc2..c655d60a61cf9009fae1043ee9833877625f2704 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 <libpspp/taint.h>
+#include "libpspp/taint.h"
 
 #include <stddef.h>
 
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 /* This code maintains two invariants:
 
index de26b198f5934b7f1c535d926ecbd18ea08437fa..1355e886add31c4b8b2624c87e9e5717a508352f 100644 (file)
@@ -98,7 +98,7 @@
    The value of a successor-taint is in summarizing the history
    of the taint objects derived from a common parent.  For
    example, consider a casereader that represents the active
-   file.  A statistical procedure can clone this casereader any
+   dataset.  A statistical procedure can clone this casereader any
    number of times and pass it to analysis functions, which may
    themselves in turn clone it themselves, pass it to sort or
    merge functions, etc.  Conventionally, all of these functions
index c1ffbea664dc6e7cce73fef03584f45d65bd024f..ffd5da7cef162dfdaef2ab20e66513b33b67b5ba 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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
@@ -56,6 +56,8 @@ create_temp_file (void)
 
   file_name = xasprintf ("%s/%d", temp_dir->dir_name, idx++);
   stream = fopen_temp (file_name, "wb+");
+  if (stream != NULL)
+    setvbuf (stream, NULL, _IOFBF, 65536);
   free (file_name);
 
   return stream;
index 9157987774e555c625d63af41a9343dc4447c574..863da820c3bf081ec1ed374d36a6411ceade7f9e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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 <libpspp/tower.h>
+#include "libpspp/tower.h"
 
 #include <limits.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <libpspp/compiler.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 *);
 static struct tower_node *first_node (const struct tower *);
index 9be8231c98ad7c9b0c7fc217a14a513d2813aa92..2ec5a0d820b354a91f19cfa1dd961f5407f52dc0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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,8 +50,8 @@
 #define LIBPSPP_TOWER_H
 
 #include <stdbool.h>
-#include <libpspp/abt.h>
-#include <libpspp/cast.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
diff --git a/src/libpspp/u8-istream.c b/src/libpspp/u8-istream.c
new file mode 100644 (file)
index 0000000..c111634
--- /dev/null
@@ -0,0 +1,477 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 "u8-istream.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <iconv.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <unistr.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/encoding-guesser.h"
+
+#include "gl/c-strcase.h"
+#include "gl/localcharset.h"
+#include "gl/minmax.h"
+
+enum u8_istream_state
+  {
+    S_AUTO,                     /* Stream encoding not yet known. */
+    S_UTF8,                     /* Stream encoding is known to be UTF-8. */
+    S_CONVERT                   /* Stream encoding is known but not UTF-8. */
+  };
+
+struct u8_istream
+  {
+    int fd;
+    iconv_t converter;
+    enum u8_istream_state state;
+
+    char *buffer;
+    char *head;
+    size_t length;
+
+    char outbuf[4];
+    size_t outlen;
+  };
+
+static ssize_t fill_buffer (struct u8_istream *);
+
+/* Opens FILENAME, which is encoded in FROMCODE, for reading as an UTF-8
+   stream, passing FLAGS to the open() function.  Returns a new u8_istream if
+   successful, otherwise returns NULL and sets errno to an appropriate value.
+
+   The accepted forms for FROMCODE are listed at the top of
+   encoding-guesser.h. */
+struct u8_istream *
+u8_istream_for_file (const char *fromcode, const char *filename, int flags)
+{
+  struct u8_istream *is;
+  int fd;
+
+  assert (!(flags & O_CREAT));
+
+  fd = open (filename, flags);
+  if (fd < 0)
+    return NULL;
+
+  is = u8_istream_for_fd (fromcode, fd);
+  if (is == NULL)
+    {
+      int save_errno = errno;
+      close (fd);
+      errno = save_errno;
+    }
+
+  return is;
+}
+
+/* Creates and returns a new u8_istream that reads its input from FD.  Returns
+   a new u8_istream if successful, otherwise returns NULL and sets errno to an
+   appropriate value.
+
+   The accepted forms for FROMCODE are listed at the top of
+   encoding-guesser.h. */
+struct u8_istream *
+u8_istream_for_fd (const char *fromcode, int fd)
+{
+  struct u8_istream *is;
+  const char *encoding;
+
+  is = malloc (sizeof *is);
+  if (is == NULL)
+    return NULL;
+
+  is->fd = fd;
+  is->converter = (iconv_t) -1;
+  is->buffer = malloc (U8_ISTREAM_BUFFER_SIZE);
+  if (is->buffer == NULL)
+    goto error;
+  is->head = is->buffer;
+  is->length = 0;
+  is->outlen = 0;
+
+  if (fill_buffer (is) < 0)
+    goto error;
+
+  encoding = encoding_guess_head_encoding (fromcode, is->buffer, is->length);
+  if (!strcmp (encoding, "UTF-8"))
+    is->state = S_UTF8;
+  else
+    {
+      if (encoding_guess_encoding_is_auto (fromcode)
+          && !strcmp (encoding, "ASCII"))
+        is->state = S_AUTO;
+      else
+        is->state = S_CONVERT;
+
+      is->converter = iconv_open ("UTF-8",
+                                  encoding_guess_parse_encoding (fromcode));
+      if (is->converter == (iconv_t) -1)
+        goto error;
+    }
+
+  return is;
+
+error:
+  u8_istream_free (is);
+  return NULL;
+}
+
+/* Closes IS and its underlying file descriptor and frees all associated
+   resources.  Returns the return value from close(). */
+int
+u8_istream_close (struct u8_istream *is)
+{
+  if (is != NULL)
+    {
+      int fd = is->fd;
+      u8_istream_free (is);
+      return close (fd);
+    }
+  return 0;
+}
+
+/* Frees IS and associated resources, but does not close the underlying file
+   descriptor.  (Thus, the client must close the file descriptor when it is no
+   longer needed.) */
+void
+u8_istream_free (struct u8_istream *is)
+{
+  if (is != NULL)
+    {
+      if (is->converter != (iconv_t) -1)
+        iconv_close (is->converter);
+      free (is->buffer);
+      free (is);
+    }
+}
+
+static void
+substitute_invalid_input_byte (struct u8_istream *is)
+{
+  assert (is->outlen == 0);
+  is->head++;
+  is->length--;
+  is->outlen = u8_uctomb (CHAR_CAST (uint8_t *, is->outbuf),
+                          0xfffd, sizeof is->outbuf);
+}
+
+static ssize_t
+fill_buffer (struct u8_istream *is)
+{
+  ssize_t n;
+
+  /* Move any unused bytes to the beginning of the input buffer. */
+  if (is->length > 0 && is->buffer != is->head)
+    memmove (is->buffer, is->head, is->length);
+  is->head = is->buffer;
+
+  /* Read more input. */
+  n = read (is->fd, is->buffer + is->length,
+            U8_ISTREAM_BUFFER_SIZE - is->length);
+  if (n > 0)
+    is->length += n;
+  return n;
+}
+
+static ssize_t
+read_auto (struct u8_istream *is, char *buffer, size_t size)
+{
+  size_t original_size = size;
+  int retval = 0;
+
+  while (size > 0)
+    {
+      if (is->length > 0)
+        {
+          size_t n_ascii;
+
+          n_ascii = encoding_guess_count_ascii (is->head,
+                                                MIN (is->length, size));
+
+          memcpy (buffer, is->head, n_ascii);
+          buffer += n_ascii;
+          size -= n_ascii;
+
+          is->head += n_ascii;
+          is->length -= n_ascii;
+
+          if (size == 0)
+            break;
+        }
+
+      if (is->length == 0)
+        {
+          retval = fill_buffer (is);
+          if (retval > 0)
+            continue;
+          else
+            break;
+        }
+
+      /* is->head points to a byte that isn't a printable ASCII character.
+         Fill up the buffer and check for UTF-8. */
+      fill_buffer (is);
+      is->state = (encoding_guess_tail_is_utf8 (is->head, is->length)
+                   ? S_UTF8 : S_CONVERT);
+      if (size == original_size)
+        return u8_istream_read (is, buffer, size);
+      break;
+    }
+
+  return original_size - size;
+}
+
+static int
+convert_iconv (iconv_t converter,
+               char **inbufp, size_t *inbytesleft,
+               char **outbufp, size_t *outbytesleft)
+{
+  size_t n = iconv (converter, (ICONV_CONST char **) inbufp, inbytesleft,
+                    outbufp, outbytesleft);
+  return n == SIZE_MAX ? errno : 0;
+}
+
+static int
+convert_utf8 (iconv_t converter UNUSED,
+              char **inbufp, size_t *inbytesleft,
+              char **outbufp, size_t *outbytesleft)
+{
+  const uint8_t *in = CHAR_CAST (const uint8_t *, *inbufp);
+  size_t n = MIN (*inbytesleft, *outbytesleft);
+  size_t ofs = 0;
+  int error;
+
+  for (;;)
+    {
+      ucs4_t uc;
+      int mblen;
+
+      if (ofs >= n)
+        {
+          error = ofs < *inbytesleft ? E2BIG : 0;
+          break;
+        }
+
+      mblen = u8_mbtouc (&uc, in + ofs, n - ofs);
+      if (uc == 0xfffd)
+        {
+          int retval = u8_mbtoucr (&uc, in + ofs, *inbytesleft - ofs);
+          if (retval == mblen)
+            {
+              /* There's an actual U+FFFD in the input stream.  Carry on. */
+            }
+          else
+            {
+              error = (retval == -1 ? EILSEQ
+                       : retval == -2 ? EINVAL
+                       : E2BIG);
+              break;
+            }
+        }
+
+      ofs += mblen;
+    }
+
+  if (ofs > 0)
+    {
+      memcpy (*outbufp, *inbufp, ofs);
+      *inbufp += ofs;
+      *inbytesleft -= ofs;
+      *outbufp += ofs;
+      *outbytesleft -= ofs;
+    }
+
+  return error;
+}
+
+static ssize_t
+read_convert (struct u8_istream *is,
+              int (*convert) (iconv_t converter,
+                              char **inbufp, size_t *inbytesleft,
+                              char **outbufp, size_t *outbytesleft),
+              char *buffer, size_t size)
+{
+  size_t original_size = size;
+
+  while (size > 0)
+    {
+      ssize_t n_read;
+
+      if (is->outlen > 0)
+        {
+          size_t n = MIN (size, is->outlen);
+
+          memcpy (buffer, is->outbuf, n);
+          is->outlen -= n;
+          if (is->outlen > 0)
+            memmove (is->outbuf, is->outbuf + n, is->outlen);
+
+          buffer += n;
+          size -= n;
+
+          if (size == 0)
+            break;
+        }
+
+      if (is->length)
+        {
+          int error = convert (is->converter,
+                               &is->head, &is->length,
+                               &buffer, &size);
+          if (size == 0)
+            break;
+
+          switch (error)
+            {
+            case 0:
+              /* Converted all of the input into output, possibly with space
+                 for output left over.
+
+                 Read more input. */
+              break;
+
+            case EILSEQ:
+              substitute_invalid_input_byte (is);
+              continue;
+
+            case EINVAL:
+              /* Incomplete byte sequence at end of input.  Read more
+                 input. */
+              break;
+
+            default:
+              /* A real error of some kind (ENOMEM?). */
+              return -1;
+
+            case E2BIG:
+              /* Ran out of room for output.
+                 Convert into outbuf and copy from there instead. */
+              {
+                char *outptr = is->outbuf;
+                size_t outleft = sizeof is->outbuf;
+
+                error = convert (is->converter,
+                                 &is->head, &is->length,
+                                 &outptr, &outleft);
+                is->outlen = outptr - is->outbuf;
+                if (is->outlen > 0)
+                  continue;
+
+                switch (error)
+                  {
+                  case EILSEQ:
+                    substitute_invalid_input_byte (is);
+                    continue;
+
+                  case E2BIG:
+                  case EINVAL:
+                    continue;
+
+                  default:
+                    /* A real error of some kind (ENOMEM?). */
+                    return -1;
+                  }
+              }
+            }
+        }
+
+      assert (is->length <= MB_LEN_MAX);
+      n_read = fill_buffer (is);
+      if (n_read <= 0)
+        {
+          if (original_size != size)
+            {
+              /* We produced some output so don't report EOF or error yet. */
+              break;
+            }
+          else if (n_read == 0 && is->length != 0)
+            {
+              /* Incomplete byte sequence at end of file. */
+              substitute_invalid_input_byte (is);
+            }
+          else
+            {
+              /* Propagate end-of-file or error to caller. */
+              return n_read;
+            }
+        }
+    }
+
+  return original_size - size;
+}
+
+/* Reads up to SIZE bytes of UTF-8 text from IS into BUFFER.  Returns the
+   number of bytes read if successful, 0 at end of file, or -1 if an error
+   occurred before any data could be read.  Upon error, sets errno to an
+   appropriate value. */
+ssize_t
+u8_istream_read (struct u8_istream *is, char *buffer, size_t size)
+{
+  switch (is->state)
+    {
+    case S_CONVERT:
+      return read_convert (is, convert_iconv, buffer, size);
+
+    case S_AUTO:
+      return read_auto (is, buffer, size);
+
+    case S_UTF8:
+      return read_convert (is, convert_utf8, buffer, size);
+    }
+
+  NOT_REACHED ();
+}
+
+/* Returns the file descriptor underlying IS. */
+int
+u8_istream_fileno (const struct u8_istream *is)
+{
+  return is->fd;
+}
+\f
+/* Test functions.
+
+   These functions are probably useful only for white-box testing. */
+
+/* Returns true if the encoding of the file being read by IS is not yet
+   known. */
+bool
+u8_istream_is_auto (const struct u8_istream *is)
+{
+  return is->state == S_AUTO;
+}
+
+/* Returns true if the encoding of the file being read by IS has been
+   determined to be UTF-8. */
+bool
+u8_istream_is_utf8 (const struct u8_istream *is)
+{
+  return is->state == S_UTF8;
+}
diff --git a/src/libpspp/u8-istream.h b/src/libpspp/u8-istream.h
new file mode 100644 (file)
index 0000000..3e2acee
--- /dev/null
@@ -0,0 +1,45 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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_U8_ISTREAM_H
+#define LIBPSPP_U8_ISTREAM_H 1
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+/* u8_istream.
+
+   Reads a text file and reencodes its contents into UTF-8, with optional
+   automatic encoding detection.
+*/
+
+#define U8_ISTREAM_BUFFER_SIZE 4096
+
+struct u8_istream *u8_istream_for_fd (const char *fromcode, int fd);
+struct u8_istream *u8_istream_for_file (const char *fromcode,
+                                        const char *filename, int flags);
+
+int u8_istream_close (struct u8_istream *);
+void u8_istream_free (struct u8_istream *);
+
+ssize_t u8_istream_read (struct u8_istream *, char *, size_t);
+
+int u8_istream_fileno (const struct u8_istream *);
+
+bool u8_istream_is_auto (const struct u8_istream *);
+bool u8_istream_is_utf8 (const struct u8_istream *);
+
+#endif /* libpspp/u8-istream.h */
index de4124efe16c5beb799c7b5d0b2af42743ff79d7..2e4545906f9d558059a0950d9ad5a551adeaf7f3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "box-whisker.h"
-#include "order-stats.h"
-#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>
-#include <libpspp/str.h>
-#include <data/case.h>
-#include <data/variable.h>
+
+#include "data/case.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "math/order-stats.h"
+#include "math/tukey-hinges.h"
+
+#include "gl/xalloc.h"
 
 static void
 destroy (struct statistic *s)
index bef091e83b448dafc5c601fab3d04eb0d60f19f6..f6856d1e8a125783242b9a67ff8f9b8f5150eacb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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
@@ -18,9 +18,9 @@
 #define __MATH_BOX_WHISKER_H__
 
 #include <stddef.h>
-#include <libpspp/ll.h>
-#include <libpspp/str.h>
-#include "order-stats.h"
+#include "libpspp/ll.h"
+#include "libpspp/str.h"
+#include "math/order-stats.h"
 
 /* This module calculates the statistics typically displayed by box-plots.
    However, there's no reason not to use it for other purposes too.
index c8b337e452012f03c2d16f5229f2253441a16b21..f40ae10b5d7dca7714cf8aea4e88314792bea795 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <stdio.h>
+#include "math/categoricals.h"
 
-#include "categoricals.h"
+#include <stdio.h>
 
-#include <gl/xalloc.h>
-#include <data/variable.h>
-#include <data/case.h>
-#include <data/value.h>
-#include <libpspp/hmap.h>
-#include <libpspp/pool.h>
-#include <libpspp/array.h>
+#include "data/case.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/array.h"
+#include "libpspp/hmap.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
 
-#include <libpspp/str.h>
+#include "gl/xalloc.h"
 
 struct value_node
 {
@@ -177,7 +177,7 @@ categoricals_dump (const struct categoricals *cat)
 
   printf ("\nReverse variable map:\n");
 
-  for (v = 0 ; v < cat->n_cats_total; ++v)
+  for (v = 0 ; v < cat->n_cats_total - cat->n_vars; ++v)
     printf ("%d ", cat->reverse_variable_map[v]);
   printf ("\n");
 }
@@ -311,7 +311,7 @@ categoricals_total (const struct categoricals *cat)
 /* This function must be called *before* any call to categoricals_get_*_by subscript an
  *after* all calls to categoricals_update */
 void
-categoricals_done (struct categoricals *cat)
+categoricals_done (const struct categoricals *cat_)
 {
   /* Implementation Note: Whilst this function is O(n) in cat->n_cats_total, in most
      uses it will be more efficient that using a tree based structure, since it
@@ -319,10 +319,11 @@ categoricals_done (struct categoricals *cat)
 
      1 call of O(n) + 10^9 calls of O(1) is better than 10^9 calls of O(log n).
   */
+  struct categoricals *cat = CONST_CAST (struct categoricals *, cat_);
   int v;
   int idx = 0;
   cat->reverse_variable_map = pool_calloc (cat->pool,
-                                          cat->n_cats_total,
+                                          cat->n_cats_total - cat->n_vars,
                                           sizeof *cat->reverse_variable_map);
   
   for (v = 0 ; v < cat->n_vp; ++v)
@@ -348,12 +349,11 @@ categoricals_done (struct categoricals *cat)
 
       /* Populate the reverse variable map.
        */
-      for (i = 0; i < vp->n_cats; ++i)
+      for (i = 0; i < vp->n_cats - 1; ++i)
        cat->reverse_variable_map[idx++] = v;
     }
 
   assert (cat->n_vars <= cat->n_vp);
-
 }
 
 
@@ -362,7 +362,7 @@ reverse_variable_lookup (const struct categoricals *cat, int subscript)
 {
   assert (cat->reverse_variable_map);
   assert (subscript >= 0);
-  assert (subscript < cat->n_cats_total);
+  assert (subscript < cat->n_cats_total - cat->n_vars);
 
   return cat->reverse_variable_map[subscript];
 }
index 09ced7d7acc2a9900fd67039697b98273aaafe0c..97cde65e74dda7f856674bb253eda6748d3ccb24 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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,7 +19,7 @@
 #define _CATEGORICALS__
 
 #include <stddef.h>
-#include <data/missing-values.h>
+#include "data/missing-values.h"
 
 struct categoricals;
 struct variable;
@@ -61,7 +61,7 @@ size_t categoricals_total (const struct categoricals *cat);
 */
 size_t categoricals_get_n_variables (const struct categoricals *cat);
 
-void categoricals_done (struct categoricals *cat);
+void categoricals_done (const struct categoricals *cat);
 
 const struct variable * categoricals_get_variable_by_subscript (const struct categoricals *cat, int subscript);
 
index 47762747340974f815207389fb48b71a59bf3605..e7ebd1f52dbc94ac8469af1c23b68eefe715547d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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 "correlation.h"
+#include "math/correlation.h"
 
 #include <gsl/gsl_matrix.h>
 #include <gsl/gsl_cdf.h>
 #include <math.h>
-#include <libpspp/misc.h>
-#include "minmax.h"
+
+#include "libpspp/misc.h"
+
+#include "gl/minmax.h"
 
 
 double
index aa7f41771c1ac9f3d55ff90d5a418010e5e032a8..a7a5f131651963716ee0b0b5e8b8589a26579b2f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 <libpspp/assertion.h>
-#include "covariance.h"
-#include <gl/xalloc.h>
-#include "moments.h"
+#include "math/covariance.h"
+
 #include <gsl/gsl_matrix.h>
-#include <data/case.h>
-#include <data/variable.h>
-#include <libpspp/misc.h>
-#include "categoricals.h"
+
+#include "data/case.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/misc.h"
+#include "math/categoricals.h"
+#include "math/moments.h"
+
+#include "gl/xalloc.h"
 
 #define n_MOMENTS (MOMENT_VARIANCE + 1)
 
@@ -529,7 +532,7 @@ cm_to_gsl (struct covariance *cov)
 }
 
 
-static const gsl_matrix *
+static gsl_matrix *
 covariance_calculate_double_pass (struct covariance *cov)
 {
   size_t i, j;
@@ -553,7 +556,7 @@ covariance_calculate_double_pass (struct covariance *cov)
   return  cm_to_gsl (cov);
 }
 
-static const gsl_matrix *
+static gsl_matrix *
 covariance_calculate_single_pass (struct covariance *cov)
 {
   size_t i, j;
@@ -598,12 +601,12 @@ covariance_calculate_single_pass (struct covariance *cov)
 }
 
 
-/* 
-   Return a pointer to gsl_matrix containing the pairwise covariances.
-   The matrix remains owned by the COV object, and must not be freed.
-   Call this function only after all data have been accumulated.
-*/
-const gsl_matrix *
+/* Return a pointer to gsl_matrix containing the pairwise covariances.  The
+   caller owns the returned matrix and must free it when it is no longer
+   needed.
+
+   Call this function only after all data have been accumulated.  */
+gsl_matrix *
 covariance_calculate (struct covariance *cov)
 {
   if ( cov->state <= 0 )
@@ -625,7 +628,7 @@ covariance_calculate (struct covariance *cov)
 /*
   Covariance computed without dividing by the sample size.
  */
-static const gsl_matrix *
+static gsl_matrix *
 covariance_calculate_double_pass_unnormalized (struct covariance *cov)
 {
   size_t i, j;
@@ -647,7 +650,7 @@ covariance_calculate_double_pass_unnormalized (struct covariance *cov)
   return  cm_to_gsl (cov);
 }
 
-static const gsl_matrix *
+static gsl_matrix *
 covariance_calculate_single_pass_unnormalized (struct covariance *cov)
 {
   size_t i, j;
@@ -679,12 +682,12 @@ covariance_calculate_single_pass_unnormalized (struct covariance *cov)
 }
 
 
-/* 
-   Return a pointer to gsl_matrix containing the pairwise covariances.
-   The matrix remains owned by the COV object, and must not be freed.
-   Call this function only after all data have been accumulated.
-*/
-const gsl_matrix *
+/* Return a pointer to gsl_matrix containing the pairwise covariances.  The
+   caller owns the returned matrix and must free it when it is no longer
+   needed.
+
+   Call this function only after all data have been accumulated.  */
+gsl_matrix *
 covariance_calculate_unnormalized (struct covariance *cov)
 {
   if ( cov->state <= 0 )
@@ -728,3 +731,28 @@ covariance_destroy (struct covariance *cov)
   free (cov->cm);
   free (cov);
 }
+
+size_t
+covariance_dim (const struct covariance * cov)
+{
+  return (cov->dim);
+}
+
+/*
+  Returns an array of variables corresponding to rows of the covariance matrix.
+  In other words, element i of the array is the variable corresponding to 
+  row (and column) i of the covariance matrix.
+ */
+void
+covariance_get_var_indices (const struct covariance *cov, struct variable **vars)
+{
+  int i;
+  for (i = 0; i < cov->n_vars; i++)
+    {
+      vars[i] = cov->vars[i];
+    }
+  for (i = cov->n_vars; i < cov->dim; i++)
+    {
+      vars[i] = categoricals_get_variable_by_subscript (cov->categoricals, i - cov->n_vars);
+    }
+}
index cb83e151409224d1bf1d982a259179b9e79f5f49..6ec645b7e27009df8b195aa96ef32604795e46e8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
 #ifndef COVARIANCE_H
 #define COVARIANCE_H
 
-#include <stddef.h>
-
-#include <data/missing-values.h>
 #include <gsl/gsl_matrix.h>
+#include <stddef.h>
+#include "data/missing-values.h"
 
 struct covariance;
 struct variable;
@@ -40,8 +39,8 @@ void covariance_accumulate (struct covariance *, const struct ccase *);
 void covariance_accumulate_pass1 (struct covariance *, const struct ccase *);
 void covariance_accumulate_pass2 (struct covariance *, const struct ccase *);
 
-const gsl_matrix * covariance_calculate (struct covariance *cov);
-const gsl_matrix * covariance_calculate_unnormalized (struct covariance *);
+gsl_matrix * covariance_calculate (struct covariance *);
+gsl_matrix * covariance_calculate_unnormalized (struct covariance *);
 
 void covariance_destroy (struct covariance *cov);
 
@@ -49,4 +48,6 @@ const gsl_matrix *covariance_moments (const struct covariance *cov, int m);
 
 const struct categoricals * covariance_get_categoricals (const struct covariance *cov);
 
+void covariance_get_var_indices (const struct covariance *cov, struct variable **vars);
+size_t covariance_dim (const struct covariance * cov);
 #endif
index 617c7ac72bb15ba646c2e9b7926188bcaa40bc04..7b82a5c4a0e4914d04c35d8c726209adadaaf9c9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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 "extrema.h"
-#include <xalloc.h>
-#include <data/case.h>
-#include <data/val-type.h>
-#include <libpspp/compiler.h>
-#include <libpspp/ll.h>
+
+#include "math/extrema.h"
+
 #include <stdlib.h>
 
+#include "data/case.h"
+#include "data/val-type.h"
+#include "libpspp/compiler.h"
+#include "libpspp/ll.h"
+
+#include "gl/xalloc.h"
+
 struct extrema
 {
   size_t capacity;
index d891c533c91824be90c37e5ea80ae90fac00424b..5c8fa6062e6118a1229a3c218b7925ae2372a977 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2011 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
@@ -18,8 +18,8 @@
 #define __EXTREMA_H__ 1
 
 #include <stddef.h>
-#include <data/case.h>
-#include <libpspp/ll.h>
+#include "data/case.h"
+#include "libpspp/ll.h"
 
 struct extremum
 {
index 3a483671fbb6bca1561943554f9a52517469b56b..6f86f87d61659800343a38ba090bf8d6472ddbe3 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, 2011 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 <stdlib.h>
-#include <libpspp/compiler.h>
-#include <libpspp/hash.h>
-#include "group.h"
-#include "group-proc.h"
-#include <libpspp/str.h>
-#include <data/variable.h>
-#include <libpspp/misc.h>
-
-#include "xalloc.h"
 
-/* Return -1 if the id of a is less than b; +1 if greater than and
-   0 if equal */
-int
-compare_group (const void *a_,
-                const void *b_,
-                const void *var)
-{
-  const struct group_statistics *a = a_;
-  const struct group_statistics *b = b_;
-  return value_compare_3way (&a->id, &b->id, var_get_width (var));
-}
+#include "math/group.h"
 
+#include <stdlib.h>
 
+#include "data/variable.h"
+#include "libpspp/compiler.h"
+#include "libpspp/hash.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "math/group-proc.h"
 
-unsigned int
-hash_group (const void *g_, const void *var)
-{
-  unsigned id_hash;
-  const struct group_statistics *g = g_;
-
-  id_hash = value_hash (&g->id, var_get_width (var), 0);
-
-  return id_hash;
-}
-
+#include "gl/xalloc.h"
 
 void
 free_group (struct group_statistics *v, void *aux UNUSED)
@@ -58,6 +35,14 @@ free_group (struct group_statistics *v, void *aux UNUSED)
   free(v);
 }
 
+static void
+group_proc_dtor (struct variable *var)
+{
+  struct group_proc *group = var_detach_aux (var);
+
+  hsh_destroy (group->group_hash);
+  free (group);
+}
 
 struct group_proc *
 group_proc_get (const struct variable *v)
@@ -66,8 +51,8 @@ group_proc_get (const struct variable *v)
   struct group_proc *group = var_get_aux (v);
   if (group == NULL)
     {
-      group = xmalloc (sizeof (struct group_proc));
-      var_attach_aux (v, group, var_dtor_free);
+      group = xzalloc (sizeof *group);
+      var_attach_aux (v, group, group_proc_dtor);
     }
   return group;
 }
index c5470b2578f2a1948e66a1ca6e6ae220d1616ecb..1e0b26724d0d2dc559966deb6b94c7984f7b7a3c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2011 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
@@ -18,7 +18,7 @@
 #ifndef GROUP_H
 #define GROUP_H
 
-#include <data/value.h>
+#include "data/value.h"
 
 /* Statistics for grouped data */
 struct group_statistics
@@ -67,18 +67,6 @@ struct group_statistics
 
 struct variable ;
 
-/* These funcs are useful for hash tables */
-
-/* Return -1 if the id of a is less than b; +1 if greater than and
-   0 if equal */
-int  compare_group (const void *a,
-                   const void *b,
-                   const void *var);
-
-unsigned int hash_group (const void *g, const void *var);
-
 void  free_group (struct group_statistics *v, void *aux);
 
-
-
 #endif
index 0c641b56e127ddbdf9a180363629101fad746b6c..1b55d204b866fa2e15dc4ff3f84d3b3a509a9915 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009, 2011 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 "histogram.h"
 
-#include <gl/xalloc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#include "math/histogram.h"
 
 #include <gsl/gsl_histogram.h>
-#include "chart-geometry.h"
 #include <math.h>
 
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "math/chart-geometry.h"
+
+#include "gl/xalloc.h"
 
 void
 histogram_add (struct histogram *h, double y, double c)
index bc4a5ae6c1354d9711a467ceba8cf904a875a8fa..4c0e54fb0488ae38cd931684f52e472476463303 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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,7 +19,7 @@
 
 #include <stddef.h>
 
-#include "statistic.h"
+#include "math/statistic.h"
 
 #include <gsl/gsl_histogram.h>
 
index 2f8da8ccaaa1fd4619a73415a8ff888cd097d9ac..87f4836da23479ced8fa9a2069841ada800408d9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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 "math/interaction.h"
+
 #include <assert.h>
-#include <data/dictionary.h>
-#include <data/value.h>
-#include <data/variable.h>
-#include <gl/unistr.h>
-#include <math/interaction.h>
 #include <string.h>
-#include <xalloc.h>
+#include <unistr.h>
+
+#include "data/dictionary.h"
+#include "data/value.h"
+#include "data/variable.h"
+
+#include "gl/xalloc.h"
 
 struct interaction_variable
 {
index 995d0684517d78a8207e040121126b1ae63f473c..13b13690f9360114826b2deda1597f4c9e3a2ae1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -16,7 +16,8 @@
 
 #ifndef INTERACTION_H
 #define INTERACTION_H
-#include <data/case.h>
+
+#include "data/case.h"
 
 struct interaction_variable;
 struct interaction_value;
index b92441b37babbf8505a931176aa00e1fd1ab7f89..13fad93e52107ebe5a16ca826fbbedb06dbf8928 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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 "levene.h"
+#include "math/levene.h"
 
 #include <math.h>
 
-#include <libpspp/misc.h>
-
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/variable.h>
-
-
-#include <libpspp/hmap.h>
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/variable.h"
+#include "libpspp/hmap.h"
+#include "libpspp/misc.h"
 
 struct lev
 {
@@ -113,6 +110,7 @@ levene (struct casereader *rx, const struct variable *gvar,
   r = casereader_clone (rx);
   for (; (c = casereader_read (r)) != NULL; case_unref (c))
     {
+      struct lev *l = NULL;
       const union value *target = case_data (c, gvar);
       int width = var_get_width (gvar);
       const double x = case_data (c, var)->f;
@@ -121,8 +119,7 @@ levene (struct casereader *rx, const struct variable *gvar,
       if (var_is_value_missing (var, case_data (c, var), exclude))
        continue;
 
-      struct lev *l = find_group (&map, target, width);
-
+      l = find_group (&map, target, width);
       assert (l);
       
       l->z_mean += fabs (x - l->t_bar) * weight;
@@ -144,6 +141,7 @@ levene (struct casereader *rx, const struct variable *gvar,
   for (; (c = casereader_read (r)) != NULL; case_unref (c))
     {
       double z;
+      struct lev *l;
       const union value *target = case_data (c, gvar);
       int width = var_get_width (gvar);
       const double x = case_data (c, var)->f;
@@ -152,10 +150,10 @@ levene (struct casereader *rx, const struct variable *gvar,
       if (var_is_value_missing (var, case_data (c, var), exclude))
        continue;
 
-      struct lev *l = find_group (&map, target, width);
+      l = find_group (&map, target, width);
       assert (l);
-      z = fabs (x - l->t_bar);
 
+      z = fabs (x - l->t_bar);
       denominator += pow2 (z - l->z_mean) * weight;
     }
   casereader_destroy (r);
@@ -164,7 +162,7 @@ levene (struct casereader *rx, const struct variable *gvar,
 
   {
     double grand_n = 0.0;
-    struct hmap_node *next;
+    struct lev *next;
     struct lev *l;
     HMAP_FOR_EACH_SAFE (l, next, struct lev, node, &map)
       {
index 63d1a0f976ee420ca52b476e67aa85cd94ff4a5e..90c62a5258640fdfb9a1eeb8b29bd4164ba77d29 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2010 Free Software Foundation, Inc. 
+   Copyright (C) 2005, 2010, 2011 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 "math/linreg.h"
+
 #include <gsl/gsl_blas.h>
 #include <gsl/gsl_cblas.h>
 #include <gsl/gsl_errno.h>
 #include <gsl/gsl_fit.h>
 #include <gsl/gsl_linalg.h>
 #include <gsl/gsl_multifit.h>
-#include <linreg/sweep.h>
-#include <math/linreg.h>
-#include <src/data/variable.h>
-#include <src/data/value.h>
-#include <gl/xalloc.h>
+
+#include "data/value.h"
+#include "data/variable.h"
+#include "linreg/sweep.h"
+
+#include "gl/xalloc.h"
 
 /*
   Find the least-squares estimate of b for the linear model:
index 31bf5651051564774d0417571a99f929a562f270..32373f5ed484eceab55fc4b1df8cf019d03860cf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005 Free Software Foundation, Inc. Written by Jason H. Stover.
+   Copyright (C) 2005, 2011 Free Software Foundation, Inc. Written by Jason H. Stover.
 
    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 LINREG_H
 #define LINREG_H
-#include <stdbool.h>
+
 #include <gsl/gsl_math.h>
-#include <gsl/gsl_vector.h>
 #include <gsl/gsl_matrix.h>
+#include <gsl/gsl_vector.h>
+#include <stdbool.h>
 
 enum
 {
index af44855ce1cbb7718dd18d48d459fc5cfe15fa8a..5b0704d9c26850518041ad52f6457b23344b1952 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009, 2011 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
    performance regression. */
 #include <config.h>
 
-#include <math/merge.h>
+#include "math/merge.h"
 
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/subcase.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <libpspp/taint.h>
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/subcase.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "libpspp/taint.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #define MAX_MERGE_ORDER 7
 
index 545c9644399a9501765455cfc99505be30e8d460..e289e8aec0ef27c2372e2c007eeb30e6b2f6d469 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011 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 "moments.h"
+
+#include "math/moments.h"
+
 #include <assert.h>
 #include <math.h>
 #include <stdlib.h>
-#include <libpspp/misc.h>
-#include <data/val-type.h>
-#include <data/value.h>
 
-#include "xalloc.h"
+#include "data/val-type.h"
+#include "data/value.h"
+#include "libpspp/misc.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 23457ce67f3771c0654099b3adea9dfe16f3a586..55c517e5217864cda1a1607485c8347d1c1bbf1f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2011 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
@@ -18,7 +18,7 @@
 #define HEADER_MOMENTS
 
 #include <stddef.h>
-#include <data/value.h>
+#include "data/value.h"
 
 /* Moments of the mean.
    Higher-order moments have higher values. */
index b631820903e6ebf4e41a536ebe7ea964924af918..ccaa51e22d24a0e96a91996f7f597df547d3c6ce 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "np.h"
+
+#include "math/np.h"
 
 #include <gsl/gsl_cdf.h>
 #include <math.h>
 #include <stdlib.h>
 
-#include <data/case.h>
-#include <data/casewriter.h>
-#include <libpspp/compiler.h>
-#include <libpspp/cast.h>
-#include <libpspp/misc.h>
-#include <math/moments.h>
+#include "data/case.h"
+#include "data/casewriter.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/misc.h"
+#include "math/moments.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 static void
 destroy (struct statistic *stat)
index 9f54e8730c9bfda7ce738b5311df3016f3c9cdbf..be9c49a3122171b6f1eee792a802e080ab2f4150 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "order-stats.h"
-#include <libpspp/assertion.h>
-#include <data/val-type.h>
-#include <gl/xalloc.h>
-#include <data/variable.h>
-#include <data/casereader.h>
+
+#include "math/order-stats.h"
+
 #include <string.h>
 
+#include "data/casereader.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+
+#include "gl/xalloc.h"
+
 #if 0
 
 #include <stdio.h>
index 07da284aa26af9faa95df9872d00163092471686..f3e470e652c32ad0020e38a88bcb4bfbf45bdc24 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2011 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
@@ -18,8 +18,8 @@
 #define __ORDER_STATS_H__
 
 #include <stddef.h>
-#include <data/missing-values.h>
-#include <math/statistic.h>
+#include "data/missing-values.h"
+#include "math/statistic.h"
 
 struct casereader;
 struct variable;
index c76bb492ba767a90ffa2c03c8d35bf8a7d532ab6..ed7b129576f1f7d6b713f46af75ef77aeab3dbf8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "percentiles.h"
-#include <math/order-stats.h>
 
+#include "math/percentiles.h"
+
+#include "data/casereader.h"
+#include "data/val-type.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "math/order-stats.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 #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>
-#include <data/casereader.h>
-
-
 const char *const ptile_alg_desc[] = {
   "",
   N_("HAverage"),
index 5b82277cb7b255f25c1663b6bbc1167f8bae72f9..3491a20bfd684abae50fe88f2f232d0bbe04a3e4 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, 2011 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 "sort.h"
+#include "math/sort.h"
 
 #include <stdio.h>
 
-#include <data/case.h>
-#include <data/casereader.h>
-#include <data/casewriter.h>
-#include <data/casewriter-provider.h>
-#include <data/settings.h>
-#include <data/subcase.h>
-#include <libpspp/array.h>
-#include <libpspp/assertion.h>
-#include <math/merge.h>
-
-#include "xalloc.h"
+#include "data/case.h"
+#include "data/casereader.h"
+#include "data/casewriter-provider.h"
+#include "data/casewriter.h"
+#include "data/settings.h"
+#include "data/subcase.h"
+#include "libpspp/array.h"
+#include "libpspp/assertion.h"
+#include "math/merge.h"
+
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index d1cc6b708279098ab8d263b95923d9b31c968ed6..5e48689626817ddf59ad46363a17e1d0e763084d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "trimmed-mean.h"
-#include <math/order-stats.h>
 
-#include <gl/xalloc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#include "math/trimmed-mean.h"
+
 #include <math.h>
-#include <data/val-type.h>
 
+#include "data/val-type.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "math/order-stats.h"
+
+#include "gl/xalloc.h"
 
 static void
 acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc, double y)
index 3ab2f3edce165ed0a709688e711867986683eee3..ba2120fb4e6bc735f41d300b5aef406be5c2828d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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 <math.h>
-#include <stdlib.h>
+#include "math/ts/innovations.h"
 
 #include <gsl/gsl_matrix.h>
 #include <gsl/gsl_vector.h>
-#include <libpspp/compiler.h>
-#include <libpspp/misc.h>
-#include <math/coefficient.h>
-#include <math/ts/innovations.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "libpspp/compiler.h"
+#include "libpspp/misc.h"
+#include "math/coefficient.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 static void
 get_mean (const gsl_matrix *data,
index f0e40c59f7e2400b0d47609534a14ba1e64c3580..7693690ce58e072e91305619b15508c7e001a644 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2011 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
@@ -25,8 +25,9 @@
  */
 #ifndef INNOVATIONS_H
 #define INNOVATIONS_H
-#include <math/coefficient.h>
-#include <math/design-matrix.h>
+
+#include "math/coefficient.h"
+#include "math/design-matrix.h"
 
 struct innovations_estimate
 {
index 22ab45210c38c98066eb4bb654663114cb496ddd..3e9ea9374eb4198b76d83688234b23de97fc7cf9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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 "tukey-hinges.h"
-#include <math/order-stats.h>
 
-#include <gl/xalloc.h>
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#include "math/tukey-hinges.h"
+
 #include <math.h>
 
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "math/order-stats.h"
+
+#include "gl/xalloc.h"
+
 void
 tukey_hinges_calculate (const struct tukey_hinges *th, double hinge[3])
 {
index c9f96b21b58cbd287d2d41152e572ee6a658bd7d..1c3e6b8238f8f7f0739310ae64bfea6b5778c3bb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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 <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <unilbrk.h>
+#include <unistr.h>
+#include <uniwidth.h>
 
 #include "data/file-name.h"
 #include "data/settings.h"
@@ -31,6 +36,7 @@
 #include "libpspp/start-date.h"
 #include "libpspp/string-map.h"
 #include "libpspp/version.h"
+#include "output/ascii.h"
 #include "output/cairo.h"
 #include "output/chart-item-provider.h"
 #include "output/driver-provider.h"
 #define H TABLE_HORZ
 #define V TABLE_VERT
 
-/* Line styles bit shifts. */
-enum
+#define N_BOX (RENDER_N_LINES * RENDER_N_LINES \
+               * RENDER_N_LINES * RENDER_N_LINES)
+
+static const ucs4_t ascii_box_chars[N_BOX] =
   {
-    LNS_TOP = 0,
-    LNS_LEFT = 2,
-    LNS_BOTTOM = 4,
-    LNS_RIGHT = 6,
+    ' ', '|', '#',
+    '-', '+', '#',
+    '=', '#', '#',
+    '|', '|', '#',
+    '+', '+', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '-', '+', '#',
+    '-', '+', '#',
+    '#', '#', '#',
+    '+', '+', '#',
+    '+', '+', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '=', '#', '#',
+    '#', '#', '#',
+    '=', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+    '#', '#', '#',
+  };
 
-    LNS_COUNT = 256
+static const ucs4_t unicode_box_chars[N_BOX] =
+  {
+    0x0020, 0x2575, 0x2551,
+    0x2574, 0x256f, 0x255c,
+    0x2550, 0x255b, 0x255d,
+    0x2577, 0x2502, 0x2551,
+    0x256e, 0x2524, 0x2562,
+    0x2555, 0x2561, 0x2563,
+    0x2551, 0x2551, 0x2551,
+    0x2556, 0x2562, 0x2562,
+    0x2557, 0x2563, 0x2563,
+    0x2576, 0x2570, 0x2559,
+    0x2500, 0x2534, 0x2568,
+    0x2550, 0x2567, 0x2569,
+    0x256d, 0x251c, 0x255f,
+    0x252c, 0x253c, 0x256a,
+    0x2564, 0x256a, 0x256c,
+    0x2553, 0x255f, 0x255f,
+    0x2565, 0x256b, 0x256b,
+    0x2566, 0x256c, 0x256c,
+    0x2550, 0x2558, 0x255a,
+    0x2550, 0x2567, 0x2569,
+    0x2550, 0x2567, 0x2569,
+    0x2552, 0x255e, 0x2560,
+    0x2564, 0x256a, 0x256c,
+    0x2564, 0x256a, 0x256c,
+    0x2554, 0x2560, 0x2560,
+    0x2566, 0x256c, 0x256c,
   };
 
 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));
+  return ((right * 3 + bottom) * 3 + left) * 3 + top;
 }
 
-/* Character attributes. */
-#define ATTR_EMPHASIS   0x100   /* Bold-face. */
-#define ATTR_BOX        0x200   /* Line drawing character. */
-
 /* A line of text. */
 struct ascii_line
   {
-    unsigned short *chars;      /* Characters and attributes. */
-    int n_chars;                /* Length. */
-    int allocated_chars;        /* Allocated "chars" elements. */
+    struct string s;            /* Content, in UTF-8. */
+    size_t width;               /* Display width, in character positions. */
   };
 
 /* How to emphasize text. */
@@ -111,8 +164,7 @@ struct ascii_driver
     int top_margin;            /* Top margin in lines. */
     int bottom_margin;         /* Bottom margin in lines. */
 
-    char *box[LNS_COUNT];       /* Line & box drawing characters. */
-    char *init;                 /* Device initialization string. */
+    const ucs4_t *box;          /* Line & box drawing characters. */
 
     /* Internal state. */
     char *command_name;
@@ -134,7 +186,6 @@ 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 *);
 
@@ -169,10 +220,10 @@ static struct output_driver *
 ascii_create (const char *file_name, enum settings_output_devices device_type,
               struct string_map *o)
 {
+  enum { BOX_ASCII, BOX_UNICODE } box;
   struct output_driver *d;
   struct ascii_driver *a;
   int paper_length;
-  int right, bottom, left, top;
 
   a = xzalloc (sizeof *a);
   d = &a->driver;
@@ -198,20 +249,11 @@ ascii_create (const char *file_name, enum settings_output_devices device_type,
   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];
-
-            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", ""));
+  box = parse_enum (opt (d, o, "box", "ascii"),
+                    "ascii", BOX_ASCII,
+                    "unicode", BOX_UNICODE,
+                    NULL_SENTINEL);
+  a->box = box == BOX_ASCII ? ascii_box_chars : unicode_box_chars;
 
   a->command_name = NULL;
   a->title = xstrdup ("");
@@ -234,29 +276,6 @@ error:
   return NULL;
 }
 
-static const char *
-get_default_box (int right, int bottom, int left, int top)
-{
-  switch ((top << 12) | (left << 8) | (bottom << 4) | (right << 0))
-    {
-    case 0x0000:
-      return " ";
-
-    case 0x0100: case 0x0101: case 0x0001:
-      return "-";
-
-    case 0x1000: case 0x1010: case 0x0010:
-      return "|";
-
-    case 0x0300: case 0x0303: case 0x0003:
-    case 0x0200: case 0x0202: case 0x0002:
-      return "=";
-
-    default:
-      return left > 1 || top > 1 || right > 1 || bottom > 1 ? "#" : "+";
-    }
-}
-
 static int
 parse_page_size (struct driver_option *option)
 {
@@ -340,11 +359,8 @@ ascii_destroy (struct output_driver *driver)
   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);
+    ds_destroy (&a->lines[i].s);
   free (a->lines);
   free (a);
 }
@@ -527,6 +543,7 @@ ascii_submit (struct output_driver *driver,
           a->subtitle = xstrdup (text);
           break;
 
+        case TEXT_ITEM_COMMAND_OPEN:
         case TEXT_ITEM_COMMAND_CLOSE:
           break;
 
@@ -568,18 +585,12 @@ static const struct output_driver_class ascii_driver_class =
     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 char *ascii_reserve (struct ascii_driver *, int y, int x0, int x1,
+                            int n);
 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 clip[TABLE_N_AXES][2],
                                int *width, int *height);
 
 static void
@@ -587,24 +598,31 @@ ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2],
                  enum render_line_style styles[TABLE_N_AXES][2])
 {
   struct ascii_driver *a = a_;
-  unsigned short int value;
-  int x1, y1;
+  char mbchar[6];
+  int x0, x1, y1;
+  ucs4_t uc;
+  int mblen;
   int x, y;
 
   /* Clip to the page. */
   if (bb[H][0] >= a->width || bb[V][0] + a->y >= a->length)
     return;
+  x0 = bb[H][0];
   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]);
+  uc = a->box[make_box_index (styles[V][0], styles[V][1],
+                              styles[H][0], styles[H][1])];
+  mblen = u8_uctomb (CHAR_CAST (uint8_t *, mbchar), uc, 6);
   for (y = bb[V][0] + a->y; y < y1; y++)
     {
-      ascii_expand_line (a, y, x1);
-      for (x = bb[H][0]; x < x1; x++)
-        a->lines[y].chars[x] = value;
+      char *p = ascii_reserve (a, y, x0, x1, mblen * (x1 - x0));
+      for (x = x0; x < x1; x++)
+        {
+          memcpy (p, mbchar, mblen);
+          p += mblen;
+        }
     }
 }
 
@@ -622,12 +640,12 @@ ascii_measure_cell_width (void *a_, const struct table_cell *cell,
   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);
+  ascii_layout_cell (a, cell, bb, clip, max_width, &h);
 
   if (strchr (cell->contents, ' '))
     {
       bb[H][1] = 1;
-      ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, min_width, &h);
+      ascii_layout_cell (a, cell, bb, clip, min_width, &h);
     }
   else
     *min_width = *max_width;
@@ -646,7 +664,7 @@ ascii_measure_cell_height (void *a_, const struct table_cell *cell, int 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);
+  ascii_layout_cell (a, cell, bb, clip, &w, &h);
   return h;
 }
 
@@ -657,34 +675,143 @@ ascii_draw_cell (void *a_, const struct table_cell *cell,
   struct ascii_driver *a = a_;
   int w, h;
 
-  ascii_layout_cell (a, cell, bb, clip, WRAP_WORD, &w, &h);
+  ascii_layout_cell (a, cell, bb, clip, &w, &h);
 }
 
-/* Ensures that at least the first LENGTH characters of line Y in
-   ascii driver A have been cleared out. */
+static int
+u8_mb_to_display (int *wp, const uint8_t *s, size_t n)
+{
+  size_t ofs;
+  ucs4_t uc;
+  int w;
+
+  ofs = u8_mbtouc (&uc, s, n);
+  if (ofs < n && s[ofs] == '\b')
+    {
+      ofs++;
+      ofs += u8_mbtouc (&uc, s + ofs, n - ofs);
+    }
+
+  w = uc_width (uc, "UTF-8");
+  if (w <= 0)
+    {
+      *wp = 0;
+      return ofs;
+    }
+
+  while (ofs < n)
+    {
+      int mblen = u8_mbtouc (&uc, s + ofs, n - ofs);
+      if (uc_width (uc, "UTF-8") > 0)
+        break;
+      ofs += mblen;
+    }
+
+  *wp = w;
+  return ofs;
+}
+
+struct ascii_pos
+  {
+    int x0;
+    int x1;
+    size_t ofs0;
+    size_t ofs1;
+  };
+
 static void
-ascii_expand_line (struct ascii_driver *a, int y, int length)
+find_ascii_pos (struct ascii_line *line, int target_x, struct ascii_pos *c)
+{
+  const uint8_t *s = CHAR_CAST (const uint8_t *, ds_cstr (&line->s));
+  size_t length = ds_length (&line->s);
+  size_t ofs;
+  int mblen;
+  int x;
+
+  x = 0;
+  for (ofs = 0; ; ofs += mblen)
+    {
+      int w;
+
+      mblen = u8_mb_to_display (&w, s + ofs, length - ofs);
+      if (x + w > target_x)
+        {
+          c->x0 = x;
+          c->x1 = x + w;
+          c->ofs0 = ofs;
+          c->ofs1 = ofs + mblen;
+          return;
+        }
+      x += w;
+    }
+}
+
+static char *
+ascii_reserve (struct ascii_driver *a, int y, int x0, int x1, int n)
 {
   struct ascii_line *line = &a->lines[y];
-  if (line->n_chars < length)
+
+  if (x0 >= line->width)
+    {
+      /* The common case: adding new characters at the end of a line. */
+      ds_put_byte_multiple (&line->s, ' ', x0 - line->width);
+      line->width = x1;
+      return ds_put_uninit (&line->s, n);
+    }
+  else if (x0 == x1)
+    return NULL;
+  else
     {
-      int x;
-      if (line->allocated_chars < length)
+      /* An unusual case: overwriting characters in the middle of a line.  We
+         don't keep any kind of mapping from bytes to display positions, so we
+         have to iterate over the whole line starting from the beginning. */
+      struct ascii_pos p0, p1;
+      char *s;
+
+      /* Find the positions of the first and last character.  We must find the
+         both characters' positions before changing the line, because that
+         would prevent finding the other character's position. */
+      find_ascii_pos (line, x0, &p0);
+      if (x1 < line->width)
+        find_ascii_pos (line, x1, &p1);
+
+      /* If a double-width character occupies both x0 - 1 and x0, then replace
+         its first character width by '?'. */
+      s = ds_data (&line->s);
+      while (p0.x0 < x0)
+        {
+          s[p0.ofs0++] = '?';
+          p0.x0++;
+        }
+
+      if (x1 >= line->width)
         {
-          line->allocated_chars = MAX (length, MIN (length * 2, a->width));
-          line->chars = xnrealloc (line->chars, line->allocated_chars,
-                                   sizeof *line->chars);
+          ds_truncate (&line->s, p0.ofs0);
+          line->width = x1;
+          return ds_put_uninit (&line->s, n);
         }
-      for (x = line->n_chars; x < length; x++)
-        line->chars[x] = ' ';
-      line->n_chars = length;
+
+      /* If a double-width character occupies both x1 - 1 and x1, then we need
+         to replace its second character width by '?'. */
+      if (p1.x0 < x1)
+        {
+          do
+            {
+              s[--p1.ofs1] = '?';
+              p1.x0++;
+            }
+          while (p1.x0 < x1);
+          return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs1 - p0.ofs0, n);
+        }
+
+      return ds_splice_uninit (&line->s, p0.ofs0, p1.ofs0 - p0.ofs0, n);
     }
 }
 
 static void
-text_draw (struct ascii_driver *a, const struct table_cell *cell,
+text_draw (struct ascii_driver *a, unsigned int options,
            int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
-           int y, const char *string, int n)
+           int y, const uint8_t *string, int n, size_t width)
 {
   int x0 = MAX (0, clip[H][0]);
   int y0 = MAX (0, clip[V][0] + a->y);
@@ -696,96 +823,253 @@ text_draw (struct ascii_driver *a, const struct table_cell *cell,
   if (y < y0 || y >= y1)
     return;
 
-  switch (cell->options & TAB_ALIGNMENT)
+  switch (options & TAB_ALIGNMENT)
     {
     case TAB_LEFT:
       x = bb[H][0];
       break;
     case TAB_CENTER:
-      x = (bb[H][0] + bb[H][1] - n + 1) / 2;
+      x = (bb[H][0] + bb[H][1] - width + 1) / 2;
       break;
     case TAB_RIGHT:
-      x = bb[H][1] - n;
+      x = bb[H][1] - width;
       break;
     default:
       NOT_REACHED ();
     }
+  if (x >= x1)
+    return;
+
+  while (x < x0)
+    {
+      ucs4_t uc;
+      int mblen;
+      int w;
+
+      if (n == 0)
+        return;
+      mblen = u8_mbtouc (&uc, string, n);
+
+      string += mblen;
+      n -= mblen;
+
+      w = uc_width (uc, "UTF-8");
+      if (w > 0)
+        {
+          x += w;
+          width -= w;
+        }
+    }
+  if (n == 0)
+    return;
 
-  if (x0 > x)
+  if (x + width > x1)
     {
-      n -= x0 - x;
-      if (n <= 0)
+      int ofs;
+
+      ofs = width = 0;
+      for (ofs = 0; ofs < n; )
+        {
+          ucs4_t uc;
+          int mblen;
+          int w;
+
+          mblen = u8_mbtouc (&uc, string + ofs, n - ofs);
+
+          w = uc_width (uc, "UTF-8");
+          if (w > 0)
+            {
+              if (width + w > x1 - x)
+                break;
+              width += w;
+            }
+          ofs += mblen;
+        }
+      n = ofs;
+      if (n == 0)
         return;
-      string += x0 - x;
-      x = x0;
     }
-  if (x + n >= x1)
-    n = x1 - x;
 
-  if (n > 0)
+  if (!(options & TAB_EMPH) || a->emphasis == EMPH_NONE)
+    memcpy (ascii_reserve (a, y, x, x + width, n), string, n);
+  else
     {
-      int attr = cell->options & TAB_EMPH ? ATTR_EMPHASIS : 0;
-      size_t i;
+      size_t n_out;
+      size_t ofs;
+      char *out;
+      int mblen;
+
+      /* First figure out how many bytes need to be inserted. */
+      n_out = n;
+      for (ofs = 0; ofs < n; ofs += mblen)
+        {
+          ucs4_t uc;
+          int w;
+
+          mblen = u8_mbtouc (&uc, string + ofs, n - ofs);
+          w = uc_width (uc, "UTF-8");
 
-      ascii_expand_line (a, y, x + n);
-      for (i = 0; i < n; i++)
-        a->lines[y].chars[x + i] = string[i] | attr;
+          if (w > 0)
+            n_out += a->emphasis == EMPH_UNDERLINE ? 2 : 1 + mblen;
+        }
+
+      /* Then insert them. */
+      out = ascii_reserve (a, y, x, x + width, n_out);
+      for (ofs = 0; ofs < n; ofs += mblen)
+        {
+          ucs4_t uc;
+          int w;
+
+          mblen = u8_mbtouc (&uc, string + ofs, n - ofs);
+          w = uc_width (uc, "UTF-8");
+
+          if (w > 0)
+            {
+              if (a->emphasis == EMPH_UNDERLINE)
+                *out++ = '_';
+              else
+                out = mempcpy (out, string + ofs, mblen);
+              *out++ = '\b';
+            }
+          out = mempcpy (out, string + ofs, mblen);
+        }
     }
 }
 
 static void
 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 *widthp, int *heightp)
 {
-  size_t length = strlen (cell->contents);
-  int y, pos;
+  const char *text = cell->contents;
+  size_t length = strlen (text);
+  char *breaks;
+  int bb_width;
+  size_t pos;
+  int y;
+
+  *widthp = 0;
+  *heightp = 0;
+  if (length == 0)
+    return;
+
+  text = cell->contents;
+  breaks = xmalloc (length + 1);
+  u8_possible_linebreaks (CHAR_CAST (const uint8_t *, text), length,
+                          "UTF-8", breaks);
+  breaks[length] = (breaks[length - 1] == UC_BREAK_MANDATORY
+                    ? UC_BREAK_PROHIBITED : UC_BREAK_POSSIBLE);
 
-  *width = 0;
   pos = 0;
+  bb_width = bb[H][1] - bb[H][0];
   for (y = bb[V][0]; y < bb[V][1] && pos < length; y++)
     {
-      const char *line = &cell->contents[pos];
-      const char *new_line;
-      size_t line_len;
-
-      /* 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;
-
-      /* Word wrap. */
-      if (pos + line_len < length && wrap != WRAP_CHAR)
+      const uint8_t *line = CHAR_CAST (const uint8_t *, text + pos);
+      const char *b = breaks + pos;
+      size_t n = length - pos;
+
+      size_t last_break_ofs = 0;
+      int last_break_width = 0;
+      int width = 0;
+      size_t ofs;
+
+      for (ofs = 0; ofs < n; )
         {
-          size_t space_len = line_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)
+          ucs4_t uc;
+          int mblen;
+          int w;
+
+          mblen = u8_mbtouc (&uc, line + ofs, n - ofs);
+          if (b[ofs] == UC_BREAK_MANDATORY)
+            break;
+          else if (b[ofs] == UC_BREAK_POSSIBLE)
             {
-              while (pos + line_len < length
-                     && !isspace ((unsigned char) line[line_len]))
-                line_len++;
+              last_break_ofs = ofs;
+              last_break_width = width;
             }
+
+          w = uc_width (uc, "UTF-8");
+          if (w > 0)
+            {
+              if (width + w > bb_width)
+                {
+                  if (isspace (line[ofs]))
+                    break;
+                  else if (last_break_ofs != 0)
+                    {
+                      ofs = last_break_ofs;
+                      width = last_break_width;
+                      break;
+                    }
+                }
+              width += w;
+            }
+          ofs += mblen;
         }
-      if (line_len > *width)
-        *width = line_len;
+      if (b[ofs] != UC_BREAK_MANDATORY)
+        {
+          while (ofs > 0 && isspace (line[ofs - 1]))
+            {
+              ofs--;
+              width--;
+            }
+        }
+      if (width > *widthp)
+        *widthp = width;
 
       /* Draw text. */
-      text_draw (a, cell, bb, clip, y, line, line_len);
+      text_draw (a, cell->options, bb, clip, y, line, ofs, width);
 
       /* Next line. */
-      pos += line_len;
-      if (pos < length && isspace ((unsigned char) cell->contents[pos]))
+      pos += ofs;
+      if (ofs < n && isspace (line[ofs]))
         pos++;
+
     }
-  *height = y - bb[V][0];
+  *heightp = y - bb[V][0];
+
+  free (breaks);
+}
+
+void
+ascii_test_write (struct output_driver *driver,
+                  const char *s, int x, int y, unsigned int options)
+{
+  struct ascii_driver *a = ascii_driver_cast (driver);
+  struct table_cell cell;
+  int bb[TABLE_N_AXES][2];
+  int width, height;
+
+  if (a->file == NULL && !ascii_open_page (a))
+    return;
+  a->y = 0;
+
+  memset (&cell, 0, sizeof cell);
+  cell.contents = s;
+  cell.options = options | TAB_LEFT;
+
+  bb[TABLE_HORZ][0] = x;
+  bb[TABLE_HORZ][1] = a->width;
+  bb[TABLE_VERT][0] = y;
+  bb[TABLE_VERT][1] = a->length;
+
+  ascii_layout_cell (a, &cell, bb, bb, &width, &height);
+
+  a->y = 1;
 }
 \f
 /* ascii_close_page () and support routines. */
 
+#if HAVE_DECL_SIGWINCH
+static struct ascii_driver *the_driver;
+
+static void
+winch_handler (int signum UNUSED)
+{
+  update_page_size (the_driver, false);
+}
+#endif
+
 static bool
 ascii_open_page (struct ascii_driver *a)
 {
@@ -799,8 +1083,19 @@ ascii_open_page (struct ascii_driver *a)
       a->file = fn_open (a->file_name, a->append ? "a" : "w");
       if (a->file != NULL)
         {
-          if (a->init != NULL)
-            fputs (a->init, a->file);
+#if HAVE_DECL_SIGWINCH
+         if ( isatty (fileno (a->file)))
+           {
+             struct sigaction action;
+             sigemptyset (&action.sa_mask);
+             action.sa_flags = 0;
+             action.sa_handler = winch_handler;
+             the_driver = a;
+             a->auto_width = true;
+             a->auto_length = true;
+             sigaction (SIGWINCH, &action, NULL);
+           }
+#endif
         }
       else
         {
@@ -819,63 +1114,27 @@ ascii_open_page (struct ascii_driver *a)
       for (i = a->allocated_lines; i < a->length; i++)
         {
           struct ascii_line *line = &a->lines[i];
-          line->chars = NULL;
-          line->allocated_chars = 0;
+          ds_init_empty (&line->s);
+          line->width = 0;
         }
       a->allocated_lines = a->length;
     }
 
   for (i = 0; i < a->length; i++)
-    a->lines[i].n_chars = 0;
-
-  return true;
-}
-
-/* Writes LINE to A's output file.  */
-static void
-output_line (struct ascii_driver *a, const struct ascii_line *line)
-{
-  size_t length;
-  size_t i;
-
-  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;
-        }
+      struct ascii_line *line = &a->lines[i];
+      ds_clear (&line->s);
+      line->width = 0;
     }
 
-  putc ('\n', a->file);
+  return true;
 }
 
 static void
 output_title_line (FILE *out, int width, const char *left, const char *right)
 {
   struct string s = DS_EMPTY_INITIALIZER;
-  ds_put_char_multiple (&s, ' ', width);
+  ds_put_byte_multiple (&s, ' ', width);
   if (left != NULL)
     {
       size_t length = MIN (strlen (left), width);
@@ -886,7 +1145,7 @@ output_title_line (FILE *out, int width, const char *left, const char *right)
       size_t length = MIN (strlen (right), width);
       memcpy (ds_end (&s) - length, right, length);
     }
-  ds_put_char (&s, '\n');
+  ds_put_byte (&s, '\n');
   fputs (ds_cstr (&s), out);
   ds_destroy (&s);
 }
@@ -927,7 +1186,7 @@ ascii_close_page (struct ascii_driver *a)
     {
       struct ascii_line *line = &a->lines[y];
 
-      if (a->squeeze_blank_lines && y > 0 && line->n_chars == 0)
+      if (a->squeeze_blank_lines && y > 0 && line->width == 0)
         any_blank = true;
       else
         {
@@ -937,7 +1196,10 @@ ascii_close_page (struct ascii_driver *a)
               any_blank = false;
             }
 
-          output_line (a, line);
+          while (ds_chomp_byte (&line->s, ' '))
+            continue;
+          fwrite (ds_data (&line->s), 1, ds_length (&line->s), a->file);
+          putc ('\n', a->file);
         }
     }
   if (!a->squeeze_blank_lines)
diff --git a/src/output/ascii.h b/src/output/ascii.h
new file mode 100644 (file)
index 0000000..5d324d8
--- /dev/null
@@ -0,0 +1,25 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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 ASCII_H
+#define ASCII_H 1
+
+struct output_driver;
+
+void ascii_test_write (struct output_driver *,
+                       const char *s, int x, int y, unsigned int options);
+
+#endif /* ascii.h */
index e5781b0af7d3bb4e3f8fdf1ff4ccfbd61acc6f87..6f9b149e82a8d7fe4ec83b208dc9ac68d1d51df0 100644 (file)
@@ -6,6 +6,7 @@ src_output_liboutput_la_CPPFLAGS = $(LIBXML2_CFLAGS) $(AM_CPPFLAGS)
 
 src_output_liboutput_la_SOURCES = \
        src/output/ascii.c \
+       src/output/ascii.h \
        src/output/chart-item-provider.h \
        src/output/chart-item.c \
        src/output/chart-item.h \
index a776eab3fc7aed926cb2de4986a235a60017fa8d..3ec00ce9a53920c978afcb05bc2ec598f0cf304c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2010, 2011 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
@@ -35,9 +35,9 @@
 #include "output/cairo.h"
 #include "output/chart-item.h"
 
-#include "error.h"
-#include "xalloc.h"
-#include "xvasprintf.h"
+#include "gl/error.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 041a169102395546db470f5fd79a693ba8f38f8c..1a23dd179329cde657b12a98cd6c5f1ef1c8b05b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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 5a310c610c8ec2f53b6c2ccaf704fee119e8063e..f74963d682b2f6c3680f0c011ab734b43a51eb94 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -471,16 +471,21 @@ xr_init_caption_cell (const char *caption, struct table_cell *cell)
 
 static struct render_page *
 xr_render_table_item (struct xr_driver *xr, const struct table_item *item,
-                      int *caption_heightp)
+                      int *caption_widthp, int *caption_heightp)
 {
   const char *caption = table_item_get_caption (item);
 
   if (caption != NULL)
     {
       /* XXX doesn't do well with very large captions */
+      int min_width, max_width;
       struct table_cell cell;
+
       xr_init_caption_cell (caption, &cell);
-      *caption_heightp = xr_measure_cell_height (xr, &cell, xr->width);
+
+      xr_measure_cell_width (xr, &cell, &min_width, &max_width);
+      *caption_widthp = MIN (max_width, xr->width);
+      *caption_heightp = xr_measure_cell_height (xr, &cell, *caption_widthp);
     }
   else
     *caption_heightp = 0;
@@ -840,6 +845,21 @@ xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell,
         *height = h;
     }
 }
+
+static void
+xr_draw_title (struct xr_driver *xr, const char *title,
+               int title_width, int title_height)
+{
+  struct table_cell cell;
+  int bb[TABLE_N_AXES][2];
+
+  xr_init_caption_cell (title, &cell);
+  bb[H][0] = 0;
+  bb[H][1] = title_width;
+  bb[V][0] = 0;
+  bb[V][1] = title_height;
+  xr_draw_cell (xr, &cell, bb, bb);
+}
 \f
 struct output_driver_factory pdf_driver_factory = { "pdf", xr_pdf_create };
 struct output_driver_factory ps_driver_factory = { "ps", xr_ps_create };
@@ -857,13 +877,13 @@ static const struct output_driver_class cairo_driver_class =
 
 struct xr_rendering
   {
+    struct output_item *item;
+
     /* Table items. */
     struct render_page *page;
     struct xr_driver *xr;
+    int title_width;
     int title_height;
-
-    /* Chart items. */
-    struct chart_item *chart;
   };
 
 #define CHART_WIDTH 500
@@ -899,7 +919,7 @@ 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);
+  table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
   r = xr_rendering_create (xr, &table_item->output_item, cr);
   table_item_unref (table_item);
 
@@ -926,15 +946,16 @@ xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
   else if (is_table_item (item))
     {
       r = xzalloc (sizeof *r);
+      r->item = output_item_ref (item);
       r->xr = xr;
       xr_set_cairo (xr, cr);
       r->page = xr_render_table_item (xr, to_table_item (item),
-                                      &r->title_height);
+                                      &r->title_width, &r->title_height);
     }
   else if (is_chart_item (item))
     {
       r = xzalloc (sizeof *r);
-      r->chart = to_chart_item (output_item_ref (item));
+      r->item = output_item_ref (item);
     }
 
   return r;
@@ -943,9 +964,11 @@ xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
 void
 xr_rendering_measure (struct xr_rendering *r, int *w, int *h)
 {
-  if (r->chart == NULL)
+  if (is_table_item (r->item))
     {
-      *w = render_page_get_size (r->page, H) / 1024;
+      int w0 = render_page_get_size (r->page, H);
+      int w1 = r->title_width;
+      *w = MAX (w0, w1) / 1024;
       *h = (render_page_get_size (r->page, V) + r->title_height) / 1024;
     }
   else
@@ -961,17 +984,26 @@ void
 xr_rendering_draw (struct xr_rendering *r, cairo_t *cr,
                    int x, int y, int w, int h)
 {
-  if (r->chart == NULL)
+  if (is_table_item (r->item))
     {
       struct xr_driver *xr = r->xr;
 
       xr_set_cairo (xr, cr);
-      xr->y = 0;
-      render_page_draw_region (r->page,
-                               x * 1024, y * 1024, w * 1024, h * 1024);
+
+      if (r->title_height > 0)
+        {
+          xr->y = 0;
+          xr_draw_title (xr, table_item_get_caption (to_table_item (r->item)),
+                         r->title_width, r->title_height);
+        }
+
+      xr->y = r->title_height;
+      render_page_draw_region (r->page, x * 1024, (y * 1024) - r->title_height,
+                               w * 1024, h * 1024);
     }
   else
-    xr_draw_chart (r->chart, cr, 0, 0, CHART_WIDTH, CHART_HEIGHT);
+    xr_draw_chart (to_chart_item (r->item), cr,
+                   0, 0, CHART_WIDTH, CHART_HEIGHT);
 }
 
 void
@@ -1089,18 +1121,9 @@ xr_table_render (struct xr_render_fsm *fsm, struct xr_driver *xr)
       if (ts->caption_height)
         {
           if (xr->cairo)
-            {
-              struct table_cell cell;
-              int bb[TABLE_N_AXES][2];
-
-              xr_init_caption_cell (table_item_get_caption (ts->table_item),
-                                    &cell);
-              bb[H][0] = 0;
-              bb[H][1] = xr->width;
-              bb[V][0] = 0;
-              bb[V][1] = ts->caption_height;
-              xr_draw_cell (xr, &cell, bb, bb);
-            }
+            xr_draw_title (xr, table_item_get_caption (ts->table_item),
+                           xr->width, ts->caption_height);
+
           xr->y += ts->caption_height;
           ts->caption_height = 0;
         }
@@ -1128,6 +1151,7 @@ xr_render_table (struct xr_driver *xr, const struct table_item *table_item)
 {
   struct xr_table_state *ts;
   struct render_page *page;
+  int caption_width;
 
   ts = xmalloc (sizeof *ts);
   ts->fsm.render = xr_table_render;
@@ -1137,7 +1161,8 @@ xr_render_table (struct xr_driver *xr, const struct table_item *table_item)
   if (xr->y > 0)
     xr->y += xr->char_height;
 
-  page = xr_render_table_item (xr, table_item, &ts->caption_height);
+  page = xr_render_table_item (xr, table_item,
+                               &caption_width, &ts->caption_height);
   xr->params->size[V] = xr->length - ts->caption_height;
 
   render_break_init (&ts->x_break, page, H);
index 4f13fcfeb6d6aa973885053ce12b5f96a8235e54..dd2fa9f12e838e854361001f80248d593be433b4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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,8 +17,8 @@
 #ifndef OUTPUT_CHART_ITEM_PROVIDER_H
 #define OUTPUT_CHART_ITEM_PROVIDER_H 1
 
-#include <output/chart-item.h>
-#include <output/output-item.h>
+#include "output/chart-item.h"
+#include "output/output-item.h"
 
 struct chart_item_class
   {
index 227994dd219060676f218ae0ee57e565adc379d1..e70099d22ac7624195be01a980aff67b5ca1a554 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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/chart-item.h>
-#include <output/chart-item-provider.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 "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "output/driver.h"
+#include "output/output-item-provider.h"
 
 #include "gl/xalloc.h"
 
index c005a46c8fc97387d1c0b4d2608d2e3770bcf390..ac25eb0a770ea4293868fa4c04c9ff74825ceeb5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -25,7 +25,7 @@
    chart_item. */
 
 #include <stdbool.h>
-#include <output/output-item.h>
+#include "output/output-item.h"
 
 /* A chart item.
 
@@ -45,7 +45,7 @@ void chart_item_set_title (struct chart_item *, const char *);
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct output_item_class chart_item_class;
 
index ddecbfccceb2564c347738b5f53f7f864d285d90..1660e86b2db1455d9a4a01bb22b4ace7ec568463 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/cairo-chart.h>
+#include "output/cairo-chart.h"
 
 #include <math.h>
 
-#include <output/charts/boxplot.h>
-#include <math/box-whisker.h>
-#include <math/chart-geometry.h>
+#include "math/box-whisker.h"
+#include "math/chart-geometry.h"
+#include "output/charts/boxplot.h"
 
 /* Draw an OUTLIER on the plot CH
  * at CENTRELINE
index 7e9248004b3c2b2662f684241e55ab06b865b0c4..deabc1fa6e8f059c026c5c079b6e4a60f43b0b5a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009, 2011 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/charts/boxplot.h>
+#include "output/charts/boxplot.h"
 
-#include <math/box-whisker.h>
-#include <output/chart-item-provider.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)
index bd5a7a32379b3b029babb89718b53908851f13eb..e18daa844cd61ed0bfb13b52d7606880c53edca5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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
@@ -18,7 +18,7 @@
 #define OUTPUT_CHARTS_BOXPLOT_H 1
 
 #include <stddef.h>
-#include <output/chart-item.h>
+#include "output/chart-item.h"
 
 /* Box-whiskers plot. */
 struct boxplot
@@ -49,7 +49,7 @@ void boxplot_add_box (struct boxplot *,
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class boxplot_class;
 
index 8c96b73fadaf517c93a388e8c26f087bf4a7b0ab..334284ba8f857c20db90cb1ff561051a9ec9793d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/np-plot.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 "data/case.h"
+#include "data/casereader.h"
+#include "math/np.h"
+#include "output/cairo-chart.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index dfc74603003f342dacc7141ee347d472aa8a127b..ccccbeff36ae192b844a3f95b25aa6ca9c4b6534 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009, 2011 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/charts/np-plot.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 "data/casereader.h"
+#include "libpspp/cast.h"
+#include "math/np.h"
+#include "output/chart-item-provider.h"
 
 #include "gl/minmax.h"
 
index 82c81ed8f35c923fcb54df5342b5bf3f4e44d3b1..15c1cb9f71b39c9d96fb7c899e4ec77733d38f3c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2008, 2009, 2011 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,7 +17,7 @@
 #ifndef OUTPUT_CHARTS_NP_PLOT_H
 #define OUTPUT_CHARTS_NP_PLOT_H 1
 
-#include <output/chart-item.h>
+#include "output/chart-item.h"
 
 struct np;
 
@@ -50,7 +50,7 @@ struct chart_item *dnp_plot_create (const struct np *,
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class np_plot_chart_class;
 
index 3917e4e14b4833b04c6519a724ce5fe728095410..9e55c56f46a0b8d83ef4b0cf2b9ad4489f1c8fec 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/piechart.h>
+#include "output/charts/piechart.h"
 
 #include <math.h>
 
-#include <output/cairo-chart.h>
+#include "output/cairo-chart.h"
 
 #include "gl/minmax.h"
 
index 0b9153d545b76d26340532a22b9e218bb29f15c6..aac8bfbf8d03429517987e4c52e4d03f7f4d85cf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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/charts/piechart.h>
+#include "output/charts/piechart.h"
 
 #include <stdlib.h>
 
-#include <libpspp/cast.h>
-#include <libpspp/str.h>
-#include <output/chart-item-provider.h>
+#include "libpspp/cast.h"
+#include "libpspp/str.h"
+#include "output/chart-item-provider.h"
 
 #include "gl/xalloc.h"
 
index 312a45ee08ce759f84e9c02e2991ca9acd3163f0..b59a7296d14e792031a595a1c024808c25a13451 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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,8 +17,8 @@
 #ifndef PIECHART_H
 #define PIECHART_H
 
-#include <libpspp/str.h>
-#include <output/chart-item.h>
+#include "libpspp/str.h"
+#include "output/chart-item.h"
 
 struct piechart
   {
@@ -40,7 +40,7 @@ struct chart_item *piechart_create (const char *title,
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class piechart_class;
 
index a70fa174fa7b72511856e67b359a18c12ece6d99..d000a1ac21e26f2961e80b6ced90c94932ee94ff 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/plot-hist.h>
+#include "output/charts/plot-hist.h"
 
 #include <gsl/gsl_randist.h>
 
-#include <data/val-type.h>
-#include <output/cairo-chart.h>
+#include "data/val-type.h"
+#include "output/cairo-chart.h"
 
 #include "gl/xvasprintf.h"
 
index 5925df6d1a35af5d0122f75312b497bc01e68eb8..5abbbb6c8c4a32ac695bb4f50478af79b538b0a7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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 <gsl/gsl_randist.h>
 #include <assert.h>
 
-#include <output/charts/plot-hist.h>
-#include <output/chart-item-provider.h>
-
-#include <libpspp/cast.h>
-#include <math/histogram.h>
-#include <math/moments.h>
+#include "libpspp/cast.h"
+#include "math/histogram.h"
+#include "math/moments.h"
+#include "output/chart-item-provider.h"
+#include "output/charts/plot-hist.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 237b8b3c11ef7d2ac612675ef879b456a96cf714..bf3674b00e53b986848b1d5bc12f2138513549bc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2009, 2011 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
@@ -46,7 +46,7 @@ struct chart_item *histogram_chart_create (const gsl_histogram *,
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class histogram_chart_class;
 
index b5c22aca5329a8e3a1af7c0449f2d8a323c1a92c..f6da35066705a18fb4af56bd8dc0d2704755a684 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/roc-chart.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 "data/case.h"
+#include "data/casereader.h"
+#include "language/stats/roc.h"
+#include "output/cairo-chart.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index 5af8f27ff35ee93eeb8ede9086ce738e71d24944..0285d6f6a107e8a599e9be7e93e3adf580389548 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/roc-chart.h>
+#include "output/charts/roc-chart.h"
 
-#include <output/chart-item-provider.h>
-#include <data/casereader.h>
-#include <language/stats/roc.h>
+#include "data/casereader.h"
+#include "language/stats/roc.h"
+#include "output/chart-item-provider.h"
 
-#include "xalloc.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index a995f9302d4f3f4d3d39feefb2045a01ba62a3fe..309ac38e987a432c67454b0e6c2996b9cd725a54 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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,7 +19,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <output/chart-item.h>
+#include "output/chart-item.h"
 
 struct roc_chart
   {
@@ -44,7 +44,7 @@ void roc_chart_add_var (struct roc_chart *, const char *var_name,
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class roc_chart_class;
 
index d48a3642a805c3190feffad8fbcaf84c8c31b71c..f9765c69f242d70f336628db354f19c406333393 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/charts/scree.h>
+#include "output/charts/scree.h"
 
 #include <math.h>
 
-#include <output/cairo-chart.h>
+#include "output/cairo-chart.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
index ffa77568bd975a4c537beef1541d4169cb0cb701..4de1f5e6fc664ecf888d9c47daa7f532542a5265 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -16,9 +16,9 @@
 
 #include <config.h>
 
-#include <output/charts/scree.h>
+#include "output/charts/scree.h"
 
-#include <output/chart-item-provider.h>
+#include "output/chart-item-provider.h"
 
 #include "gl/xalloc.h"
 
index 43f5b822482c066bbf7b7364ce301f4fdd3e02a2..5691451d7cdbf250285e0f5b6f0d39d4916afd92 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -18,7 +18,7 @@
 #define OUTPUT_CHARTS_SCREE_H 1
 
 #include <gsl/gsl_vector.h>
-#include <output/chart-item.h>
+#include "output/chart-item.h"
 
 /* A scree plot. */
 struct scree
@@ -38,7 +38,7 @@ struct chart *scree_get_chart (struct scree *scree);
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct chart_item_class scree_class;
 
index c648bfa79c30ae0e9330f3f7bae60290e1d96210..c8619a9a7d403ebc84ebc55d9c307976a49b734b 100644 (file)
@@ -43,7 +43,11 @@ struct csv_driver
   {
     struct output_driver driver;
 
-    char *separator;            /* Comma or tab. */
+    char *separator;            /* Field separator (usually comma or tab). */
+    int quote;                  /* Quote character (usually ' or ") or 0. */
+    char *quote_set;            /* Characters that force quoting. */
+    bool captions;              /* Print table captions? */
+
     char *file_name;            /* Output file name. */
     char *command_name;         /* Current command. */
     FILE *file;                 /* Output file. */
@@ -72,12 +76,18 @@ csv_create (const char *file_name, enum settings_output_devices device_type,
 {
   struct output_driver *d;
   struct csv_driver *csv;
+  char *quote;
 
   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", ","));
+  quote = parse_string (opt (d, o, "quote", "\""));
+  csv->quote = quote[0];
+  free (quote);
+  csv->quote_set = xasprintf ("\n\r\t%s%c", csv->separator, csv->quote);
+  csv->captions = parse_boolean (opt (d, o, "captions", "true"));
   csv->file_name = xstrdup (file_name);
   csv->file = fn_open (csv->file_name, "w");
   csv->n_items = 0;
@@ -101,6 +111,7 @@ csv_destroy (struct output_driver *driver)
     fn_close (csv->file_name, csv->file);
 
   free (csv->separator);
+  free (csv->quote_set);
   free (csv->file_name);
   free (csv);
 }
@@ -114,34 +125,34 @@ csv_flush (struct output_driver *driver)
 }
 
 static void
-csv_output_field (FILE *file, const char *field)
+csv_output_field (struct csv_driver *csv, const char *field)
 {
   while (*field == ' ')
     field++;
 
-  if (field[strcspn (field, "\"\n\r,\t")])
+  if (csv->quote && field[strcspn (field, csv->quote_set)])
     {
       const char *p;
 
-      putc ('"', file);
+      putc (csv->quote, csv->file);
       for (p = field; *p != '\0'; p++)
         {
-          if (*p == '"')
-            putc ('"', file);
-          putc (*p, file);
+          if (*p == csv->quote)
+            putc (csv->quote, csv->file);
+          putc (*p, csv->file);
         }
-      putc ('"', file);
+      putc (csv->quote, csv->file);
     }
   else
-    fputs (field, file);
+    fputs (field, csv->file);
 }
 
 static void
-csv_output_field_format (FILE *file, const char *format, ...)
+csv_output_field_format (struct csv_driver *csv, const char *format, ...)
   PRINTF_FORMAT (2, 3);
 
 static void
-csv_output_field_format (FILE *file, const char *format, ...)
+csv_output_field_format (struct csv_driver *csv, const char *format, ...)
 {
   va_list args;
   char *s;
@@ -150,7 +161,7 @@ csv_output_field_format (FILE *file, const char *format, ...)
   s = xvasprintf (format, args);
   va_end (args);
 
-  csv_output_field (file, s);
+  csv_output_field (csv, s);
   free (s);
 }
 
@@ -178,9 +189,9 @@ csv_submit (struct output_driver *driver,
 
       csv_put_separator (csv);
 
-      if (caption != NULL)
+      if (csv->captions && caption != NULL)
         {
-          csv_output_field_format (csv->file, "Table: %s", caption);
+          csv_output_field_format (csv, "Table: %s", caption);
           putc ('\n', csv->file);
         }
 
@@ -196,9 +207,9 @@ csv_submit (struct output_driver *driver,
                 fputs (csv->separator, csv->file);
 
               if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
-                csv_output_field (csv->file, "");
+                csv_output_field (csv, "");
               else
-                csv_output_field (csv->file, cell.contents);
+                csv_output_field (csv, cell.contents);
 
               table_cell_free (&cell);
             }
@@ -219,15 +230,15 @@ csv_submit (struct output_driver *driver,
       switch (type)
         {
         case TEXT_ITEM_TITLE:
-          csv_output_field_format (csv->file, "Title: %s", text);
+          csv_output_field_format (csv, "Title: %s", text);
           break;
 
         case TEXT_ITEM_SUBTITLE:
-          csv_output_field_format (csv->file, "Subtitle: %s", text);
+          csv_output_field_format (csv, "Subtitle: %s", text);
           break;
 
         default:
-          csv_output_field (csv->file, text);
+          csv_output_field (csv, text);
           break;
         }
       putc ('\n', csv->file);
@@ -238,7 +249,7 @@ csv_submit (struct output_driver *driver,
       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);
+      csv_output_field (csv, s);
       free (s);
       putc ('\n', csv->file);
     }
index 136b4c4f2705cc0a6fbb67f8a9c1281e14d3f2cc..c0a525edae2f4963c3b34067c8c8f474b5b1a017 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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,8 +50,8 @@ 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;
+/* TEXT_ITEM_SYNTAX being accumulated until another kind of output arrives. */
+static struct string deferred_syntax = DS_EMPTY_INITIALIZER;
 
 void
 output_close (void)
@@ -108,47 +108,34 @@ output_submit__ (struct output_item *item)
 static void
 flush_deferred_syntax (void)
 {
-  if (deferred_syntax != NULL)
+  if (!ds_is_empty (&deferred_syntax))
     {
-      output_submit__ (deferred_syntax);
-      deferred_syntax = NULL;
+      char *syntax = ds_steal_cstr (&deferred_syntax);
+      output_submit__ (text_item_super (
+                         text_item_create_nocopy (TEXT_ITEM_SYNTAX, syntax)));
     }
 }
 
+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);
+}
+
 /* 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))
+  if (is_syntax_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;
-        }
+      ds_put_cstr (&deferred_syntax, text_item_get_text (to_text_item (item)));
+      output_item_unref (item);
+      return;
     }
 
+  flush_deferred_syntax ();
   output_submit__ (item);
 }
 
@@ -159,6 +146,7 @@ output_flush (void)
 {
   struct llx *llx;
 
+  flush_deferred_syntax ();
   for (llx = llx_head (&drivers); llx != llx_null (&drivers);
        llx = llx_next (llx))
     {
index 5aec959c740a16a69888d9f5da76ad2d56778528..45c9a1ef730762df544128f488f227568d082517 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009, 2010, 2011 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
@@ -55,8 +55,6 @@ struct html_driver
     char *command_name;
     FILE *file;
     size_t chart_cnt;
-
-    bool in_syntax;
   };
 
 static const struct output_driver_class html_driver_class;
@@ -200,11 +198,6 @@ html_destroy (struct output_driver *driver)
 
   if (html->file != NULL)
     {
-      if (html->in_syntax)
-        {
-          fprintf (html->file, "</PRE>\n");
-          html->in_syntax = false;
-        }
       fprintf (html->file,
                "</BODY>\n"
                "</HTML>\n"
@@ -217,13 +210,6 @@ html_destroy (struct output_driver *driver)
   free (html);
 }
 
-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);
-}
-
 static void
 html_submit (struct output_driver *driver,
              const struct output_item *output_item)
@@ -232,12 +218,6 @@ html_submit (struct output_driver *driver,
 
   output_driver_track_current_command (output_item, &html->command_name);
 
-  if (html->in_syntax && !is_syntax_item (output_item))
-    {
-      fprintf (html->file, "</PRE>\n");
-      html->in_syntax = false;
-    }
-
   if (is_table_item (output_item))
     {
       struct table_item *table_item = to_table_item (output_item);
@@ -291,14 +271,9 @@ html_submit (struct output_driver *driver,
           break;
 
         case TEXT_ITEM_SYNTAX:
-          if (!html->in_syntax)
-            {
-              fprintf (html->file, "<PRE class=\"syntax\">");
-              html->in_syntax = true;
-            }
-          else
-            putc ('\n', html->file);
+          fprintf (html->file, "<PRE class=\"syntax\">");
           escape_string (html->file, s, strlen (s), " ");
+          fprintf (html->file, "</PRE>\n");
           break;
 
         case TEXT_ITEM_PARAGRAPH:
index 8de7ed1d486bf9ca62a4d399c2b12f4fcb6d8281..14cd5dab9fdb56de6e263a4b4162a94df60dc4cb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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/measure.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 "data/file-name.h"
+#include "libpspp/str.h"
 
 #include "gl/error.h"
 
index a97b2270d6f1d1cc055a244ed04c4e0f6d1952ed..88450f1adee4cc91276e649853794eaab767fe95 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Sonftware Foundation, Inc.
+   Copyright (C) 2010, 2011 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
@@ -29,7 +29,7 @@
    the message gets routed properly for the PSPP user interface in use. */
 
 #include <stdbool.h>
-#include <output/output-item.h>
+#include "output/output-item.h"
 
 /* A message item. */
 struct message_item
@@ -46,7 +46,7 @@ const struct msg *message_item_get_msg (const struct message_item *);
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct output_item_class message_item_class;
 
index b2191aae3b2e1b7a8e3958ca187dfa35011e9f66..3541c150a6a3fb3ed240b91f9ce1259994e00152 100755 (executable)
@@ -10,7 +10,7 @@ while (<>) {
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct ${super}_class ${class}_class;
 
index 721e7c87d9766dec20761e7100aba0ca6b24ea5b..fdaa6f902de642efbd7a438a745e67feb21e56f2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -501,8 +501,10 @@ odt_submit (struct output_driver *driver,
     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)));
+      struct text_item *text_item = to_text_item (output_item);
+
+      if (text_item_get_type (text_item) != TEXT_ITEM_COMMAND_CLOSE)
+        odt_output_text (odt, text_item_get_text (text_item));
     }
   else if (is_message_item (output_item))
     {
index a810f97c7d2627ae60bc49631b4554c68e408ebe..1273f13419df8819c139f7fd07a60d60ff9dfd49 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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,7 +17,7 @@
 #ifndef OUTPUT_ITEM_PROVIDER_H
 #define OUTPUT_ITEM_PROVIDER_H 1
 
-#include <output/output-item.h>
+#include "output/output-item.h"
 
 /* Class structure for an output item.
 
index e1c889ffe33b09967f3bcf798198ed825363fe05..dd4e70c2ee48b8591813767374d166b8a1615b0e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/output-item-provider.h>
+#include "output/output-item-provider.h"
 
 #include <assert.h>
 #include <stdlib.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
 
-#include "xalloc.h"
+#include "gl/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
index b45e008720dee14132c1d03ee25ad49df982915a..13a5c34a74348d3361653d8b3842071b033a2097 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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,8 +31,8 @@
         - Messages (see output/message-item.h).
 */
 
-#include <libpspp/cast.h>
 #include <stdbool.h>
+#include "libpspp/cast.h"
 
 /* A single output item. */
 struct output_item
index 094e68799cf93b7e72be846075f8e04da80ec499..a4fe9e24e65eae7d82b9f7fa984cca010b2dfc0e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -359,9 +359,14 @@ distribute_spanned_width (int width,
      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.
+
+     (We actually compute the unspanned width of a column as twice the
+     unspanned width, plus the width of the rule on the left, plus the width of
+     the rule on the right.  That way each rule contributes to both the cell on
+     its left and on its right.)
   */
   d0 = n;
-  d1 = total_unspanned * 2.0;
+  d1 = 2.0 * (total_unspanned > 0 ? total_unspanned : 1.0);
   d = d0 * d1;
   if (total_unspanned > 0)
     d *= 2.0;
@@ -450,7 +455,7 @@ measure_rule (const struct render_params *params, const struct table *table,
   enum table_axis b = !a;
   unsigned int rules;
   int d[TABLE_N_AXES];
-  int width, i;
+  int width;
 
   /* 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. */
@@ -461,10 +466,11 @@ measure_rule (const struct render_params *params, const struct table *table,
 
   /* 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)]);
-
+  if (rules & (1u << TAL_1)
+      || (z > 0 && z < table->n[a] && rules & (1u << TAL_GAP)))
+    width = params->line_widths[a][RENDER_LINE_SINGLE];
+  if (rules & (1u << TAL_2))
+    width = MAX (width, params->line_widths[a][RENDER_LINE_DOUBLE]);
   return width;
 }
 
index f6035cf0ab52fae1c16c55d9acdc383bf3be4a02..51b84a3005cf03705739266c6e68e3d357f8833b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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,7 +19,7 @@
 
 #include <stdbool.h>
 #include <stddef.h>
-#include <output/table-provider.h>
+#include "output/table-provider.h"
 
 struct table;
 
index e4ff158ccd39c74a5c2cb71c240cb955f9d1f477..f5f1f1f84b6ba5ea4535213d23f84948e7a1fb43 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 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/tab.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 "data/data-out.h"
+#include "data/format.h"
+#include "data/settings.h"
+#include "data/value.h"
+#include "data/variable.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.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 "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -359,7 +360,7 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
    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 union value *v, const struct variable *var,
           const struct fmt_spec *f)
 {
   char *contents;
@@ -378,7 +379,9 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
     }
 #endif
 
-  contents = data_out_pool (v, dict_get_encoding (dict), f, table->container);
+  contents = data_out_pool (v, var_get_encoding (var),
+                            f != NULL ? f : var_get_print_format (var),
+                            table->container);
 
   table->cc[c + r * table->cf] = contents;
   table->ct[c + r * table->cf] = opt;
@@ -416,7 +419,7 @@ tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  s = data_out_pool (&double_value, LEGACY_NATIVE, &f, table->container);
+  s = data_out_pool (&double_value, C_ENCODING, &f, table->container);
 
   table->cc[c + r * table->cf] = s + strspn (s, " ");
   table->ct[c + r * table->cf] = opt;
@@ -458,7 +461,7 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  s = data_out_pool (&double_value, LEGACY_NATIVE, fmt, table->container);
+  s = data_out_pool (&double_value, C_ENCODING, fmt, table->container);
   table->cc[c + r * table->cf] = s + strspn (s, " ");
   table->ct[c + r * table->cf] = opt;
 }
index db38b6b8144d0b94cb638a7abe0c65174d1b7b48..dd6840c63cad291ea4354dba84030a593fc53dff 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997, 1998, 1999, 2000, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2009, 2011 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
@@ -38,8 +38,8 @@
          the table code here.
 */
 
-#include <libpspp/compiler.h>
-#include <output/table.h>
+#include "libpspp/compiler.h"
+#include "output/table.h"
 
 /* A table. */
 struct tab_table
@@ -111,7 +111,7 @@ 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 union value *, const struct variable *,
                const struct fmt_spec *);
 
 void tab_fixed (struct tab_table *, int c, int r, unsigned char opt,
index 4a1452c0e91eea776b2eb4af75c57f4b2c53bdb8..672dd87f49bc74200400fff3d4a978547af3f3b1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/table-provider.h>
+#include "output/table-provider.h"
 
-#include <data/casereader.h>
-#include <data/data-out.h>
-#include <data/format.h>
-#include <libpspp/i18n.h>
+#include "data/casereader.h"
+#include "data/data-out.h"
+#include "data/format.h"
+#include "libpspp/i18n.h"
 
 #include "gl/xalloc.h"
 
@@ -142,7 +142,10 @@ 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;
+  if (axis == TABLE_VERT)
+    return tc->heading != NULL && y == 1 ? TAL_1 : TAL_0;
+  else
+    return TAL_GAP;
 }
 
 static const struct table_class table_casereader_class =
index c7c0f91c9cea8ca20911661fa0ee7698f72d95bf..664f093abfb792d9fde5afbb017bba493b5ec9ad 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/table-provider.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 "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"
 
index 01e9899b880e9dfe93b961c5ea88cf0f05eed356..dddf846ca952a08ea0709ffc72f737b9654da175 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -23,8 +23,8 @@
    contains a table (see table.h) and some formatting properties (currently
    just a caption). */
 
-#include <libpspp/compiler.h>
-#include <output/output-item.h>
+#include "libpspp/compiler.h"
+#include "output/output-item.h"
 
 /* A table item.
 
@@ -48,7 +48,7 @@ void table_item_set_caption (struct table_item *, const char *);
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct output_item_class table_item_class;
 
index 102b51404d3da130d29f3176404eb94317964e53..5f6d3f83e0e9a0e4f5e5ab39e97e27954c6ad31b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -16,9 +16,9 @@
 
 #include <config.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/tower.h>
-#include <output/table-provider.h>
+#include "libpspp/assertion.h"
+#include "libpspp/tower.h"
+#include "output/table-provider.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
index 6d1a415618e18529d8ab029a79893fb5a6b321a0..36a666534fe42486fa1350f1d0775f0ca1bf308e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997, 1998, 1999, 2000, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2009, 2011 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,7 +17,7 @@
 #ifndef OUTPUT_TABLE_PROVIDER
 #define OUTPUT_TABLE_PROVIDER 1
 
-#include <output/table.h>
+#include "output/table.h"
 
 /* A cell in a table. */
 struct table_cell
index 241448e572538491186e0506168b025be8533e13..dcc6b7de2af8c8a4ead62190a532fd96d8d83c56 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -16,9 +16,9 @@
 
 #include <config.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <output/table-provider.h>
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "output/table-provider.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
index 59801942cb9b2dd6af4a324949b7c87ff47b7dc1..3dd862026274e3185dc18e4ab27e2a44d9e264be 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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
@@ -16,9 +16,9 @@
 
 #include <config.h>
 
-#include <libpspp/assertion.h>
-#include <libpspp/cast.h>
-#include <output/table-provider.h>
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "output/table-provider.h"
 
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
index 696931ae50980147be4212dd1af477a73c2448d1..bd51f494033ad346d3377e3f25e00db9e536a559 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 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/table.h>
-#include <output/table-provider.h>
+#include "output/table.h"
+#include "output/table-provider.h"
 
 #include <assert.h>
 #include <stdlib.h>
 
-#include <libpspp/cast.h>
-#include <libpspp/compiler.h>
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
 
 #include "gl/xalloc.h"
 
index 16588ae5c54e2beef6a1e96d3fbfd170a29572c3..1531656276c7dd01116eff4b094fc9933362494e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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/text-item.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 "libpspp/cast.h"
+#include "output/driver.h"
+#include "output/output-item-provider.h"
 
-#include "xalloc.h"
-#include "xvasprintf.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static struct text_item *
-allocate_text_item (enum text_item_type type, char *text)
+/* Creates and returns a new text item containing TEXT and the specified TYPE.
+   The new text item takes ownership of TEXT. */
+struct text_item *
+text_item_create_nocopy (enum text_item_type type, char *text)
 {
   struct text_item *item = xmalloc (sizeof *item);
   output_item_init (&item->output_item, &text_item_class);
@@ -47,7 +49,7 @@ allocate_text_item (enum text_item_type type, char *text)
 struct text_item *
 text_item_create (enum text_item_type type, const char *text)
 {
-  return allocate_text_item (type, xstrdup (text));
+  return text_item_create_nocopy (type, xstrdup (text));
 }
 
 /* Creates and returns a new text item containing a copy of FORMAT, which is
@@ -60,7 +62,7 @@ text_item_create_format (enum text_item_type type, const char *format, ...)
   va_list args;
 
   va_start (args, format);
-  item = allocate_text_item (type, xvasprintf (format, args));
+  item = text_item_create_nocopy (type, xvasprintf (format, args));
   va_end (args);
 
   return item;
index b62e7dc4011e8616b843c0bc604938fa9fd04a8a..da1b208a5ea8cfd40ec5c27339cd2c8307d814a3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009 Free Sonftware Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -25,8 +25,8 @@
    A text item is just a text string. */
 
 #include <stdbool.h>
-#include <libpspp/compiler.h>
-#include <output/output-item.h>
+#include "libpspp/compiler.h"
+#include "output/output-item.h"
 
 enum text_item_type
   {
@@ -67,6 +67,7 @@ struct text_item
   };
 
 struct text_item *text_item_create (enum text_item_type, const char *text);
+struct text_item *text_item_create_nocopy (enum text_item_type, char *text);
 struct text_item *text_item_create_format (enum text_item_type,
                                            const char *format, ...)
   PRINTF_FORMAT (2, 3);
@@ -78,7 +79,7 @@ const char *text_item_get_text (const struct text_item *);
    autogenerated by mk-class-boilerplate. */
 
 #include <assert.h>
-#include <libpspp/cast.h>
+#include "libpspp/cast.h"
 
 extern const struct output_item_class text_item_class;
 
index 9ab455aa72ffa0a050b937f6da924eee0dbeab5c..207bbd4d8d884826e08464a73d6524504aaeb0b3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2010  Free Software Foundation
+   Copyright (C) 2010, 2011  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
@@ -17,7 +17,6 @@
 #include <config.h>
 
 #include "dialog-common.h"
-#include <language/syntax-string-source.h>
 
 #include <language/stats/aggregate.h>
 
@@ -457,7 +456,7 @@ set_initial_pos (GtkPaned *pane)
                "max-position", &max_pos,
                NULL);
 
-  gtk_paned_set_position (pane, max_pos / 2);
+  gtk_paned_set_position (pane, max_pos);
 }
 
 
@@ -591,22 +590,10 @@ aggregate_dialog (PsppireDataWindow *dw)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&fd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (dw, generate_syntax (&fd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&fd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&fd)));
       break;
     default:
       break;
index 302e594347a788c299588974583e82fceaea4a7a..4ebfecfcdd8d8b85862fb3c421e03916beb74eca 100644 (file)
@@ -17,8 +17,6 @@
 #ifndef __AGGREGATE_DIALOG_H
 #define __AGGREGATE_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void aggregate_dialog (PsppireDataWindow * data);
index 193d112d699da3222f4c5674aa0ea28172b89fdb..8cbcf2af8ebc64892ef2888edacc46142b13ba78 100644 (file)
@@ -17,6 +17,7 @@
             <property name="visible">True</property>
             <child>
               <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="width_request">200</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="hscrollbar_policy">automatic</property>
@@ -34,7 +35,7 @@
                 </child>
               </object>
               <packing>
-                <property name="resize">False</property>
+                <property name="resize">True</property>
                 <property name="shrink">True</property>
               </packing>
             </child>
               </object>
               <packing>
                 <property name="resize">True</property>
-                <property name="shrink">True</property>
+                <property name="shrink">False</property>
               </packing>
             </child>
           </object>
index fd78196df891d92fa48d2345bb61575db8b714b0..6097d16b82d3a2d9dcec1b46963d4cf06330a337 100644 (file)
@@ -10,11 +10,13 @@ UI_FILES = \
        src/ui/gui/crosstabs.ui \
        src/ui/gui/chi-square.ui \
        src/ui/gui/descriptives.ui \
+       src/ui/gui/entry-dialog.ui \
        src/ui/gui/examine.ui \
        src/ui/gui/goto-case.ui \
        src/ui/gui/factor.ui \
        src/ui/gui/find.ui \
        src/ui/gui/frequencies.ui \
+       src/ui/gui/k-related.ui \
        src/ui/gui/oneway.ui \
        src/ui/gui/psppire.ui \
        src/ui/gui/rank.ui \
@@ -147,6 +149,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/dialog-common.h \
        src/ui/gui/dict-display.h \
        src/ui/gui/dict-display.c \
+       src/ui/gui/entry-dialog.c \
+       src/ui/gui/entry-dialog.h \
        src/ui/gui/examine-dialog.c \
        src/ui/gui/examine-dialog.h \
        src/ui/gui/executor.c \
@@ -163,6 +167,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/help-menu.c \
        src/ui/gui/help-menu.h \
        src/ui/gui/helper.h \
+       src/ui/gui/k-related-dialog.c \
+       src/ui/gui/k-related-dialog.h \
        src/ui/gui/main.c \
        src/ui/gui/missing-val-dialog.c \
        src/ui/gui/missing-val-dialog.h \
@@ -185,6 +191,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dict.h \
        src/ui/gui/psppire-dictview.c \
        src/ui/gui/psppire-dictview.h \
+       src/ui/gui/psppire-encoding-selector.c \
+       src/ui/gui/psppire-encoding-selector.h \
        src/ui/gui/psppire-hbuttonbox.h \
        src/ui/gui/psppire-keypad.h \
        src/ui/gui/psppire-output-window.c \
@@ -223,8 +231,6 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/sort-cases-dialog.h \
        src/ui/gui/split-file-dialog.c \
        src/ui/gui/split-file-dialog.h \
-       src/ui/gui/syntax-editor-source.c \
-       src/ui/gui/syntax-editor-source.h \
        src/ui/gui/text-data-import-dialog.c \
        src/ui/gui/text-data-import-dialog.h \
        src/ui/gui/transpose-dialog.c \
@@ -256,7 +262,6 @@ nodist_src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-marshal.c \
        src/ui/gui/psppire-marshal.h
 
-
 yelp-check:
        @if ! yelp --version > /dev/null 2>&1 ; then \
                echo    ; \
@@ -289,3 +294,20 @@ endif HAVE_GUI
 #ensure the installcheck passes even if there is no X server available
 installcheck-local:
        DISPLAY=/invalid/port $(MAKE) $(AM_MAKEFLAGS) installcheck-binPROGRAMS
+
+# <gtk/gtk.h> wrapper
+src_ui_gui_psppire_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/ui/gui/include
+BUILT_SOURCES += src/ui/gui/include/gtk/gtk.h
+src/ui/gui/include/gtk/gtk.h: src/ui/gui/include/gtk/gtk.in.h
+       @$(MKDIR_P) src/ui/gui/include/gtk
+       $(AM_V_GEN)rm -f $@-t $@ && \
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+             -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+             -e 's|@''NEXT_GTK_GTK_H''@|$(NEXT_GTK_GTK_H)|g' \
+             < $(srcdir)/src/ui/gui/include/gtk/gtk.in.h; \
+       } > $@-t && \
+       mv $@-t $@
+CLEANFILES += src/ui/gui/include/gtk/gtk.h
+EXTRA_DIST += src/ui/gui/include/gtk/gtk.in.h
index 130c3dd6d4645ad66ca20f3111013843089bac14..195c420193d90d2fd3a6ff487b43fd6cfc7bd150 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2010  Free Software Foundation
+   Copyright (C) 2010, 2011  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
@@ -18,8 +18,6 @@
 
 #include "binomial-dialog.h"
 
-#include <language/syntax-string-source.h>
-
 #include "psppire-dialog.h"
 #include "psppire-var-view.h"
 #include "psppire-acr.h"
@@ -187,21 +185,10 @@ binomial_dialog (PsppireDataWindow *dw)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&bin_d);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (dw, generate_syntax (&bin_d)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&bin_d);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&bin_d)));
       break;
     default:
       break;
index 8f2f9a18e4d2b9fe78817be688f681c4f69f3fc7..b50e444cf4d70ed068b3318435a735c72df0e274 100644 (file)
@@ -17,7 +17,6 @@
 #ifndef __BINOMIAL_DIALOG_H
 #define __BINOMIAL_DIALOG_H
 
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void binomial_dialog (PsppireDataWindow * data);
index 6bb42e4755c302ca5e0b702ecb8a633fe5be5a56..c7aaf52b4cc6e7ce514dd7464dbdb077a2d97eb1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2010  Free Software Foundation
+   Copyright (C) 2010, 2011  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
@@ -18,8 +18,6 @@
 
 #include "chi-square-dialog.h"
 
-#include <language/syntax-string-source.h>
-
 #include "psppire-dialog.h"
 #include "psppire-var-view.h"
 #include "psppire-acr.h"
@@ -230,21 +228,10 @@ chisquare_dialog (PsppireDataWindow *dw)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&csd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (dw, generate_syntax (&csd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&csd);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&csd)));
       break;
     default:
       break;
index 8292ff966890cfc4e53011e76262a13bafed6671..d372b60e120f05b80c98dd8b71090d65748eebbd 100644 (file)
@@ -17,7 +17,6 @@
 #ifndef __CHI_SQUARE_DIALOG_H
 #define __CHI_SQUARE_DIALOG_H
 
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void chisquare_dialog (PsppireDataWindow * data);
index 306e3b40a20846b3c0512bec74783d19b70315bb..69a8096b24f01e11eec4a2b0bb550f16e4eff605 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -20,7 +20,6 @@
 #include "helper.h"
 #include "psppire-data-window.h"
 #include "psppire-data-editor.h"
-#include <language/syntax-string-source.h>
 #include "executor.h"
 #include "psppire-var-store.h"
 #include <ui/syntax-gen.h>
@@ -164,23 +163,10 @@ comments_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&cd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&cd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&cd);
-
-       paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&cd)));
       break;
     default:
       break;
@@ -209,13 +195,7 @@ refresh (PsppireDialog *dialog, const struct comment_dialog *cd)
   gtk_text_buffer_set_text (buffer, "", 0);
 
   for ( i = 0 ; i < dict_get_document_line_cnt (cd->dict->dict); ++i )
-    {
-      struct string str;
-      ds_init_empty (&str);
-      dict_get_document_line (cd->dict->dict, i, &str);
-      add_line_to_buffer (buffer, ds_cstr (&str));
-      ds_destroy (&str);
-    }
+    add_line_to_buffer (buffer, dict_get_document_line (cd->dict->dict, i));
 }
 
 
@@ -230,11 +210,10 @@ generate_syntax (const struct comment_dialog *cd)
   GtkWidget *tv = get_widget_assert (cd->xml, "comments-textview1");
   GtkWidget *check = get_widget_assert (cd->xml, "comments-checkbutton1");
   GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
-  const char *existing_docs = dict_get_documents (cd->dict->dict);
 
   str = g_string_new ("\n* Data File Comments.\n\n");
 
-  if ( NULL != existing_docs)
+  if (dict_get_documents (cd->dict->dict) != NULL)
     g_string_append (str, "DROP DOCUMENTS.\n");
 
   g_string_append (str, "ADD DOCUMENT\n");
index 1154b5125581abc203ef04ace7ba202d2a5448b3..6f9ec222eb001764105850369bd8a7b6835e5b7f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -27,7 +27,6 @@
 #include <libpspp/i18n.h>
 
 #include <language/expressions/public.h>
-#include <language/syntax-string-source.h>
 #include "executor.h"
 
 static void function_list_populate (GtkTreeView *tv);
@@ -435,23 +434,10 @@ compute_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&scd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&scd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&scd);
-
-       paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&scd)));
       break;
     default:
       break;
index 4594f5c2797de8f5e3dc6ac998124c71c6cda71c..6e136074a4fb615b14588b164477638de112de4b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -17,8 +17,6 @@
 #ifndef __COMPUTE_DIALOG_H
 #define __COMPUTE_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void compute_dialog (PsppireDataWindow * data);
index afc23447a7af3636e58b1b69b28f3864951e5b48..2e715039a9979783ea44426dcfe62b0dddc59d7e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -17,7 +17,6 @@
 #include <config.h>
 
 #include "dialog-common.h"
-#include <language/syntax-string-source.h>
 #include <ui/syntax-gen.h>
 #include <libpspp/str.h>
 
@@ -118,22 +117,10 @@ correlation_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index f9342f26ac0ec9680f19a0a5e7f1fb319429b839..9a05837c7b3d9e19fcacde1f8a373f16a4f95903 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 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
@@ -17,7 +17,6 @@
 #ifndef __CORRELATION_DIALOG_H
 #define __CORRELATION_DIALOG_H
 
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void correlation_dialog (PsppireDataWindow * data);
index 7d94e375c0ab3042e91edb9e7ee239a1f6f15a01..34a3921301ba0b93d61412ccf920f37d24a40c31 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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
@@ -23,7 +23,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -464,23 +463,10 @@ crosstabs_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&cd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&cd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&cd);
-
-       paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&cd)));
       break;
     default:
       break;
index dee6110b865f302c0d57b9ebc31c93b8ec8922a1..65e47610d615bf885216bce188ce44756c8e5bd5 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
@@ -17,8 +17,6 @@
 #ifndef __CROSSTABS_DIALOG_H
 #define __CROSSTABS_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void crosstabs_dialog (PsppireDataWindow * data);
index 7b3104693589d95d28aa03745d8811baa9b8e176..04e738f23b335bca9b413eecb1b8b7a04bff3c2a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2007  Free Software Foundation
+   Copyright (C) 2005, 2007, 2010, 2011  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
@@ -55,8 +55,7 @@
 
 #include <config.h>
 
-#include <gtk/gtksignal.h>
-#include <gtk/gtkentry.h>
+#include <gtk/gtk.h>
 #include "customentry.h"
 
 
@@ -107,7 +106,7 @@ psppire_custom_entry_get_type (void)
 static void
 psppire_custom_entry_map (GtkWidget *widget)
 {
-  if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
+  if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget))
     {
       GTK_WIDGET_CLASS (parent_class)->map (widget);
       gdk_window_show (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
@@ -117,7 +116,7 @@ psppire_custom_entry_map (GtkWidget *widget)
 static void
 psppire_custom_entry_unmap (GtkWidget *widget)
 {
-  if (GTK_WIDGET_MAPPED (widget))
+  if (gtk_widget_get_mapped (widget))
     {
       gdk_window_hide (PSPPIRE_CUSTOM_ENTRY (widget)->panel);
       GTK_WIDGET_CLASS (parent_class)->unmap (widget);
@@ -233,7 +232,7 @@ psppire_custom_entry_redraw (PsppireCustomEntry *custom_entry)
 
   widget = GTK_WIDGET (custom_entry);
 
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
       gtk_widget_queue_draw (widget);
 
@@ -254,7 +253,7 @@ psppire_custom_entry_expose (GtkWidget      *widget,
   g_return_val_if_fail (PSPPIRE_IS_CUSTOM_ENTRY (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
       gboolean is_editable;
       GtkShadowType shadow_type;
@@ -369,7 +368,7 @@ psppire_custom_entry_button_press (GtkWidget *widget,
   if (event->window == ce->panel)
     {
       gboolean is_editable ;
-      if (!GTK_WIDGET_HAS_FOCUS (widget))
+      if (!gtk_widget_has_focus (widget))
        gtk_widget_grab_focus (widget);
 
       g_object_get (ce, "editable", &is_editable, NULL);
@@ -426,7 +425,7 @@ psppire_custom_entry_size_allocate (GtkWidget     *widget,
 
   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
 
-  if (GTK_WIDGET_REALIZED (widget))
+  if (gtk_widget_get_realized (widget))
     {
       gdk_window_move_resize (PSPPIRE_CUSTOM_ENTRY (widget)->panel,
                              panel_allocation.x,
index 69f2b413901f43aa4e67e5f6cb5c01bce72ef468..012605e534fedbc68345f284479fca1d6a7eb65d 100644 (file)
           <object class="GtkAction" id="file_open">
             <property name="stock-id">gtk-open</property>
             <property name="name">file_open</property>
+            <property name="label" translatable="yes">_Open...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="file_import-text">
             <property name="name">file_import-text</property>
-            <property name="label" translatable="yes">_Import Delimited Text Data</property>
+            <property name="label" translatable="yes">_Import Delimited Text Data...</property>
            <property name="stock-id">gtk-convert</property>
           </object>
         </child>
+        <child>
+          <object class="GtkAction" id="rename_dataset">
+            <property name="name">rename_dataset</property>
+           <property name="label" translatable="yes">_Rename Dataset...</property>
+          </object>
+        </child>
         <child>
           <object class="GtkAction" id="file_save">
             <property name="stock-id">gtk-save</property>
@@ -64,6 +71,7 @@
           <object class="GtkAction" id="file_save_as">
             <property name="stock-id">gtk-save-as</property>
             <property name="name">file_save_as</property>
+            <property name="label" translatable="yes">Save _As...</property>
           </object>
         </child>
         <child>
@@ -82,7 +90,7 @@
         <child>
           <object class="GtkAction" id="file_information_external-file">
             <property name="name">file_information_external-file</property>
-            <property name="label" translatable="yes">External File</property>
+            <property name="label" translatable="yes">External File...</property>
           </object>
         </child>
         <child>
         </child>
         <child>
           <object class="GtkAction" id="edit_goto-case">
-            <property name="label" translatable="yes">Go To Case</property>
+            <property name="label" translatable="yes">Go To Case...</property>
             <property name="name">edit_goto-case</property>
             <property name="tooltip" translatable="yes">Jump to a case in the data sheet</property>
            <property name="stock-id">gtk-jump-to</property>
           <object class="GtkAction" id="edit_find">
             <property name="stock-id">gtk-find</property>
             <property name="name">edit_find</property>
+            <property name="label" translatable="yes">_Find...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="view_fonts">
             <property name="name">view_fonts</property>
             <property name="stock-id">gtk-select-font</property>
+            <property name="label" translatable="yes">_Font...</property>
           </object>
         </child>
         <child>
           </object>
         </child>
         <child>
-          <object class="GtkAction" id="view_data">
+          <object class="GtkRadioAction" id="view_data">
             <property name="name">view_data</property>
             <property name="label" translatable="yes">_Data</property>
           </object>
         </child>
         <child>
-          <object class="GtkAction" id="view_variables">
+          <object class="GtkRadioAction" id="view_variables">
             <property name="name">view_variables</property>
             <property name="label" translatable="yes">_Variables</property>
+           <property name="group">view_data</property>
           </object>
         </child>
         <child>
         </child>
         <child>
           <object class="GtkAction" id="data_sort-cases">
-            <property name="label" translatable="yes">_Sort Cases</property>
+            <property name="label" translatable="yes">_Sort Cases...</property>
             <property name="name">data_sort-cases</property>
            <property name="stock-id">gtk-sort-ascending</property>
-           <property name="tooltip" translatable="yes">Sort cases in the active file</property>
+           <property name="tooltip" translatable="yes">Sort cases in the active dataset</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="data_transpose">
            <property name="stock-id">pspp-transpose</property>
             <property name="name">data_transpose</property>
-            <property name="label" translatable="yes">_Transpose</property>
+            <property name="label" translatable="yes">_Transpose...</property>
            <property name="tooltip" translatable="yes">Transpose the cases with the variables</property>
           </object>
         </child>
           <object class="GtkAction" id="data_aggregate">
            <property name="stock-id">pspp-aggregate</property>
             <property name="name">data_aggregate</property>
-            <property name="label" translatable="yes">_Aggregate</property>
+            <property name="label" translatable="yes">_Aggregate...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="data_split-file">
             <property name="name">data_split-file</property>
-            <property name="label" translatable="yes">S_plit File</property>
-           <property name="tooltip" translatable="yes">Split the active file</property>
+            <property name="label" translatable="yes">S_plit File...</property>
+           <property name="tooltip" translatable="yes">Split the active dataset</property>
            <property name="stock-id">pspp-split-file</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="data_select-cases">
             <property name="name">data_select-cases</property>
-            <property name="label" translatable="yes">Select _Cases</property>
+            <property name="label" translatable="yes">Select _Cases...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="data_weight-cases">
             <property name="name">data_weight-cases</property>
-            <property name="label" translatable="yes">_Weight Cases</property>
+            <property name="label" translatable="yes">_Weight Cases...</property>
            <property name="tooltip" translatable="yes">Weight cases by variable</property>
            <property name="stock-id">pspp-weight-cases</property>
           </object>
         <child>
           <object class="GtkAction" id="transform_compute">
             <property name="name">transform_compute</property>
-            <property name="label" translatable="yes">_Compute</property>
+            <property name="label" translatable="yes">_Compute...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="transform_rank">
             <property name="name">transform_rank</property>
-            <property name="label" translatable="yes">Ran_k Cases</property>
+            <property name="label" translatable="yes">Ran_k Cases...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="transform_recode-same">
             <property name="name">transform_recode-same</property>
-            <property name="label" translatable="yes">Recode into _Same Variables</property>
+            <property name="label" translatable="yes">Recode into _Same Variables...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="transform_recode-different">
             <property name="name">transform_recode-different</property>
-            <property name="label" translatable="yes">Recode into _Different Variables</property>
+            <property name="label" translatable="yes">Recode into _Different Variables...</property>
           </object>
         </child>
         <child>
         <child>
           <object class="GtkAction" id="analyze_frequencies">
             <property name="name">analyze_frequencies</property>
-            <property name="label" translatable="yes">_Frequencies</property>
+            <property name="label" translatable="yes">_Frequencies...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="analyze_descriptives">
             <property name="name">analyze_descriptives</property>
-            <property name="label" translatable="yes">_Descriptives</property>
+            <property name="label" translatable="yes">_Descriptives...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="analyze_explore">
             <property name="name">analyze_explore</property>
-            <property name="label" translatable="yes">_Explore</property>
+            <property name="label" translatable="yes">_Explore...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="crosstabs">
             <property name="name">crosstabs</property>
-            <property name="label" translatable="yes">_Crosstabs</property>
+            <property name="label" translatable="yes">_Crosstabs...</property>
           </object>
         </child>
         <child>
         <child>
           <object class="GtkAction" id="one-sample-t-test">
             <property name="name">one-sample-t-test</property>
-            <property name="label" translatable="yes">_One Sample T Test</property>
+            <property name="label" translatable="yes">_One Sample T Test...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="indep-t-test">
             <property name="name">indep-t-test</property>
-            <property name="label" translatable="yes">_Independent Samples T Test</property>
+            <property name="label" translatable="yes">_Independent Samples T Test...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="paired-t-test">
             <property name="name">paired-t-test</property>
-            <property name="label" translatable="yes">_Paired Samples T Test</property>
+            <property name="label" translatable="yes">_Paired Samples T Test...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="oneway-anova">
             <property name="name">oneway-anova</property>
-            <property name="label" translatable="yes">One Way _ANOVA</property>
+            <property name="label" translatable="yes">One Way _ANOVA...</property>
           </object>
         </child>
         <child>
         <child>
           <object class="GtkAction" id="factor-analysis">
             <property name="name">factor-analysis</property>
-            <property name="label" translatable="yes">Factor _Analysis</property>
+            <property name="label" translatable="yes">Factor _Analysis...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="reliability">
             <property name="name">reliability</property>
-            <property name="label" translatable="yes">Re_liability</property>
+            <property name="label" translatable="yes">Re_liability...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="linear-regression">
             <property name="name">linear-regression</property>
-            <property name="label" translatable="yes">Linear _Regression</property>
+            <property name="label" translatable="yes">Linear _Regression...</property>
           </object>
         </child>
         <child>
         <child>
           <object class="GtkAction" id="chi-square">
             <property name="name">chi-square</property>
-            <property name="label" translatable="yes">_Chi-Square</property>
+            <property name="label" translatable="yes">_Chi-Square...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="binomial">
             <property name="name">binomial</property>
-            <property name="label" translatable="yes">_Binomial</property>
+            <property name="label" translatable="yes">_Binomial...</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkAction" id="k-related-samples">
+            <property name="name">"k-related-samples"></property>
+            <property name="label" translatable="yes">K Related _Samples...</property>
           </object>
         </child>
         <child>
         <child>
           <object class="GtkAction" id="utilities_variables">
             <property name="name">utilities_variables</property>
-            <property name="label" translatable="yes">_Variables</property>
+            <property name="label" translatable="yes">_Variables...</property>
            <property name="tooltip" translatable="yes">Jump to variable</property>
            <property name="stock-id">pspp-goto-variable</property>
           </object>
         <child>
           <object class="GtkAction" id="utilities_comments">
             <property name="name">utilities_comments</property>
-            <property name="label" translatable="yes">Data File _Comments</property>
+            <property name="label" translatable="yes">Data File _Comments...</property>
           </object>
         </child>
         <child>
           <separator/>
           <menuitem action="file_save"/>
           <menuitem action="file_save_as"/>
+          <menuitem action="rename_dataset"/>
           <separator/>
           <menu action="file-information">
             <menuitem action="file_information_working-file"/>
           <menu action="non-parametrics">
             <menuitem action="chi-square"/>
             <menuitem action="binomial"/>
+            <menuitem action="k-related-samples"/>
           </menu>
           <menuitem action="roc-curve"/>
         </menu>
index 5a774902556e43e36e21e8a39cd3c90df6e5703f..c6343d5bbb7ccfc57d90bc64a6049a51594a5de5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2010  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -23,7 +23,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -258,21 +257,10 @@ descriptives_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&scd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&scd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&scd);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&scd)));
       break;
     default:
       break;
index b0dc7fab2d2c143d7abb12fb0283b2e6a2e01949..18195761ff1949406e073ba6f39c2090c290a0dc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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 __DESCRIPTIVES_DIALOG_H
 #define __DESCRIPTIVES_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
-
 void descriptives_dialog (PsppireDataWindow * data);
 
 #endif
diff --git a/src/ui/gui/entry-dialog.c b/src/ui/gui/entry-dialog.c
new file mode 100644 (file)
index 0000000..148af74
--- /dev/null
@@ -0,0 +1,62 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 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 "ui/gui/entry-dialog.h"
+
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-dialog.h"
+
+#include "gl/xalloc.h"
+
+/* Creates a modal dialog with PARENT as its parent (this should be the
+   application window that the dialog is associated with), with TITLE as its
+   title, that prompts for a text string with PROMPT as the explanation and
+   DEFAULT_VALUE as the default value.
+
+   Returns a malloc()'d string owned by the caller if the user clicks on OK or
+   otherwise accepts a value, or NULL if the user cancels. */
+char *
+entry_dialog_run (GtkWindow *parent,
+                  const char *title,
+                  const char *prompt,
+                  const char *default_value)
+{
+  GtkBuilder *xml = builder_new ("entry-dialog.ui");
+  GtkWidget *dialog;
+  GtkWidget *label;
+  GtkWidget *entry;
+  char *result;
+
+  dialog = get_widget_assert (xml, "entry-dialog");
+  gtk_window_set_title (GTK_WINDOW (dialog), title);
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+  label = get_widget_assert (xml, "label");
+  gtk_label_set_text (GTK_LABEL (label), prompt);
+
+  entry = get_widget_assert (xml, "entry");
+  gtk_entry_set_text (GTK_ENTRY (entry), default_value);
+
+  result = (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK
+            ? xstrdup (gtk_entry_get_text (GTK_ENTRY (entry)))
+            : NULL);
+
+  g_object_unref (xml);
+
+  return result;
+}
diff --git a/src/ui/gui/entry-dialog.h b/src/ui/gui/entry-dialog.h
new file mode 100644 (file)
index 0000000..8f71acd
--- /dev/null
@@ -0,0 +1,27 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 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 ENTRY_DIALOG_H
+#define ENTRY_DIALOG_H 1
+
+#include <gtk/gtk.h>
+
+char *entry_dialog_run (GtkWindow *parent,
+                        const char *title,
+                        const char *prompt,
+                        const char *default_value);
+
+#endif /* ui/gui/entry-dialog.h */
diff --git a/src/ui/gui/entry-dialog.ui b/src/ui/gui/entry-dialog.ui
new file mode 100644 (file)
index 0000000..a0246cb
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="psppire" version="2054.17080"/>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy project-wide -->
+  <object class="PsppireDialog" id="entry-dialog">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="modal">True</property>
+    <property name="orientation">Vertical</property>
+    <child internal-child="hbox">
+      <object class="GtkVBox" id="dialog-hbox8">
+        <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">5</property>
+       <child>
+         <object class="GtkLabel" id="label">
+            <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>
+         </object>
+       </child>
+       <child>
+         <object class="GtkEntry" id="entry">
+            <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="activates-default">True</property>
+         </object>
+       </child>
+        <child>
+          <object class="PsppireHButtonBox" id="psppire-hbuttonbox5">
+            <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="border_width">5</property>
+            <property name="layout_style">spread</property>
+            <property name="buttons">PSPPIRE_BUTTON_OK_MASK | PSPPIRE_BUTTON_CANCEL_MASK</property>
+            <property name="default">PSPPIRE_BUTTON_OK_MASK</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
index 87a048acfe3d4e07bd6f2697cfd9b692fa660ef7..7b33ac4541a975628ec63a96cf271619cb105799 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2008, 2009  Free Software Foundation
+   Copyright (C) 2007, 2008, 2009, 2010, 2011  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
@@ -22,7 +22,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -301,22 +300,10 @@ examine_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&ex_d);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&ex_d)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&ex_d);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&ex_d)));
       break;
     default:
       break;
index 707b4f0c59160189336c6167cb544294a5b36347..15835a0ecdbb47af195ca35e76623a558406ad8c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -17,8 +17,6 @@
 #ifndef __EXAMINE_DIALOG_H
 #define __EXAMINE_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void examine_dialog (PsppireDataWindow * data);
index 6ccb5a534deca402d8e879dd2f3f6376a13e30e3..8fb4c2603e37662c0753041b1221a131a0ee52cf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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 "executor.h"
-#include "psppire-data-store.h"
-#include <data/lazy-casereader.h>
-#include <data/procedure.h>
-#include <libpspp/getl.h>
-#include <language/lexer/lexer.h>
-#include <language/command.h>
-#include <output/driver.h>
-#include "psppire-output-window.h"
+#include "ui/gui/executor.h"
 
-extern struct dataset *the_dataset;
-extern struct source_stream *the_source_stream;
-extern PsppireDataStore *the_data_store;
+#include "data/dataset.h"
+#include "data/lazy-casereader.h"
+#include "data/session.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/cast.h"
+#include "output/driver.h"
+#include "ui/gui/psppire-data-store.h"
+#include "ui/gui/psppire-output-window.h"
 
 /* Lazy casereader callback function used by execute_syntax. */
 static struct casereader *
@@ -38,52 +36,94 @@ create_casereader_from_data_store (void *data_store_)
   return psppire_data_store_get_reader (data_store);
 }
 
+static void
+new_pdw_cb (struct dataset *ds, void *aux UNUSED)
+{
+  PsppireDataWindow *pdw = psppire_data_window_for_dataset (ds);
+  if (pdw == NULL)
+    pdw = PSPPIRE_DATA_WINDOW (psppire_data_window_new (ds));
+
+  switch (dataset_get_display (ds))
+    {
+    case DATASET_ASIS:
+      break;
+
+    case DATASET_FRONT:
+      gtk_widget_show (GTK_WIDGET (pdw));
+      gtk_window_deiconify (GTK_WINDOW (pdw));
+      gdk_window_raise (gtk_widget_get_window (GTK_WIDGET (pdw)));
+      psppire_data_window_set_default (pdw);
+      break;
+
+    case DATASET_MINIMIZED:
+      gtk_window_iconify (GTK_WINDOW (pdw));
+      gtk_widget_show (GTK_WIDGET (pdw));
+      psppire_data_window_undefault (pdw);
+      break;
+
+    case DATASET_HIDDEN:
+      gtk_widget_hide (GTK_WIDGET (pdw));
+      psppire_data_window_undefault (pdw);
+      break;
+    }
+  dataset_set_display (ds, DATASET_ASIS);
+}
+
 gboolean
-execute_syntax (struct getl_interface *sss)
+execute_syntax (PsppireDataWindow *window, struct lex_reader *lex_reader)
 {
   struct lexer *lexer;
   gboolean retval = TRUE;
 
-  struct casereader *reader;
-  const struct caseproto *proto;
-  casenumber case_cnt;
-  unsigned long int lazy_serial;
-
-  /* When the user executes a number of snippets of syntax in a
-     row, none of which read from the active file, the GUI becomes
-     progressively less responsive.  The reason is that each syntax
-     execution encapsulates the active file data in another
-     datasheet layer.  The cumulative effect of having a number of
-     layers of datasheets wastes time and space.
-
-     To solve the problem, we use a "lazy casereader", a wrapper
-     around the casereader obtained from the data store, that
-     only actually instantiates that casereader when it is
-     needed.  If the data store casereader is never needed, then
-     it is reused the next time syntax is run, without wrapping
-     it in another layer. */
-  proto = psppire_data_store_get_proto (the_data_store);
-  case_cnt = psppire_data_store_get_case_count (the_data_store);
-  reader = lazy_casereader_create (proto, case_cnt,
-                                   create_casereader_from_data_store,
-                                   the_data_store, &lazy_serial);
-  proc_set_active_file_data (the_dataset, reader);
-
-  g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
-
-  lexer = lex_create (the_source_stream);
-
-  getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
+  PsppireDataWindow *pdw, *next_pdw;
+
+  ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
+    {
+      const struct caseproto *proto;
+      struct casereader *reader;
+      casenumber case_cnt;
+
+      /* When the user executes a number of snippets of syntax in a
+         row, none of which read from the active dataset, the GUI becomes
+         progressively less responsive.  The reason is that each syntax
+         execution encapsulates the active dataset data in another
+         datasheet layer.  The cumulative effect of having a number of
+         layers of datasheets wastes time and space.
+
+         To solve the problem, we use a "lazy casereader", a wrapper
+         around the casereader obtained from the data store, that
+         only actually instantiates that casereader when it is
+         needed.  If the data store casereader is never needed, then
+         it is reused the next time syntax is run, without wrapping
+         it in another layer. */
+      proto = psppire_data_store_get_proto (pdw->data_store);
+      case_cnt = psppire_data_store_get_case_count (pdw->data_store);
+      reader = lazy_casereader_create (proto, case_cnt,
+                                       create_casereader_from_data_store,
+                                       pdw->data_store, &pdw->lazy_serial);
+      dataset_set_source (pdw->dataset, reader);
+
+      if (pdw == window)
+        session_set_active_dataset (the_session, pdw->dataset);
+
+      g_return_val_if_fail (dataset_has_source (pdw->dataset), FALSE);
+
+      pdw->dataset_seqno = dataset_seqno (pdw->dataset);
+    }
+
+  lexer = lex_create ();
+  psppire_set_lexer (lexer);
+  lex_append (lexer, lex_reader);
 
   for (;;)
     {
-      enum cmd_result result = cmd_parse (lexer, the_dataset);
+      struct dataset *ds = session_active_dataset (the_session);
+      enum cmd_result result = cmd_parse (lexer, ds);
 
       if ( cmd_result_is_failure (result))
        {
          retval = FALSE;
-         if ( source_stream_current_error_mode (the_source_stream)
-              == ERRMODE_STOP )
+         if ( lex_get_error_mode (lexer) == LEX_ERROR_STOP )
            break;
        }
 
@@ -91,18 +131,58 @@ execute_syntax (struct getl_interface *sss)
        break;
     }
 
-  getl_abort_noninteractive (the_source_stream);
+  ll_for_each_safe (pdw, next_pdw, PsppireDataWindow, ll, &all_data_windows)
+    {
+      struct dataset *ds;
 
-  lex_destroy (lexer);
+      ds = session_get_dataset_by_seqno (the_session, pdw->dataset_seqno);
+      if (ds != NULL)
+        {
+          struct casereader *reader;
 
-  psppire_dict_replace_dictionary (the_data_store->dict,
-                                  dataset_dict (the_dataset));
+          pdw->dataset = ds;
+          proc_execute (pdw->dataset);
 
-  reader = proc_extract_active_file_data (the_dataset);
-  if (!lazy_casereader_destroy (reader, lazy_serial))
-    psppire_data_store_set_reader (the_data_store, reader);
+          psppire_dict_replace_dictionary (pdw->data_store->dict,
+                                           dataset_dict (pdw->dataset));
+
+          reader = dataset_steal_source (pdw->dataset);
+          if (!lazy_casereader_destroy (reader, pdw->lazy_serial))
+            psppire_data_store_set_reader (pdw->data_store, reader);
+
+          g_object_set (G_OBJECT (pdw), "id", dataset_name (pdw->dataset),
+                        (void *) NULL);
+        }
+      else
+        gtk_widget_destroy (GTK_WIDGET (pdw));
+    }
+
+  session_for_each_dataset (the_session, new_pdw_cb, NULL);
+
+  /* Destroy the lexer only after obtaining the dataset, because the dataset
+     might depend on the lexer, if the casereader specifies inline data.  (In
+     such a case then we'll always get an error message--the inline data is
+     missing, otherwise it would have been parsed in the loop above.) */
+  lex_destroy (lexer);
+  psppire_set_lexer (NULL);
 
   output_flush ();
 
   return retval;
 }
+
+/* Executes null-terminated string SYNTAX as syntax.
+   Returns SYNTAX. */
+gchar *
+execute_syntax_string (PsppireDataWindow *window, gchar *syntax)
+{
+  execute_const_syntax_string (window, syntax);
+  return syntax;
+}
+
+/* Executes null-terminated string SYNTAX as syntax. */
+void
+execute_const_syntax_string (PsppireDataWindow *window, const gchar *syntax)
+{
+  execute_syntax (window, lex_reader_for_string (syntax));
+}
index 40925beeae6842887341549d0178342ff3934766..d7d5182f15a8b63384f409341be716091effe82f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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
 #define EXECUTOR_H
 
 #include <glib.h>
+#include "ui/gui/psppire-data-window.h"
 
-struct getl_interface;
-
-gboolean execute_syntax (struct getl_interface *sss);
+struct lex_reader;
 
+gboolean execute_syntax (PsppireDataWindow *, struct lex_reader *);
+gchar *execute_syntax_string (PsppireDataWindow *, gchar *syntax);
+void execute_const_syntax_string (PsppireDataWindow *, const gchar *syntax);
 
 #endif
index 61427cc23285f25a928afdae15a664af0a8f120e..c10fa597c18fae9a5f562b5d9f4320bb82e4c781 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -17,7 +17,6 @@
 #include <config.h>
 
 #include "dialog-common.h"
-#include <language/syntax-string-source.h>
 #include <ui/syntax-gen.h>
 #include <libpspp/str.h>
 
@@ -400,22 +399,10 @@ factor_dialog (PsppireDataWindow *dw)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&fd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (dw, generate_syntax (&fd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&fd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&fd)));
       break;
     default:
       break;
index b735d46a765b4b2ea9da9f983ed5764565b8b312..04ecbca22e691536d78ab7c801245ec3d475b9d8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 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
@@ -17,8 +17,6 @@
 #ifndef __FACTOR_DIALOG_H
 #define __FACTOR_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void factor_dialog (PsppireDataWindow * data);
index 1e4125d14e7698dd23e08c9b2a9b2a8cb0b1c293..6782f6bf7e4ccae228cc0e7d5e3199382eb47e9e 100644 (file)
                         <child type="label">
                           <object class="GtkLabel" id="label3">
                             <property name="visible">True</property>
-                            <property name="label" translatable="yes">Analyse</property>
+                            <property name="label" translatable="yes">Analyze</property>
                             <property name="use_markup">True</property>
                           </object>
                         </child>
                                 <property name="layout_style">spread</property>
                                 <child>
                                   <object class="GtkCheckButton" id="unrotated-button">
-                                    <property name="label" translatable="yes">Unrotatated factor solution</property>
+                                    <property name="label" translatable="yes">Unrotated factor solution</property>
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="receives_default">False</property>
index 63604cf496e4a0ccb71329d18376f6571c6f1760..51645d6f62b1073614cb2b51b1ae8a3cdd695b17 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2011  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
@@ -423,7 +423,6 @@ struct comparator
 {
   const struct variable *var;
   enum string_cmp_flags flags;
-  const PsppireDict *dict;
 
   bool (*compare) (const struct comparator *,
                   const union value *);
@@ -498,7 +497,7 @@ string_value_compare (const struct comparator *cmptr,
   g_return_val_if_fail (width > 0, false);
   assert ( ! (cmptr->flags & STR_CMP_LABELS));
 
-  text = value_to_text (*val, cmptr->dict, *var_get_write_format (cmptr->var));
+  text = value_to_text (*val, cmptr->var);
 
   if ( cmptr->flags & STR_CMP_SUBSTR)
     found =  (NULL != g_strstr_len (text, width, ssc->pattern));
@@ -527,7 +526,7 @@ regexp_value_compare (const struct comparator *cmptr,
 
   g_return_val_if_fail (width > 0, false);
 
-  text = value_to_text (*val, cmptr->dict, *var_get_write_format (cmptr->var));
+  text = value_to_text (*val, cmptr->var);
   /* We must remove trailing whitespace, otherwise $ will not match where
      one would expect */
   g_strchomp (text);
@@ -581,7 +580,7 @@ cmptr_value_destroy (struct comparator *cmptr)
 
 
 static struct comparator *
-value_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target)
+value_comparator_create (const struct variable *var, const char *target)
 {
   struct value_comparator *vc = xzalloc (sizeof (*vc));
   struct comparator *cmptr = &vc->parent;
@@ -590,16 +589,14 @@ value_comparator_create (const struct variable *var, const PsppireDict *dict, co
   cmptr->var = var;
   cmptr->compare  = value_compare ;
   cmptr->destroy = cmptr_value_destroy;
-  cmptr->dict = dict;
 
-  text_to_value (target, dict, var, &vc->pattern);
+  text_to_value (target, var, &vc->pattern);
 
   return cmptr;
 }
 
 static struct comparator *
-string_comparator_create (const struct variable *var, const PsppireDict *dict, 
-                         const char *target,
+string_comparator_create (const struct variable *var, const char *target,
                          enum string_cmp_flags flags)
 {
   struct string_comparator *ssc = xzalloc (sizeof (*ssc));
@@ -607,7 +604,6 @@ string_comparator_create (const struct variable *var, const PsppireDict *dict,
 
   cmptr->flags = flags;
   cmptr->var = var;
-  cmptr->dict = dict;
 
   if ( flags & STR_CMP_LABELS)
     cmptr->compare = string_label_compare;
@@ -621,7 +617,7 @@ string_comparator_create (const struct variable *var, const PsppireDict *dict,
 
 
 static struct comparator *
-regexp_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target,
+regexp_comparator_create (const struct variable *var, const char *target,
                          enum string_cmp_flags flags)
 {
   int code;
@@ -630,7 +626,6 @@ regexp_comparator_create (const struct variable *var, const PsppireDict *dict, c
 
   cmptr->flags = flags;
   cmptr->var = var;
-  cmptr->dict = dict;
   cmptr->compare  = (flags & STR_CMP_LABELS)
     ? regexp_label_compare : regexp_value_compare ;
 
@@ -680,16 +675,16 @@ comparator_destroy (struct comparator *cmptr)
 
 
 static struct comparator *
-comparator_factory (const struct variable *var, const PsppireDict *dict, const char *str,
+comparator_factory (const struct variable *var, const char *str,
                    enum string_cmp_flags flags)
 {
   if ( flags & STR_CMP_REGEXP )
-    return regexp_comparator_create (var, dict, str, flags);
+    return regexp_comparator_create (var, str, flags);
 
   if ( flags & (STR_CMP_SUBSTR | STR_CMP_LABELS) )
-    return string_comparator_create (var, dict, str, flags);
+    return string_comparator_create (var, str, flags);
 
-  return value_comparator_create (var, dict, str);
+  return value_comparator_create (var, str);
 }
 
 
@@ -735,7 +730,7 @@ find_value (const struct find_dialog *fd, casenumber current_row,
     casenumber i;
     const struct casenum_iterator *ip = get_iteration_params (fd);
     struct comparator *cmptr =
-      comparator_factory (var, fd->dict, target_string, flags);
+      comparator_factory (var, target_string, flags);
 
     value_init (&val, width);
     if ( ! cmptr)
index bba986bca6c11c9bbb4388255531361538303aa0..65053d57e529b00782e7b9a4b919ac01ce63ddb8 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -18,7 +18,6 @@
 #ifndef FIND_DIALOG_H
 #define FIND_DIALOG_H
 
-#include <glib.h>
 #include "psppire-data-window.h"
 
 /* Pops up the Find dialog box */
index 2bbb5546cdd9bc9dec38664bdab5d4df9f7fc146..016682e432c19ee913a5e73473a2c255425b710e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2010  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -23,7 +23,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -570,21 +569,10 @@ frequencies_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&fd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&fd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&fd);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&fd)));
       break;
     default:
       break;
index 605f1de13195dc8a2f6766786e62d0c09fd585ba..5632ab5e7766617b7f1dd5e0e11d62c12ef62871 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -17,8 +17,6 @@
 #ifndef __FREQUENCIES_DIALOG_H
 #define __FREQUENCIES_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void frequencies_dialog (PsppireDataWindow * data);
index 3a3cbac0657863b1864b72f8306c0a505f5c79d7..9435cb2c1f44ee805f1c4155a90ea7155c31ac2c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -17,8 +17,6 @@
 #ifndef __GOTO_CASE_DIALOG_H
 #define __GOTO_CASE_DIALOG_H
 
-
-#include <gtk/gtk.h>
 #include "psppire-data-window.h"
 
 void goto_case_dialog (PsppireDataWindow * data);
index 1ad77bc96ebf0190a633ca02b70179970980e3fb..09bfe7acae61d81e285ab9762a1b58a93c4c1a8b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009, 2010  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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,7 +31,7 @@
 #include <data/casereader-provider.h>
 #include <libpspp/message.h>
 #include "psppire-syntax-window.h"
-#include <gtk/gtkbuilder.h>
+#include <gtk/gtk.h>
 #include <libpspp/i18n.h>
 
 #include <ctype.h>
 
 #include <gettext.h>
 
-/* Formats a value according to FORMAT
-   The returned string must be freed when no longer required */
+/* Formats a value according to VAR's print format and strips white space
+   appropriately for VAR's type.  That is, if VAR is numeric, strips leading
+   white space (because numbers are right-justified within their fields), and
+   if VAR is string, strips trailing white space (because spaces pad out string
+   values on the right).
+
+   Returns an allocated string.  The returned string must be freed when no
+   longer required. */
 gchar *
-value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format)
+value_to_text (union value v, const struct variable *var)
 {
-  gchar *s = 0;
+  gchar *s;
 
-  s = data_out (&v, dict_get_encoding (dict->dict),  &format);
-  g_strchug (s);
+  s = data_out (&v, var_get_encoding (var), var_get_print_format (var));
+  if (var_is_numeric (var))
+    g_strchug (s);
+  else
+    g_strchomp (s);
 
   return s;
 }
@@ -65,14 +74,12 @@ value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format)
 
    VAL will be initialised and filled by this function.
    It is the caller's responsibility to destroy VAL when no longer needed.
-   VAR and DICT must be the variable and dictionary with which VAL
-   is associated.
+   VAR must be the variable with which VAL is associated.
 
    On success, VAL is returned, NULL otherwise.
 */
 union value *
 text_to_value (const gchar *text,
-              const PsppireDict *dict,
               const struct variable *var,
               union value *val)
 {
@@ -98,7 +105,7 @@ text_to_value (const gchar *text,
 
   value_init (val, width);
   free (data_in (ss_cstr (text), UTF8, format->type, val, width,
-                 dict_get_encoding (dict->dict)));
+                 var_get_encoding (var)));
 
   return val;
 }
@@ -208,9 +215,8 @@ connect_help (GtkBuilder *xml)
       GObject *o = i->data;
       if ( GTK_IS_WIDGET (o) )
        {
-         gchar *name = NULL;
+         const gchar *name = gtk_buildable_get_name (GTK_BUILDABLE (o));
          gchar s[12] = {0};
-         g_object_get (o, "name", &name, NULL);
 
          if ( name)
            strncpy (s, name, 11);
@@ -282,8 +288,8 @@ on_delete (GtkWindow *window, GdkEvent *e, GtkWindow **addr)
   return FALSE;
 }
 
-void
-paste_syntax_to_window (const gchar *syntax)
+char *
+paste_syntax_to_window (gchar *syntax)
 {
   static GtkWidget *the_syntax_pasteboard = NULL;
 
@@ -291,7 +297,7 @@ paste_syntax_to_window (const gchar *syntax)
 
   if ( NULL == the_syntax_pasteboard)
     {
-      the_syntax_pasteboard = psppire_syntax_window_new ();
+      the_syntax_pasteboard = psppire_syntax_window_new (NULL);
       g_signal_connect (the_syntax_pasteboard, "delete-event", G_CALLBACK (on_delete),
                        &the_syntax_pasteboard);
     }
@@ -304,6 +310,8 @@ paste_syntax_to_window (const gchar *syntax)
   gtk_text_buffer_end_user_action (buffer);
 
   gtk_widget_show (the_syntax_pasteboard);
+
+  return syntax;
 }
 
 
index 77abc1d8742214046c794f8ba96fc7694eaa5dce..597fdd78b48171c68098950879b8379491815475 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2009, 2010  Free Software Foundation
+   Copyright (C) 2004, 2009, 2010, 2011  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 "gl/configmake.h"
 
-void paste_syntax_to_window (const gchar *syntax);
+gchar *paste_syntax_to_window (gchar *syntax);
 
 struct fmt_spec;
 
+/* Returns a new GParamSpec for a string.  An attempt to store the empty string
+   in the parameter will be silently translated into storing a null pointer. */
+static inline GParamSpec *
+null_if_empty_param (const gchar *name, const gchar *nick,
+                     const gchar *blurb, const gchar *default_value,
+                     GParamFlags flags)
+{
+  GParamSpec *param;
 
-/* Formats a value according to FORMAT
-   The returned string must be freed when no longer required */
-gchar * value_to_text (union value v, const PsppireDict *dict, struct fmt_spec format);
+  param = g_param_spec_string (name, nick, blurb, default_value, flags);
+  ((GParamSpecString *) param)->null_fold_if_empty = TRUE;
+  return param;
+}
+
+
+gchar * value_to_text (union value v, const struct variable *);
 
 
 union value *
 text_to_value (const gchar *text,
-              const PsppireDict *dict,
               const struct variable *var,
               union value *);
 
diff --git a/src/ui/gui/include/gtk/gtk.in.h b/src/ui/gui/include/gtk/gtk.in.h
new file mode 100644 (file)
index 0000000..83f0b64
--- /dev/null
@@ -0,0 +1,166 @@
+/* Wrapper for <gtk/gtk.h>.
+   Copyright (C) 2011 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 PSPP_GTK_GTK_H
+#define PSPP_GTK_GTK_H
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+#@INCLUDE_NEXT@ @NEXT_GTK_GTK_H@
+
+#if !GTK_CHECK_VERSION(2,20,0)
+/**
+ * gtk_widget_get_realized:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget is realized.
+ *
+ * Return value: %TRUE if @widget is realized, %FALSE otherwise
+ *
+ * Since: 2.20
+ **/
+static inline gboolean
+gtk_widget_get_realized (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return (GTK_WIDGET_FLAGS (widget) & GTK_REALIZED) != 0;
+}
+#endif  /* gtk < 2.20 */
+
+#if !GTK_CHECK_VERSION(2,20,0)
+/**
+ * gtk_widget_get_mapped:
+ * @widget: a #GtkWidget
+ *
+ * Whether the widget is mapped.
+ *
+ * Return value: %TRUE if the widget is mapped, %FALSE otherwise.
+ *
+ * Since: 2.20
+ */
+static inline gboolean
+gtk_widget_get_mapped (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  return (GTK_WIDGET_FLAGS (widget) & GTK_MAPPED) != 0;
+}
+#endif  /* gtk < 2.20 */
+
+#if !GTK_CHECK_VERSION(2,18,0)
+/**
+ * gtk_widget_get_visible:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether the widget is visible. Note that this doesn't
+ * take into account whether the widget's parent is also visible
+ * or the widget is obscured in any way.
+ *
+ * See gtk_widget_set_visible().
+ *
+ * Return value: %TRUE if the widget is visible
+ *
+ * Since: 2.18
+ **/
+static inline gboolean
+gtk_widget_get_visible (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return (GTK_WIDGET_FLAGS (widget) & GTK_VISIBLE) != 0;
+}
+#endif  /* gtk < 2.18 */
+
+#if !GTK_CHECK_VERSION(2,18,0)
+/**
+ * gtk_widget_is_drawable:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget can be drawn to. A widget can be drawn
+ * to if it is mapped and visible.
+ *
+ * Return value: %TRUE if @widget is drawable, %FALSE otherwise
+ *
+ * Since: 2.18
+ **/
+static inline gboolean
+gtk_widget_is_drawable (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return ((GTK_WIDGET_FLAGS (wid) & GTK_VISIBLE) != 0 &&
+          (GTK_WIDGET_FLAGS (wid) & GTK_MAPPED) != 0);
+}
+#endif  /* gtk < 2.18 */
+
+#if !GTK_CHECK_VERSION(2,18,0)
+/**
+ * gtk_widget_has_focus:
+ * @widget: a #GtkWidget
+ *
+ * Determines if the widget has the global input focus. See
+ * gtk_widget_is_focus() for the difference between having the global
+ * input focus, and only having the focus within a toplevel.
+ *
+ * Return value: %TRUE if the widget has the global input focus.
+ *
+ * Since: 2.18
+ **/
+static inline gboolean
+gtk_widget_has_focus (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return GTK_WIDGET_HAS_FOCUS (widget);
+}
+#endif  /* gtk < 2.18 */
+
+#if !GTK_CHECK_VERSION(2,18,0)
+/**
+ * gtk_widget_set_can_focus:
+ * @widget: a #GtkWidget
+ * @can_focus: whether or not @widget can own the input focus.
+ *
+ * Specifies whether @widget can own the input focus. See
+ * gtk_widget_grab_focus() for actually setting the input focus on a
+ * widget.
+ *
+ * Since: 2.18
+ **/
+static inline void
+gtk_widget_set_can_focus (GtkWidget *widget,
+                          gboolean   can_focus)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  if (can_focus != GTK_WIDGET_CAN_FOCUS (widget))
+    {
+      if (can_focus)
+        GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+      else
+        GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
+
+      gtk_widget_queue_resize (widget);
+      g_object_notify (G_OBJECT (widget), "can-focus");
+    }
+}
+#endif  /* gtk < 2.18 */
+
+#endif /* PSPP_GTK_GTK_H */
diff --git a/src/ui/gui/k-related-dialog.c b/src/ui/gui/k-related-dialog.c
new file mode 100644 (file)
index 0000000..fd84900
--- /dev/null
@@ -0,0 +1,173 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2010, 2011  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 "k-related-dialog.h"
+
+#include "psppire-dialog.h"
+#include "psppire-var-view.h"
+#include "psppire-acr.h"
+#include "dialog-common.h"
+
+#include "helper.h"
+#include "executor.h"
+
+
+#include <gtk/gtk.h>
+
+struct k_related_dialog
+{
+  PsppireDict *dict;
+  GtkWidget *var_view;
+
+  GtkWidget *friedman;
+  GtkWidget *kendal;
+  GtkWidget *cochran;
+};
+
+static gboolean
+dialog_state_valid (gpointer data)
+{
+  struct k_related_dialog *krd = data;
+
+  GtkTreeModel *vars =
+    gtk_tree_view_get_model (GTK_TREE_VIEW (krd->var_view));
+
+  /* Tests using less than 3 variables are not useful */
+  if (gtk_tree_model_iter_n_children (vars, NULL) < 3)
+    return FALSE;
+
+  /* At least one checkbutton must be active */
+  if ( 
+      ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->friedman))
+      && 
+      ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->kendal))
+      && 
+      ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->cochran))
+       )
+    return FALSE;
+
+  return TRUE;
+}
+
+
+static void
+refresh (struct k_related_dialog *krd)
+{
+  GtkTreeModel *liststore =
+    gtk_tree_view_get_model (GTK_TREE_VIEW (krd->var_view));
+
+  gtk_list_store_clear (GTK_LIST_STORE (liststore));
+
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (krd->friedman), TRUE);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (krd->kendal), FALSE);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (krd->cochran), FALSE);
+}
+
+
+static char *
+generate_syntax (const struct k_related_dialog *krd)
+{
+  gchar *text;
+  GString *string;
+
+  string = g_string_new ("NPAR TEST");
+
+  if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->friedman)))
+    {
+      g_string_append (string, "\n\t/FRIEDMAN = ");
+      psppire_var_view_append_names (PSPPIRE_VAR_VIEW (krd->var_view), 0, string);
+    }
+
+  if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->kendal)))
+    {
+      g_string_append (string, "\n\t/KENDALL = ");
+      psppire_var_view_append_names (PSPPIRE_VAR_VIEW (krd->var_view), 0, string);
+    }
+
+  if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (krd->cochran)))
+    {
+      g_string_append (string, "\n\t/COCHRAN = ");
+      psppire_var_view_append_names (PSPPIRE_VAR_VIEW (krd->var_view), 0, string);
+    }
+
+  g_string_append (string, ".\n");
+
+  text = string->str;
+
+  g_string_free (string, FALSE);
+
+  return text;
+}
+
+
+
+/* Pops up the K-Related dialog box */
+void
+k_related_dialog (PsppireDataWindow *dw)
+{
+  gint response;
+
+  struct k_related_dialog krd;
+
+  GtkBuilder *xml = builder_new ("k-related.ui");
+  PsppireVarStore *vs;
+
+  GtkWidget *dialog = get_widget_assert   (xml, "k-related-dialog");
+
+  GtkWidget *dict_view = get_widget_assert   (xml, "dict-view");
+
+  g_object_get (dw->data_editor, "var-store", &vs, NULL);
+
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (dw));
+
+  krd.var_view  = get_widget_assert (xml, "variables-treeview");
+
+  krd.friedman =  get_widget_assert (xml, "friedman-checkbutton");
+  krd.kendal =  get_widget_assert (xml, "kendal-checkbutton");
+  krd.cochran =  get_widget_assert (xml, "cochran-checkbutton");
+
+  g_object_get (vs, "dictionary", &krd.dict, NULL);
+  g_object_set (dict_view,
+               "model", krd.dict, 
+               "predicate", var_is_numeric,
+               NULL);
+
+
+  g_signal_connect_swapped (dialog, "refresh", G_CALLBACK (refresh),  &krd);
+
+  psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog),
+                                     dialog_state_valid, &krd);
+
+  response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
+
+
+  switch (response)
+    {
+    case GTK_RESPONSE_OK:
+      g_free (execute_syntax_string (dw, generate_syntax (&krd)));
+      break;
+    case PSPPIRE_RESPONSE_PASTE:
+      g_free (paste_syntax_to_window (generate_syntax (&krd)));
+      break;
+    default:
+      break;
+    }
+
+  g_object_unref (xml);
+}
diff --git a/src/ui/gui/k-related-dialog.h b/src/ui/gui/k-related-dialog.h
new file mode 100644 (file)
index 0000000..73288b6
--- /dev/null
@@ -0,0 +1,25 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 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
+   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 K_RELATED_DIALOG
+#define K_RELATED_DIALOG 1
+
+#include "psppire-data-window.h"
+
+void k_related_dialog (PsppireDataWindow *dw);
+
+
+#endif
diff --git a/src/ui/gui/k-related.ui b/src/ui/gui/k-related.ui
new file mode 100644 (file)
index 0000000..ec12c72
--- /dev/null
@@ -0,0 +1,194 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires psppire 0.0 -->
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="PsppireDialog" id="k-related-dialog">
+    <property name="title" translatable="yes">Tests for Several Related Samples</property>
+    <property name="modal">True</property>
+    <property name="orientation">Vertical</property>
+    <child internal-child="hbox">
+      <object class="GtkVBox" id="dialog-hbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkHBox" id="hbox1">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">automatic</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">in</property>
+                <child>
+                  <object class="PsppireDictView" id="dict-view">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="border_width">5</property>
+                    <property name="headers_visible">False</property>
+                    <property name="headers_clickable">False</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAspectFrame" id="aspectframe1">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="label_yalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="PsppireSelector" id="psppire-selector1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="border_width">5</property>
+                    <property name="source_widget">dict-view</property>
+                    <property name="dest_widget">variables-treeview</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame2">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object 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>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="PsppireVarView" id="variables-treeview">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="border_width">5</property>
+                            <property name="headers_visible">False</property>
+                            <property name="headers_clickable">False</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">_Test Variables:</property>
+                    <property name="use_markup">True</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="label_xalign">0</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkHButtonBox" id="hbuttonbox1">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckButton" id="friedman-checkbutton">
+                        <property name="label" translatable="yes">_Friedman</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="kendal-checkbutton">
+                        <property name="label" translatable="yes">_Kendall's W</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="cochran-checkbutton">
+                        <property name="label" translatable="yes">_Cochran's Q</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="frame">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Test Type</property>
+                <property name="use_markup">True</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="PsppireHButtonBox" id="psppire-hbuttonbox1">
+            <property name="visible">True</property>
+            <property name="border_width">5</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
index 0c88204ae1469347daf7b25347cb4873883f8eec..7e9d4ee51a8960f2d52cb365076888e2eeca715e 100644 (file)
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
+#include "language/lexer/include-path.h"
 #include "libpspp/argv-parser.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
-#include "libpspp/getl.h"
-#include "libpspp/version.h"
 #include "libpspp/copyleft.h"
 #include "libpspp/str.h"
+#include "libpspp/string-array.h"
+#include "libpspp/version.h"
 #include "ui/source-init-opts.h"
 
 #include "gl/configmake.h"
@@ -58,28 +59,10 @@ static const struct argv_option startup_options[N_STARTUP_OPTIONS] =
     {"no-splash", 'q', no_argument, OPT_NO_SPLASH}
   };
 
-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);
-}
-
 static void
 usage (void)
 {
-  char *default_include_path = get_default_include_path ();
+  char *inc_path = string_array_join (include_path_default (), " ");
   GOptionGroup *gtk_options;
   GOptionContext *ctx;
   gchar *gtk_help_base, *gtk_help;
@@ -116,16 +99,16 @@ Language options:\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\
+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\
 A non-option argument is interpreted as a .sav or .por file to load.\n"),
-          program_name, gtk_help, default_include_path);
+          program_name, gtk_help, inc_path);
 
-  free (default_include_path);
+  free (inc_path);
   g_free (gtk_help_base);
 
   emit_bug_reporting_address ();
@@ -202,7 +185,6 @@ quit_one_loop (gpointer data)
 
 struct initialisation_parameters
 {
-  struct source_stream *ss;
   const char *data_file;
   GtkWidget *splash_window;
 };
@@ -212,7 +194,7 @@ static gboolean
 run_inner_loop (gpointer data)
 {
   struct initialisation_parameters *ip = data;
-  initialize (ip->ss, ip->data_file);
+  initialize (ip->data_file);
 
   g_timeout_add (500, hide_splash_window, ip->splash_window);
 
@@ -240,7 +222,6 @@ main (int argc, char *argv[])
   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]);
@@ -264,7 +245,6 @@ main (int argc, char *argv[])
     }
 
 
-  ss = create_source_stream ();
   /* Parse our own options. 
      This must come BEFORE gdk_init otherwise options such as 
      --help --version which ought to work without an X server, won't.
@@ -272,7 +252,7 @@ main (int argc, char *argv[])
   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);
+  source_init_register_argv_parser (parser);
   if (!argv_parser_run (parser, argc, argv))
     exit (EXIT_FAILURE);
   argv_parser_destroy (parser);
@@ -283,7 +263,6 @@ main (int argc, char *argv[])
   gdk_init (&argc, &argv);
 
   init_p.splash_window = create_splash_window ();
-  init_p.ss = ss;
   init_p.data_file = optind < argc ? argv[optind] : NULL;
 
   if ( show_splash )
index 7e04b8548e02fb6cd02602645e2b8fbd99287b59..dbb80a2d585864b27f55b1575b906a1543ba3929 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2006, 2009  Free Software Foundation
+   Copyright (C) 2005, 2006, 2009, 2011  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
@@ -98,7 +98,7 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
              continue;
            }
 
-         if ( text_to_value (text, dialog->dict, dialog->pv, &v))
+         if ( text_to_value (text, dialog->pv, &v))
            {
              nvals++;
              mv_add_value (&dialog->mvl, &v);
@@ -125,9 +125,9 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
       const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
       const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
 
-      if ( text_to_value (low_text, dialog->dict, dialog->pv, &low_val)
+      if ( text_to_value (low_text, dialog->pv, &low_val)
           &&
-          text_to_value (high_text, dialog->dict, dialog->pv, &high_val))
+          text_to_value (high_text, dialog->pv, &high_val))
        {
          if ( low_val.f > high_val.f )
            {
@@ -160,7 +160,6 @@ missing_val_dialog_accept (GtkWidget *w, gpointer data)
        {
          union value discrete_val;
          if ( !text_to_value (discrete_text, 
-                              dialog->dict,
                               dialog->pv,
                               &discrete_val))
            {
@@ -284,16 +283,12 @@ missing_val_dialog_create (GtkWindow *toplevel)
 void
 missing_val_dialog_show (struct missing_val_dialog *dialog)
 {
-  const struct fmt_spec *write_spec ;
-
   gint i;
   g_return_if_fail (dialog);
   g_return_if_fail (dialog->pv);
 
   mv_copy (&dialog->mvl, var_get_missing_values (dialog->pv));
 
-  write_spec = var_get_write_format (dialog->pv);
-
   /* Blank all entry boxes and make them insensitive */
   gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
   gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
@@ -320,8 +315,8 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
       mv_get_range (&dialog->mvl, &low.f, &high.f);
 
 
-      low_text = value_to_text (low, dialog->dict, *write_spec);
-      high_text = value_to_text (high, dialog->dict,  *write_spec);
+      low_text = value_to_text (low, dialog->pv);
+      high_text = value_to_text (high, dialog->pv);
 
       gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
       gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
@@ -331,7 +326,7 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
       if ( mv_has_value (&dialog->mvl))
        {
          gchar *text;
-         text = value_to_text (*mv_get_value (&dialog->mvl, 0), dialog->dict, *write_spec);
+         text = value_to_text (*mv_get_value (&dialog->mvl, 0), dialog->pv);
          gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
          g_free (text);
        }
@@ -352,8 +347,7 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
            {
              gchar *text ;
 
-             text = value_to_text (*mv_get_value (&dialog->mvl, i), dialog->dict,
-                                    *write_spec);
+             text = value_to_text (*mv_get_value (&dialog->mvl, i), dialog->pv);
              gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
              g_free (text);
            }
index 82acf9757f0738eea85ec186a9a51047c18ebad3..2322b84094b5632910efae7dcccfd2e68d0978ec 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005  Free Software Foundation
+   Copyright (C) 2005, 2011  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
@@ -32,9 +32,6 @@ struct missing_val_dialog
   /* The variable whose missing values are to be updated */
   struct variable *pv;
 
-  /* The dictionary to which that value belongs */
-  PsppireDict *dict;
-
   /* local copy */
   struct missing_values mvl;
 
index 0d6f5aa546694fddf4c404427d2582119f61db60..8b91a5134d709274d2f37d8586a0e23871e9434f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -29,7 +29,6 @@
 #include "psppire-selector.h"
 #include "dict-display.h"
 
-#include <language/syntax-string-source.h>
 #include "executor.h"
 
 
@@ -211,22 +210,10 @@ oneway_anova_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&ow);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&ow)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&ow);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&ow)));
       break;
     default:
       break;
index 579a5bedcc3e93404530c05f34e17e538a2af536..d3baad714148dd3dee0ba020328d01bb78ef6595 100644 (file)
           <object class="GtkAction" id="file_print">
             <property name="name">file_print</property>
             <property name="stock-id">gtk-print</property>
+            <property name="label" translatable="yes">_Print...</property>
           </object>
         </child>
         <child>
           <object class="GtkAction" id="file_export">
             <property name="name">file_export</property>
             <property name="stock-id">gtk-convert</property>
-            <property name="label" translatable="yes">_Export</property>
+            <property name="label" translatable="yes">_Export...</property>
           </object>
         </child>
         <child>
index 9796b2d935ea76edcda0f71d7d22d736cbde2116..d06df1444bbe39ceda8375b1b7519897bb0c83ee 100644 (file)
@@ -2,8 +2,10 @@
 Name=GNU PSPP
 GenericName=Statistical Software
 GenericName[de]=Statistiksoftware
+GenericName[lt]=Statistinė programinė įranga
 Comment=Analyze statistical data with a free alternative to SPSS
 Comment[de]= Statistische Daten mit einer freien Alternative zu SPSS analysieren
+Comment[lt]= Statistinių duomenų analizavimas su nemokama SPSS alternatyva 
 Exec=psppire %F
 TryExec=psppire
 Icon=psppicon.png
@@ -11,3 +13,4 @@ StartupNotify=false
 Terminal=false
 Type=Application
 Categories=GTK;Education;Science;Math;
+MimeType=application/x-spss-sav;application/x-spss-por;
index ba38631d22dadbce0c10fcba79ca65609e08ee3b..b58385524a6308001e3e9f2036631c222e8024b7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   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
@@ -43,9 +43,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtktreeselection.h>
+#include <gtk/gtk.h>
 
 
 G_BEGIN_DECLS
index ab7fe3d41bb976f996a4ca27b075c85c564dbdb5..de265e1fcdf32480d767bb231f81f4780db0fcd1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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,7 +19,6 @@
 
 #include <glib.h>
 #include <gtk/gtk.h>
-#include <gtk/gtksignal.h>
 #include "psppire-buttonbox.h"
 #include "psppire-dialog.h"
 
@@ -65,57 +64,85 @@ psppire_button_box_get_type (void)
 }
 
 enum {
-  PROP_BUTTONS = 1
+  PROP_BUTTONS = 1,
+  PROP_DEFAULT = 2
 };
 
+static void
+set_default (PsppireButtonBox *bb)
+{
+  int i;
+
+  for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
+    if (bb->def == (1 << i))
+      {
+        gtk_widget_set_can_default (bb->button[i], TRUE);
+        gtk_widget_grab_default (bb->button[i]);
+      }
+}
+
 static void
 psppire_buttonbox_set_property (GObject         *object,
-                              guint            prop_id,
-                              const GValue    *value,
-                              GParamSpec      *pspec)
+                                guint            prop_id,
+                                const GValue    *value,
+                                GParamSpec      *pspec)
 {
   gint i;
   guint flags;
   PsppireButtonBox *bb = PSPPIRE_BUTTONBOX (object);
-  if ( prop_id != PROP_BUTTONS)
+
+  switch (prop_id)
     {
+    case PROP_BUTTONS:
+      flags = g_value_get_flags (value);
+      for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
+        g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
+      break;
+
+    case PROP_DEFAULT:
+      bb->def = g_value_get_flags (value);
+      if (gtk_widget_get_realized (GTK_WIDGET (bb)))
+        set_default (bb);
+      break;
+
+    default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      return ;
     }
-
-  flags = g_value_get_flags (value);
-
-  for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
-    g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
 }
 
 static void
 psppire_buttonbox_get_property (GObject         *object,
-                              guint            prop_id,
-                              GValue          *value,
-                              GParamSpec      *pspec)
+                                guint            prop_id,
+                                GValue          *value,
+                                GParamSpec      *pspec)
 {
   guint flags = 0;
   gint i;
 
   PsppireButtonBox *bb = PSPPIRE_BUTTONBOX (object);
 
-  if  (PROP_BUTTONS != prop_id)
+  switch (prop_id)
     {
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      return;
-    }
+    case PROP_BUTTONS:
+      for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
+        {
+          gboolean visibility;
+          g_object_get (bb->button[i], "visible", &visibility, NULL);
 
-  for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
-    {
-      gboolean visibility;
-      g_object_get (bb->button[i], "visible", &visibility, NULL);
+          if ( visibility )
+            flags |= (0x01 << i);
+        }
 
-      if ( visibility )
-       flags |= (0x01 << i);
-    }
+      g_value_set_flags (value, flags);
+      break;
+
+    case PROP_DEFAULT:
+      g_value_set_flags (value, bb->def);
 
-  g_value_set_flags (value, flags);
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 
@@ -131,6 +158,7 @@ typedef enum
   } PsppireButtonMask;
 
 static GParamSpec *button_flags;
+static GParamSpec *default_flags;
 
 static void
 psppire_button_box_class_init (PsppireButtonBoxClass *class)
@@ -151,12 +179,20 @@ psppire_button_box_class_init (PsppireButtonBoxClass *class)
                        PSPPIRE_BUTTON_HELP_MASK |
                        PSPPIRE_BUTTON_PASTE_MASK,
                        G_PARAM_READWRITE);
-
-
   g_object_class_install_property (object_class,
                                   PROP_BUTTONS,
                                   button_flags);
 
+  default_flags =
+    g_param_spec_flags ("default",
+                       "Default",
+                       "The mask that decides what what button grabs the default",
+                       PSPPIRE_TYPE_BUTTON_MASK,
+                       0,
+                       G_PARAM_READWRITE);
+  g_object_class_install_property (object_class,
+                                  PROP_DEFAULT,
+                                  default_flags);
 }
 
 static void
@@ -250,11 +286,13 @@ on_realize (GtkWidget *buttonbox, gpointer data)
       g_signal_connect (toplevel, "validity-changed",
                        G_CALLBACK (on_validity_change), buttonbox);
     }
+  set_default (PSPPIRE_BUTTONBOX (buttonbox));
 }
 
 static void
 psppire_button_box_init (PsppireButtonBox *bb)
 {
+  bb->def = PSPPIRE_BUTTON_CONTINUE;
 
   bb->button[PSPPIRE_BUTTON_OK] = gtk_button_new_from_stock (GTK_STOCK_OK);
   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_OK]);
@@ -274,12 +312,6 @@ psppire_button_box_init (PsppireButtonBox *bb)
   bb->button[PSPPIRE_BUTTON_CONTINUE] =
     gtk_button_new_with_mnemonic (_("Continue"));
 
-  GTK_WIDGET_SET_FLAGS (bb->button[PSPPIRE_BUTTON_CONTINUE],
-                       GTK_CAN_DEFAULT);
-
-  g_signal_connect (bb->button[PSPPIRE_BUTTON_CONTINUE], "realize",
-        G_CALLBACK (gtk_widget_grab_default), NULL);
-
   psppire_box_pack_start_defaults (GTK_BOX (bb),
                               bb->button[PSPPIRE_BUTTON_CONTINUE]);
   g_signal_connect (bb->button[PSPPIRE_BUTTON_CONTINUE], "clicked",
@@ -399,7 +431,7 @@ _psppire_button_box_child_requisition (GtkWidget *widget,
       child = children->data;
       children = children->next;
 
-      if (GTK_WIDGET_VISIBLE (child->widget))
+      if (gtk_widget_get_visible (child->widget))
        {
          nchildren += 1;
          gtk_widget_size_request (child->widget, &child_requisition);
index 03f9fe34e6a737e5ae12558a704f80042cd81ce7..654f18144231b04ba5f33c2fbac6636720dbee73 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -21,7 +21,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkbbox.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
@@ -53,6 +53,7 @@ struct _PsppireButtonBox
 
   /* <private> */
   GtkWidget *button[n_PsppireButtonBoxButtons];
+  guint def;
 };
 
 struct _PsppireButtonBoxClass
index 4e7ece0a5a6ce2c1f1c922c5d097ad474ced7367..674577e778a8586d6c41c9ce610b77306dd01095 100644 (file)
@@ -18,7 +18,7 @@
 #include <glib-object.h>
 #include <glib.h>
 
-#include <gtk/gtkwindow.h>
+#include <gtk/gtk.h>
 
 #ifndef __PSPPIRE_CONF_H__
 #define __PSPPIRE_CONF_H__
index 036b9b7746cbabd9cf878662cdc63a435a84e877..1c2442d89398d492990bd61a038dcb16d1aa0445 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 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 <gtk/gtksignal.h>
 #include <gtk/gtk.h>
 #include <gtk-contrib/gtkextra-sheet.h>
 #include "psppire-data-editor.h"
 #include "psppire-var-sheet.h"
+#include "psppire.h"
 
-#include <language/syntax-string-source.h>
 #include "psppire-data-store.h"
 #include <libpspp/i18n.h>
 #include <ui/gui/sheet/psppire-axis.h>
@@ -90,6 +89,7 @@ psppire_data_editor_dispose (GObject *obj)
   if (de->dispose_has_run)
     return;
 
+  g_object_unref (de->data_window);
   g_object_unref (de->data_store);
   g_object_unref (de->var_store);
 
@@ -196,6 +196,7 @@ traverse_cell_callback (PsppireSheet *sheet,
 enum
   {
     PROP_0,
+    PROP_DATA_WINDOW,
     PROP_DATA_STORE,
     PROP_VAR_STORE,
     PROP_VS_ROW_MENU,
@@ -224,6 +225,13 @@ new_data_callback (PsppireDataStore *ds, gpointer data)
       psppire_axis_clear (de->vaxis[i]);
       psppire_axis_append_n (de->vaxis[i], n_cases, DEFAULT_ROW_HEIGHT);
     }
+
+  /* All of the data (potentially) changed, so unselect any selected cell(s) in
+     the data sheets.  If we don't do this, then the sheet remembers the value
+     that was in the selected cell and stores it back, wiping out whatever
+     value there is in the new data.  Bug #30502. */
+  if (de->data_sheet[0] != NULL)
+    psppire_sheet_unselect_range (PSPPIRE_SHEET (de->data_sheet[0]));
 }
 
 static void
@@ -375,6 +383,10 @@ psppire_data_editor_set_property (GObject         *object,
     case PROP_SPLIT_WINDOW:
       psppire_data_editor_split_window (de, g_value_get_boolean (value));
       break;
+    case PROP_DATA_WINDOW:
+      de->data_window = g_value_get_pointer (value);
+      g_object_ref (de->data_window);
+      break;
     case PROP_DATA_STORE:
       if ( de->data_store) g_object_unref (de->data_store);
       de->data_store = g_value_get_pointer (value);
@@ -502,6 +514,9 @@ psppire_data_editor_get_property (GObject         *object,
     case PROP_SPLIT_WINDOW:
       g_value_set_boolean (value, de->split);
       break;
+    case PROP_DATA_WINDOW:
+      g_value_set_pointer (value, de->data_window);
+      break;
     case PROP_DATA_STORE:
       g_value_set_pointer (value, de->data_store);
       break;
@@ -535,6 +550,7 @@ psppire_data_editor_get_property (GObject         *object,
 static void
 psppire_data_editor_class_init (PsppireDataEditorClass *klass)
 {
+  GParamSpec *data_window_spec ;
   GParamSpec *data_store_spec ;
   GParamSpec *var_store_spec ;
   GParamSpec *column_menu_spec;
@@ -557,6 +573,16 @@ psppire_data_editor_class_init (PsppireDataEditorClass *klass)
 
   
 
+  data_window_spec =
+    g_param_spec_pointer ("data-window",
+                         "Data Window",
+                         "A pointer to the data window associated with this editor",
+                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE );
+
+  g_object_class_install_property (object_class,
+                                   PROP_DATA_WINDOW,
+                                   data_window_spec);
+
   data_store_spec =
     g_param_spec_pointer ("data-store",
                          "Data Store",
@@ -1009,13 +1035,15 @@ psppire_data_editor_init (PsppireDataEditor *de)
 
 
 GtkWidget*
-psppire_data_editor_new (PsppireVarStore *var_store,
+psppire_data_editor_new (PsppireDataWindow *data_window,
+                         PsppireVarStore *var_store,
                         PsppireDataStore *data_store)
 {
   return  g_object_new (PSPPIRE_DATA_EDITOR_TYPE,
-                                    "var-store",  var_store,
-                                    "data-store",  data_store,
-                                    NULL);
+                        "data-window", data_window,
+                        "var-store",  var_store,
+                        "data-store",  data_store,
+                        NULL);
 }
 
 
@@ -1247,23 +1275,15 @@ popup_cases_menu (PsppireSheet *sheet, gint row,
 /* Sorting */
 
 static void
-do_sort (PsppireDataStore *ds, int var, gboolean descend)
+do_sort (PsppireDataEditor *de, int var, gboolean descend)
 {
-  GString *string = g_string_new ("SORT CASES BY ");
+  const struct variable *v
+    = psppire_dict_get_variable (de->data_store->dict, var);
+  gchar *syntax;
 
-  const struct variable *v =
-    psppire_dict_get_variable (ds->dict, var);
-
-  g_string_append_printf (string, "%s", var_get_name (v));
-
-  if ( descend )
-    g_string_append (string, " (D)");
-
-  g_string_append (string, ".");
-
-  execute_syntax (create_syntax_string_source (string->str));
-
-  g_string_free (string, TRUE);
+  syntax = g_strdup_printf ("SORT CASES BY %s%s.",
+                            var_get_name (v), descend ? " (D)" : "");
+  g_free (execute_syntax_string (de->data_window, syntax));
 }
 
 
@@ -1275,7 +1295,7 @@ psppire_data_editor_sort_ascending  (PsppireDataEditor *de)
   PsppireSheetRange range;
   psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
 
-  do_sort (de->data_store,  range.col0, FALSE);
+  do_sort (de,  range.col0, FALSE);
 }
 
 
@@ -1287,7 +1307,7 @@ psppire_data_editor_sort_descending (PsppireDataEditor *de)
   PsppireSheetRange range;
   psppire_sheet_get_selected_range (PSPPIRE_SHEET(de->data_sheet[0]), &range);
 
-  do_sort (de->data_store,  range.col0, TRUE);
+  do_sort (de,  range.col0, TRUE);
 }
 
 
@@ -1621,8 +1641,7 @@ data_sheet_set_clip (PsppireSheet *sheet)
     }
 
   /* Construct clip dictionary. */
-  clip_dict = dict_create ();
-  dict_set_encoding (clip_dict, dict_get_encoding (ds->dict->dict));
+  clip_dict = dict_create (dict_get_encoding (ds->dict->dict));
   for (i = col0; i <= coli; i++)
     dict_clone_var_assert (clip_dict, dict_get_var (ds->dict->dict, i));
 
index b5b3f3600a5d490f17bcf606788ec4bee5e738cb..f6f55d7ca5c56c9381dc8dd0b332248eb09738a2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   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
@@ -20,7 +20,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtknotebook.h>
+#include <gtk/gtk.h>
 
 #include <ui/gui/sheet/psppire-axis.h>
 #include "psppire-var-store.h"
@@ -48,6 +48,7 @@ struct _PsppireDataEditor
   GtkWidget *cell_ref_entry;
   GtkWidget *datum_entry;
   GtkWidget *var_sheet;
+  struct _PsppireDataWindow *data_window;
   PsppireDataStore *data_store;
   PsppireVarStore *var_store;
 
@@ -74,7 +75,7 @@ struct _PsppireDataEditorClass
 
 
 GType          psppire_data_editor_get_type        (void);
-GtkWidget*     psppire_data_editor_new             (PsppireVarStore *, PsppireDataStore *);
+GtkWidget*     psppire_data_editor_new             (struct _PsppireDataWindow *, PsppireVarStore *, PsppireDataStore *);
 void           psppire_data_editor_clip_copy       (PsppireDataEditor *);
 void           psppire_data_editor_clip_paste      (PsppireDataEditor *);
 void           psppire_data_editor_clip_cut        (PsppireDataEditor *);
index 9b1b26a21748a41ad1b203d182dc370f96bf9327..2fabf4d5d423466179a4bc6d9c39cb2f33302c46 100644 (file)
@@ -621,7 +621,7 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
         }
     }
 
-  fp = var_get_write_format (pv);
+  fp = var_get_print_format (pv);
 
   text = data_out (&v, dict_get_encoding (dict), fp);
 
@@ -679,7 +679,7 @@ psppire_data_store_set_string (PsppireDataStore *store,
 
   psppire_data_store_data_in (store, row,
                              var_get_case_index (pv), ss_cstr (text),
-                             var_get_write_format (pv));
+                             var_get_print_format (pv));
 
   psppire_sheet_model_range_changed (PSPPIRE_SHEET_MODEL (store), row, col, row, col);
 
index aace66fa5a5947138087bd3656d6bc5c1741be77..be4702d34349ee65a1e4ca47726dc08c262a1c34 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  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 <gtk/gtksignal.h>
-#include <gtk/gtkbox.h>
+#include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include "data/any-reader.h"
-#include "data/procedure.h"
-#include "language/syntax-string-source.h"
+#include "data/dataset.h"
+#include "data/session.h"
+#include "language/lexer/lexer.h"
 #include "libpspp/message.h"
-#include "ui/gui/help-menu.h"
+#include "libpspp/str.h"
+#include "ui/gui/aggregate-dialog.h"
 #include "ui/gui/binomial-dialog.h"
+#include "ui/gui/chi-square-dialog.h"
 #include "ui/gui/comments-dialog.h"
 #include "ui/gui/compute-dialog.h"
 #include "ui/gui/correlation-dialog.h"
-#include "ui/gui/chi-square-dialog.h"
 #include "ui/gui/crosstabs-dialog.h"
 #include "ui/gui/descriptives-dialog.h"
+#include "ui/gui/entry-dialog.h"
 #include "ui/gui/examine-dialog.h"
 #include "ui/gui/executor.h"
 #include "ui/gui/factor-dialog.h"
 #include "ui/gui/find-dialog.h"
 #include "ui/gui/frequencies-dialog.h"
 #include "ui/gui/goto-case-dialog.h"
+#include "ui/gui/help-menu.h"
 #include "ui/gui/helper.h"
+#include "ui/gui/k-related-dialog.h"
 #include "ui/gui/oneway-anova-dialog.h"
 #include "ui/gui/psppire-data-window.h"
 #include "ui/gui/psppire-syntax-window.h"
 #include "ui/gui/t-test-paired-samples.h"
 #include "ui/gui/text-data-import-dialog.h"
 #include "ui/gui/transpose-dialog.h"
-#include "ui/gui/aggregate-dialog.h"
 #include "ui/gui/variable-info-dialog.h"
 #include "ui/gui/weight-cases-dialog.h"
 #include "ui/syntax-gen.h"
 
+#include "gl/c-strcase.h"
+#include "gl/c-strcasestr.h"
+#include "gl/xvasprintf.h"
+
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+struct session *the_session;
+struct ll_list all_data_windows = LL_INITIALIZER (all_data_windows);
 
-
-static void psppire_data_window_base_finalize (PsppireDataWindowClass *, gpointer);
-static void psppire_data_window_base_init     (PsppireDataWindowClass *class);
 static void psppire_data_window_class_init    (PsppireDataWindowClass *class);
 static void psppire_data_window_init          (PsppireDataWindow      *data_editor);
 
 
 static void psppire_data_window_iface_init (PsppireWindowIface *iface);
 
+static void psppire_data_window_dispose (GObject *object);
+static void psppire_data_window_set_property (GObject         *object,
+                                              guint            prop_id,
+                                              const GValue    *value,
+                                              GParamSpec      *pspec);
+static void psppire_data_window_get_property (GObject         *object,
+                                              guint            prop_id,
+                                              GValue          *value,
+                                              GParamSpec      *pspec);
 
 GType
 psppire_data_window_get_type (void)
@@ -87,8 +101,8 @@ psppire_data_window_get_type (void)
       static const GTypeInfo psppire_data_window_info =
        {
          sizeof (PsppireDataWindowClass),
-         (GBaseInitFunc) psppire_data_window_base_init,
-         (GBaseFinalizeFunc) psppire_data_window_base_finalize,
+         NULL,
+         NULL,
          (GClassInitFunc)psppire_data_window_class_init,
          (GClassFinalizeFunc) NULL,
          NULL,
@@ -119,51 +133,28 @@ psppire_data_window_get_type (void)
 
 static GObjectClass *parent_class ;
 
-static void
-psppire_data_window_finalize (GObject *object)
-{
-  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (object);
-
-  g_object_unref (de->builder);
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    (*G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
+enum {
+    PROP_DATASET = 1
+};
 
 static void
 psppire_data_window_class_init (PsppireDataWindowClass *class)
-{
-  parent_class = g_type_class_peek_parent (class);
-}
-
-
-static void
-psppire_data_window_base_init (PsppireDataWindowClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
-  object_class->finalize = psppire_data_window_finalize;
-}
-
+  parent_class = g_type_class_peek_parent (class);
 
+  object_class->dispose = psppire_data_window_dispose;
+  object_class->set_property = psppire_data_window_set_property;
+  object_class->get_property = psppire_data_window_get_property;
 
-static void
-psppire_data_window_base_finalize (PsppireDataWindowClass *class,
-                                  gpointer class_data)
-{
+  g_object_class_install_property (
+    object_class, PROP_DATASET,
+    g_param_spec_pointer ("dataset", "Dataset",
+                          "'struct datset *' represented by the window",
+                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
 }
-
-
 \f
-
-
-extern PsppireVarStore *the_var_store;
-extern struct dataset *the_dataset;
-extern PsppireDataStore *the_data_store ;
-
-extern GtkRecentManager *the_recent_mgr;
-
 static void
 set_paste_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
 {
@@ -184,11 +175,9 @@ set_cut_copy_menuitem_sensitivity (PsppireDataWindow *de, gboolean x)
 
 /* Run the EXECUTE command. */
 static void
-execute (void)
+execute (PsppireDataWindow *dw)
 {
-  struct getl_interface *sss = create_syntax_string_source ("EXECUTE.");
-
-  execute_syntax (sss);
+  execute_const_syntax_string (dw, "EXECUTE.");
 }
 
 static void
@@ -348,165 +337,71 @@ dump_rm (GtkRecentManager *rm)
 }
 #endif
 
-
 static gboolean
-load_file (PsppireWindow *de, const gchar *file_name)
+name_has_por_suffix (const gchar *name)
 {
-  gchar *native_file_name;
-  struct getl_interface *sss;
-  struct string filename;
-
-  ds_init_empty (&filename);
-
-  native_file_name =
-    convert_glib_filename_to_system_filename (file_name, NULL);
-
-  syntax_gen_string (&filename, ss_cstr (native_file_name));
-
-  g_free (native_file_name);
-
-  sss = create_syntax_format_source ("GET FILE=%s.",
-                                    ds_cstr (&filename));
-
-  ds_destroy (&filename);
-
-  if (execute_syntax (sss) )
-    return TRUE;
-
-  return FALSE;
+  size_t length = strlen (name);
+  return length > 4 && !c_strcasecmp (&name[length - 4], ".por");
 }
 
-static GtkWidget *
-sysfile_chooser_dialog (PsppireWindow *toplevel)
+static gboolean
+name_has_sav_suffix (const gchar *name)
 {
-  GtkWidget *dialog =
-    gtk_file_chooser_dialog_new (_("Open"),
-                                GTK_WINDOW (toplevel),
-                                GTK_FILE_CHOOSER_ACTION_OPEN,
-                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-                                NULL);
-
-  GtkFileFilter *filter;
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("Data and Syntax Files"));
-  gtk_file_filter_add_pattern (filter, "*.sav");
-  gtk_file_filter_add_pattern (filter, "*.SAV");
-  gtk_file_filter_add_pattern (filter, "*.por");
-  gtk_file_filter_add_pattern (filter, "*.POR");
-  gtk_file_filter_add_pattern (filter, "*.sps");
-  gtk_file_filter_add_pattern (filter, "*.SPS");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
-  gtk_file_filter_add_pattern (filter, "*.sav");
-  gtk_file_filter_add_pattern (filter, "*.SAV");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
-  gtk_file_filter_add_pattern (filter, "*.por");
-  gtk_file_filter_add_pattern (filter, "*.POR");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
-  gtk_file_filter_add_pattern (filter, "*.sps");
-  gtk_file_filter_add_pattern (filter, "*.SPS");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  filter = gtk_file_filter_new ();
-  gtk_file_filter_set_name (filter, _("All Files"));
-  gtk_file_filter_add_pattern (filter, "*");
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
-
-  {
-    gchar *dir_name;
-    gchar *filename = NULL;
-    g_object_get (toplevel, "filename", &filename, NULL);
-
-    if ( ! g_path_is_absolute (filename))
-      {
-       gchar *path =
-         g_build_filename (g_get_current_dir (), filename, NULL);
-       dir_name = g_path_get_dirname (path);
-       g_free (path);
-      }
-    else
-      {
-       dir_name = g_path_get_dirname (filename);
-      }
-    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
-                                        dir_name);
-    free (dir_name);
-  }
+  size_t length = strlen (name);
+  return length > 4 && !c_strcasecmp (&name[length - 4], ".sav");
+}
 
-  return dialog;
+/* Returns true if NAME has a suffix which might denote a PSPP file */
+static gboolean
+name_has_suffix (const gchar *name)
+{
+  return name_has_por_suffix (name) || name_has_sav_suffix (name);
 }
 
-/* Callback for the data_open action.
-   Prompts for a filename and opens it */
-static void
-open_window (PsppireWindow *de)
+static gboolean
+load_file (PsppireWindow *de, const gchar *file_name)
 {
-  GtkWidget *dialog = sysfile_chooser_dialog (de);
+  struct string filename;
+  gchar *utf8_file_name;
+  const char *mime_type;
+  gchar *syntax;
+  bool ok;
 
-  switch (gtk_dialog_run (GTK_DIALOG (dialog)))
-    {
-    case GTK_RESPONSE_ACCEPT:
-      {
-       gchar *name =
-         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+  ds_init_empty (&filename);
 
-       gchar *sysname = convert_glib_filename_to_system_filename (name, NULL);
+  utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
 
-       if (any_reader_may_open (sysname))
-         psppire_window_load (de, name);
-       else
-         open_new_syntax_window (name);
+  syntax_gen_string (&filename, ss_cstr (utf8_file_name));
 
-       g_free (sysname);
-       g_free (name);
-      }
-      break;
-    default:
-      break;
-    }
+  g_free (utf8_file_name);
 
-  gtk_widget_destroy (dialog);
-}
+  syntax = g_strdup_printf ("GET FILE=%s.", ds_cstr (&filename));
+  ds_destroy (&filename);
 
-/* Returns true if NAME has a suffix which might denote a PSPP file */
-static gboolean
-name_has_suffix (const gchar *name)
-{
-  if ( g_str_has_suffix (name, ".sav"))
-    return TRUE;
-  if ( g_str_has_suffix (name, ".SAV"))
-    return TRUE;
-  if ( g_str_has_suffix (name, ".por"))
-    return TRUE;
-  if ( g_str_has_suffix (name, ".POR"))
-    return TRUE;
-
-  return FALSE;
-}
+  ok = execute_syntax (PSPPIRE_DATA_WINDOW (de),
+                       lex_reader_for_string (syntax));
+  g_free (syntax);
 
+  mime_type = (name_has_por_suffix (file_name)
+               ? "application/x-spss-por"
+               : "application/x-spss-sav");
+  add_most_recent (ds_cstr (&filename), mime_type);
+
+  return ok;
+}
 
 /* Save DE to file */
 static void
 save_file (PsppireWindow *w)
 {
-  gchar *native_file_name = NULL;
-  gchar *file_name = NULL;
+  const gchar *file_name = NULL;
+  gchar *utf8_file_name = NULL;
   GString *fnx;
-  struct getl_interface *sss;
   struct string filename ;
   PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (w);
+  gchar *syntax;
 
-  g_object_get (w, "filename", &file_name, NULL);
+  file_name = psppire_window_get_filename (w);
 
   fnx = g_string_new (file_name);
 
@@ -520,28 +415,20 @@ save_file (PsppireWindow *w)
 
   ds_init_empty (&filename);
 
-  native_file_name =
-    convert_glib_filename_to_system_filename (fnx->str, NULL);
+  utf8_file_name = g_filename_to_utf8 (fnx->str, -1, NULL, NULL, NULL);
 
   g_string_free (fnx, TRUE);
 
-  syntax_gen_string (&filename, ss_cstr (native_file_name));
-  g_free (native_file_name);
+  syntax_gen_string (&filename, ss_cstr (utf8_file_name));
+  g_free (utf8_file_name);
 
-  if ( de->save_as_portable )
-    {
-      sss = create_syntax_format_source ("EXPORT OUTFILE=%s.",
-                                        ds_cstr (&filename));
-    }
-  else
-    {
-      sss = create_syntax_format_source ("SAVE OUTFILE=%s.",
-                                        ds_cstr (&filename));
-    }
+  syntax = g_strdup_printf ("%s OUTFILE=%s.",
+                            de->save_as_portable ? "EXPORT" : "SAVE",
+                            ds_cstr (&filename));
 
   ds_destroy (&filename);
 
-  execute_syntax (sss);
+  g_free (execute_syntax_string (de, syntax));
 }
 
 
@@ -561,47 +448,44 @@ on_insert_variable (PsppireDataWindow *dw)
 static void
 display_dict (PsppireDataWindow *de)
 {
-
-  struct getl_interface *sss =
-    create_syntax_string_source ("DISPLAY DICTIONARY.");
-
-  execute_syntax (sss);
+  execute_const_syntax_string (de, "DISPLAY DICTIONARY.");
 }
 
 static void
 sysfile_info (PsppireDataWindow *de)
 {
-  GtkWidget *dialog = sysfile_chooser_dialog (PSPPIRE_WINDOW (de));
+  GtkWidget *dialog = psppire_window_file_chooser_dialog (PSPPIRE_WINDOW (de));
 
   if  ( GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (dialog)))
     {
       struct string filename;
-      struct getl_interface *sss;
       gchar *file_name =
        gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
-      gchar *native_file_name =
-       convert_glib_filename_to_system_filename (file_name, NULL);
+      gchar *utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL,
+                                                  NULL);
+
+      gchar *syntax;
 
       ds_init_empty (&filename);
 
-      syntax_gen_string (&filename, ss_cstr (native_file_name));
+      syntax_gen_string (&filename, ss_cstr (utf8_file_name));
 
-      g_free (native_file_name);
+      g_free (utf8_file_name);
 
-      sss = create_syntax_format_source ("SYSFILE INFO %s.",
-                                        ds_cstr (&filename));
-      execute_syntax (sss);
+      syntax = g_strdup_printf ("SYSFILE INFO %s.", ds_cstr (&filename));
+      g_free (execute_syntax_string (de, syntax));
     }
 
   gtk_widget_destroy (dialog);
 }
 
 
-/* Callback for data_save_as action. Prompt for a filename and save */
+/* PsppireWindow 'pick_filename' callback: prompt for a filename to save as. */
 static void
-data_save_as_dialog (PsppireDataWindow *de)
+data_pick_filename (PsppireWindow *window)
 {
+  PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (window);
   GtkWidget *button_sys;
   GtkWidget *dialog =
     gtk_file_chooser_dialog_new (_("Save"),
@@ -647,6 +531,9 @@ data_save_as_dialog (PsppireDataWindow *de)
     gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER(dialog), vbox);
   }
 
+  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
+                                                  TRUE);
+
   switch (gtk_dialog_run (GTK_DIALOG (dialog)))
     {
     case GTK_RESPONSE_ACCEPT:
@@ -670,8 +557,6 @@ data_save_as_dialog (PsppireDataWindow *de)
 
        psppire_window_set_filename (PSPPIRE_WINDOW (de), filename->str);
 
-       save_file (PSPPIRE_WINDOW (de));
-
        g_string_free (filename, TRUE);
       }
       break;
@@ -682,35 +567,67 @@ data_save_as_dialog (PsppireDataWindow *de)
   gtk_widget_destroy (dialog);
 }
 
-
-/* Callback for data_save action.
- */
-static void
-data_save (PsppireWindow *de)
+static bool
+confirm_delete_dataset (PsppireDataWindow *de,
+                        const char *old_dataset,
+                        const char *new_dataset,
+                        const char *existing_dataset)
 {
-  const gchar *fn = psppire_window_get_filename (de);
+  GtkWidget *dialog;
+  int result;
 
-  if ( NULL != fn)
-    psppire_window_save (de);
-  else
-    data_save_as_dialog (PSPPIRE_DATA_WINDOW (de));
-}
+  dialog = gtk_message_dialog_new (
+    GTK_WINDOW (de), 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s",
+    _("Delete Existing Dataset?"));
 
+  gtk_message_dialog_format_secondary_text (
+    GTK_MESSAGE_DIALOG (dialog),
+    _("Renaming \"%s\" to \"%s\" will delete destroy the existing "
+      "dataset named \"%s\".  Are you sure that you want to do this?"),
+    old_dataset, new_dataset, existing_dataset);
 
-/* Callback for data_new action.
-   Performs the NEW FILE command */
-static void
-new_file (PsppireDataWindow *de)
-{
-  struct getl_interface *sss =
-    create_syntax_string_source ("NEW FILE.");
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                          GTK_STOCK_DELETE, GTK_RESPONSE_OK,
+                          NULL);
 
-  execute_syntax (sss);
+  g_object_set (dialog, "icon-name", "psppicon", NULL);
 
-  psppire_window_set_filename (PSPPIRE_WINDOW (de), NULL);
-}
+  result = gtk_dialog_run (GTK_DIALOG (dialog));
 
+  gtk_widget_destroy (dialog);
 
+  return result == GTK_RESPONSE_OK;
+}
+
+static void
+on_rename_dataset (PsppireDataWindow *de)
+{
+  struct dataset *ds = de->dataset;
+  struct session *session = dataset_session (ds);
+  const char *old_name = dataset_name (ds);
+  struct dataset *existing_dataset;
+  char *new_name;
+  char *prompt;
+
+  prompt = xasprintf (_("Please enter a new name for dataset \"%s\":"),
+                      old_name);
+  new_name = entry_dialog_run (GTK_WINDOW (de), _("Rename Dataset"), prompt,
+                               old_name);
+  free (prompt);
+
+  if (new_name == NULL)
+    return;
+
+  existing_dataset = session_lookup_dataset (session, new_name);
+  if (existing_dataset == NULL || existing_dataset == ds
+      || confirm_delete_dataset (de, old_name, new_name,
+                                 dataset_name (existing_dataset)))
+    g_free (execute_syntax_string (de, g_strdup_printf ("DATASET NAME %s.",
+                                                        new_name)));
+
+  free (new_name);
+}
 
 static void
 on_edit_paste (PsppireDataWindow  *de)
@@ -819,13 +736,11 @@ toggle_split_window (PsppireDataWindow  *de, GtkToggleAction *ta)
 
 
 static void
-file_quit (void)
+file_quit (PsppireDataWindow *de)
 {
   /* FIXME: Need to be more intelligent here.
      Give the user the opportunity to save any unsaved data.
   */
-  g_object_unref (the_data_store);
-
   psppire_quit ();
 }
 
@@ -843,24 +758,73 @@ on_recent_data_select (GtkMenuShell *menushell,
 
   g_free (uri);
 
-  psppire_window_load (window, file);
+  open_data_window (window, file);
 
   g_free (file);
 }
 
+static char *
+charset_from_mime_type (const char *mime_type)
+{
+  const char *charset;
+  struct string s;
+  const char *p;
+
+  if (mime_type == NULL)
+    return NULL;
+
+  charset = c_strcasestr (mime_type, "charset=");
+  if (charset == NULL)
+    return NULL;
+
+  ds_init_empty (&s);
+  p = charset + 8;
+  if (*p == '"')
+    {
+      /* Parse a "quoted-string" as defined by RFC 822. */
+      for (p++; *p != '\0' && *p != '"'; p++)
+        {
+          if (*p != '\\')
+            ds_put_byte (&s, *p);
+          else if (*++p != '\0')
+            ds_put_byte (&s, *p);
+        }
+    }
+  else
+    {
+      /* Parse a "token" as defined by RFC 2045. */
+      while (*p > 32 && *p < 127 && strchr ("()<>@,;:\\\"/[]?=", *p) == NULL)
+        ds_put_byte (&s, *p++);
+    }
+  if (!ds_is_empty (&s))
+    return ds_steal_cstr (&s);
+
+  ds_destroy (&s);
+  return NULL;
+}
+
 static void
 on_recent_files_select (GtkMenuShell *menushell,   gpointer user_data)
 {
+  GtkRecentInfo *item;
+  char *encoding;
+  GtkWidget *se;
   gchar *file;
 
-  gchar *uri =
-    gtk_recent_chooser_get_current_uri (GTK_RECENT_CHOOSER (menushell));
+  /* Get the file name and its encoding. */
+  item = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (menushell));
+  file = g_filename_from_uri (gtk_recent_info_get_uri (item), NULL, NULL);
+  encoding = charset_from_mime_type (gtk_recent_info_get_mime_type (item));
+  gtk_recent_info_unref (item);
 
-  file = g_filename_from_uri (uri, NULL, NULL);
+  se = psppire_syntax_window_new (encoding);
 
-  g_free (uri);
+  free (encoding);
 
-  open_new_syntax_window (file);
+  if ( psppire_window_load (PSPPIRE_WINDOW (se), file) ) 
+    gtk_widget_show (se);
+  else
+    gtk_widget_destroy (se);
 
   g_free (file);
 }
@@ -904,15 +868,14 @@ on_switch_sheet (GtkNotebook *notebook,
   switch (page_num)
     {
     case PSPPIRE_DATA_EDITOR_VARIABLE_VIEW:
-      gtk_widget_hide (view_variables);
-      gtk_widget_show (view_data);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_variables),
+                                      TRUE);
       gtk_action_set_sensitive (de->insert_variable, TRUE);
       gtk_action_set_sensitive (de->insert_case, FALSE);
       gtk_action_set_sensitive (de->invoke_goto_dialog, FALSE);
       break;
     case PSPPIRE_DATA_EDITOR_DATA_VIEW:
-      gtk_widget_show (view_variables);
-      gtk_widget_hide (view_data);
+      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (view_data), TRUE);
       gtk_action_set_sensitive (de->invoke_goto_dialog, TRUE);
       gtk_action_set_sensitive (de->insert_case, TRUE);
       break;
@@ -949,36 +912,68 @@ connect_action (PsppireDataWindow *dw, const char *action_name,
   return action;
 }
 
+/* Initializes as much of a PsppireDataWindow as we can and must before the
+   dataset has been set.
+
+   In particular, the 'menu' member is required in case the "filename" property
+   is set before the "dataset" property: otherwise PsppireWindow will try to
+   modify the menu as part of the "filename" property_set() function and end up
+   with a Gtk-CRITICAL since 'menu' is NULL.  */
 static void
 psppire_data_window_init (PsppireDataWindow *de)
 {
-  PsppireVarStore *vs;
-  PsppireDict *dict = NULL;
+  GtkUIManager *uim;
+
+  de->builder = builder_new ("data-editor.ui");
+
+  uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
+
+  PSPPIRE_WINDOW (de)->menu =
+    GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
+}
+
+static void
+psppire_data_window_finish_init (PsppireDataWindow *de,
+                                 struct dataset *ds)
+{
+  static const struct dataset_callbacks cbs =
+    {
+      set_unsaved,                    /* changed */
+      transformation_change_callback, /* transformations_changed */
+    };
+
+  PsppireDict *dict;
 
   GtkWidget *menubar;
   GtkWidget *hb ;
   GtkWidget *sb ;
 
   GtkWidget *box = gtk_vbox_new (FALSE, 0);
-  de->builder = builder_new ("data-editor.ui");
+
+  de->dataset = ds;
+  dict = psppire_dict_new_from_dict (dataset_dict (ds));
+  de->var_store = psppire_var_store_new (dict);
+  de->data_store = psppire_data_store_new (dict);
+  psppire_data_store_set_reader (de->data_store, NULL);
 
   menubar = get_widget_assert (de->builder, "menubar");
   hb = get_widget_assert (de->builder, "handlebox1");
   sb = get_widget_assert (de->builder, "status-bar");
 
   de->data_editor =
-    PSPPIRE_DATA_EDITOR (psppire_data_editor_new (the_var_store, the_data_store));
+    PSPPIRE_DATA_EDITOR (psppire_data_editor_new (de, de->var_store,
+                                                  de->data_store));
 
-  g_signal_connect_swapped (the_data_store, "case-changed",
+  g_signal_connect_swapped (de->data_store, "case-changed",
                            G_CALLBACK (set_unsaved), de);
 
-  g_signal_connect_swapped (the_data_store, "case-inserted",
+  g_signal_connect_swapped (de->data_store, "case-inserted",
                            G_CALLBACK (set_unsaved), de);
 
-  g_signal_connect_swapped (the_data_store, "cases-deleted",
+  g_signal_connect_swapped (de->data_store, "cases-deleted",
                            G_CALLBACK (set_unsaved), de);
 
-  dataset_set_callback (the_dataset, set_unsaved, de);
+  dataset_set_callbacks (de->dataset, &cbs, de);
 
   connect_help (de->builder);
 
@@ -1000,17 +995,6 @@ psppire_data_window_init (PsppireDataWindow *de)
   g_signal_connect_swapped (de->data_editor, "data-available-changed",
                            G_CALLBACK (set_paste_menuitem_sensitivity), de);
 
-  dataset_add_transform_change_callback (the_dataset,
-                                        transformation_change_callback,
-                                        de);
-
-
-  vs = the_var_store;
-
-  g_assert(vs); /* Traps a possible bug in w32 build */
-
-  g_object_get (vs, "dictionary", &dict, NULL);
-
   g_signal_connect (dict, "weight-changed",
                    G_CALLBACK (on_weight_change),
                    de);
@@ -1028,15 +1012,17 @@ psppire_data_window_init (PsppireDataWindow *de)
 
   connect_action (de, "edit_cut", G_CALLBACK (on_edit_cut));
 
-  connect_action (de, "file_new_data", G_CALLBACK (new_file));
+  connect_action (de, "file_new_data", G_CALLBACK (create_data_window));
 
   connect_action (de, "file_import-text", G_CALLBACK (text_data_import_assistant));
 
-  connect_action (de, "file_save", G_CALLBACK (data_save));
+  connect_action (de, "file_save", G_CALLBACK (psppire_window_save));
  
-  connect_action (de, "file_open", G_CALLBACK (open_window));
+  connect_action (de, "file_open", G_CALLBACK (psppire_window_open));
+
+  connect_action (de, "file_save_as", G_CALLBACK (psppire_window_save_as));
 
-  connect_action (de, "file_save_as", G_CALLBACK (data_save_as_dialog));
+  connect_action (de, "rename_dataset", G_CALLBACK (on_rename_dataset));
 
   connect_action (de, "file_information_working-file", G_CALLBACK (display_dict));
 
@@ -1126,6 +1112,8 @@ psppire_data_window_init (PsppireDataWindow *de)
   connect_action (de, "chi-square", G_CALLBACK (chisquare_dialog));
 
   connect_action (de, "binomial", G_CALLBACK (binomial_dialog));
+
+  connect_action (de, "k-related-samples", G_CALLBACK (k_related_dialog));
  
 
   {
@@ -1138,11 +1126,11 @@ psppire_data_window_init (PsppireDataWindow *de)
       gtk_ui_manager_get_widget (uim,"/ui/menubar/file/file_recent-files");
 
 
-    GtkWidget *menu_data =
-      gtk_recent_chooser_menu_new_for_manager (the_recent_mgr);
+    GtkWidget *menu_data = gtk_recent_chooser_menu_new_for_manager (
+      gtk_recent_manager_get_default ());
 
-    GtkWidget *menu_files =
-      gtk_recent_chooser_menu_new_for_manager (the_recent_mgr);
+    GtkWidget *menu_files = gtk_recent_chooser_menu_new_for_manager (
+      gtk_recent_manager_get_default ());
 
     {
       GtkRecentFilter *filter = gtk_recent_filter_new ();
@@ -1222,9 +1210,6 @@ psppire_data_window_init (PsppireDataWindow *de)
     GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (de->builder, "uimanager1", GTK_TYPE_UI_MANAGER));
 
     merge_help_menu (uim);
-    
-    PSPPIRE_WINDOW (de)->menu =
-      GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows/windows_minimise_all")->parent);
   }
 
   {
@@ -1254,24 +1239,179 @@ psppire_data_window_init (PsppireDataWindow *de)
 
   gtk_widget_show (GTK_WIDGET (de->data_editor));
   gtk_widget_show (box);
+
+  ll_push_head (&all_data_windows, &de->ll);
+}
+
+static void
+psppire_data_window_dispose (GObject *object)
+{
+  PsppireDataWindow *dw = PSPPIRE_DATA_WINDOW (object);
+
+  if (dw->builder != NULL)
+    {
+      g_object_unref (dw->builder);
+      dw->builder = NULL;
+    }
+
+  if (dw->var_store)
+    {
+      g_object_unref (dw->var_store);
+      dw->var_store = NULL;
+    }
+
+  if (dw->data_store)
+    {
+      g_object_unref (dw->data_store);
+      dw->data_store = NULL;
+    }
+
+  if (dw->ll.next != NULL)
+    {
+      ll_remove (&dw->ll);
+      dw->ll.next = NULL;
+    }
+
+  if (G_OBJECT_CLASS (parent_class)->dispose)
+    G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
+static void
+psppire_data_window_set_property (GObject         *object,
+                                  guint            prop_id,
+                                  const GValue    *value,
+                                  GParamSpec      *pspec)
+{
+  PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
+
+  switch (prop_id)
+    {
+    case PROP_DATASET:
+      psppire_data_window_finish_init (window, g_value_get_pointer (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+static void
+psppire_data_window_get_property (GObject         *object,
+                                  guint            prop_id,
+                                  GValue          *value,
+                                  GParamSpec      *pspec)
+{
+  PsppireDataWindow *window = PSPPIRE_DATA_WINDOW (object);
+
+  switch (prop_id)
+    {
+    case PROP_DATASET:
+      g_value_set_pointer (value, window->dataset);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
 
 GtkWidget*
-psppire_data_window_new (void)
+psppire_data_window_new (struct dataset *ds)
 {
-  return GTK_WIDGET (g_object_new (psppire_data_window_get_type (),
-                                  /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
-                                  "filename", _("PSPP-data"),
-                                  "description", _("Data Editor"),
-                                  NULL));
+  GtkWidget *dw;
+
+  if (the_session == NULL)
+    the_session = session_create ();
+
+  if (ds == NULL)
+    {
+      static int n_datasets;
+      char *dataset_name;
+
+      dataset_name = xasprintf ("DataSet%d", ++n_datasets);
+      ds = dataset_create (the_session, dataset_name);
+      free (dataset_name);
+    }
+  assert (dataset_session (ds) == the_session);
+
+  dw = GTK_WIDGET (
+    g_object_new (
+      psppire_data_window_get_type (),
+      /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
+      "description", _("Data Editor"),
+      "dataset", ds,
+      NULL));
+
+  if (dataset_name (ds) != NULL)
+    g_object_set (dw, "id", dataset_name (ds), (void *) NULL);
+
+  return dw;
 }
 
+bool
+psppire_data_window_is_empty (PsppireDataWindow *dw)
+{
+  return psppire_var_store_get_var_cnt (dw->var_store) == 0;
+}
 
 static void
 psppire_data_window_iface_init (PsppireWindowIface *iface)
 {
   iface->save = save_file;
+  iface->pick_filename = data_pick_filename;
   iface->load = load_file;
 }
+\f
+PsppireDataWindow *
+psppire_default_data_window (void)
+{
+  if (ll_is_empty (&all_data_windows))
+    create_data_window ();
+  return ll_data (ll_head (&all_data_windows), PsppireDataWindow, ll);
+}
+
+void
+psppire_data_window_set_default (PsppireDataWindow *pdw)
+{
+  ll_remove (&pdw->ll);
+  ll_push_head (&all_data_windows, &pdw->ll);
+}
+
+void
+psppire_data_window_undefault (PsppireDataWindow *pdw)
+{
+  ll_remove (&pdw->ll);
+  ll_push_tail (&all_data_windows, &pdw->ll);
+}
+
+PsppireDataWindow *
+psppire_data_window_for_dataset (struct dataset *ds)
+{
+  PsppireDataWindow *pdw;
+
+  ll_for_each (pdw, PsppireDataWindow, ll, &all_data_windows)
+    if (pdw->dataset == ds)
+      return pdw;
+
+  return NULL;
+}
 
+void
+create_data_window (void)
+{
+  gtk_widget_show (psppire_data_window_new (NULL));
+}
+
+void
+open_data_window (PsppireWindow *victim, const char *file_name)
+{
+  GtkWidget *window;
+
+  if (PSPPIRE_IS_DATA_WINDOW (victim)
+      && psppire_data_window_is_empty (PSPPIRE_DATA_WINDOW (victim)))
+    window = GTK_WIDGET (victim);
+  else
+    window = psppire_data_window_new (NULL);
+
+  psppire_window_load (PSPPIRE_WINDOW (window), file_name);
+  gtk_widget_show (window);
+}
index c3bcb84099e3c66bd7043b38b61787547d6b74ec..93b51b0cee9aa7e5f7e973672869de8dd923e620 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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 <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkaction.h>
-#include "psppire-window.h"
-#include "psppire-data-editor.h"
 #include <gtk/gtk.h>
 
+#include "libpspp/ll.h"
+#include "ui/gui/psppire-window.h"
+#include "ui/gui/psppire-data-editor.h"
+
 G_BEGIN_DECLS
 
 #define PSPPIRE_DATA_WINDOW_TYPE            (psppire_data_window_get_type ())
@@ -50,6 +51,9 @@ struct _PsppireDataWindow
   PsppireDataEditor *data_editor;
   GtkBuilder *builder;
 
+  PsppireVarStore *var_store;
+  struct dataset *dataset;
+  PsppireDataStore *data_store;
 
   GtkAction *invoke_goto_dialog;
 
@@ -60,6 +64,10 @@ struct _PsppireDataWindow
 
 
   gboolean save_as_portable;
+
+  struct ll ll;                 /* In global 'all_data_windows' list. */
+  unsigned long int lazy_serial;
+  unsigned int dataset_seqno;
 };
 
 struct _PsppireDataWindowClass
@@ -67,8 +75,21 @@ struct _PsppireDataWindowClass
   PsppireWindowClass parent_class;
 };
 
+extern struct session *the_session;
+extern struct ll_list all_data_windows;
+
 GType      psppire_data_window_get_type        (void);
-GtkWidget* psppire_data_window_new             (void);
+GtkWidget* psppire_data_window_new             (struct dataset *);
+
+PsppireDataWindow *psppire_default_data_window (void);
+void psppire_data_window_set_default (PsppireDataWindow *);
+void psppire_data_window_undefault (PsppireDataWindow *);
+
+PsppireDataWindow *psppire_data_window_for_dataset (struct dataset *);
+
+bool psppire_data_window_is_empty (PsppireDataWindow *);
+void create_data_window (void);
+void open_data_window (PsppireWindow *victim, const char *file_name);
 
 G_END_DECLS
 
index e4d04a1fa3cfecccdb3468c916dbb636e2543f75..e7e0ad042daa1763ce2ff0c5b29242fcad56727d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2010  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -18,8 +18,6 @@
 #include <config.h>
 
 #include <gtk/gtk.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkbuildable.h>
 #include "psppire-dialog.h"
 #include "psppire-buttonbox.h"
 #include "psppire-selector.h"
@@ -296,14 +294,14 @@ static gboolean
 configure_event_callback (GtkDialog *dialog,
                          GdkEvent *event, gpointer data)
 {
-  gchar *base = NULL;
+  const gchar *base;
 
   PsppireConf *conf = psppire_conf_new ();
 
-  if ( ! GTK_WIDGET_MAPPED (dialog))
+  if ( ! gtk_widget_get_mapped (GTK_WIDGET (dialog)))
     return FALSE;
 
-  g_object_get (dialog, "name", &base, NULL);
+  base = gtk_buildable_get_name (GTK_BUILDABLE (dialog));
 
   psppire_conf_save_window_geometry (conf, base, GTK_WINDOW (dialog));
 
@@ -316,9 +314,7 @@ on_realize (GtkWindow *dialog, gpointer data)
 {
   PsppireConf *conf = psppire_conf_new ();
 
-  const gchar *base = NULL;
-
-  g_object_get (dialog, "name", &base, NULL);
+  const gchar *base = gtk_buildable_get_name (GTK_BUILDABLE (dialog));
 
   psppire_conf_set_window_geometry (conf, base, dialog);
 }
index 6c175cfb8a690d0de4632f5daabacfc12bf754e5..a939d0f904becdf74c5650cb5342f790e36075f9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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
@@ -21,7 +21,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkwindow.h>
+#include <gtk/gtk.h>
 
 
 #define PSPPIRE_RESPONSE_PASTE 1
index d19fc809edccf68c8cde11f01f0c6dc8172030b6..91bfed2597be89d297be3c00c7c4d36a021945d6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2006, 2007, 2009  Free Software Foundation
+   Copyright (C) 2004, 2006, 2007, 2009, 2010, 2011  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
@@ -23,6 +23,7 @@
 #include <gtk/gtk.h>
 
 #include "data/dictionary.h"
+#include "data/identifier.h"
 #include "data/missing-values.h"
 #include "data/value-labels.h"
 #include "data/variable.h"
@@ -425,7 +426,7 @@ psppire_dict_set_name (PsppireDict* d, gint idx, const gchar *name)
   g_assert (d);
   g_assert (PSPPIRE_IS_DICT (d));
 
-  if ( ! var_is_valid_name (name, false))
+  if ( ! dict_id_is_valid (d->dict, name, false))
     return FALSE;
 
   if ( idx < dict_get_var_cnt (d->dict))
@@ -527,7 +528,7 @@ gboolean
 psppire_dict_check_name (const PsppireDict *dict,
                         const gchar *name, gboolean report)
 {
-  if ( ! var_is_valid_name (name, report ) )
+  if ( ! dict_id_is_valid (dict->dict, name, report ) )
     return FALSE;
 
   if (psppire_dict_lookup_var (dict, name))
@@ -835,7 +836,7 @@ gboolean
 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
                         const gchar *name)
 {
-  if ( ! var_is_valid_name (name, false))
+  if ( ! dict_id_is_valid (dict->dict, name, false))
     return FALSE;
 
   /* Make sure no other variable has this name */
index 4d56eda9052318128e2b6575edfe296b6226dbd8..baccea7b6b49108d5d07215ee2247bc03951f0f7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <gtk/gtktreeview.h>
+#include <gtk/gtk.h>
 #include "psppire-dictview.h"
 #include "psppire-dict.h"
 #include "psppire-conf.h"
@@ -344,7 +344,7 @@ var_icon_cell_data_func (GtkTreeViewColumn *col,
     }
   else
     {
-      const struct fmt_spec *fs = var_get_write_format (var);
+      const struct fmt_spec *fs = var_get_print_format (var);
       int cat = fmt_get_category (fs->type);
       switch ( var_get_measure (var))
        {
index dd08d78f125ce2f735dc2b10193b4b9c637e5296..1a8ddbb9235d1708ee4de4dbefb09f738bcbbfff 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 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
@@ -21,7 +21,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtktreeview.h>
+#include <gtk/gtk.h>
 
 #include "psppire-dict.h"
 #include "dict-display.h"
diff --git a/src/ui/gui/psppire-encoding-selector.c b/src/ui/gui/psppire-encoding-selector.c
new file mode 100644 (file)
index 0000000..2e861df
--- /dev/null
@@ -0,0 +1,255 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 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 "ui/gui/psppire-encoding-selector.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+
+#include "gl/c-strcase.h"
+#include "gl/localcharset.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+enum
+  {
+    COL_DESCRIPTION,
+    COL_ENCODING
+  };
+
+static void SENTINEL (0)
+add_encodings (GtkTreeStore *store, const char *category, ...)
+{
+  const char *encodings[16];
+  va_list args;
+  int n;
+
+  /* Count encoding arguments. */
+  va_start (args, category);
+  n = 0;
+  while ((encodings[n] = va_arg (args, const char *)) != NULL)
+    {
+      const char *encoding = encodings[n];
+      if (!strcmp (encoding, "Auto") || is_encoding_supported (encoding))
+        n++;
+    }
+  assert (n < sizeof encodings / sizeof *encodings);
+  va_end (args);
+
+  if (n == 0)
+    return;
+
+  va_start (args, category);
+  if (n == 1)
+    {
+      char *description;
+
+      if (strcmp (encodings[0], "Auto"))
+        description = xasprintf ("%s (%s)", category, encodings[0]);
+      else
+        description = xstrdup (category);
+
+      gtk_tree_store_insert_with_values (
+        store, NULL, NULL, G_MAXINT,
+        COL_DESCRIPTION, description,
+        COL_ENCODING, encodings[0],
+        -1);
+
+      free (description);
+    }
+  else
+    {
+      GtkTreeIter head;
+      int i;
+
+      gtk_tree_store_insert_with_values (
+        store, &head, NULL, G_MAXINT,
+        COL_DESCRIPTION, category,
+        -1);
+
+      for (i = 0; i < n; i++)
+        gtk_tree_store_insert_with_values (
+          store, NULL, &head, G_MAXINT,
+          COL_DESCRIPTION, encodings[i],
+          COL_ENCODING, encodings[i],
+          -1);
+    }
+  va_end (args);
+}
+
+static void
+set_sensitive (GtkCellLayout   *cell_layout,
+               GtkCellRenderer *cell,
+               GtkTreeModel    *tree_model,
+               GtkTreeIter     *iter,
+               gpointer         data)
+{
+  gboolean sensitive;
+
+  sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
+  g_object_set (cell, "sensitive", sensitive, NULL);
+}
+
+struct find_default_encoding_aux
+  {
+    const char *default_encoding;
+    GtkTreeIter iter;
+  };
+
+static gboolean
+find_default_encoding (GtkTreeModel *model,
+                       GtkTreePath *path,
+                       GtkTreeIter *iter,
+                       gpointer aux_)
+{
+  struct find_default_encoding_aux *aux = aux_;
+  gchar *encoding;
+  gboolean found;
+
+  gtk_tree_model_get (model, iter, COL_ENCODING, &encoding, -1);
+  found = encoding != NULL && !c_strcasecmp (encoding, aux->default_encoding);
+  if (found)
+    aux->iter = *iter;
+  g_free (encoding);
+  return found;
+}
+
+GtkWidget *
+psppire_encoding_selector_new (const char *default_encoding,
+                               gboolean allow_auto)
+{
+  struct find_default_encoding_aux aux;
+  GtkCellRenderer *renderer;
+  GtkWidget *hbox;
+  GtkWidget *combo_box;
+  GtkTreeStore *store;
+
+  store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+
+  if (allow_auto)
+    add_encodings (store, _("Automatically Detect"), "Auto", NULL_SENTINEL);
+  add_encodings (store, _("Locale Encoding"), locale_charset (),
+                 NULL_SENTINEL);
+  add_encodings (store, "Unicode", "UTF-8", "UTF-16", "UTF-16BE", "UTF-16LE",
+                 "UTF-32", "UTF-32BE", "UTF-32LE", NULL_SENTINEL);
+  add_encodings (store, _("Arabic"), "IBM864", "ISO-8859-6", "Windows-1256",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Armenian"), "ARMSCII-8", NULL_SENTINEL);
+  add_encodings (store, _("Baltic"), "ISO-8859-13", "ISO-8859-4",
+                 "Windows-1257", NULL_SENTINEL);
+  add_encodings (store, _("Celtic"), "ISO-8859-14", NULL_SENTINEL);
+  add_encodings (store, _("Central European"), "IBM852", "ISO-8859-2",
+                 "Mac-CentralEurope", "Windows-1250", NULL_SENTINEL);
+  add_encodings (store, _("Chinese Simplified"), "GB18030", "GB2312", "GBK",
+                 "HZ-GB-2312", "ISO-2022-CN", NULL_SENTINEL);
+  add_encodings (store, _("Chinese Traditional"), "Big5", "Big5-HKSCS",
+                 "EUC-TW", NULL_SENTINEL);
+  add_encodings (store, _("Croatian"), "MacCroatian", NULL_SENTINEL);
+  add_encodings (store, _("Cyrillic"), "IBM855", "ISO-8859-5", "ISO-IR-111",
+                 "KOI8-R", "MacCyrillic", NULL_SENTINEL);
+  add_encodings (store, _("Cyrillic/Russian"), "IBM866", NULL_SENTINEL);
+  add_encodings (store, _("Cyrillic/Ukrainian"), "KOI8-U", "MacUkrainian",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Georgian"), "GEOSTD8", NULL_SENTINEL);
+  add_encodings (store, _("Greek"), "ISO-8859-7", "MacGreek", NULL_SENTINEL);
+  add_encodings (store, _("Gujarati"), "MacGujarati", NULL_SENTINEL);
+  add_encodings (store, _("Gurmukhi"), "MacGurmukhi", NULL_SENTINEL);
+  add_encodings (store, _("Hebrew"), "IBM862", "ISO-8859-8-I", "Windows-1255",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Hebrew Visual"), "ISO-8859-8", NULL_SENTINEL);
+  add_encodings (store, _("Hindi"), "MacDevangari", NULL_SENTINEL);
+  add_encodings (store, _("Icelandic"), "MacIcelandic", NULL_SENTINEL);
+  add_encodings (store, _("Japanese"), "EUC-JP", "ISO-2022-JP", "Shift_JIS",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Korean"), "EUC-KR", "ISO-2022-KR", "JOHAB", "UHC",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Nordic"), "ISO-8859-10", NULL_SENTINEL);
+  add_encodings (store, _("Romanian"), "ISO-8859-16", "MacRomanian",
+                 NULL_SENTINEL);
+  add_encodings (store, _("South European"), "ISO-8859-3", NULL_SENTINEL);
+  add_encodings (store, _("Thai"), "ISO-8859-11", "TIS-620", "Windows-874",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Turkish"), "IBM857", "ISO-8859-9", "Windows-1254",
+                 NULL_SENTINEL);
+  add_encodings (store, _("Vietnamese"), "TVCN", "VISCII", "VPS",
+                 "Windows-1258", NULL_SENTINEL);
+  add_encodings (store, _("Western European"), "ISO-8859-1", "ISO-8859-15",
+                 "Windows-1252", "IBM850", "MacRoman", NULL_SENTINEL);
+
+  combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+
+  aux.default_encoding = default_encoding ? default_encoding : "Auto";
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &aux.iter);
+  gtk_tree_model_foreach (GTK_TREE_MODEL (store), find_default_encoding, &aux);
+  gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &aux.iter);
+
+  g_object_unref (store);
+
+  renderer = gtk_cell_renderer_text_new ();
+  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
+                                  "text", COL_DESCRIPTION,
+                                  NULL);
+  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
+                                      renderer, set_sensitive,
+                                      NULL, NULL);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox),
+                      gtk_label_new (_("Character Encoding: ")),
+                      FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, TRUE, 0);
+  gtk_widget_show_all (hbox);
+
+  return hbox;
+}
+
+gchar *
+psppire_encoding_selector_get_encoding (GtkWidget *selector)
+{
+  gchar *encoding = NULL;
+  GList *list, *pos;
+
+  list = gtk_container_get_children (GTK_CONTAINER (selector));
+  for (pos = list; pos; pos = pos->next)
+    {
+      GtkWidget *widget = pos->data;
+      if (GTK_IS_COMBO_BOX (widget))
+        {
+          GtkTreeModel *model;
+          GtkTreeIter iter;
+
+          if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
+            break;
+
+          model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+          gtk_tree_model_get (model, &iter, COL_ENCODING, &encoding, -1);
+          break;
+        }
+    }
+  g_list_free (list);
+  return encoding;
+}
diff --git a/src/ui/gui/psppire-encoding-selector.h b/src/ui/gui/psppire-encoding-selector.h
new file mode 100644 (file)
index 0000000..107f871
--- /dev/null
@@ -0,0 +1,26 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2011 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 PSPPIRE_ENCODING_SELECTOR_H
+#define PSPPIRE_ENCODING_SELECTOR_H 1
+
+#include <gtk/gtk.h>
+
+GtkWidget *psppire_encoding_selector_new (const char *default_encoding,
+                                          gboolean allow_auto);
+gchar *psppire_encoding_selector_get_encoding (GtkWidget *selector);
+
+#endif /* PSPPIRE_ENCODING_SELECTOR_H */
index 3332a354b93126d178b840dd9e05519555514446..2d036a415630df7621df1afd9df9de4a0a14117c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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 <glib.h>
 #include <gtk/gtk.h>
-#include <gtk/gtksignal.h>
 #include "psppire-hbuttonbox.h"
 #include "psppire-dialog.h"
 
-#include <gtk/gtkbbox.h>
-
 #include <gettext.h>
 
 #define _(msgid) gettext (msgid)
@@ -246,7 +243,7 @@ gtk_hbutton_box_size_allocate (GtkWidget     *widget,
       child = children->data;
       children = children->next;
 
-      if (GTK_WIDGET_VISIBLE (child->widget))
+      if (gtk_widget_get_visible (child->widget))
        {
          child_allocation.width = child_width;
          child_allocation.height = child_height;
index 23ddccb550aa1c5648c0099f93f8ce8612028883..6f7865eb770afd775187a6cef0e4f10de5a0292c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2010, 2011 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 <gtk/gtksignal.h>
-#include <gtk/gtktable.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtklabel.h>
+#include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 #include "psppire-keypad.h"
 
@@ -220,7 +217,7 @@ key_release_callback (GtkWidget   *widget,
                      GdkEventKey *event,
                      gpointer     user_data)
 {
-  if ( ! (GTK_WIDGET_FLAGS (widget) & GTK_HAS_FOCUS) )
+  if ( ! gtk_widget_has_focus (widget))
     return FALSE;
 
   switch (event->keyval)
index 97938fb84a858615b3d24d59a52743dc220ea732..553dbf7e596bbc8b91b219420d65fd7dd099b556 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   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
@@ -49,8 +49,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkeventbox.h>
-#include <gtk/gtktable.h>
+#include <gtk/gtk.h>
 
 
 G_BEGIN_DECLS
index 4bf8ce5b287918488249cd7df3af47448047d89d..cf65a2f9e6c518c7dbd7b6581a0808b10ea06c92 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  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
@@ -29,6 +29,7 @@
 #include "output/cairo.h"
 #include "output/chart-item.h"
 #include "output/driver-provider.h"
+#include "output/message-item.h"
 #include "output/output-item.h"
 #include "output/tab.h"
 #include "output/table-item.h"
@@ -149,6 +150,7 @@ struct psppire_output_driver
     struct output_driver driver;
     PsppireOutputWindow *viewer;
     struct xr_driver *xr;
+    int font_height;
   };
 
 static struct output_driver_class psppire_output_class;
@@ -222,8 +224,10 @@ psppire_output_submit (struct output_driver *this,
     {
       const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (viewer));
       struct string_map options = STRING_MAP_INITIALIZER (options);
+      struct text_item *text_item;
       PangoFontDescription *font_desc;
       char *font_name;
+      int font_width;
 
       /* Use GTK+ default font as proportional font. */
       font_name = pango_font_description_to_string (style->font_desc);
@@ -252,7 +256,15 @@ psppire_output_submit (struct output_driver *this,
       pod->xr = xr_driver_create (cr, &options);
 
       string_map_destroy (&options);
+
+      text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X");
+      r = xr_rendering_create (pod->xr, text_item_super (text_item), cr);
+      xr_rendering_measure (r, &font_width, &pod->font_height);
+      /* xr_rendering_destroy (r); */
+      text_item_unref (text_item);
     }
+  else
+    pod->viewer->y += pod->font_height / 2;
 
   r = xr_rendering_create (pod->xr, item, cr);
   if (r == NULL)
@@ -294,6 +306,13 @@ psppire_output_submit (struct output_driver *this,
       ds_clear (&title);
       if (is_text_item (item))
         ds_put_cstr (&title, text_item_get_text (to_text_item (item)));
+      else if (is_message_item (item))
+        {
+          const struct message_item *msg_item = to_message_item (item);
+          const struct msg *msg = message_item_get_msg (msg_item);
+          ds_put_format (&title, "%s: %s", _("Message"),
+                         msg_severity_to_string (msg->severity));
+        }
       else if (is_table_item (item))
         {
           const char *caption = table_item_get_caption (to_table_item (item));
@@ -472,7 +491,7 @@ on_combo_change (GtkFileChooser *chooser)
   int x = 0; 
   gchar *fn = gtk_file_chooser_get_filename (chooser);
 
-  if (combo &&  GTK_WIDGET_REALIZED (combo))
+  if (combo &&  gtk_widget_get_realized (combo))
     x = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
 
   if (fn == NULL)
@@ -508,7 +527,7 @@ on_file_chooser_change (GObject *w, GParamSpec *pspec, gpointer data)
   GtkFileChooser *chooser = data;
   const gchar *name = g_param_spec_get_name (pspec);
 
-  if ( ! GTK_WIDGET_REALIZED (chooser))
+  if ( ! gtk_widget_get_realized (GTK_WIDGET (chooser)))
     return;
 
   /* Ignore this one.  It causes recursion. */
index c242e732881f4076e179da6a618b1b04352f463b..7ceaee7f06728d733381de1eaf35755bcec2bf1e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009  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 <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkaction.h>
-#include <gtk/gtktextbuffer.h>
+#include <gtk/gtk.h>
 #include "psppire-window.h"
 #include "psppire.h"
-#include <gtk/gtk.h>
 
 extern int viewer_length;
 extern int viewer_width ;
index c46abcee67de7de95804651cb45f359bf3cea66c..b9d0eba6f1549dca17d5a1d593288a7fa43108cc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 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
@@ -17,7 +17,7 @@
 
 #include <config.h>
 #include "psppire-select-dest.h"
-#include <gtk/gtkwidget.h>
+#include <gtk/gtk.h>
 
 GType
 psppire_select_dest_widget_get_type (void)
index 74d2bffcfbff15be6faa182b011f67836045727e..135bac9958191065ea5c48bc3aa2cd1d8f7b26c9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009 Free Software Foundation
+   Copyright (C) 2007, 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 "psppire-dict.h"
 #include "psppire-select-dest.h"
 
-#include <gtk/gtksignal.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtkentry.h>
+#include <gtk/gtk.h>
 
 #include "psppire-selector.h"
 
-#include <gtk/gtktreeview.h>
-#include <gtk/gtktreeselection.h>
-#include <gtk/gtktextview.h>
-#include <gtk/gtkwidget.h>
-
 static void psppire_selector_base_finalize (PsppireSelectorClass *, gpointer);
 static void psppire_selector_base_init     (PsppireSelectorClass *class);
 static void psppire_selector_class_init    (PsppireSelectorClass *class);
index bb267cd49cf08631a02e5cfd07e19cf54f31df4a..028af187ea6b3cf2e21224b13c711f59c1cc798a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 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 <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkbutton.h>
-#include <gtk/gtkaction.h>
-#include <gtk/gtkarrow.h>
-#include <gtk/gtktreemodel.h>
-#include <gtk/gtktreemodelfilter.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
index c7251a1ab77206c9772df3f377b408708ef67ad3..b5cf0d3345d27cc45474bcc24e3cbe53c6562c0c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  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 "relocatable.h"
-
-#include <gtk/gtksignal.h>
-#include <gtk/gtkbox.h>
-#include "executor.h"
-#include "helper.h"
+#include <gtk/gtk.h>
+#include <stdlib.h>
 
 #include <gtksourceview/gtksourcebuffer.h>
 #include <gtksourceview/gtksourcelanguage.h>
 #include <gtksourceview/gtksourcelanguagemanager.h>
 #include <gtksourceview/gtksourceprintcompositor.h>
 
-#include <libpspp/message.h>
-#include <stdlib.h>
-
-#include "psppire.h"
-
-#include "psppire-data-window.h"
-#include "psppire-window-register.h"
-#include "psppire.h"
-#include "help-menu.h"
-#include "psppire-syntax-window.h"
-#include "syntax-editor-source.h"
-#include <language/lexer/lexer.h>
 
-#include "xalloc.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/encoding-guesser.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/help-menu.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-encoding-selector.h"
+#include "ui/gui/psppire-syntax-window.h"
+#include "ui/gui/psppire-syntax-window.h"
+#include "ui/gui/psppire-window-register.h"
+#include "ui/gui/psppire.h"
+#include "ui/gui/psppire.h"
+
+#include "gl/localcharset.h"
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
@@ -56,6 +57,53 @@ static void psppire_syntax_window_init          (PsppireSyntaxWindow      *synta
 static void psppire_syntax_window_iface_init (PsppireWindowIface *iface);
 
 
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_ENCODING
+};
+
+static void
+psppire_syntax_window_set_property (GObject         *object,
+                                    guint            prop_id,
+                                    const GValue    *value,
+                                    GParamSpec      *pspec)
+{
+  PsppireSyntaxWindow *window = PSPPIRE_SYNTAX_WINDOW (object);
+
+  switch (prop_id)
+    {
+    case PROP_ENCODING:
+      g_free (window->encoding);
+      window->encoding = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
+
+static void
+psppire_syntax_window_get_property (GObject         *object,
+                                    guint            prop_id,
+                                    GValue          *value,
+                                    GParamSpec      *pspec)
+{
+  PsppireSyntaxWindow *window = PSPPIRE_SYNTAX_WINDOW (object);
+
+  switch (prop_id)
+    {
+    case PROP_ENCODING:
+      g_value_set_string (value, window->encoding);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    };
+}
+
 GType
 psppire_syntax_window_get_type (void)
 {
@@ -116,6 +164,9 @@ psppire_syntax_window_dispose (GObject *obj)
   if (sw->dispose_has_run)
     return;
 
+  g_free (sw->encoding);
+  sw->encoding = NULL;
+
   clip_selection = gtk_widget_get_clipboard (GTK_WIDGET (sw), GDK_SELECTION_CLIPBOARD);
   clip_primary =   gtk_widget_get_clipboard (GTK_WIDGET (sw), GDK_SELECTION_PRIMARY);
 
@@ -135,6 +186,7 @@ psppire_syntax_window_dispose (GObject *obj)
 static void
 psppire_syntax_window_class_init (PsppireSyntaxWindowClass *class)
 {
+  GParamSpec *encoding_spec;
   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
   GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default ();
@@ -159,9 +211,22 @@ psppire_syntax_window_class_init (PsppireSyntaxWindowClass *class)
 
   g_strfreev (new_paths);
 
+  encoding_spec =
+    null_if_empty_param ("encoding",
+                         "Character encoding",
+                         "IANA character encoding in this syntax file",
+                        NULL,
+                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
+
   parent_class = g_type_class_peek_parent (class);
 
+  gobject_class->set_property = psppire_syntax_window_set_property;
+  gobject_class->get_property = psppire_syntax_window_get_property;
   gobject_class->dispose = psppire_syntax_window_dispose;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ENCODING,
+                                   encoding_spec);
 }
 
 
@@ -186,13 +251,16 @@ editor_execute_syntax (const PsppireSyntaxWindow *sw, GtkTextIter start,
                       GtkTextIter stop)
 {
   PsppireWindow *win = PSPPIRE_WINDOW (sw);
-  const gchar *name = psppire_window_get_filename (win);
-  execute_syntax (create_syntax_editor_source (GTK_TEXT_BUFFER (sw->buffer), start, stop, name));
-}
+  struct lex_reader *reader;
+  gchar *text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (sw->buffer), &start, &stop, FALSE);
+  reader = lex_reader_for_string (text);
+  g_free (text);
 
+  lex_reader_set_file_name (reader, psppire_window_get_filename (win));
 
+  execute_syntax (psppire_default_data_window (), reader);
+}
 \f
-
 /* Delete the currently selected text */
 static void
 on_edit_delete (PsppireSyntaxWindow *sw)
@@ -477,6 +545,7 @@ save_editor_to_file (PsppireSyntaxWindow *se,
                     GError **err)
 {
   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (se->buffer);
+  struct substring text_locale;
   gboolean result ;
   GtkTextIter start, stop;
   gchar *text;
@@ -491,8 +560,13 @@ save_editor_to_file (PsppireSyntaxWindow *se,
 
   text = gtk_text_buffer_get_text (buffer, &start, &stop, FALSE);
 
-  result =  g_file_set_contents (suffixedname, text, -1, err);
+  text_locale = recode_substring_pool (se->encoding, "UTF-8", ss_cstr (text),
+                                       NULL);
 
+  result =  g_file_set_contents (suffixedname, ss_data (text_locale),
+                                 ss_length (text_locale), err);
+
+  ss_dealloc (&text_locale);
   g_free (suffixedname);
 
   if ( result )
@@ -509,10 +583,12 @@ save_editor_to_file (PsppireSyntaxWindow *se,
 }
 
 
-/* Callback for the File->SaveAs menuitem */
+/* PsppireWindow 'pick_Filename' callback. */
 static void
-syntax_save_as (PsppireWindow *se)
+syntax_pick_filename (PsppireWindow *window)
 {
+  PsppireSyntaxWindow *se = PSPPIRE_SYNTAX_WINDOW (window);
+  const char *default_encoding;
   GtkFileFilter *filter;
   gint response;
 
@@ -537,44 +613,47 @@ syntax_save_as (PsppireWindow *se)
 
   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
                                                  TRUE);
+
+  default_encoding = se->encoding != NULL ? se->encoding : locale_charset ();
+  gtk_file_chooser_set_extra_widget (
+    GTK_FILE_CHOOSER (dialog),
+    psppire_encoding_selector_new (default_encoding, false));
+
   response = gtk_dialog_run (GTK_DIALOG (dialog));
 
   if ( response == GTK_RESPONSE_ACCEPT )
     {
-      GError *err = NULL;
-      char *filename =
-       gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
-
-      if ( ! save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err) )
-       {
-         msg ( ME, "%s", err->message );
-         g_error_free (err);
-       }
+      gchar *encoding;
+      char *filename;
 
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog) );
+      psppire_window_set_filename (window, filename);
       free (filename);
+
+      encoding = psppire_encoding_selector_get_encoding (
+        gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
+      if (encoding != NULL)
+        {
+          g_free (se->encoding);
+          se->encoding = encoding;
+        }
     }
 
   gtk_widget_destroy (dialog);
 }
 
 
-/* Callback for the File->Save menuitem */
+/* PsppireWindow 'save' callback. */
 static void
 syntax_save (PsppireWindow *se)
 {
   const gchar *filename = psppire_window_get_filename (se);
-
-  if ( filename == NULL )
-    syntax_save_as (se);
-  else
+  GError *err = NULL;
+  save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err);
+  if ( err )
     {
-      GError *err = NULL;
-      save_editor_to_file (PSPPIRE_SYNTAX_WINDOW (se), filename, &err);
-      if ( err )
-       {
-         msg (ME, "%s", err->message);
-         g_error_free (err);
-       }
+      msg (ME, "%s", err->message);
+      g_error_free (err);
     }
 }
 
@@ -607,14 +686,14 @@ load_and_show_syntax_window (GtkWidget *se, const gchar *filename)
 void
 create_syntax_window (void)
 {
-  GtkWidget *w = psppire_syntax_window_new ();
+  GtkWidget *w = psppire_syntax_window_new (NULL);
   gtk_widget_show (w);
 }
 
 void
-open_new_syntax_window (const char *file_name)
+open_syntax_window (const char *file_name, const gchar *encoding)
 {
-  GtkWidget *se = psppire_syntax_window_new ();
+  GtkWidget *se = psppire_syntax_window_new (encoding);
 
   if ( file_name)
     load_and_show_syntax_window (se, file_name);
@@ -631,8 +710,6 @@ on_modified_changed (GtkTextBuffer *buffer, PsppireWindow *window)
     psppire_window_set_unsaved (window);
 }
 
-extern struct source_stream *the_source_stream ;
-
 static void undo_redo_update (PsppireSyntaxWindow *window);
 static void undo_last_edit (PsppireSyntaxWindow *window);
 static void redo_last_edit (PsppireSyntaxWindow *window);
@@ -661,7 +738,6 @@ psppire_syntax_window_init (PsppireSyntaxWindow *window)
   GtkClipboard *clip_selection = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
   GtkClipboard *clip_primary =   gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_PRIMARY);
 
-
   window->print_settings = NULL;
   window->undo_menuitem = get_action_assert (xml, "edit_undo");
   window->redo_menuitem = get_action_assert (xml, "edit_redo");
@@ -685,6 +761,8 @@ psppire_syntax_window_init (PsppireSyntaxWindow *window)
                "highlight-current-line", TRUE,
                NULL);
 
+  window->encoding = NULL;
+
   window->cliptext = NULL;
   window->dispose_has_run = FALSE;
 
@@ -693,7 +771,7 @@ psppire_syntax_window_init (PsppireSyntaxWindow *window)
   window->edit_cut = get_action_assert (xml, "edit_cut");
   window->edit_paste = get_action_assert (xml, "edit_paste");
 
-  window->lexer = lex_create (the_source_stream);
+  window->buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)));
 
   window->sb = get_widget_assert (xml, "statusbar2");
   window->text_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (window->sb), "Text Context");
@@ -744,21 +822,24 @@ psppire_syntax_window_init (PsppireSyntaxWindow *window)
 
   g_signal_connect_swapped (get_action_assert (xml,"file_new_syntax"), "activate", G_CALLBACK (create_syntax_window), NULL);
 
-#if 0
   g_signal_connect (get_action_assert (xml,"file_new_data"),
                    "activate",
                    G_CALLBACK (create_data_window),
                    window);
-#endif
+
+  g_signal_connect_swapped (get_action_assert (xml, "file_open"),
+                   "activate",
+                   G_CALLBACK (psppire_window_open),
+                   window);
 
   g_signal_connect_swapped (get_action_assert (xml, "file_save"),
                    "activate",
-                   G_CALLBACK (syntax_save),
+                   G_CALLBACK (psppire_window_save),
                    window);
 
   g_signal_connect_swapped (get_action_assert (xml, "file_save_as"),
                    "activate",
-                   G_CALLBACK (syntax_save_as),
+                   G_CALLBACK (psppire_window_save_as),
                    window);
 
   g_signal_connect (get_action_assert (xml,"file_quit"),
@@ -831,12 +912,11 @@ psppire_syntax_window_init (PsppireSyntaxWindow *window)
 
 
 GtkWidget*
-psppire_syntax_window_new (void)
+psppire_syntax_window_new (const char *encoding)
 {
   return GTK_WIDGET (g_object_new (psppire_syntax_window_get_type (),
-                                  /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
-                                  "filename", _("Syntax"),
                                   "description", _("Syntax Editor"),
+                                   "encoding", encoding,
                                   NULL));
 }
 
@@ -879,6 +959,9 @@ syntax_load (PsppireWindow *window, const gchar *filename)
   GtkTextIter iter;
   PsppireSyntaxWindow *sw = PSPPIRE_SYNTAX_WINDOW (window);
   GtkTextBuffer *buffer = GTK_TEXT_BUFFER (sw->buffer);
+  gchar *encoding;
+  char *mime_type;
+
   /* FIXME: What if it's a very big file ? */
   if ( ! g_file_get_contents (filename, &text_locale, &len_locale, &err) )
     {
@@ -887,8 +970,17 @@ syntax_load (PsppireWindow *window, const gchar *filename)
       return FALSE;
     }
 
-  text_utf8 = g_locale_to_utf8 (text_locale, len_locale, NULL, &len_utf8, &err);
-
+  /* Determine the file's encoding and update sw->encoding.  (The ordering is
+     important here because encoding_guess_whole_file() often returns its
+     argument instead of a copy of it.) */
+  encoding = g_strdup (encoding_guess_whole_file (sw->encoding, text_locale,
+                                                  len_locale));
+  g_free (sw->encoding);
+  sw->encoding = encoding;
+
+  text_utf8 = recode_substring_pool ("UTF-8", encoding,
+                                     ss_buffer (text_locale, len_locale),
+                                     NULL).string;
   free (text_locale);
 
   if ( text_utf8 == NULL )
@@ -906,6 +998,10 @@ syntax_load (PsppireWindow *window, const gchar *filename)
 
   free (text_utf8);
 
+  mime_type = xasprintf ("text/x-spss-syntax; charset=%s", sw->encoding);
+  add_most_recent (filename, mime_type);
+  free (mime_type);
+
   return TRUE;
 }
 
@@ -915,6 +1011,7 @@ static void
 psppire_syntax_window_iface_init (PsppireWindowIface *iface)
 {
   iface->save = syntax_save;
+  iface->pick_filename = syntax_pick_filename;
   iface->load = syntax_load;
 }
 
index df16ed3ba62fd650552c8897c01f1b3d48f925f5..c4a6d2c07a5d56c8816460107efc668ce65a6bb4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2010  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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 <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkaction.h>
-#include <gtk/gtktextbuffer.h>
-#include "psppire-window.h"
 #include <gtk/gtk.h>
+#include "psppire-window.h"
 
 #include <gtksourceview/gtksourcelanguage.h>
 #include <gtksourceview/gtksourcelanguagemanager.h>
@@ -54,6 +52,7 @@ struct _PsppireSyntaxWindow
 
   GtkSourceBuffer *buffer;  /* The buffer which contains the text */
   struct lexer *lexer;    /* Lexer to parse syntax */
+  gchar *encoding;              /* File's encoding. */
   GtkWidget *sb;
   guint text_context;
 
@@ -84,11 +83,10 @@ struct _PsppireSyntaxWindowClass
 };
 
 GType      psppire_syntax_window_get_type        (void);
-GtkWidget* psppire_syntax_window_new             (void);
+GtkWidget* psppire_syntax_window_new             (const char *encoding);
 
 void create_syntax_window (void);
-void open_new_syntax_window (const char *file_name);
-
+void open_syntax_window (const char *file_name, const char *encoding);
 
 G_END_DECLS
 
index 48f34f6d03f9ae7211b3bb63d95cecfe923ca011..dcec70bd3af7015418adbdda45abfe8779e97548 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2011 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
@@ -387,8 +387,6 @@ var_sheet_change_active_cell (PsppireVarSheet *vs,
        vs->missing_val_dialog->pv =
          psppire_var_store_get_var (var_store, row);
 
-       vs->missing_val_dialog->dict = var_store->dictionary;
-
        g_signal_connect_swapped (customEntry,
                                  "clicked",
                                  G_CALLBACK (missing_val_dialog_show),
@@ -433,7 +431,7 @@ var_sheet_change_active_cell (PsppireVarSheet *vs,
                const gint current_value  = g_strtod (s, NULL);
                GtkObject *adj ;
 
-               const struct fmt_spec *fmt = var_get_write_format (var);
+               const struct fmt_spec *fmt = var_get_print_format (var);
                switch (column)
                  {
                  case PSPPIRE_VAR_STORE_COL_WIDTH:
@@ -483,12 +481,10 @@ psppire_var_sheet_realize (GtkWidget *w)
 
   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (vs));
 
-  vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel),
-                                               PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs))));
+  vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel));
 
   vs->missing_val_dialog = missing_val_dialog_create (GTK_WINDOW (toplevel));
-  vs->var_type_dialog = var_type_dialog_create (GTK_WINDOW (toplevel),
-                                               PSPPIRE_VAR_STORE (psppire_sheet_get_model (PSPPIRE_SHEET (vs))));
+  vs->var_type_dialog = var_type_dialog_create (GTK_WINDOW (toplevel));
 
   /* Chain up to the parent class */
   GTK_WIDGET_CLASS (parent_class)->realize (w);
index a2e6685443e3dd5a525d5f985f8e7acb1f4dd709..f924c17027fbf3c78547e63271fb4e38477ad4b4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2009, 2010  Free Software Foundation
+   Copyright (C) 2006, 2009, 2010, 2011  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
@@ -489,7 +489,7 @@ psppire_var_store_clear (PsppireSheetModel *model,  glong row, glong col)
   switch (col)
     {
     case PSPPIRE_VAR_STORE_COL_LABEL:
-      var_set_label (pv, NULL);
+      var_clear_label (pv);
       return TRUE;
       break;
     }
@@ -550,7 +550,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
             bool for_input
               = var_store->format_type == PSPPIRE_VAR_STORE_INPUT_FORMATS;
            struct fmt_spec fmt ;
-           fmt = *var_get_write_format (pv);
+           fmt = *var_get_print_format (pv);
            if ( width < fmt_min_width (fmt.type, for_input)
                 ||
                 width > fmt_max_width (fmt.type, for_input))
@@ -573,7 +573,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
        struct fmt_spec fmt;
        if ( ! text) return FALSE;
        decimals = atoi (text);
-       fmt = *var_get_write_format (pv);
+       fmt = *var_get_print_format (pv);
        if ( decimals >
             fmt_max_decimals (fmt.type,
                                fmt.w,
@@ -588,7 +588,7 @@ psppire_var_store_set_string (PsppireSheetModel *model,
       break;
     case PSPPIRE_VAR_STORE_COL_LABEL:
       {
-       var_set_label (pv, text);
+       var_set_label (pv, text, true);
        return TRUE;
       }
       break;
@@ -616,22 +616,8 @@ text_for_column (PsppireVarStore *vs,
                 const struct variable *pv, gint c, GError **err)
 {
   PsppireDict *dict = vs->dictionary;
-  static const gchar *const type_label[] =
-    {
-      N_("Numeric"),
-      N_("Comma"),
-      N_("Dot"),
-      N_("Scientific"),
-      N_("Date"),
-      N_("Dollar"),
-      N_("Custom"),
-      N_("String")
-    };
-
-  enum {VT_NUMERIC, VT_COMMA, VT_DOT, VT_SCIENTIFIC, VT_DATE, VT_DOLLAR,
-       VT_CUSTOM, VT_STRING};
 
-  const struct fmt_spec *write_spec = var_get_write_format (pv);
+  const struct fmt_spec *format = var_get_print_format (pv);
 
   switch (c)
     {
@@ -639,64 +625,13 @@ text_for_column (PsppireVarStore *vs,
       return xstrdup (var_get_name (pv));
       break;
     case PSPPIRE_VAR_STORE_COL_TYPE:
-      {
-       switch ( write_spec->type )
-         {
-         case FMT_F:
-           return xstrdup (gettext (type_label[VT_NUMERIC]));
-           break;
-         case FMT_COMMA:
-           return xstrdup (gettext (type_label[VT_COMMA]));
-           break;
-         case FMT_DOT:
-           return xstrdup (gettext (type_label[VT_DOT]));
-           break;
-         case FMT_E:
-           return xstrdup (gettext (type_label[VT_SCIENTIFIC]));
-           break;
-         case FMT_DATE:
-         case FMT_EDATE:
-         case FMT_SDATE:
-         case FMT_ADATE:
-         case FMT_JDATE:
-         case FMT_QYR:
-         case FMT_MOYR:
-         case FMT_WKYR:
-         case FMT_DATETIME:
-         case FMT_TIME:
-         case FMT_DTIME:
-         case FMT_WKDAY:
-         case FMT_MONTH:
-           return xstrdup (gettext (type_label[VT_DATE]));
-           break;
-         case FMT_DOLLAR:
-           return xstrdup (gettext (type_label[VT_DOLLAR]));
-           break;
-         case FMT_CCA:
-         case FMT_CCB:
-         case FMT_CCC:
-         case FMT_CCD:
-         case FMT_CCE:
-           return xstrdup (gettext (type_label[VT_CUSTOM]));
-           break;
-         case FMT_A:
-           return xstrdup (gettext (type_label[VT_STRING]));
-           break;
-         default:
-            {
-              char str[FMT_STRING_LEN_MAX + 1];
-              g_warning ("Unknown format: `%s'\n",
-                        fmt_to_string (write_spec, str));
-            }
-           break;
-         }
-      }
+      return xstrdup (fmt_gui_name (format->type));
       break;
     case PSPPIRE_VAR_STORE_COL_WIDTH:
       {
        gchar *s;
        GString *gstr = g_string_sized_new (10);
-       g_string_printf (gstr, _("%d"), write_spec->w);
+       g_string_printf (gstr, _("%d"), format->w);
        s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
        g_string_free (gstr, TRUE);
        return s;
@@ -706,7 +641,7 @@ text_for_column (PsppireVarStore *vs,
       {
        gchar *s;
        GString *gstr = g_string_sized_new (10);
-       g_string_printf (gstr, _("%d"), write_spec->d);
+       g_string_printf (gstr, _("%d"), format->d);
        s = g_locale_to_utf8 (gstr->str, gstr->len, 0, 0, err);
        g_string_free (gstr, TRUE);
        return s;
@@ -750,9 +685,10 @@ text_for_column (PsppireVarStore *vs,
            g_assert (vl);
 
            {
-             gchar *const vstr = value_to_text (vl->value, dict, *write_spec);
+             gchar *const vstr = value_to_text (vl->value, pv);
 
-             return g_strdup_printf (_("{%s,`%s'}_"), vstr, val_lab_get_label (vl));
+             return g_strdup_printf (_("{%s,`%s'}_"), vstr,
+                                      val_lab_get_escaped_label (vl));
            }
          }
       }
@@ -762,12 +698,12 @@ text_for_column (PsppireVarStore *vs,
        const gint align = var_get_alignment (pv);
 
        g_assert (align < n_ALIGNMENTS);
-       return xstrdup (gettext (alignments[align]));
+       return xstrdup (alignment_to_string (align));
       }
       break;
     case PSPPIRE_VAR_STORE_COL_MEASURE:
       {
-       return xstrdup (measure_to_string (pv, err));
+       return xstrdup (measure_to_string (var_get_measure (pv)));
       }
       break;
     }
index 73bd9d8de225cf33fbe86e5768486e6f9d1edfb9..009aad62d03eec6539a22ffaf9a9580452058e2c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -16,8 +16,7 @@
 
 #include <config.h>
 
-#include <gtk/gtktreeview.h>
-#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtk.h>
 #include "psppire-var-view.h"
 #include "psppire-var-ptr.h"
 #include "psppire-select-dest.h"
@@ -141,7 +140,7 @@ display_cell_var_name (GtkTreeViewColumn *tree_column,
 
   g_value_unset (&value);
 
-  g_object_set (cell, "text", var_get_name (var), NULL);
+  g_object_set (cell, "text", var ? var_get_name (var) : "", NULL);
 }
 
 
index 35dc91d2b98f3af1460e19cd571480fe2aeebe31..45832eba0e8804a46b7381e48f5079cff9fc1b2c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 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
@@ -21,7 +21,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <gtk/gtktreeview.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
index 98c2898ce2b4709edacf8d738fff3757e9ae57d7..e1496576a586e9ee042aa3c002d7ce5b2c199136 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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 <glib.h>
 #include <gtk/gtk.h>
-#include <gtk/gtksignal.h>
 #include "psppire-vbuttonbox.h"
 #include "psppire-dialog.h"
 
-#include <gtk/gtkbbox.h>
-
 #include <gettext.h>
 
 #define _(msgid) gettext (msgid)
@@ -245,7 +242,7 @@ gtk_vbutton_box_size_allocate (GtkWidget     *widget,
       child = children->data;
       children = children->next;
 
-      if (GTK_WIDGET_VISIBLE (child->widget))
+      if (gtk_widget_get_visible (child->widget))
        {
          child_allocation.width = child_width;
          child_allocation.height = child_height;
index e03732fc365c6c555adf0e513454a91e22e66db6..edaa372670755020b0cfc9594e8cb0c6d5fde3db 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009, 2010  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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 "psppire-window.h"
 
-#include <gtk/gtkstock.h>
-#include <gtk/gtkmessagedialog.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkcheckmenuitem.h>
-#include <gtk/gtkmain.h>
+#include <gtk/gtk.h>
 
 #include <stdlib.h>
 #include <xalloc.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-#include "psppire-window.h"
-#include "psppire-window-register.h"
+#include "data/any-reader.h"
+#include "data/dataset.h"
+
+#include "helper.h"
 #include "psppire-conf.h"
+#include "psppire-data-window.h"
+#include "psppire-encoding-selector.h"
+#include "psppire-syntax-window.h"
+#include "psppire-window-register.h"
+#include "psppire.h"
 
 static void psppire_window_base_finalize (PsppireWindowClass *, gpointer);
 static void psppire_window_base_init     (PsppireWindowClass *class);
@@ -77,7 +80,8 @@ enum
 {
   PROP_0,
   PROP_FILENAME,
-  PROP_DESCRIPTION
+  PROP_DESCRIPTION,
+  PROP_ID
 };
 
 
@@ -87,25 +91,87 @@ uniquify (const gchar *str, int *x)
   return g_strdup_printf ("%s%d", str, (*x)++);
 }
 
-static gchar mdash[6] = {0,0,0,0,0,0};
-
 static void
 psppire_window_set_title (PsppireWindow *window)
 {
   GString *title = g_string_sized_new (80);
 
-  g_string_printf (title, _("%s %s PSPPIRE %s"),
-                  window->basename ? window->basename : "",
-                  mdash, window->description);
-
   if (window->dirty)
-    g_string_prepend_c (title, '*');
+    g_string_append_c (title, '*');
+
+  if (window->basename || window->id)
+    {
+      if (window->basename)
+        g_string_append_printf (title, "%s ", window->basename);
+
+      if (window->id != '\0')
+        g_string_append_printf (title, "[%s] ", window->id);
+
+      g_string_append_unichar (title, 0x2014); /* em dash */
+      g_string_append_c (title, ' '); /* em dash */
+    }
+
+  g_string_append_printf (title, "PSPPIRE %s", window->description);
 
   gtk_window_set_title (GTK_WINDOW (window), title->str);
 
   g_string_free (title, TRUE);
 }
 
+static void
+psppire_window_update_list_name (PsppireWindow *window)
+{
+  PsppireWindowRegister *reg = psppire_window_register_new ();
+  GString *candidate = g_string_sized_new (80);
+  int n;
+
+  n = 1;
+  do
+    {
+      /* Compose a name. */
+      g_string_truncate (candidate, 0);
+      if (window->filename)
+        {
+          gchar *display_filename = g_filename_display_name (window->filename);
+          g_string_append (candidate, display_filename);
+          g_free (display_filename);
+
+          if (window->id)
+            g_string_append_printf (candidate, " [%s]", window->id);
+        }
+      else if (window->id)
+        g_string_append_printf (candidate, "[%s]", window->id);
+      else
+        g_string_append (candidate, window->description);
+
+      if (n++ > 1)
+        g_string_append_printf (candidate, " #%d", n);
+
+      if (window->list_name && !strcmp (candidate->str, window->list_name))
+        {
+          /* Keep the existing name. */
+          g_string_free (candidate, TRUE);
+          return;
+        }
+    }
+  while (psppire_window_register_lookup (reg, candidate->str));
+
+  if (window->list_name)
+    psppire_window_register_remove (reg, window->list_name);
+
+  g_free (window->list_name);
+  window->list_name = g_string_free (candidate, FALSE);
+
+  psppire_window_register_insert (reg, window, window->list_name);
+}
+
+static void
+psppire_window_name_changed (PsppireWindow *window)
+{
+  psppire_window_set_title (window);
+  psppire_window_update_list_name (window);
+}
+
 static void
 psppire_window_set_property (GObject         *object,
                             guint            prop_id,
@@ -117,50 +183,24 @@ psppire_window_set_property (GObject         *object,
   switch (prop_id)
     {
     case PROP_DESCRIPTION:
+      g_free (window->description);
       window->description = g_value_dup_string (value);
       psppire_window_set_title (window);
       break;
     case PROP_FILENAME:
-      {
-       PsppireWindowRegister *reg = psppire_window_register_new ();
-
-       gchar *candidate_name ;
-
-       {
-         const gchar *name = g_value_get_string (value);
-         int x = 0;
-         GValue def = {0};
-         g_value_init (&def, pspec->value_type);
-
-         if ( NULL == name)
-           {
-             g_param_value_set_default (pspec, &def);
-             name = g_value_get_string (&def);
-           }
-
-         candidate_name = xstrdup (name);
-
-         while ( psppire_window_register_lookup (reg, candidate_name))
-           {
-             free (candidate_name);
-             candidate_name = uniquify (name, &x);
-           }
-
-         window->basename = g_filename_display_basename (candidate_name);
-
-         g_value_unset (&def);
-       }
-
-       psppire_window_set_title (window);
-
-       if ( window->name)
-         psppire_window_register_remove (reg, window->name);
-
-       free (window->name);
-       window->name = candidate_name;
-
-       psppire_window_register_insert (reg, window, window->name);
-      }
+      g_free (window->filename);
+      window->filename = g_value_dup_string (value);
+      g_free (window->basename);
+      window->basename = (window->filename
+                          ? g_filename_display_basename (window->filename)
+                          : NULL);
+      psppire_window_name_changed (window);
+      break;
+      break;
+    case PROP_ID:
+      g_free (window->id);
+      window->id = g_value_dup_string (value);
+      psppire_window_name_changed (window);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -180,11 +220,14 @@ psppire_window_get_property (GObject         *object,
   switch (prop_id)
     {
     case PROP_FILENAME:
-      g_value_set_string (value, window->name);
+      g_value_set_string (value, window->filename);
       break;
     case PROP_DESCRIPTION:
       g_value_set_string (value, window->description);
       break;
+    case PROP_ID:
+      g_value_set_string (value, window->id);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -210,9 +253,12 @@ psppire_window_finalize (GObject *object)
 
   PsppireWindowRegister *reg = psppire_window_register_new ();
 
-  psppire_window_register_remove (reg, window->name);
-  free (window->name);
-  free (window->description);
+  psppire_window_register_remove (reg, window->list_name);
+  g_free (window->filename);
+  g_free (window->basename);
+  g_free (window->id);
+  g_free (window->description);
+  g_free (window->list_name);
 
   g_signal_handler_disconnect (psppire_window_register_new (),
                               window->remove_handler);
@@ -226,28 +272,32 @@ psppire_window_finalize (GObject *object)
     G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-
 static void
 psppire_window_class_init (PsppireWindowClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
   GParamSpec *description_spec =
-    g_param_spec_string ("description",
+    null_if_empty_param ("description",
                       "Description",
                       "A string describing the usage of the window",
-                        "??????", /*Should be overridden by derived classes */
+                        NULL, /*Should be overridden by derived classes */
                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
 
   GParamSpec *filename_spec =
-    g_param_spec_string ("filename",
+    null_if_empty_param ("filename",
                       "File name",
                       "The name of the file associated with this window, if any",
-                        /* TRANSLATORS: This will form a filename.  Please avoid whitespace. */
-                        _("Untitled"),
+                        NULL,
                         G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
 
-  g_unichar_to_utf8 (0x2014, mdash);
+  GParamSpec *id_spec =
+    null_if_empty_param ("id",
+                         "Identifier",
+                         "The PSPP language identifier for the data associated "
+                         "with this window (e.g. dataset name)",
+                        NULL,
+                        G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
 
   object_class->set_property = psppire_window_set_property;
   object_class->get_property = psppire_window_get_property;
@@ -260,6 +310,10 @@ psppire_window_class_init (PsppireWindowClass *class)
                                    PROP_FILENAME,
                                    filename_spec);
 
+  g_object_class_install_property (object_class,
+                                   PROP_ID,
+                                   id_spec);
+
   parent_class = g_type_class_peek_parent (class);
 }
 
@@ -304,9 +358,20 @@ menu_activate (GtkMenuItem *mi, gpointer data)
 static void
 insert_menuitem_into_menu (PsppireWindow *window, gpointer key)
 {
-  gchar *filename = g_filename_display_name (key);
-  GtkWidget *item = gtk_check_menu_item_new_with_label (filename);
+  gchar *filename;
+  GtkWidget *item;
 
+  /* Add a separator before adding the first real item.  If we add a separator
+     at any other time, sometimes GtkUIManager removes it. */
+  if (g_hash_table_size (window->menuitem_table) == 0)
+    {
+      GtkWidget *separator = gtk_separator_menu_item_new ();
+      gtk_widget_show (separator);
+      gtk_menu_shell_append (window->menu, separator);
+    }
+
+  filename = g_filename_display_name (key);
+  item = gtk_check_menu_item_new_with_label (filename);
   g_free (filename);
 
   g_signal_connect (item, "toggled", G_CALLBACK (menu_toggled), NULL);
@@ -389,6 +454,11 @@ on_delete (PsppireWindow *w, GdkEvent *event, gpointer user_data)
          break;
        case GTK_RESPONSE_APPLY:
          psppire_window_save (w);
+          if (w->dirty)
+            {
+              /* Save failed, or user exited Save As dialog with Cancel. */
+              return TRUE;
+            }
          break;
        case GTK_RESPONSE_REJECT:
          break;
@@ -405,9 +475,12 @@ on_delete (PsppireWindow *w, GdkEvent *event, gpointer user_data)
 static void
 psppire_window_init (PsppireWindow *window)
 {
-  window->name = NULL;
   window->menu = NULL;
-  window->description = xstrdup ("");
+  window->filename = NULL;
+  window->basename = NULL;
+  window->id = NULL;
+  window->description = NULL;
+  window->list_name = NULL;
 
   window->menuitem_table  = g_hash_table_new (g_str_hash, g_str_equal);
 
@@ -432,7 +505,6 @@ psppire_window_init (PsppireWindow *window)
 
   g_signal_connect (window, "realize",
                    G_CALLBACK (on_realize), window);
-
 }
 
 /*
@@ -442,33 +514,30 @@ psppire_window_init (PsppireWindow *window)
 gint
 psppire_window_query_save (PsppireWindow *se)
 {
-  gchar *fn;
   gint response;
   GtkWidget *dialog;
   GtkWidget *cancel_button;
 
-  const gchar *description;
-  const gchar *filename = psppire_window_get_filename (se);
+  gchar *description;
 
   GTimeVal time;
 
   g_get_current_time (&time);
 
-  g_object_get (se, "description", &description, NULL);
-
-  g_return_val_if_fail (filename != NULL, GTK_RESPONSE_NONE);
-
-
-  fn = g_filename_display_basename (filename);
-
+  if (se->filename)
+    description = g_filename_display_basename (se->filename);
+  else if (se->id)
+    description = g_strdup (se->id);
+  else
+    description = g_strdup (se->description);
   dialog =
     gtk_message_dialog_new (GTK_WINDOW (se),
                            GTK_DIALOG_MODAL,
                            GTK_MESSAGE_WARNING,
                            GTK_BUTTONS_NONE,
                            _("Save the changes to `%s' before closing?"),
-                           fn);
-  g_free (fn);
+                           description);
+  g_free (description);
 
   g_object_set (dialog, "icon-name", "psppicon", NULL);
 
@@ -498,16 +567,15 @@ psppire_window_query_save (PsppireWindow *se)
 }
 
 
-
+/* The return value is encoded in the glib filename encoding. */
 const gchar *
 psppire_window_get_filename (PsppireWindow *w)
 {
-  const gchar *name = NULL;
-  g_object_get (w, "filename", &name, NULL);
-  return name;
+  return w->filename;
 }
 
 
+/* FILENAME must be encoded in the glib filename encoding. */
 void
 psppire_window_set_filename (PsppireWindow *w, const gchar *filename)
 {
@@ -589,22 +657,42 @@ psppire_window_save (PsppireWindow *w)
 {
   PsppireWindowIface *i = PSPPIRE_WINDOW_MODEL_GET_IFACE (w);
 
-  g_assert (PSPPIRE_IS_WINDOW_MODEL (w));
-
   g_assert (i);
-
   g_return_if_fail (i->save);
 
-  i->save (w);
-
-  w->dirty = FALSE;
-  psppire_window_set_title (w);
+  if (w->filename == NULL)
+    psppire_window_save_as (w);
+  else
+    {
+      i->save (w);
+      w->dirty = FALSE;
+      psppire_window_set_title (w);
+    }
 }
 
-extern GtkRecentManager *the_recent_mgr;
+void
+psppire_window_save_as (PsppireWindow *w)
+{
+  PsppireWindowIface *i = PSPPIRE_WINDOW_MODEL_GET_IFACE (w);
+  gchar *old_filename;
 
-static void add_most_recent (const char *file_name, GtkRecentManager *rm);
-static void delete_recent (const char *file_name, GtkRecentManager *rm);
+  g_assert (i);
+  g_return_if_fail (i->pick_filename);
+
+  old_filename = w->filename;
+  w->filename = NULL;
+
+  i->pick_filename (w);
+  if (w->filename == NULL)
+    w->filename = old_filename;
+  else
+    {
+      g_free (old_filename);
+      psppire_window_save (w);
+    }
+}
+
+static void delete_recent (const char *file_name);
 
 gboolean
 psppire_window_load (PsppireWindow *w, const gchar *file)
@@ -623,28 +711,149 @@ psppire_window_load (PsppireWindow *w, const gchar *file)
   if ( ok )
     {
       psppire_window_set_filename (w, file);
-      add_most_recent (file, the_recent_mgr);
       w->dirty = FALSE;
     }
   else
-    delete_recent (file, the_recent_mgr);
-
-  psppire_window_set_title (w);
+    delete_recent (file);
 
   return ok;
 }
 
+GtkWidget *
+psppire_window_file_chooser_dialog (PsppireWindow *toplevel)
+{
+  GtkWidget *dialog =
+    gtk_file_chooser_dialog_new (_("Open"),
+                                GTK_WINDOW (toplevel),
+                                GTK_FILE_CHOOSER_ACTION_OPEN,
+                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+                                NULL);
+
+  GtkFileFilter *filter;
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Data and Syntax Files"));
+  gtk_file_filter_add_pattern (filter, "*.sav");
+  gtk_file_filter_add_pattern (filter, "*.SAV");
+  gtk_file_filter_add_pattern (filter, "*.por");
+  gtk_file_filter_add_pattern (filter, "*.POR");
+  gtk_file_filter_add_pattern (filter, "*.sps");
+  gtk_file_filter_add_pattern (filter, "*.SPS");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("System Files (*.sav)"));
+  gtk_file_filter_add_pattern (filter, "*.sav");
+  gtk_file_filter_add_pattern (filter, "*.SAV");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Portable Files (*.por) "));
+  gtk_file_filter_add_pattern (filter, "*.por");
+  gtk_file_filter_add_pattern (filter, "*.POR");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Syntax Files (*.sps) "));
+  gtk_file_filter_add_pattern (filter, "*.sps");
+  gtk_file_filter_add_pattern (filter, "*.SPS");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Files"));
+  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+  if (toplevel->filename)
+    {
+      const gchar *filename = toplevel->filename;
+      gchar *dir_name;
+
+      if ( ! g_path_is_absolute (filename))
+        {
+          gchar *path =
+            g_build_filename (g_get_current_dir (), filename, NULL);
+          dir_name = g_path_get_dirname (path);
+          g_free (path);
+        }
+      else
+        {
+          dir_name = g_path_get_dirname (filename);
+        }
+      gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
+                                           dir_name);
+      free (dir_name);
+    }
 
-/* Puts FILE_NAME into the recent list.
-   If it's already in the list, it moves it to the top
-*/
-static void
-add_most_recent (const char *file_name, GtkRecentManager *rm)
+  gtk_file_chooser_set_extra_widget (
+    GTK_FILE_CHOOSER (dialog), psppire_encoding_selector_new ("Auto", true));
+
+  return dialog;
+}
+
+/* Callback for the file_open action.
+   Prompts for a filename and opens it */
+void
+psppire_window_open (PsppireWindow *de)
+{
+  GtkWidget *dialog = psppire_window_file_chooser_dialog (de);
+
+  switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+    {
+    case GTK_RESPONSE_ACCEPT:
+      {
+       gchar *name =
+         gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+
+       gchar *sysname = convert_glib_filename_to_system_filename (name, NULL);
+
+        gchar *encoding = psppire_encoding_selector_get_encoding (
+          gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
+
+       if (any_reader_may_open (sysname))
+          open_data_window (de, name);
+       else
+         open_syntax_window (name, encoding);
+
+        g_free (encoding);
+       g_free (sysname);
+       g_free (name);
+      }
+      break;
+    default:
+      break;
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+
+/* Puts FILE_NAME (encoded in the glib file name encoding) into the recent list
+   with associated MIME_TYPE.  If it's already in the list, it moves it to the
+   top. */
+void
+add_most_recent (const char *file_name, const char *mime_type)
 {
   gchar *uri = g_filename_to_uri  (file_name, NULL, NULL);
 
   if ( uri )
-    gtk_recent_manager_add_item (rm, uri);
+    {
+      GtkRecentData recent_data;
+
+      recent_data.display_name = NULL;
+      recent_data.description = NULL;
+      recent_data.mime_type = CONST_CAST (gchar *, mime_type);
+      recent_data.app_name = CONST_CAST (gchar *, g_get_application_name ());
+      recent_data.app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
+      recent_data.groups = NULL;
+      recent_data.is_private = FALSE;
+
+      gtk_recent_manager_add_full (gtk_recent_manager_get_default (),
+                                   uri, &recent_data);
+
+      g_free (recent_data.app_exec);
+    }
 
   g_free (uri);
 }
@@ -655,12 +864,12 @@ add_most_recent (const char *file_name, GtkRecentManager *rm)
    If FILE_NAME exists in the recent list, then  delete it.
  */
 static void
-delete_recent (const char *file_name, GtkRecentManager *rm)
+delete_recent (const char *file_name)
 {
   gchar *uri = g_filename_to_uri  (file_name, NULL, NULL);
 
   if ( uri )
-    gtk_recent_manager_remove_item (rm, uri, NULL);
+    gtk_recent_manager_remove_item (gtk_recent_manager_get_default (), uri, NULL);
 
   g_free (uri);
 }
index 441e12af3f2454eaa7c3aae16e5fba181e9343b7..b80f79d699af04d14a647be6d817830ff9a5b65b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  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 <glib.h>
 #include <glib-object.h>
-#include <gtk/gtkwindow.h>
-#include <gtk/gtkaction.h>
-#include <gtk/gtkmenushell.h>
-#include <gtk/gtkrecentmanager.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
@@ -63,9 +60,11 @@ struct _PsppireWindow
   GtkWindow parent;
 
   /* <private> */
-  gchar *name;
-  gchar *description;
-  gchar *basename;
+  gchar *filename;             /* File name, in file name encoding, or NULL. */
+  gchar *basename;             /* Last component of filename, in UTF-8 */
+  gchar *id;                   /* Dataset name, or NULL.  */
+  gchar *description;          /* e.g. "Data Editor" */
+  gchar *list_name;            /* Name for "Windows" menu list. */
 
   GHashTable *menuitem_table;
   GtkMenuShell *menu;
@@ -89,6 +88,7 @@ struct _PsppireWindowIface
   GTypeInterface g_iface;
 
   void (*save) (PsppireWindow *w);
+  void (*pick_filename) (PsppireWindow *);
   gboolean (*load) (PsppireWindow *w, const gchar *);
 };
 
@@ -109,8 +109,12 @@ gboolean psppire_window_get_unsaved (PsppireWindow *);
 gint psppire_window_query_save (PsppireWindow *);
 
 void psppire_window_save (PsppireWindow *w);
+void psppire_window_save_as (PsppireWindow *w);
 gboolean psppire_window_load (PsppireWindow *w, const gchar *file);
+void psppire_window_open (PsppireWindow *de);
+GtkWidget *psppire_window_file_chooser_dialog (PsppireWindow *toplevel);
 
+void add_most_recent (const char *file_name, const char *mime_type);
 
 G_END_DECLS
 
index 61042efe546cdedaf59470764312c6fa5e817361..453bc3a80a7b8ae6e6bf35cb96e7548defd27947 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006, 2009, 2010  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011  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
@@ -16,8 +16,6 @@
 
 #include <config.h>
 
-#include "ui/gui/psppire.h"
-
 #include <assert.h>
 #include <gsl/gsl_errno.h>
 #include <gtk/gtk.h>
 #include <unistd.h>
 
 #include "data/casereader.h"
+#include "data/dataset.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/session.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.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;
-PsppireVarStore *the_var_store = 0;
-
+static void inject_renamed_icons (void);
 static void create_icon_factory (void);
-
-struct source_stream *the_source_stream ;
-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)
-{
-  psppire_data_store_set_reader (the_data_store, s);
-}
+static void load_data_file (PsppireDataWindow *, const char *);
 
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 
-
-
 void
-initialize (struct source_stream *ss, const char *data_file)
+initialize (const char *data_file)
 {
-  PsppireDict *dictionary = 0;
+  PsppireDataWindow *data_window;
 
   i18n_init ();
 
@@ -99,21 +81,11 @@ initialize (struct source_stream *ss, const char *data_file)
   settings_init ();
   fh_init ();
 
-  the_dataset = create_dataset ();
-
-  the_source_stream = ss;
-  msg_init (ss, handle_msg);
-
-  dictionary = psppire_dict_new_from_dict (dataset_dict (the_dataset));
+  psppire_set_lexer (NULL);
 
   bind_textdomain_codeset (PACKAGE, "UTF-8");
 
-  /* Create the model for the var_sheet */
-  the_var_store = psppire_var_store_new (dictionary);
-
-  the_data_store = psppire_data_store_new (dictionary);
-  replace_casereader (NULL);
-
+  inject_renamed_icons ();
   create_icon_factory ();
 
   psppire_output_window_setup ();
@@ -121,33 +93,24 @@ initialize (struct source_stream *ss, const char *data_file)
   journal_enable ();
   textdomain (PACKAGE);
 
-
-  the_recent_mgr = gtk_recent_manager_get_default ();
-
   psppire_selector_set_default_selection_func (GTK_TYPE_ENTRY, insert_source_row_into_entry);
   psppire_selector_set_default_selection_func (PSPPIRE_VAR_VIEW_TYPE, insert_source_row_into_tree_view);
   psppire_selector_set_default_selection_func (GTK_TYPE_TREE_VIEW, insert_source_row_into_tree_view);
 
-  the_data_window = psppire_data_window_new ();
+  data_window = psppire_default_data_window ();
   if (data_file != NULL)
-    load_data_file (data_file);
-
-  execute_syntax (create_syntax_string_source (""));
-
-  gtk_widget_show (the_data_window);
+    load_data_file (data_window, data_file);
 }
 
 
 void
 de_initialize (void)
 {
-  destroy_source_stream (the_source_stream);
   settings_done ();
   output_close ();
   i18n_done ();
 }
 
-
 static void
 func (gpointer key, gpointer value, gpointer data)
 {
@@ -166,6 +129,46 @@ psppire_quit (void)
   gtk_main_quit ();
 }
 
+static void
+inject_renamed_icon (const char *icon, const char *substitute)
+{
+  GtkIconTheme *theme = gtk_icon_theme_get_default ();
+  if (!gtk_icon_theme_has_icon (theme, icon)
+      && gtk_icon_theme_has_icon (theme, substitute))
+    {
+      gint *sizes = gtk_icon_theme_get_icon_sizes (theme, substitute);
+      gint *p;
+
+      for (p = sizes; *p != 0; p++)
+        {
+          gint size = *p;
+          GdkPixbuf *pb;
+
+          pb = gtk_icon_theme_load_icon (theme, substitute, size, 0, NULL);
+          if (pb != NULL)
+            {
+              GdkPixbuf *copy = gdk_pixbuf_copy (pb);
+              if (copy != NULL)
+                gtk_icon_theme_add_builtin_icon (icon, size, copy);
+            }
+        }
+    }
+}
+
+/* Avoid a bug in GTK+ 2.22 that can cause a segfault at startup time.  Earlier
+   and later versions of GTK+ do not have the bug.  Bug #31511.
+
+   Based on this patch against Inkscape:
+   https://launchpadlibrarian.net/60175914/copy_renamed_icons.patch */
+static void
+inject_renamed_icons (void)
+{
+  if (gtk_major_version == 2 && gtk_minor_version == 22)
+    {
+      inject_renamed_icon ("gtk-file", "document-x-generic");
+      inject_renamed_icon ("gtk-directory", "folder");
+    }
+}
 
 struct icon_info
 {
@@ -240,7 +243,7 @@ create_icon_factory (void)
 }
 \f
 static void
-load_data_file (const char *arg)
+load_data_file (PsppireDataWindow *window, const char *arg)
 {
   gchar *filename = NULL;
   gchar *utf8 = NULL;
@@ -292,13 +295,31 @@ load_data_file (const char *arg)
   if ( filename == NULL)
     filename = xstrdup (arg);
 
-  psppire_window_load (PSPPIRE_WINDOW (the_data_window), filename);
+  psppire_window_load (PSPPIRE_WINDOW (window), filename);
 
   g_free (filename);
 }
 
 static void
-handle_msg (const struct msg *m)
+handle_msg (const struct msg *m_, void *lexer_)
+{
+  struct lexer *lexer = lexer_;
+  struct msg m = *m_;
+
+  if (lexer != NULL && m.file_name == NULL)
+    {
+      m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
+      m.first_line = lex_get_first_line_number (lexer, 0);
+      m.last_line = lex_get_last_line_number (lexer, 0);
+      m.first_column = lex_get_first_column (lexer, 0);
+      m.last_column = lex_get_last_column (lexer, 0);
+    }
+
+  message_item_submit (message_item_create (&m));
+}
+
+void
+psppire_set_lexer (struct lexer *lexer)
 {
-  message_item_submit (message_item_create (m));
+  msg_set_handler (handle_msg, lexer);
 }
index ee747ef90606b200b195d9fa497ce239457fe58d..8817824a9c936fbb387fb20390253152d8a5a9fb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2004, 2005, 2006, 2009, 2010  Free Software Foundation
+   Copyright (C) 2004, 2005, 2006, 2009, 2010, 2011  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
 
-struct source_stream;
+struct lexer;
 
-void initialize (struct source_stream *, const char *data_file);
+void initialize (const char *data_file);
 void de_initialize (void);
 
 void psppire_quit (void);
 
 const char * output_file_name (void);
 
+void psppire_set_lexer (struct lexer *);
+
 #endif /* PSPPIRE_H */
index fa998b47116b0c5d4ffff0d1e9b821f3b009cd83..58e4f5115948a219fc59d5eb3fd3b3571399f536 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -21,7 +21,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -322,21 +321,10 @@ rank_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-       paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index 27f6972557bcb350e9ecfebacc8ba83a9b7e5915..55376644f1b00cda4f80431ec175cab1baa5be66 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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,7 +31,6 @@
 #include <gtk/gtk.h>
 
 #include <xalloc.h>
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -1060,22 +1059,10 @@ recode_dialog (PsppireDataWindow *de, gboolean diff)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index d6997f74e716d6065b3477db92d95cfbc3934b7a..7bea89e185a27f0f5307f9540c16204c6e69778f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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
@@ -23,7 +23,6 @@
 #include <gtk/gtk.h>
 #include <stdlib.h>
 
-#include <language/syntax-string-source.h>
 #include <ui/gui/psppire-data-window.h>
 #include <ui/gui/dialog-common.h>
 #include <ui/gui/dict-display.h>
@@ -288,22 +287,10 @@ regression_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index 957d9e11ca2da65d6bf439e24a398f7d09518a62..c60f0df504968e25b66c0b670141e38b155b4fa3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -17,7 +17,6 @@
 #include <config.h>
 
 #include "dialog-common.h"
-#include <language/syntax-string-source.h>
 #include "reliability-dialog.h"
 #include "psppire-selector.h"
 #include "psppire-dictview.h"
@@ -167,22 +166,10 @@ reliability_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index 45972d547640d19a7fa1c8437efecebb66239ca0..a024c9c46dbb080f7ac2bc2057cc17659ab5b5e7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2009  Free Software Foundation
+   Copyright (C) 2009, 2010, 2011  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
@@ -17,7 +17,6 @@
 #include <config.h>
 
 #include "dialog-common.h"
-#include <language/syntax-string-source.h>
 #include <ui/syntax-gen.h>
 #include <libpspp/str.h>
 
@@ -162,22 +161,10 @@ roc_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&rd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&rd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&rd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&rd)));
       break;
     default:
       break;
index 0f50c91a3f96cf8dcbe60049cdfaa4158c74efb1..381fc3dd8a104649404358b1abb5a7f4a7f08735 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010, 2011 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
@@ -25,7 +25,6 @@
 #include "dict-display.h"
 #include "dialog-common.h"
 #include "widget-io.h"
-#include <language/syntax-string-source.h>
 #include "helper.h"
 #include <xalloc.h>
 
@@ -348,22 +347,10 @@ select_cases_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&scd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&scd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&scd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&scd)));
       break;
     default:
       break;
@@ -379,7 +366,7 @@ generate_syntax_filter (const struct select_cases_dialog *scd)
   gchar *text = NULL;
   GString *string = g_string_new ("");
 
-  const gchar filter[]="filter_$";
+  const gchar *filter = "filter_$";
   const gchar key[]="case_$";
 
   if ( gtk_toggle_button_get_active
@@ -475,6 +462,13 @@ generate_syntax_filter (const struct select_cases_dialog *scd)
       g_string_append (string, "EXECUTE.\n");
 
     }
+  else
+    {
+      GtkEntry *entry =
+       GTK_ENTRY (get_widget_assert (scd->xml,
+                                     "filter-variable-entry"));
+      filter = gtk_entry_get_text (entry);
+    }
 
 
   g_string_append_printf  (string, "FILTER BY %s.\n", filter);
index 8252e3208f1d6c3362a2414940a8921287801d85..6977469b7ecdd6b101a3058b0e40c321495d896b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -26,7 +26,6 @@
 #include "dict-display.h"
 #include "psppire-var-view.h"
 
-#include <language/syntax-string-source.h>
 #include "helper.h"
 
 static void
@@ -129,22 +128,10 @@ sort_cases_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&scd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&scd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&scd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&scd)));
       break;
     default:
       break;
index 1748651a0bcf8e54556e17d90b93ba46fbc3e267..46758ed5b88827b2c867edfbdbb347f799d69abe 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2010  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -22,7 +22,6 @@
 #include "executor.h"
 #include "psppire-data-window.h"
 #include "dict-display.h"
-#include <language/syntax-string-source.h>
 #include "helper.h"
 #include <data/dictionary.h>
 
@@ -200,22 +199,10 @@ split_file_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&sfd);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&sfd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&sfd);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&sfd)));
       break;
     default:
       break;
diff --git a/src/ui/gui/syntax-editor-source.c b/src/ui/gui/syntax-editor-source.c
deleted file mode 100644 (file)
index 6ec866c..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   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
-   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/getl.h>
-#include <libpspp/compiler.h>
-#include <libpspp/cast.h>
-#include <libpspp/str.h>
-
-#include <stdlib.h>
-
-#include <gtk/gtk.h>
-
-#include "syntax-editor-source.h"
-#include "psppire-syntax-window.h"
-
-#include "xalloc.h"
-
-struct syntax_editor_source
-  {
-    struct getl_interface parent;
-    GtkTextBuffer *buffer;
-    GtkTextIter i;
-    GtkTextIter end;
-    const gchar *name;
-  };
-
-
-static bool
-always_false (const struct getl_interface *i UNUSED)
-{
-  return false;
-}
-
-/* Returns the name of the source */
-static const char *
-name (const struct getl_interface *i)
-{
-  const struct syntax_editor_source *ses = (const struct syntax_editor_source *) i;
-  return ses->name;
-}
-
-
-/* Returns the location within the source */
-static int
-location (const struct getl_interface *i)
-{
-  const struct syntax_editor_source *ses = (const struct syntax_editor_source *) i;
-
-  return gtk_text_iter_get_line (&ses->i);
-}
-
-
-static bool
-read_line_from_buffer (struct getl_interface *i,
-                      struct string *line)
-{
-  gchar *text;
-  GtkTextIter next_line;
-
-  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;
-
-  next_line = ses->i;
-  gtk_text_iter_forward_line (&next_line);
-
-  text = gtk_text_buffer_get_text (ses->buffer,
-                                  &ses->i, &next_line,
-                                  FALSE);
-  g_strchomp (text);
-
-  ds_assign_cstr (line, text);
-
-  g_free (text);
-
-  gtk_text_iter_forward_line (&ses->i);
-
-  return true;
-}
-
-
-static void
-do_close (struct getl_interface *i )
-{
-  free (i);
-}
-
-struct getl_interface *
-create_syntax_editor_source (GtkTextBuffer *buffer,
-                            GtkTextIter start,
-                            GtkTextIter stop,
-                            const gchar *nm
-                            )
-{
-  struct syntax_editor_source *ses = xzalloc (sizeof *ses);
-
-  ses->buffer = buffer;
-  ses->i = start;
-  ses->end = stop;
-  ses->name = nm;
-
-
-  ses->parent.interactive = always_false;
-  ses->parent.read = read_line_from_buffer;
-  ses->parent.close = do_close;
-
-  ses->parent.name = name;
-  ses->parent.location = location;
-
-
-  return &ses->parent;
-}
diff --git a/src/ui/gui/syntax-editor-source.h b/src/ui/gui/syntax-editor-source.h
deleted file mode 100644 (file)
index f8d08ea..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006  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 SYNTAX_EDITOR_SOURCE_H
-#define SYNTAX_EDITOR_SOURCE_H
-
-#include <gtk/gtk.h>
-struct getl_interface;
-
-struct syntax_editor;
-
-struct getl_interface *
-create_syntax_editor_source (GtkTextBuffer *buffer,
-                            GtkTextIter start,
-                            GtkTextIter stop,
-                            const gchar *name
-                            );
-
-
-
-#endif
index 4f134c2e1cb51b966674a5c0dc764941b7a5b93e..51e589ec730c048cbd2a72799fc8c4800dff0f1c 100644 (file)
           </object>
         </child>
         <child>
-          <object class="GtkAction" id="open2">
+          <object class="GtkAction" id="file_open">
             <property name="stock-id">gtk-open</property>
-            <property name="name">open2</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="file_open_syntax">
-            <property name="name">file_open_syntax</property>
-            <property name="label" translatable="yes">_Syntax</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkAction" id="file_open_data">
-            <property name="name">file_open_data</property>
-            <property name="label" translatable="yes">_Data</property>
+            <property name="name">file_open</property>
+            <property name="label" translatable="yes">_Open...</property>
           </object>
         </child>
         <child>
@@ -56,6 +45,7 @@
           <object class="GtkAction" id="file_save_as">
             <property name="stock-id">gtk-save-as</property>
             <property name="name">file_save_as</property>
+            <property name="label" translatable="yes">Save _As...</property>
           </object>
         </child>
         <child>
             <menuitem action="file_new_syntax"/>
             <menuitem action="file_new_data"/>
           </menu>
-          <menu action="open2">
-            <menuitem action="file_open_syntax"/>
-            <menuitem action="file_open_data"/>
-          </menu>
+          <menuitem action="file_open"/>
           <menuitem action="file_save"/>
           <menuitem action="file_save_as"/>
           <separator/>
index 93102c058166f6785e685448ab790a6ae7c3b47f..8983bc6741917825884944d77967d31516064d89 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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,7 +31,6 @@
 #include "t-test-options.h"
 #include <ui/syntax-gen.h>
 
-#include <language/syntax-string-source.h>
 #include "helper.h"
 
 #include <gl/xalloc.h>
@@ -455,21 +454,10 @@ t_test_independent_samples_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&tt_d)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-        paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&tt_d)));
       break;
     default:
       break;
index ea92a9212946f05a5fdf9a932751c80616a496de..befe868204a156e67ed7f7e9ca71414b26d910a1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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,7 +31,6 @@
 #include "executor.h"
 
 #include "t-test-options.h"
-#include <language/syntax-string-source.h>
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
@@ -166,23 +165,10 @@ t_test_one_sample_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&tt_d)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&tt_d)));
       break;
     default:
       break;
index 5f226d4e194a2963881d5ac05c09f3835ca04558..6233aa30263cefd6c8bc30e3f51e999f4c813f19 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2010  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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
@@ -17,7 +17,6 @@
 
 #include <config.h>
 #include <gtk/gtk.h>
-#include <language/syntax-string-source.h>
 
 #include "psppire-data-window.h"
 #include "psppire-selector.h"
@@ -210,22 +209,10 @@ t_test_paired_samples_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&tt_d)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&tt_d);
-        paste_syntax_to_window (syntax);
-
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&tt_d)));
       break;
     default:
       break;
index 13c6d96804e48903a72cf37e16699c0e788d0e3b..215a444c4861ba2d5d2faa0117b0608158af982a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2009, 2010  Free Software Foundation
+   Copyright (C) 2008, 2009, 2010, 2011  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 <gtk/gtk.h>
-
-
-#include "widget-io.h"
-#include "checkbox-treeview.h"
-#include "descriptives-dialog.h"
+#include "ui/gui/text-data-import-dialog.h"
 
 #include <errno.h>
-
 #include <gtk-contrib/psppire-sheet.h>
+#include <gtk/gtk.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include <data/data-in.h>
-#include <data/data-out.h>
-#include <data/format-guesser.h>
-#include <data/value-labels.h>
-#include <language/data-io/data-parser.h>
-#include <language/syntax-string-source.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <ui/syntax-gen.h>
-#include <ui/gui/psppire-data-window.h>
-#include <ui/gui/dialog-common.h>
-#include <ui/gui/helper.h>
-#include <ui/gui/psppire-dialog.h>
-#include <ui/gui/psppire-var-sheet.h>
-#include <ui/gui/psppire-var-store.h>
-#include "executor.h"
-
-#include "error.h"
-#include "xalloc.h"
+#include "data/data-in.h"
+#include "data/data-out.h"
+#include "data/format-guesser.h"
+#include "data/value-labels.h"
+#include "language/data-io/data-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "ui/gui/checkbox-treeview.h"
+#include "ui/gui/descriptives-dialog.h"
+#include "ui/gui/dialog-common.h"
+#include "ui/gui/executor.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/psppire-data-window.h"
+#include "ui/gui/psppire-dialog.h"
+#include "ui/gui/psppire-var-sheet.h"
+#include "ui/gui/psppire-var-store.h"
+#include "ui/gui/widget-io.h"
+#include "ui/syntax-gen.h"
+
+#include "gl/error.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -227,14 +226,15 @@ static GtkTreeViewColumn *make_data_column (struct import_assistant *,
                                             gint column_idx);
 static GtkTreeView *create_data_tree_view (bool input, GtkContainer *parent,
                                            struct import_assistant *);
-static void escape_underscores (const char *in, char *out);
+static char *escape_underscores (const char *in);
 static void push_watch_cursor (struct import_assistant *);
 static void pop_watch_cursor (struct import_assistant *);
 
 /* Pops up the Text Data Import assistant. */
 void
-text_data_import_assistant (GtkWindow *parent_window)
+text_data_import_assistant (PsppireDataWindow *dw)
 {
+  GtkWindow *parent_window = GTK_WINDOW (dw);
   struct import_assistant *ia;
 
   ia = xzalloc (sizeof *ia);
@@ -259,18 +259,10 @@ text_data_import_assistant (GtkWindow *parent_window)
   switch (ia->asst.response)
     {
     case GTK_RESPONSE_APPLY:
-      {
-       char *syntax = generate_syntax (ia);
-       execute_syntax (create_syntax_string_source (syntax));
-       free (syntax);
-      }
+      free (execute_syntax_string (dw, generate_syntax (ia)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       char *syntax = generate_syntax (ia);
-        paste_syntax_to_window (syntax);
-       free (syntax);
-      }
+      free (paste_syntax_to_window (generate_syntax (ia)));
       break;
     default:
       break;
@@ -338,8 +330,8 @@ apply_dict (const struct dictionary *dict, struct string *s)
               const struct val_lab *vl = labels[i];
               ds_put_cstr (s, "\n  ");
               syntax_gen_value (s, &vl->value, width, format);
-              ds_put_char (s, ' ');
-              syntax_gen_string (s, ss_cstr (val_lab_get_label (vl)));
+              ds_put_byte (s, ' ');
+              syntax_gen_string (s, ss_cstr (val_lab_get_escaped_label (vl)));
             }
           free (labels);
           ds_put_cstr (s, ".\n");
@@ -398,9 +390,9 @@ generate_syntax (const struct import_assistant *ia)
   if (ia->first_line.skip_lines > 0)
     ds_put_format (&s, "  /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
   ds_put_cstr (&s, "  /DELIMITERS=\"");
-  if (ds_find_char (&ia->separators.separators, '\t') != SIZE_MAX)
+  if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
     ds_put_cstr (&s, "\\t");
-  if (ds_find_char (&ia->separators.separators, '\\') != SIZE_MAX)
+  if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
     ds_put_cstr (&s, "\\\\");
   for (i = 0; i < ds_length (&ia->separators.separators); i++)
     {
@@ -408,7 +400,7 @@ generate_syntax (const struct import_assistant *ia)
       if (c == '"')
         ds_put_cstr (&s, "\"\"");
       else if (c != '\t' && c != '\\')
-        ds_put_char (&s, c);
+        ds_put_byte (&s, c);
     }
   ds_put_cstr (&s, "\"\n");
   if (!ds_is_empty (&ia->separators.quotes))
@@ -485,8 +477,8 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
           destroy_file (ia);
           return false;
         }
-      ds_chomp (line, '\n');
-      ds_chomp (line, '\r');
+      ds_chomp_byte (line, '\n');
+      ds_chomp_byte (line, '\r');
     }
 
   if (file->line_cnt == 0)
@@ -881,7 +873,7 @@ create_lines_tree_view (GtkContainer *parent, struct import_assistant *ia)
   size_t max_line_length;
   gint content_width, header_width;
   size_t i;
-  gchar *title = _("Text");
+  const gchar *title = _("Text");
 
   make_tree_view (ia, 0, &tree_view);
 
@@ -1169,7 +1161,7 @@ split_fields (struct import_assistant *ia)
   clear_fields (ia);
 
   /* Is space in the set of separators? */
-  space_sep = ss_find_char (ds_ss (&s->separators), ' ') != SIZE_MAX;
+  space_sep = ss_find_byte (ds_ss (&s->separators), ' ') != SIZE_MAX;
 
   /* Split all the lines, not just those from
      ia->first_line.skip_lines on, so that we split the line that
@@ -1196,9 +1188,9 @@ split_fields (struct import_assistant *ia)
               field = text;
             }
           else if (!ds_is_empty (&s->quotes)
-                   && ds_find_char (&s->quotes, text.string[0]) != SIZE_MAX)
+                   && ds_find_byte (&s->quotes, text.string[0]) != SIZE_MAX)
             {
-              int quote = ss_get_char (&text);
+              int quote = ss_get_byte (&text);
               if (!s->escape)
                 ss_get_until (&text, quote, &field);
               else
@@ -1207,18 +1199,18 @@ split_fields (struct import_assistant *ia)
                   int c;
 
                   ds_init_empty (&s);
-                  while ((c = ss_get_char (&text)) != EOF)
+                  while ((c = ss_get_byte (&text)) != EOF)
                     if (c != quote)
-                      ds_put_char (&s, c);
-                    else if (ss_match_char (&text, quote))
-                      ds_put_char (&s, quote);
+                      ds_put_byte (&s, c);
+                    else if (ss_match_byte (&text, quote))
+                      ds_put_byte (&s, quote);
                     else
                       break;
                   field = ds_ss (&s);
                 }
             }
           else
-            ss_get_chars (&text, ss_cspan (text, ds_ss (&s->separators)),
+            ss_get_bytes (&text, ss_cspan (text, ds_ss (&s->separators)),
                           &field);
 
           if (column_idx >= s->column_cnt)
@@ -1243,7 +1235,7 @@ split_fields (struct import_assistant *ia)
             ss_ltrim (&text, ss_cstr (" "));
           if (ss_is_empty (text))
             break;
-          if (ss_find_char (ds_ss (&s->separators), ss_first (text))
+          if (ss_find_byte (ds_ss (&s->separators), ss_first (text))
               != SIZE_MAX)
             ss_advance (&text, 1);
         }
@@ -1261,19 +1253,17 @@ choose_column_names (struct import_assistant *ia)
   struct column *col;
   size_t name_row;
 
-  dict = dict_create ();
+  dict = dict_create (get_default_encoding ());
   name_row = f->variable_names && f->skip_lines ? f->skip_lines : 0;
   for (col = s->columns; col < &s->columns[s->column_cnt]; col++)
     {
-      char name[VAR_NAME_LEN + 1];
-      char *hint;
+      char *hint, *name;
 
       hint = name_row ? ss_xstrdup (col->contents[name_row - 1]) : NULL;
-      if (!dict_make_unique_var_name (dict, hint, &generated_name_count, name))
-        NOT_REACHED ();
+      name = dict_make_unique_var_name (dict, hint, &generated_name_count);
       free (hint);
 
-      col->name = xstrdup (name);
+      col->name = name;
       dict_create_var_assert (dict, name, 0);
     }
   dict_destroy (dict);
@@ -1331,7 +1321,7 @@ find_commonest_chars (unsigned long int histogram[UCHAR_MAX + 1],
   if (max_count > 0)
     {
       ds_clear (result);
-      ds_put_char (result, max);
+      ds_put_byte (result, max);
     }
   else
     ds_assign_cstr (result, def);
@@ -1387,7 +1377,7 @@ set_separators (struct import_assistant *ia)
             }
         }
 
-      ds_put_char (&custom, c);
+      ds_put_byte (&custom, c);
     next:;
     }
 
@@ -1430,7 +1420,7 @@ get_separators (struct import_assistant *ia)
       const struct separator *sep = &separators[i];
       GtkWidget *button = get_widget_assert (ia->asst.builder, sep->name);
       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
-        ds_put_char (&s->separators, sep->c);
+        ds_put_byte (&s->separators, sep->c);
     }
 
   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (s->custom_cb)))
@@ -1606,12 +1596,11 @@ prepare_formats_page (struct import_assistant *ia)
 
   push_watch_cursor (ia);
 
-  dict = dict_create ();
+  dict = dict_create (get_default_encoding ());
   fg = fmt_guesser_create ();
   for (column_idx = 0; column_idx < s->column_cnt; column_idx++)
     {
       struct variable *modified_var;
-      char name[VAR_NAME_LEN + 1];
 
       modified_var = (column_idx < p->modified_var_cnt
                       ? p->modified_vars[column_idx] : NULL);
@@ -1620,11 +1609,11 @@ prepare_formats_page (struct import_assistant *ia)
           struct column *column = &s->columns[column_idx];
           struct variable *var;
           struct fmt_spec format;
+          char *name;
           size_t row;
 
           /* Choose variable name. */
-          if (!dict_make_unique_var_name (dict, column->name, &number, name))
-            NOT_REACHED ();
+          name = dict_make_unique_var_name (dict, column->name, &number);
 
           /* Choose variable format. */
           fmt_guesser_clear (fg);
@@ -1636,13 +1625,17 @@ prepare_formats_page (struct import_assistant *ia)
           /* Create variable. */
           var = dict_create_var_assert (dict, name, fmt_var_width (&format));
           var_set_both_formats (var, &format);
+
+          free (name);
         }
       else
         {
-          if (!dict_make_unique_var_name (dict, var_get_name (modified_var),
-                                          &number, name))
-            NOT_REACHED ();
+          char *name;
+
+          name = dict_make_unique_var_name (dict, var_get_name (modified_var),
+                                            &number);
           dict_clone_var_as_assert (dict, modified_var, name);
+          free (name);
         }
     }
   fmt_guesser_destroy (fg);
@@ -1777,8 +1770,7 @@ parse_field (struct import_assistant *ia,
     {
       char *error;
 
-      error = data_in (field, LEGACY_NATIVE, in->type, &val,
-                       var_get_width (var),
+      error = data_in (field, C_ENCODING, in->type, &val, var_get_width (var),
                        dict_get_encoding (ia->formats.dict));
       if (error != NULL)
         {
@@ -1890,7 +1882,7 @@ get_tooltip_location (GtkWidget *widget, gint wx, gint wy,
      to make the data related to the tool tips part of a GObject
      that only gets destroyed when all references are released,
      but this solution appears to be effective too. */
-  if (!GTK_WIDGET_MAPPED (widget))
+  if (!gtk_widget_get_mapped (widget))
     return FALSE;
 
   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
@@ -1952,8 +1944,8 @@ get_monospace_width (GtkTreeView *treeview, GtkCellRenderer *renderer,
   gint width;
 
   ds_init_empty (&s);
-  ds_put_char_multiple (&s, '0', char_cnt);
-  ds_put_char (&s, ' ');
+  ds_put_byte_multiple (&s, '0', char_cnt);
+  ds_put_byte (&s, ' ');
   width = get_string_width (treeview, renderer, ds_cstr (&s));
   ds_destroy (&s);
 
@@ -1977,17 +1969,17 @@ make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
 {
   struct variable *var = NULL;
   struct column *column = NULL;
-  char name[(VAR_NAME_LEN * 2) + 1];
   size_t char_cnt;
   gint content_width, header_width;
   GtkTreeViewColumn *tree_column;
+  char *name;
 
   if (input)
     column = &ia->separators.columns[dict_idx];
   else
     var = dict_get_var (ia->formats.dict, dict_idx);
 
-  escape_underscores (input ? column->name : var_get_name (var), name);
+  name = escape_underscores (input ? column->name : var_get_name (var));
   char_cnt = input ? column->width : var_get_print_format (var)->w;
   content_width = get_monospace_width (tree_view, ia->asst.fixed_renderer,
                                        char_cnt);
@@ -2007,6 +1999,8 @@ make_data_column (struct import_assistant *ia, GtkTreeView *tree_view,
   gtk_tree_view_column_set_fixed_width (tree_column, MAX (content_width,
                                                           header_width));
 
+  free (name);
+
   return tree_column;
 }
 
@@ -2037,16 +2031,22 @@ create_data_tree_view (bool input, GtkContainer *parent,
   return tree_view;
 }
 
-static void
-escape_underscores (const char *in, char *out)
+static char *
+escape_underscores (const char *in)
 {
+  char *out = xmalloc (2 * strlen (in) + 1);
+  char *p;
+
+  p = out;
   for (; *in != '\0'; in++)
     {
       if (*in == '_')
-        *out++ = '_';
-      *out++ = *in;
+        *p++ = '_';
+      *p++ = *in;
     }
-  *out = '\0';
+  *p = '\0';
+
+  return out;
 }
 \f
 /* TextImportModel, a GtkTreeModel implementation used by some
index f770dfac25f6ce3c9e4cf2f43299dc91edbb5e4f..664249c9644ef46cbbae74b6acf9976a94ecedb1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008  Free Software Foundation
+   Copyright (C) 2008, 2010, 2011  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
@@ -18,7 +18,8 @@
 #define TEXT_DATA_IMPORT_DIALOG_H
 
 #include <glib-object.h>
+#include "ui/gui/psppire-data-window.h"
 
-void text_data_import_assistant (GObject *o, gpointer data);
+void text_data_import_assistant (PsppireDataWindow *);
 
 #endif
index ebc34bd8546f253d97a0c72d4ad3e61e48e99d38..87e3b1e4657ea169a7130a9f176a56f96a4fb932 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -23,7 +23,6 @@
 #include "executor.h"
 #include "psppire-data-window.h"
 #include "dict-display.h"
-#include <language/syntax-string-source.h>
 #include "helper.h"
 
 #include "dialog-common.h"
@@ -111,14 +110,7 @@ transpose_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (dict, xml);
-
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (dict, xml)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
       {
index efeb548e29d61060c5a781c1057716cff103fdab..6126afc1dddacd5a6f6e67451c5d4977d813e36d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005, 2009  Free Software Foundation
+   Copyright (C) 2005, 2009, 2010, 2011  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
@@ -38,9 +38,6 @@ struct val_labs_dialog
 {
   GtkWidget *window;
 
-  PsppireVarStore *var_store;
-  PsppireDict *dict;
-
   /* The variable to be updated */
   struct variable *pv;
 
@@ -77,7 +74,6 @@ on_label_entry_change (GtkEntry *entry, gpointer data)
   text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
 
   text_to_value (text,
-                dialog->dict,
                 dialog->pv,
                 &v);
 
@@ -150,7 +146,6 @@ on_value_entry_change (GtkEntry *entry, gpointer data)
 
   union value v;
   text_to_value (text,
-                dialog->dict,
                 dialog->pv,
                 &v);
 
@@ -192,7 +187,7 @@ val_labs_ok (GtkWidget *w, gpointer data)
 
   val_labs_destroy (dialog->labs);
 
-  dialog->labs = 0;
+  dialog->labs = NULL;
 
   gtk_widget_hide (dialog->window);
 
@@ -206,7 +201,7 @@ val_labs_cancel (struct val_labs_dialog *dialog)
 {
   val_labs_destroy (dialog->labs);
 
-  dialog->labs = 0;
+  dialog->labs = NULL;
 
   gtk_widget_hide (dialog->window);
 }
@@ -261,7 +256,11 @@ get_selected_tuple (struct val_labs_dialog *dialog,
   if (valuep != NULL)
     *valuep = value;
   if (label != NULL)
-    *label = val_labs_find (dialog->labs, &value);
+    {
+      struct val_lab *vl = val_labs_lookup (dialog->labs, &value);
+      if (vl != NULL)
+        *label = val_lab_get_escaped_label (vl);
+    }
 }
 
 
@@ -278,7 +277,6 @@ on_change (GtkWidget *w, gpointer data)
   union value v;
 
   text_to_value (val_text,
-                dialog->dict,
                 dialog->pv,
                 &v);
 
@@ -304,7 +302,6 @@ on_add (GtkWidget *w, gpointer data)
   const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
 
   text_to_value (text,
-                dialog->dict,
                 dialog->pv,
                 &v);
 
@@ -356,7 +353,7 @@ on_select_row (GtkTreeView *treeview, gpointer data)
   gchar *text;
 
   get_selected_tuple (dialog, &value, &label);
-  text = value_to_text (value, dialog->dict, *var_get_write_format (dialog->pv));
+  text = value_to_text (value, dialog->pv);
 
   g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
                         dialog->value_handler_id);
@@ -385,7 +382,7 @@ on_select_row (GtkTreeView *treeview, gpointer data)
 /* Create a new dialog box
    (there should  normally be only one)*/
 struct val_labs_dialog *
-val_labs_dialog_create (GtkWindow *toplevel, PsppireVarStore *var_store)
+val_labs_dialog_create (GtkWindow *toplevel)
 {
   GtkTreeViewColumn *column;
 
@@ -395,8 +392,6 @@ val_labs_dialog_create (GtkWindow *toplevel, PsppireVarStore *var_store)
 
   struct val_labs_dialog *dialog = g_malloc (sizeof (*dialog));
 
-  dialog->var_store = var_store;
-  g_object_get (var_store, "dictionary", &dialog->dict, NULL);
   dialog->window = get_widget_assert (xml,"val_labs_dialog");
   dialog->value_entry = get_widget_assert (xml,"value_entry");
   dialog->label_entry = get_widget_assert (xml,"label_entry");
@@ -457,7 +452,7 @@ val_labs_dialog_create (GtkWindow *toplevel, PsppireVarStore *var_store)
   g_signal_connect (dialog->add_button, "clicked",
                   G_CALLBACK (on_add), dialog);
 
-  dialog->labs = 0;
+  dialog->labs = NULL;
 
   g_object_unref (xml);
 
@@ -509,11 +504,10 @@ repopulate_dialog (struct val_labs_dialog *dialog)
       const struct val_lab *vl = labels[i];
 
       gchar *const vstr  =
-       value_to_text (vl->value, dialog->dict,
-                     *var_get_write_format (dialog->pv));
+       value_to_text (vl->value, dialog->pv);
 
-      gchar *const text = g_strdup_printf (_("%s = `%s'"),
-                                          vstr, val_lab_get_label (vl));
+      gchar *const text = g_strdup_printf (_("%s = `%s'"), vstr,
+                                           val_lab_get_escaped_label (vl));
 
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
index 745e0a0ae5f795b2786a078d9e435ca633ad242c..85feaaca7891ec1115639d70886730fc26078c08 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005  Free Software Foundation
+   Copyright (C) 2005, 2011  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
@@ -30,7 +30,7 @@
 struct val_labs;
 
 
-struct val_labs_dialog * val_labs_dialog_create (GtkWindow *, PsppireVarStore *);
+struct val_labs_dialog * val_labs_dialog_create (GtkWindow *);
 
 void val_labs_dialog_show (struct val_labs_dialog *);
 
index 1b9bf71c4764db71d4a3b88fef9ca0035035b68b..db0020f4f426729160a6ab665e408b7da677239c 100644 (file)
 static const gchar none[] = N_("None");
 
 
-gchar *
-measure_to_string (const struct variable *var, GError **err)
-{
-  const gint measure = var_get_measure (var);
-
-  g_assert (measure < n_MEASURES);
-  return gettext (measures[measure]);
-}
-
-
 gchar *
 missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GError **err)
 {
-  const struct fmt_spec *fmt =  var_get_print_format (pv);
   gchar *s;
   const struct missing_values *miss = var_get_missing_values (pv);
   if ( mv_is_empty (miss))
@@ -44,7 +33,7 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
          gint i;
          for (i = 0 ; i < n; ++i )
            {
-             mv[i] = value_to_text (*mv_get_value (miss, i), dict, *fmt);
+             mv[i] = value_to_text (*mv_get_value (miss, i), pv);
              if ( i > 0 )
                g_string_append (gstr, ", ");
              g_string_append (gstr, mv[i]);
@@ -60,8 +49,8 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
          union value low, high;
          mv_get_range (miss, &low.f, &high.f);
 
-         l = value_to_text (low, dict, *fmt);
-         h = value_to_text (high, dict,*fmt);
+         l = value_to_text (low, pv);
+         h = value_to_text (high, pv);
 
          g_string_printf (gstr, "%s - %s", l, h);
          g_free (l);
@@ -69,9 +58,9 @@ missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GE
 
          if ( mv_has_value (miss))
            {
-             gchar *ss = 0;
+             gchar *ss = NULL;
 
-             ss = value_to_text (*mv_get_value (miss, 0), dict, *fmt);
+             ss = value_to_text (*mv_get_value (miss, 0), pv);
 
              g_string_append (gstr, ", ");
              g_string_append (gstr, ss);
index 927e235c21419d48e80875284412dd9268424f3e..3590d7cb81342b53299a8c0b7b5a5398baf7a044 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2011  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
@@ -30,6 +30,5 @@ extern const gchar *const alignments[n_ALIGNMENTS + 1];
 extern const gchar *const measures[n_MEASURES + 1];
 
 gchar *missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GError **err);
-gchar *measure_to_string (const struct variable *var, GError **err);
 
 #endif
index f196e554f9d0c224ee6bfc5a268814e566472050..a4c2a22769c3be34911893232659125d14dd726b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-    Copyright (C) 2005, 2006, 2010  Free Software Foundation
+    Copyright (C) 2005, 2006, 2010, 2011  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 <gtk/gtk.h>
-
 #include <stdlib.h>
 #include <string.h>
 
-#include "var-type-dialog.h"
-
-#include "helper.h"
-
-#include <data/variable.h>
-#include <data/settings.h>
-#include <libpspp/message.h>
-
+#include "data/data-out.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "libpspp/message.h"
+#include "ui/gui/helper.h"
+#include "ui/gui/var-type-dialog.h"
 
 struct tgs
 {
@@ -125,7 +122,7 @@ static void update_width_decimals (const struct var_type_dialog *dialog);
 static void
 set_local_width_decimals (struct var_type_dialog *dialog)
 {
-  dialog->fmt_l = * var_get_write_format (dialog->pv);
+  dialog->fmt_l = * var_get_print_format (dialog->pv);
 
   switch (dialog->active_button)
     {
@@ -262,12 +259,12 @@ preview_custom (GtkWidget *w, gpointer data)
       union value v;
       v.f = 1234.56;
 
-      sample_text = value_to_text (v, dialog->vs->dictionary, dialog->fmt_l);
+      sample_text = g_strchug (data_out (&v, NULL, &dialog->fmt_l));
       gtk_label_set_text (GTK_LABEL (dialog->label_psample), sample_text);
       g_free (sample_text);
 
       v.f = -v.f;
-      sample_text = value_to_text (v, dialog->vs->dictionary, dialog->fmt_l);
+      sample_text = g_strchug (data_out (&v, NULL, &dialog->fmt_l));
       gtk_label_set_text (GTK_LABEL (dialog->label_nsample), sample_text);
       g_free (sample_text);
     }
@@ -320,15 +317,13 @@ set_format_type_from_treeview (GtkTreeView *treeview, gpointer data)
 
 /* Create the structure */
 struct var_type_dialog *
-var_type_dialog_create (GtkWindow *toplevel, PsppireVarStore *vs)
+var_type_dialog_create (GtkWindow *toplevel)
 {
   gint i;
   struct var_type_dialog *dialog = g_malloc (sizeof (struct var_type_dialog));
 
   GtkBuilder *xml = builder_new ("var-sheet-dialogs.ui");
 
-  dialog->vs = vs;
-
   dialog->window = get_widget_assert (xml,"var_type_dialog");
   dialog->active_button = -1;
 
@@ -664,21 +659,21 @@ select_treeview_from_format_type (GtkTreeView *treeview,
 static void
 var_type_dialog_set_state (struct var_type_dialog *dialog)
 {
-  const struct fmt_spec *write_spec ;
+  const struct fmt_spec *format ;
   GString *str = g_string_new ("");
 
   g_assert (dialog);
   g_assert (dialog->pv);
 
   /* Populate width and decimals */
-  write_spec = var_get_write_format (dialog->pv);
+  format = var_get_print_format (dialog->pv);
 
-  g_string_printf (str, "%d", write_spec->d);
+  g_string_printf (str, "%d", format->d);
 
   gtk_entry_set_text (GTK_ENTRY (dialog->entry_decimals),
                     str->str);
 
-  g_string_printf (str, "%d", write_spec->w);
+  g_string_printf (str, "%d", format->w);
 
   gtk_entry_set_text (GTK_ENTRY (dialog->entry_width),
                     str->str);
@@ -686,7 +681,7 @@ var_type_dialog_set_state (struct var_type_dialog *dialog)
   g_string_free (str, TRUE);
 
   /* Populate the radio button states */
-  switch (write_spec->type)
+  switch (format->type)
     {
     case FMT_F:
       var_type_dialog_set_active_button (dialog, BUTTON_NUMERIC);
@@ -709,7 +704,7 @@ var_type_dialog_set_state (struct var_type_dialog *dialog)
       var_type_dialog_set_active_button (dialog, BUTTON_DOLLAR);
       gtk_widget_show_all (dialog->width_decimals);
 
-      select_treeview_from_format (dialog->dollar_treeview, write_spec);
+      select_treeview_from_format (dialog->dollar_treeview, format);
       break;
     case FMT_DATE:
     case FMT_EDATE:
@@ -727,7 +722,7 @@ var_type_dialog_set_state (struct var_type_dialog *dialog)
       var_type_dialog_set_active_button (dialog, BUTTON_DATE);
       gtk_widget_hide (dialog->width_decimals);
       gtk_widget_show (dialog->date_format_list);
-      select_treeview_from_format (dialog->date_format_treeview, write_spec);
+      select_treeview_from_format (dialog->date_format_treeview, format);
       break;
     case FMT_CCA:
     case FMT_CCB:
@@ -736,7 +731,7 @@ var_type_dialog_set_state (struct var_type_dialog *dialog)
     case FMT_CCE:
       var_type_dialog_set_active_button (dialog, BUTTON_CUSTOM);
       select_treeview_from_format_type (dialog->custom_treeview,
-                                      write_spec->type);
+                                      format->type);
       gtk_widget_show_all (dialog->width_decimals);
       break;
     default:
index 4bb681aaa0e0688e96965fb73c1a82eff0c3505b..e194771667e73fe5840d57de84f1aa5419744815 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005  Free Software Foundation
+   Copyright (C) 2005, 2011  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
@@ -47,10 +47,6 @@ struct var_type_dialog
   /* Variable to be updated */
   struct variable *pv;
   
-  /* The variable store to which this dialog relates */
-  PsppireVarStore *vs;
-  
-
   /* Local copy of format specifier */
   struct fmt_spec fmt_l;
 
@@ -88,7 +84,7 @@ struct var_type_dialog
 };
 
 
-struct var_type_dialog * var_type_dialog_create (GtkWindow *, PsppireVarStore *vs);
+struct var_type_dialog * var_type_dialog_create (GtkWindow *);
 
 void var_type_dialog_show (struct var_type_dialog *dialog);
 
index 521864f417c6cd041570a705c91d6638bbe570ac..d5b41a98686cb13172f22c1e1e69f2ccded41617 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011  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 <gtk/gtk.h>
 
-#include "variable-info-dialog.h"
-#include "var-display.h"
 #include <data/variable.h>
 #include <data/format.h>
 #include <data/value-labels.h>
+#include <libpspp/i18n.h>
+
+#include "variable-info-dialog.h"
+#include "var-display.h"
+
 #include "psppire-data-window.h"
 #include "psppire-dialog.h"
-#include "psppire-var-store.h"
 #include "psppire-dictview.h"
+#include "psppire-var-store.h"
 #include "helper.h"
 
-#include <language/syntax-string-source.h>
-#include <libpspp/i18n.h>
-#include "helper.h"
 
 
 #include <gettext.h>
@@ -55,7 +55,7 @@ label_to_string (const struct variable *var)
 static void
 populate_text (PsppireDictView *treeview, gpointer data)
 {
-  gchar *text = 0;
+  gchar *text = NULL;
   GString *gstring;
   PsppireDict *dict;
 
@@ -89,9 +89,8 @@ populate_text (PsppireDictView *treeview, gpointer data)
                          text);
   g_free (text);
 
-  text = measure_to_string (var, NULL);
   g_string_append_printf (gstring, _("Measurement Level: %s\n"),
-                         text);
+                         measure_to_string (var_get_measure (var)));
 
 
   /* Value Labels */
@@ -110,10 +109,10 @@ populate_text (PsppireDictView *treeview, gpointer data)
       for (i = 0; i < n_labels; i++)
         {
           const struct val_lab *vl = labels[i];
-         gchar *const vstr  =
-           value_to_text (vl->value,  dict, *var_get_print_format (var));
+         gchar *const vstr  = value_to_text (vl->value,  var);
 
-         g_string_append_printf (gstring, _("%s %s\n"), vstr, val_lab_get_label (vl));
+         g_string_append_printf (gstring, _("%s %s\n"),
+                                  vstr, val_lab_get_escaped_label (vl));
 
          g_free (vstr);
        }
index fc50aea944b56889a7dd31009a31047fbbee4df2..fa85ae4a02ce045c56af6cbc343b9a28f6b9b1f9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007  Free Software Foundation
+   Copyright (C) 2007, 2010, 2011  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
@@ -22,7 +22,6 @@
 #include "executor.h"
 #include "psppire-data-window.h"
 #include "dict-display.h"
-#include <language/syntax-string-source.h>
 #include "helper.h"
 
 #include <gtk/gtk.h>
@@ -153,20 +152,10 @@ weight_cases_dialog (PsppireDataWindow *de)
   switch (response)
     {
     case GTK_RESPONSE_OK:
-      {
-       gchar *syntax = generate_syntax (&wcd);
-       struct getl_interface *sss = create_syntax_string_source (syntax);
-       execute_syntax (sss);
-
-       g_free (syntax);
-      }
+      g_free (execute_syntax_string (de, generate_syntax (&wcd)));
       break;
     case PSPPIRE_RESPONSE_PASTE:
-      {
-       gchar *syntax = generate_syntax (&wcd);
-        paste_syntax_to_window (syntax);
-       g_free (syntax);
-      }
+      g_free (paste_syntax_to_window (generate_syntax (&wcd)));
       break;
     default:
       break;
index 3771cad6454a6e8598427dd0834139184ec31f27..73a7301662033e366a1d8180692c131646b82aac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009  Free Software Foundation
+   Copyright (C) 2007, 2009, 2011  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
@@ -100,7 +100,8 @@ widget_printf (const gchar *fmt, ...)
     }
   va_end (ap);
 
-  g_free (a.arg);
+  if (a.arg != a.direct_alloc_arg)
+    free (a.arg);
 
   output = g_string_sized_new (strlen (fmt));
 
@@ -128,7 +129,8 @@ widget_printf (const gchar *fmt, ...)
     }
 
   free (widgets);
-  free (d.dir);
+  if (d.dir != d.direct_alloc_dir)
+    free (d.dir);
 
   if (*s)
     g_string_append_len (output, s, -1);
@@ -162,7 +164,8 @@ widget_scanf (const gchar *fmt, ...)
   if ( 0 !=  printf_parse (fmt, &d, &a) )
     return NULL;
 
-  g_free (a.arg);
+  if (a.arg != a.direct_alloc_arg)
+    free (a.arg);
 
   va_start (ap, fmt);
 
@@ -232,7 +235,8 @@ widget_scanf (const gchar *fmt, ...)
 
   g_free (widgets);
 
-  free (d.dir);
+  if (d.dir != d.direct_alloc_dir)
+    free (d.dir);
 
   return hbox;
 }
index a984b3d099546d59b09b1487e1ec0e832ed3cb67..9627fdf57a5525696f2ba5953b110a0b2f14cf94 100644 (file)
 #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 "language/lexer/include-path.h"
+#include "language/lexer/lexer.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"
@@ -62,10 +61,8 @@ static const struct argv_option source_init_options[N_SOURCE_INIT_OPTIONS] =
   };
 
 static void
-source_init_option_callback (int id, void *ss_)
+source_init_option_callback (int id, void *aux UNUSED)
 {
-  struct source_stream *ss = ss_;
-
   switch (id)
     {
     case OPT_ALGORITHM:
@@ -82,13 +79,13 @@ source_init_option_callback (int id, void *ss_)
 
     case OPT_INCLUDE:
       if (!strcmp (optarg, "-"))
-       getl_clear_include_path (ss);
+        include_path_clear ();
       else
-       getl_add_include_dir (ss, optarg);
+        include_path_add (optarg);
       break;
 
     case OPT_NO_INCLUDE:
-      getl_clear_include_path (ss);
+      include_path_clear ();
       break;
 
     case OPT_SAFER:
@@ -113,9 +110,8 @@ source_init_option_callback (int id, void *ss_)
 }
 
 void
-source_init_register_argv_parser (struct argv_parser *ap,
-                                  struct source_stream *ss)
+source_init_register_argv_parser (struct argv_parser *ap)
 {
   argv_parser_add_options (ap, source_init_options, N_SOURCE_INIT_OPTIONS,
-                           source_init_option_callback, ss);
+                           source_init_option_callback, NULL);
 }
index cfd87f3fa0322266114d346b850b73332dfd42bf..ee1de0319a2af3c7ecd2d7ba096b841c0b85d8ee 100644 (file)
@@ -19,9 +19,7 @@
 #define UI_SOURCE_INIT_OPTS
 
 struct argv_parser;
-struct source_stream;
 
-void source_init_register_argv_parser (struct argv_parser *,
-                                       struct source_stream *);
+void source_init_register_argv_parser (struct argv_parser *);
 
 #endif /* ui/source/source-init-opts.h */
index b49911f5e8f06fd81a2726a1a0bc67b51e68f558..bcec18e5565bab56169eee50766d541c9f5e0999 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2010, 2011 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
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <ui/syntax-gen.h>
+#include "ui/syntax-gen.h"
 
 #include <ctype.h>
 #include <mbchar.h>
 #include "data/value.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/ftoastr.h"
+
 /* Appends to OUTPUT a pair of hex digits for each byte in IN. */
 static void
 syntax_gen_hex_digits (struct string *output, struct substring in)
@@ -38,8 +41,8 @@ syntax_gen_hex_digits (struct string *output, struct substring in)
   for (i = 0; i < in.length; i++)
     {
       unsigned char c = in.string[i];
-      ds_put_char (output, "0123456789ABCDEF"[c >> 4]);
-      ds_put_char (output, "0123456789ABCDEF"[c & 0xf]);
+      ds_put_byte (output, "0123456789ABCDEF"[c >> 4]);
+      ds_put_byte (output, "0123456789ABCDEF"[c & 0xf]);
     }
 }
 
@@ -59,13 +62,13 @@ has_control_chars (struct substring in)
 static bool
 has_single_quote (struct substring str)
 {
-  return (SIZE_MAX != ss_find_char (str, '\''));
+  return (SIZE_MAX != ss_find_byte (str, '\''));
 }
 
 static bool
 has_double_quote (struct substring str)
 {
-  return (SIZE_MAX != ss_find_char (str, '"'));
+  return (SIZE_MAX != ss_find_byte (str, '"'));
 }
 
 /* Appends to OUTPUT valid PSPP syntax for a quoted string that
@@ -84,7 +87,7 @@ syntax_gen_string (struct string *output, struct substring in)
     {
       ds_put_cstr (output, "X'");
       syntax_gen_hex_digits (output, in);
-      ds_put_char (output, '\'');
+      ds_put_byte (output, '\'');
     }
   else
     {
@@ -99,15 +102,15 @@ syntax_gen_string (struct string *output, struct substring in)
       assert (is_basic ('\''));
 
       quote = has_double_quote (in) && !has_single_quote (in) ? '\'' : '"';
-      ds_put_char (output, quote);
+      ds_put_byte (output, quote);
       for (i = 0; i < in.length; i++)
         {
           char c = in.string[i];
           if (c == quote)
-            ds_put_char (output, quote);
-          ds_put_char (output, c);
+            ds_put_byte (output, quote);
+          ds_put_byte (output, c);
         }
-      ds_put_char (output, quote);
+      ds_put_byte (output, quote);
     }
 }
 
@@ -154,8 +157,7 @@ syntax_gen_number (struct string *output,
       s = data_out (&v_in, "FIXME",  format);
 
       /* FIXME: UTF8 encoded strings will fail here */
-      error = data_in (ss_cstr (s), LEGACY_NATIVE,
-                       format->type, &v_out, 0, NULL);
+      error = data_in (ss_cstr (s), C_ENCODING, format->type, &v_out, 0, NULL);
       ok = error == NULL;
       free (error);
 
@@ -172,18 +174,10 @@ syntax_gen_number (struct string *output,
     ds_put_cstr (output, "SYSMIS");
   else
     {
-      /* FIXME: This should consistently yield precisely the same
-         value as NUMBER on input, but its results for values
-         cannot be exactly represented in decimal are ugly: many
-         of them will have far more decimal digits than are
-         needed.  The free-format floating point output routine
-         from Steele and White, "How to Print Floating-Point
-         Numbers Accurately" is really what we want.  The MPFR
-         library has an implementation of this, or equivalent
-         functionality, in its mpfr_strtofr routine, but it would
-         not be nice to make PSPP depend on this.  Probably, we
-         should implement something equivalent to it. */
-      ds_put_format (output, "%.*g", DBL_DIG + 1, number);
+      char s[DBL_BUFSIZE_BOUND];
+
+      dtoastr (s, sizeof s, 0, 0, number);
+      ds_put_cstr (output, s);
     }
 }
 
@@ -286,7 +280,7 @@ syntax_gen_pspp_valist (struct string *output, const char *format,
           }
 
         case '%':
-          ds_put_char (output, '%');
+          ds_put_byte (output, '%');
           break;
 
         default:
index 244e528b0748cd349c1481d3856aff5990c98e8a..78ae5ea999375b44aaa3e03e5f2d96bee320939f 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2011 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,8 +21,8 @@
 
 #include <stdarg.h>
 #include <stddef.h>
-#include <libpspp/compiler.h>
-#include <libpspp/str.h>
+#include "libpspp/compiler.h"
+#include "libpspp/str.h"
 
 struct fmt_spec;
 struct substring;
index 81b896dc878839d44590f9e3205ebc53d5e07fb0..af397a10302079b5c566527b792f9e9e6a570f84 100644 (file)
@@ -3,16 +3,13 @@
 noinst_LTLIBRARIES += src/ui/terminal/libui.la
 
 src_ui_terminal_libui_la_SOURCES = \
-       src/ui/terminal/read-line.c \
-       src/ui/terminal/read-line.h \
        src/ui/terminal/main.c \
-       src/ui/terminal/msg-ui.c \
-       src/ui/terminal/msg-ui.h \
-       src/ui/terminal/terminal.c \
-       src/ui/terminal/terminal.h \
        src/ui/terminal/terminal-opts.c \
-       src/ui/terminal/terminal-opts.h 
-
+       src/ui/terminal/terminal-opts.h \
+       src/ui/terminal/terminal-reader.c \
+       src/ui/terminal/terminal-reader.h \
+       src/ui/terminal/terminal.c \
+       src/ui/terminal/terminal.h
 
 src_ui_terminal_libui_la_CFLAGS = $(NCURSES_CFLAGS)
 
@@ -27,8 +24,7 @@ src_ui_terminal_pspp_LDADD = \
        src/libpspp-core.la \
        $(CAIRO_LIBS) \
        $(NCURSES_LIBS) \
-       $(LIBICONV) \
-       $(LIBINTL) $(LIBREADLINE)
+       $(LIBREADLINE)
 
 
 src_ui_terminal_pspp_LDFLAGS = $(PSPP_LDFLAGS) $(PG_LDFLAGS)
index 64a7d2ec013e97a732b782570c25869b85fa669b..c19a1c78eaade7c0c40e72cfe736d1ac7849b60a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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
 #endif
 #include <unistd.h>
 
+#include "data/dataset.h"
 #include "data/dictionary.h"
 #include "data/file-handle-def.h"
 #include "data/file-name.h"
-#include "data/procedure.h"
+#include "data/session.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 "language/syntax-file.h"
+#include "language/lexer/include-path.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 "output/message-item.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-reader.h"
 #include "ui/terminal/terminal.h"
+#include "ui/terminal/terminal-opts.h"
 
 #include "gl/fatal-signal.h"
 #include "gl/progname.h"
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static struct dataset * the_dataset = NULL;
-
-static struct lexer *the_lexer;
-static struct source_stream *the_source_stream ;
+static struct session *the_session;
 
-static void add_syntax_file (struct source_stream *, enum syntax_mode,
-                             const char *file_name);
+static void add_syntax_reader (struct lexer *, const char *file_name,
+                               const char *encoding, enum lex_syntax_mode);
 static void bug_handler(int sig);
 static void fpu_init (void);
+static void output_msg (const struct msg *, void *);
 
 /* Program entry point. */
 int
@@ -79,8 +77,10 @@ main (int argc, char **argv)
 {
   struct terminal_opts *terminal_opts;
   struct argv_parser *parser;
-  enum syntax_mode syntax_mode;
+  enum lex_syntax_mode syntax_mode;
+  char *syntax_encoding;
   bool process_statrc;
+  struct lexer *lexer;
 
   set_program_name (argv[0]);
 
@@ -93,32 +93,33 @@ main (int argc, char **argv)
   gsl_set_error_handler_off ();
 
   fh_init ();
-  the_source_stream = create_source_stream ();
-  prompt_init ();
-  readln_initialize ();
   settings_init ();
   terminal_check_size ();
   random_init ();
 
-  the_dataset = create_dataset ();
+  lexer = lex_create ();
+  the_session = session_create ();
+  dataset_create (the_session, "");
 
   parser = argv_parser_create ();
-  terminal_opts = terminal_opts_init (parser, &syntax_mode, &process_statrc);
-  source_init_register_argv_parser (parser, the_source_stream);
+  terminal_opts = terminal_opts_init (parser, &syntax_mode, &process_statrc,
+                                      &syntax_encoding);
+  source_init_register_argv_parser (parser);
   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);
+  msg_set_handler (output_msg, lexer);
+  session_set_default_syntax_encoding (the_session, syntax_encoding);
 
   /* Add syntax files to source stream. */
   if (process_statrc)
     {
-      char *rc = fn_search_path ("rc", getl_include_path (the_source_stream));
+      char *rc = include_path_search ("rc");
       if (rc != NULL)
         {
-          add_syntax_file (the_source_stream, GETL_BATCH, rc);
+          add_syntax_reader (lexer, rc, "Auto", LEX_SYNTAX_AUTO);
           free (rc);
         }
     }
@@ -127,47 +128,52 @@ main (int argc, char **argv)
       int i;
 
       for (i = optind; i < argc; i++)
-        add_syntax_file (the_source_stream, syntax_mode, argv[i]);
+        add_syntax_reader (lexer, argv[i], syntax_encoding, syntax_mode);
     }
   else
-    add_syntax_file (the_source_stream, syntax_mode, "-");
+    add_syntax_reader (lexer, "-", syntax_encoding, syntax_mode);
 
   /* Parse and execute syntax. */
-  the_lexer = lex_create (the_source_stream);
+  lex_get (lexer);
   for (;;)
     {
-      int result = cmd_parse (the_lexer, the_dataset);
+      int result = cmd_parse (lexer, session_active_dataset (the_session));
 
       if (result == CMD_EOF || result == CMD_FINISH)
        break;
-      if (result == CMD_CASCADING_FAILURE &&
-         !getl_is_interactive (the_source_stream))
-       {
-         msg (SE, _("Stopping syntax file processing here to avoid "
-                    "a cascade of dependent command failures."));
-         getl_abort_noninteractive (the_source_stream);
-       }
-      else if (msg_ui_too_many_errors ())
-        getl_abort_noninteractive (the_source_stream);
+      else if (cmd_result_is_failure (result) && lex_token (lexer) != T_STOP)
+        {
+          if (lex_get_error_mode (lexer) == LEX_ERROR_STOP)
+            {
+              msg (MW, _("Error encountered while ERROR=STOP is effective."));
+              lex_discard_noninteractive (lexer);
+            }
+          else if (result == CMD_CASCADING_FAILURE
+                   && lex_get_error_mode (lexer) != LEX_ERROR_INTERACTIVE)
+            {
+              msg (SE, _("Stopping syntax file processing here to avoid "
+                         "a cascade of dependent command failures."));
+              lex_discard_noninteractive (lexer);
+            }
+        }
+
+      if (msg_ui_too_many_errors ())
+        lex_discard_noninteractive (lexer);
     }
 
 
-  destroy_dataset (the_dataset);
+  session_destroy (the_session);
 
   random_done ();
   settings_done ();
   fh_done ();
-  lex_destroy (the_lexer);
-  destroy_source_stream (the_source_stream);
-  prompt_done ();
-  readln_uninitialize ();
+  lex_destroy (lexer);
   output_close ();
-  msg_ui_done ();
   i18n_done ();
 
   return msg_ui_any_errors ();
 }
-
+\f
 static void
 fpu_init (void)
 {
@@ -213,13 +219,32 @@ bug_handler(int sig)
 }
 
 static void
-add_syntax_file (struct source_stream *ss, enum syntax_mode syntax_mode,
-                 const char *file_name)
+output_msg (const struct msg *m_, void *lexer_)
 {
-  struct getl_interface *source;
+  struct lexer *lexer = lexer_;
+  struct msg m = *m_;
+
+  if (m.file_name == NULL)
+    {
+      m.file_name = CONST_CAST (char *, lex_get_file_name (lexer));
+      m.first_line = lex_get_first_line_number (lexer, 0);
+      m.last_line = lex_get_last_line_number (lexer, 0);
+    }
+
+  message_item_submit (message_item_create (&m));
+}
+
+static void
+add_syntax_reader (struct lexer *lexer, const char *file_name,
+                   const char *encoding, enum lex_syntax_mode syntax_mode)
+{
+  struct lex_reader *reader;
+
+  reader = (!strcmp (file_name, "-") && isatty (STDIN_FILENO)
+            ? terminal_reader_create ()
+            : lex_reader_for_file (file_name, encoding, syntax_mode,
+                                   LEX_ERROR_CONTINUE));
 
-  source = (!strcmp (file_name, "-") && isatty (STDIN_FILENO)
-           ? create_readln_source ()
-           : create_syntax_file_source (file_name));
-  getl_append_source (ss, source, syntax_mode, ERRMODE_CONTINUE);
+  if (reader)
+    lex_append (lexer, reader);
 }
diff --git a/src/ui/terminal/msg-ui.c b/src/ui/terminal/msg-ui.c
deleted file mode 100644 (file)
index 63682d1..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   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
-   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 "msg-ui.h"
-#include "libpspp/message.h"
-#include "libpspp/msg-locator.h"
-#include "output/message-item.h"
-
-static void
-handle_msg (const struct msg *m)
-{
-  message_item_submit (message_item_create (m));
-}
-
-void
-msg_ui_init (struct source_stream *ss)
-{
-  msg_init (ss, handle_msg);
-}
-
-void
-msg_ui_done (void)
-{
-  msg_done ();
-  msg_locator_done ();
-}
diff --git a/src/ui/terminal/msg-ui.h b/src/ui/terminal/msg-ui.h
deleted file mode 100644 (file)
index 197d7c0..0000000
+++ /dev/null
@@ -1,29 +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 MSG_UI_H
-#define MSG_UI_H 1
-
-#include <stdbool.h>
-#include <stdio.h>
-
-struct source_stream;
-
-void msg_ui_set_error_file (FILE *);
-void msg_ui_init (struct source_stream *);
-void msg_ui_done (void);
-
-#endif /* msg-ui.h */
diff --git a/src/ui/terminal/read-line.c b/src/ui/terminal/read-line.c
deleted file mode 100644 (file)
index 0fa145c..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/* 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 "read-line.h"
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <assert.h>
-#include <errno.h>
-#if ! HAVE_READLINE
-#include <stdint.h>
-#endif
-
-#include "msg-ui.h"
-
-#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/driver.h>
-#include <ui/terminal/terminal.h>
-
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-#if HAVE_READLINE
-#include <readline/readline.h>
-#include <readline/history.h>
-
-static char *history_file;
-
-static char **complete_command_name (const char *, int, int);
-static char **dont_complete (const char *, int, int);
-#endif /* HAVE_READLINE */
-
-
-struct readln_source
-{
-  struct getl_interface parent ;
-
-  bool (*interactive_func) (struct string *line,
-                           enum prompt_style) ;
-};
-
-
-static bool initialised = false;
-
-/* Initialize getl. */
-void
-readln_initialize (void)
-{
-  initialised = true;
-
-#if HAVE_READLINE
-  rl_basic_word_break_characters = "\n";
-  using_history ();
-  stifle_history (500);
-  if (history_file == NULL)
-    {
-      const char *home_dir = getenv ("HOME");
-      if (home_dir != NULL)
-        {
-          history_file = xasprintf ("%s/.pspp_history", home_dir);
-          read_history (history_file);
-        }
-    }
-#endif
-}
-
-/* Close getl. */
-void
-readln_uninitialize (void)
-{
-  initialised = false;
-
-#if HAVE_READLINE
-  if (history_file != NULL && false == settings_get_testing_mode () )
-    write_history (history_file);
-  clear_history ();
-  free (history_file);
-#endif
-}
-
-
-static bool
-read_interactive (struct getl_interface *s,
-                  struct string *line)
-{
-  struct readln_source *is  = UP_CAST (s, struct readln_source, parent);
-
-  return is->interactive_func (line, prompt_get_style ());
-}
-
-static bool
-always_true (const struct getl_interface *s UNUSED)
-{
-  return true;
-}
-
-/* Display a welcoming message. */
-static void
-welcome (void)
-{
-  static bool welcomed = false;
-  if (welcomed)
-    return;
-  welcomed = true;
-  fputs ("PSPP is free software and you are welcome to distribute copies of "
-        "it\nunder certain conditions; type \"show copying.\" to see the "
-        "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
-        "warranty.\" for details.\n", stdout);
-  puts (stat_version);
-  readln_initialize ();
-  journal_enable ();
-}
-
-/* Gets a line from the user and stores it into LINE.
-   Prompts the user with PROMPT.
-   Returns true if successful, false at end of file.
-   */
-static bool
-readln_read (struct string *line, enum prompt_style style)
-{
-  const char *prompt = prompt_get (style);
-#if HAVE_READLINE
-  char *string;
-#endif
-  bool eof;
-
-  assert (initialised);
-
-  msg_ui_reset_counts ();
-
-  welcome ();
-
-  output_flush ();
-
-#if HAVE_READLINE
-  rl_attempted_completion_function = (style == PROMPT_FIRST
-                                      ? complete_command_name
-                                      : dont_complete);
-  string = readline (prompt);
-  if (string == NULL)
-    eof = true;
-  else
-    {
-      if (string[0])
-        add_history (string);
-      ds_assign_cstr (line, string);
-      free (string);
-      eof = false;
-    }
-#else
-  fputs (prompt, stdout);
-  fflush (stdout);
-  if (ds_read_line (line, stdin, SIZE_MAX))
-    {
-      ds_chomp (line, '\n');
-      eof = false;
-    }
-  else
-    eof = true;
-#endif
-
-  /* Check whether the size of the window has changed, so that
-     the output drivers can adjust their settings as needed.  We
-     only do this for the first line of a command, as it's
-     possible that the output drivers are actually in use
-     afterward, and we don't want to confuse them in the middle
-     of output. */
-  if (style == PROMPT_FIRST)
-    terminal_check_size ();
-
-  return !eof;
-}
-
-static void
-readln_close (struct getl_interface *i)
-{
-  free (i);
-}
-
-/* Creates a source which uses readln to get its line */
-struct getl_interface *
-create_readln_source (void)
-{
-  struct readln_source *rlns  = xzalloc (sizeof (*rlns));
-
-  rlns->interactive_func = readln_read;
-
-  rlns->parent.interactive = always_true;
-  rlns->parent.read = read_interactive;
-  rlns->parent.close = readln_close;
-
-  return &rlns->parent;
-}
-
-
-#if HAVE_READLINE
-static char *command_generator (const char *text, int state);
-
-/* Returns a set of command name completions for TEXT.
-   This is of the proper form for assigning to
-   rl_attempted_completion_function. */
-static char **
-complete_command_name (const char *text, int start, int end UNUSED)
-{
-  if (start == 0)
-    {
-      /* Complete command name at start of line. */
-      return rl_completion_matches (text, command_generator);
-    }
-  else
-    {
-      /* Otherwise don't do any completion. */
-      rl_attempted_completion_over = 1;
-      return NULL;
-    }
-}
-
-/* Do not do any completion for TEXT. */
-static char **
-dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
-{
-  rl_attempted_completion_over = 1;
-  return NULL;
-}
-
-/* If STATE is 0, returns the first command name matching TEXT.
-   Otherwise, returns the next command name matching TEXT.
-   Returns a null pointer when no matches are left. */
-static char *
-command_generator (const char *text, int state)
-{
-  static const struct command *cmd;
-  const char *name;
-
-  if (state == 0)
-    cmd = NULL;
-  name = cmd_complete (text, &cmd);
-  return name ? xstrdup (name) : NULL;
-}
-#endif /* HAVE_READLINE */
diff --git a/src/ui/terminal/read-line.h b/src/ui/terminal/read-line.h
deleted file mode 100644 (file)
index 6738411..0000000
+++ /dev/null
@@ -1,31 +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/>. */
-
-#ifndef READLN_H
-#define READLN_H
-
-#include <libpspp/str.h>
-#include <libpspp/getl.h>
-
-void readln_initialize (void);
-void readln_uninitialize (void);
-
-struct getl_interface *create_readln_source (void);
-
-
-
-#endif /* READLN_H */
-
index d55a8a2e9607d5622dcb1f52b192a78263f7f28b..121d89d5712a5bb127ff73f1778d5e498bb7a234 100644 (file)
 
 #include "data/settings.h"
 #include "data/file-name.h"
-#include "language/syntax-file.h"
+#include "language/lexer/include-path.h"
 #include "libpspp/argv-parser.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
-#include "libpspp/getl.h"
 #include "libpspp/llx.h"
 #include "libpspp/str.h"
 #include "libpspp/string-array.h"
@@ -38,8 +37,6 @@
 #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"
 
 struct terminal_opts
   {
-    enum syntax_mode *syntax_mode;
     struct string_map options;  /* Output driver options. */
     bool has_output_driver;
     bool has_terminal_driver;
     bool has_error_file;
+    enum lex_syntax_mode *syntax_mode;
     bool *process_statrc;
+    char **syntax_encoding;
   };
 
 enum
@@ -68,7 +66,9 @@ enum
     OPT_OUTPUT,
     OPT_OUTPUT_OPTION,
     OPT_NO_OUTPUT,
+    OPT_BATCH,
     OPT_INTERACTIVE,
+    OPT_SYNTAX_ENCODING,
     OPT_NO_STATRC,
     OPT_HELP,
     OPT_VERSION,
@@ -82,7 +82,9 @@ static struct argv_option terminal_argv_options[N_TERMINAL_OPTIONS] =
     {"output", 'o', required_argument, OPT_OUTPUT},
     {NULL, 'O', required_argument, OPT_OUTPUT_OPTION},
     {"no-output", 0, no_argument, OPT_NO_OUTPUT},
+    {"batch", 'b', no_argument, OPT_BATCH},
     {"interactive", 'i', no_argument, OPT_INTERACTIVE},
+    {"syntax-encoding", 0, required_argument, OPT_SYNTAX_ENCODING},
     {"no-statrc", 'r', no_argument, OPT_NO_STATRC},
     {"help", 'h', no_argument, OPT_HELP},
     {"version", 'V', no_argument, OPT_VERSION},
@@ -160,29 +162,11 @@ get_supported_formats (void)
   return format_string;
 }
 
-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);
-}
-
 static void
 usage (void)
 {
   char *supported_formats = get_supported_formats ();
-  char *default_include_path = get_default_include_path ();
+  char *inc_path = string_array_join (include_path_default (), " ");
 
   printf (_("\
 PSPP, a program for statistical analysis of sample data.\n\
@@ -208,19 +192,21 @@ Language options:\n\
                             calculated from broken algorithms\n\
   -x, --syntax={compatible|enhanced}\n\
                             set to `compatible' to disable PSPP extensions\n\
+  -b, --batch               interpret syntax in batch mode\n\
   -i, --interactive         interpret syntax in interactive mode\n\
+  --syntax-encoding=ENCODING  specify encoding for syntax files\n\
   -s, --safer               don't allow some unsafe operations\n\
-Default search path:%s\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);
+          program_name, supported_formats, inc_path);
 
   free (supported_formats);
-  free (default_include_path);
+  free (inc_path);
 
   emit_bug_reporting_address ();
   exit (EXIT_SUCCESS);
@@ -257,8 +243,16 @@ terminal_option_callback (int id, void *to_)
       to->has_output_driver = true;
       break;
 
+    case OPT_BATCH:
+      *to->syntax_mode = LEX_SYNTAX_BATCH;
+      break;
+
     case OPT_INTERACTIVE:
-      *to->syntax_mode = GETL_INTERACTIVE;
+      *to->syntax_mode = LEX_SYNTAX_INTERACTIVE;
+      break;
+
+    case OPT_SYNTAX_ENCODING:
+      *to->syntax_encoding = optarg;
       break;
 
     case OPT_NO_STATRC:
@@ -282,19 +276,23 @@ terminal_option_callback (int id, void *to_)
 
 struct terminal_opts *
 terminal_opts_init (struct argv_parser *ap,
-                    enum syntax_mode *syntax_mode, bool *process_statrc)
+                    enum lex_syntax_mode *syntax_mode, bool *process_statrc,
+                    char **syntax_encoding)
 {
   struct terminal_opts *to;
 
-  *syntax_mode = GETL_BATCH;
+  *syntax_mode = LEX_SYNTAX_AUTO;
   *process_statrc = true;
+  *syntax_encoding = "Auto";
 
   to = xzalloc (sizeof *to);
   to->syntax_mode = syntax_mode;
   string_map_init (&to->options);
   to->has_output_driver = false;
   to->has_error_file = false;
+  to->syntax_mode = syntax_mode;
   to->process_statrc = process_statrc;
+  to->syntax_encoding = syntax_encoding;
 
   argv_parser_add_options (ap, terminal_argv_options, N_TERMINAL_OPTIONS,
                            terminal_option_callback, to);
index 50f2319690fb53d32abf074f67cdc80788431ead..64581baea304c81558074e3298d9c8744854ca03 100644 (file)
 #define UI_TERMINAL_TERMINAL_OPTS_H 1
 
 #include <stdbool.h>
-#include "libpspp/getl.h"
+#include "language/lexer/lexer.h"
 
 struct argv_parser;
+struct lexer;
 struct terminal_opts;
 
 struct terminal_opts *terminal_opts_init (struct argv_parser *,
-                                          enum syntax_mode *,
-                                          bool *process_statrc);
+                                          enum lex_syntax_mode *,
+                                          bool *process_statrc,
+                                          char **syntax_encoding);
 void terminal_opts_done (struct terminal_opts *, int argc, char *argv[]);
 
 #endif /* ui/terminal/terminal-opts.h */
diff --git a/src/ui/terminal/terminal-reader.c b/src/ui/terminal/terminal-reader.c
new file mode 100644 (file)
index 0000000..7c80d27
--- /dev/null
@@ -0,0 +1,308 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011 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 "ui/terminal/terminal-reader.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "data/file-name.h"
+#include "data/settings.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/prompt.h"
+#include "libpspp/str.h"
+#include "libpspp/version.h"
+#include "output/driver.h"
+#include "output/journal.h"
+#include "ui/terminal/terminal.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct terminal_reader
+  {
+    struct lex_reader reader;
+    struct substring s;
+    size_t offset;
+    bool eof;
+  };
+
+static int n_terminal_readers;
+
+static void readline_init (void);
+static void readline_done (void);
+static struct substring readline_read (enum prompt_style);
+
+/* Display a welcoming message. */
+static void
+welcome (void)
+{
+  static bool welcomed = false;
+  if (welcomed)
+    return;
+  welcomed = true;
+  fputs ("PSPP is free software and you are welcome to distribute copies of "
+        "it\nunder certain conditions; type \"show copying.\" to see the "
+        "conditions.\nThere is ABSOLUTELY NO WARRANTY for PSPP; type \"show "
+        "warranty.\" for details.\n", stdout);
+  puts (stat_version);
+  journal_enable ();
+}
+
+static struct terminal_reader *
+terminal_reader_cast (struct lex_reader *r)
+{
+  return UP_CAST (r, struct terminal_reader, reader);
+}
+
+static size_t
+terminal_reader_read (struct lex_reader *r_, char *buf, size_t n,
+                      enum prompt_style prompt_style)
+{
+  struct terminal_reader *r = terminal_reader_cast (r_);
+  size_t chunk;
+
+  if (r->offset >= r->s.length && !r->eof)
+    {
+      welcome ();
+      msg_ui_reset_counts ();
+      output_flush ();
+
+      ss_dealloc (&r->s);
+      r->s = readline_read (prompt_style);
+      r->offset = 0;
+      r->eof = ss_is_empty (r->s);
+
+      /* Check whether the size of the window has changed, so that
+         the output drivers can adjust their settings as needed.  We
+         only do this for the first line of a command, as it's
+         possible that the output drivers are actually in use
+         afterward, and we don't want to confuse them in the middle
+         of output. */
+      if (prompt_style == PROMPT_FIRST)
+        terminal_check_size ();
+    }
+
+  chunk = MIN (n, r->s.length - r->offset);
+  memcpy (buf, r->s.string + r->offset, chunk);
+  r->offset += chunk;
+  return chunk;
+}
+
+static void
+terminal_reader_close (struct lex_reader *r_)
+{
+  struct terminal_reader *r = terminal_reader_cast (r_);
+
+  ss_dealloc (&r->s);
+  free (r->reader.file_name);
+  free (r);
+
+  if (!--n_terminal_readers)
+    readline_done ();
+}
+
+static struct lex_reader_class terminal_reader_class =
+  {
+    terminal_reader_read,
+    terminal_reader_close
+  };
+
+/* Creates a source which uses readln to get its line */
+struct lex_reader *
+terminal_reader_create (void)
+{
+  struct terminal_reader *r;
+
+  if (!n_terminal_readers++)
+    readline_init ();
+
+  r = xzalloc (sizeof *r);
+  r->reader.class = &terminal_reader_class;
+  r->reader.syntax = LEX_SYNTAX_INTERACTIVE;
+  r->reader.error = LEX_ERROR_INTERACTIVE;
+  r->reader.file_name = NULL;
+  r->s = ss_empty ();
+  r->offset = 0;
+  r->eof = false;
+  return &r->reader;
+}
+\f
+#if HAVE_READLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+
+static char *history_file;
+
+static char **complete_command_name (const char *, int, int);
+static char **dont_complete (const char *, int, int);
+static char *command_generator (const char *text, int state);
+
+static void
+readline_init (void)
+{
+  rl_basic_word_break_characters = "\n";
+  using_history ();
+  stifle_history (500);
+  if (history_file == NULL)
+    {
+      const char *home_dir = getenv ("HOME");
+      if (home_dir != NULL)
+        {
+          history_file = xasprintf ("%s/.pspp_history", home_dir);
+          read_history (history_file);
+        }
+    }
+}
+
+static void
+readline_done (void)
+{
+  if (history_file != NULL && false == settings_get_testing_mode () )
+    write_history (history_file);
+  clear_history ();
+  free (history_file);
+}
+
+static const char *
+readline_prompt (enum prompt_style style)
+{
+  switch (style)
+    {
+    case PROMPT_FIRST:
+      return "PSPP> ";
+
+    case PROMPT_LATER:
+      return "    > ";
+
+    case PROMPT_DATA:
+      return "data> ";
+
+    case PROMPT_COMMENT:
+      return "comment> ";
+
+    case PROMPT_DOCUMENT:
+      return "document> ";
+
+    case PROMPT_DO_REPEAT:
+      return "DO REPEAT> ";
+    }
+
+  NOT_REACHED ();
+}
+
+static struct substring
+readline_read (enum prompt_style style)
+{
+  char *string;
+
+  rl_attempted_completion_function = (style == PROMPT_FIRST
+                                      ? complete_command_name
+                                      : dont_complete);
+  string = readline (readline_prompt (style));
+  if (string != NULL)
+    {
+      char *end;
+
+      if (string[0])
+        add_history (string);
+
+      end = strchr (string, '\0');
+      *end = '\n';
+      return ss_buffer (string, end - string + 1);
+    }
+  else
+    return ss_empty ();
+}
+
+/* Returns a set of command name completions for TEXT.
+   This is of the proper form for assigning to
+   rl_attempted_completion_function. */
+static char **
+complete_command_name (const char *text, int start, int end UNUSED)
+{
+  if (start == 0)
+    {
+      /* Complete command name at start of line. */
+      return rl_completion_matches (text, command_generator);
+    }
+  else
+    {
+      /* Otherwise don't do any completion. */
+      rl_attempted_completion_over = 1;
+      return NULL;
+    }
+}
+
+/* Do not do any completion for TEXT. */
+static char **
+dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
+{
+  rl_attempted_completion_over = 1;
+  return NULL;
+}
+
+/* If STATE is 0, returns the first command name matching TEXT.
+   Otherwise, returns the next command name matching TEXT.
+   Returns a null pointer when no matches are left. */
+static char *
+command_generator (const char *text, int state)
+{
+  static const struct command *cmd;
+  const char *name;
+
+  if (state == 0)
+    cmd = NULL;
+  name = cmd_complete (text, &cmd);
+  return name ? xstrdup (name) : NULL;
+}
+#else  /* !HAVE_READLINE */
+static void
+readline_init (void)
+{
+}
+
+static void
+readline_done (void)
+{
+}
+
+static struct substring
+readline_read (enum prompt_style style)
+{
+  const char *prompt = prompt_get (style);
+  struct string line;
+
+  fputs (prompt, stdout);
+  fflush (stdout);
+  ds_init_empty (&line);
+  ds_read_line (&line, stdin, SIZE_MAX);
+
+  return line.ss;
+}
+#endif /* !HAVE_READLINE */
diff --git a/src/ui/terminal/terminal-reader.h b/src/ui/terminal/terminal-reader.h
new file mode 100644 (file)
index 0000000..2d51c9b
--- /dev/null
@@ -0,0 +1,23 @@
+/* PSPP - a program for statistical analysis.
+   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
+   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 TERMINAL_READER_H
+#define TERMINAL_READER_H
+
+struct lex_reader *terminal_reader_create (void);
+
+#endif /* terminal-reader.h */
+
index 4c2e0efd7f6b354eef954e5146a44b81f56f888c..9b54a705b4755cbda91b9f46ddce34b1e589a62b 100644 (file)
@@ -6,6 +6,7 @@ GNM_SUPPORT='@GNM_SUPPORT@'
 PERL='@PERL@'
 WITH_PERL_MODULE='@WITH_PERL_MODULE@'
 host='@host@'
+SIZEOF_SIZE_T='@SIZEOF_SIZE_T@'
 
 PSQL_SUPPORT='@PSQL_SUPPORT@'
 if test "$PSQL_SUPPORT" = yes; then
@@ -13,6 +14,17 @@ if test "$PSQL_SUPPORT" = yes; then
     : ${PG_DBASE:=pspptest}
     : ${PG_PORT:=6543}
     : ${PG_PATH:=`$PG_CONFIG --bindir`}
+
+    # PSQL_SUPPORT indicates that PSPP was built against the PostgreSQL client
+    # library, but it does not mean that the PostgreSQL utilities are
+    # installed.  So check for them and turn off PSQL_SUPPORT if they are not
+    # available.
+    if (PATH=$PG_PATH:$PATH; export PATH; initdb --version) >/dev/null 2>&1
+    then
+       :
+    else
+       PSQL_SUPPORT=no
+    fi
 fi
 
 # Variables used by programs invoked by the testsuite.
index 017e573ee39c16e880d839c3f82b50dbe077e1d3..61c7996fb9501097d1eca7fcff43c966d3778bf7 100644 (file)
@@ -2,9 +2,14 @@
 
 check_PROGRAMS += \
        tests/data/datasheet-test \
+       tests/data/sack \
        tests/data/inexactify \
+       tests/language/lexer/command-name-test \
+       tests/language/lexer/scan-test \
+       tests/language/lexer/segment-test \
        tests/libpspp/abt-test \
        tests/libpspp/bt-test \
+       tests/libpspp/encoding-guesser-test \
        tests/libpspp/heap-test \
        tests/libpspp/hmap-test \
        tests/libpspp/hmapx-test \
@@ -21,67 +26,71 @@ check_PROGRAMS += \
        tests/libpspp/string-set-test \
        tests/libpspp/stringi-set-test \
        tests/libpspp/tower-test \
+       tests/libpspp/u8-istream-test \
        tests/output/render-test
 
+check-programs: $(check_PROGRAMS)
+
 tests_data_datasheet_test_SOURCES = \
        tests/data/datasheet-test.c
-tests_data_datasheet_test_LDADD = src/libpspp-core.la $(LIBINTL) 
+tests_data_datasheet_test_LDADD = src/libpspp-core.la
 tests_data_datasheet_test_CFLAGS = $(AM_CFLAGS)
 
+tests_data_sack_SOURCES = \
+       tests/data/sack.c
+tests_data_sack_LDADD = src/libpspp-core.la 
+tests_data_sack_CFLAGS = $(AM_CFLAGS)
+
 tests_libpspp_ll_test_SOURCES = \
        src/libpspp/ll.c \
        tests/libpspp/ll-test.c
-tests_libpspp_ll_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_ll_test_CFLAGS = $(AM_CFLAGS)
 
 tests_libpspp_llx_test_SOURCES = \
        src/libpspp/ll.c \
        src/libpspp/llx.c \
        tests/libpspp/llx-test.c
-tests_libpspp_llx_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_llx_test_CFLAGS = $(AM_CFLAGS)
 
+tests_libpspp_encoding_guesser_test_SOURCES = \
+       tests/libpspp/encoding-guesser-test.c
+tests_libpspp_encoding_guesser_test_LDADD = src/libpspp/libpspp.la gl/libgl.la
+
 tests_libpspp_heap_test_SOURCES = \
        src/libpspp/heap.c \
        src/libpspp/pool.c \
        src/libpspp/temp-file.c \
        tests/libpspp/heap-test.c
-tests_libpspp_heap_test_LDADD = gl/libgl.la $(LIBINTL) 
 tests_libpspp_heap_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_hmap_test_SOURCES = \
        src/libpspp/hmap.c \
        tests/libpspp/hmap-test.c
-tests_libpspp_hmap_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_hmap_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_hmapx_test_SOURCES = \
        src/libpspp/hmap.c \
        src/libpspp/hmapx.c \
        tests/libpspp/hmapx-test.c
-tests_libpspp_hmapx_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_hmapx_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_i18n_test_SOURCES = tests/libpspp/i18n-test.c
-tests_libpspp_i18n_test_LDADD = src/libpspp/libpspp.la gl/libgl.la $(LIBINTL) 
+tests_libpspp_i18n_test_LDADD = src/libpspp/libpspp.la gl/libgl.la 
 
 tests_libpspp_abt_test_SOURCES = \
        src/libpspp/abt.c \
        tests/libpspp/abt-test.c
-tests_libpspp_abt_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_abt_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_bt_test_SOURCES = \
        src/libpspp/bt.c \
        tests/libpspp/bt-test.c
-tests_libpspp_bt_test_LDADD = gl/libgl.la
 tests_libpspp_bt_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_range_map_test_SOURCES = \
        src/libpspp/bt.c \
        src/libpspp/range-map.c \
        tests/libpspp/range-map-test.c
-tests_libpspp_range_map_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_range_map_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_range_set_test_SOURCES = \
@@ -90,12 +99,11 @@ tests_libpspp_range_set_test_SOURCES = \
        src/libpspp/range-set.c \
        src/libpspp/temp-file.c \
        tests/libpspp/range-set-test.c
-tests_libpspp_range_set_test_LDADD = gl/libgl.la $(LIBINTL) 
 tests_libpspp_range_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 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_str_test_LDADD = src/libpspp/libpspp.la gl/libgl.la 
 
 tests_libpspp_string_map_test_SOURCES = \
        src/libpspp/hash-functions.c \
@@ -103,7 +111,6 @@ tests_libpspp_string_map_test_SOURCES = \
        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_stringi_map_test_SOURCES = \
@@ -116,7 +123,6 @@ tests_libpspp_stringi_map_test_SOURCES = \
        src/libpspp/stringi-set.c \
        src/libpspp/temp-file.c \
        tests/libpspp/stringi-map-test.c
-tests_libpspp_stringi_map_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_stringi_map_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_string_set_test_SOURCES = \
@@ -124,7 +130,6 @@ tests_libpspp_string_set_test_SOURCES = \
        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_stringi_set_test_SOURCES = \
@@ -135,7 +140,6 @@ tests_libpspp_stringi_set_test_SOURCES = \
        src/libpspp/stringi-set.c \
        src/libpspp/temp-file.c \
        tests/libpspp/stringi-set-test.c
-tests_libpspp_stringi_set_test_LDADD = gl/libgl.la $(LIBINTL)
 tests_libpspp_stringi_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_tower_test_SOURCES = \
@@ -144,15 +148,16 @@ tests_libpspp_tower_test_SOURCES = \
        src/libpspp/temp-file.c \
        src/libpspp/tower.c \
        tests/libpspp/tower-test.c
-tests_libpspp_tower_test_LDADD = gl/libgl.la $(LIBINTL) 
 tests_libpspp_tower_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
+tests_libpspp_u8_istream_test_SOURCES = tests/libpspp/u8-istream-test.c
+tests_libpspp_u8_istream_test_LDADD = src/libpspp/libpspp.la gl/libgl.la
+
 tests_libpspp_sparse_array_test_SOURCES = \
        src/libpspp/sparse-array.c \
        src/libpspp/pool.c \
        tests/libpspp/sparse-array-test.c \
        src/libpspp/temp-file.c
-tests_libpspp_sparse_array_test_LDADD = gl/libgl.la $(LIBINTL) 
 tests_libpspp_sparse_array_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_libpspp_sparse_xarray_test_SOURCES = \
@@ -168,27 +173,52 @@ tests_libpspp_sparse_xarray_test_SOURCES = \
        src/libpspp/pool.c \
        src/libpspp/temp-file.c \
        tests/libpspp/sparse-xarray-test.c
-tests_libpspp_sparse_xarray_test_LDADD = gl/libgl.la $(LIBINTL) 
 tests_libpspp_sparse_xarray_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
 
 tests_data_inexactify_SOURCES = tests/data/inexactify.c
 
-noinst_PROGRAMS += tests/dissect-sysfile
-tests_dissect_sysfile_SOURCES = \
-       src/libpspp/integer-format.c \
-       src/libpspp/float-format.c \
-       tests/dissect-sysfile.c
-tests_dissect_sysfile_LDADD = gl/libgl.la $(LIBINTL) 
-tests_dissect_sysfile_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\"
+check_PROGRAMS += tests/language/lexer/command-name-test
+tests_language_lexer_command_name_test_SOURCES = \
+       src/data/identifier.c \
+       src/language/lexer/command-name.c \
+       tests/language/lexer/command-name-test.c
+tests_language_lexer_command_name_test_LDADD = \
+       src/libpspp/libpspp.la \
+       gl/libgl.la 
+tests_language_lexer_command_name_test_CFLAGS = $(AM_CFLAGS)
+
+check_PROGRAMS += tests/language/lexer/scan-test
+tests_language_lexer_scan_test_SOURCES = \
+       src/data/identifier.c \
+       src/language/lexer/command-name.c \
+       src/language/lexer/scan.c \
+       src/language/lexer/segment.c \
+       src/language/lexer/token.c \
+       src/libpspp/pool.c \
+       src/libpspp/prompt.c \
+       src/libpspp/str.c \
+       src/libpspp/temp-file.c \
+       tests/language/lexer/scan-test.c
+tests_language_lexer_scan_test_CFLAGS = $(AM_CFLAGS)
+
+check_PROGRAMS += tests/language/lexer/segment-test
+tests_language_lexer_segment_test_SOURCES = \
+       src/data/identifier.c \
+       src/language/lexer/command-name.c \
+       src/language/lexer/segment.c \
+       src/libpspp/pool.c \
+       src/libpspp/prompt.c \
+       src/libpspp/str.c \
+       src/libpspp/temp-file.c \
+       tests/language/lexer/segment-test.c
+tests_language_lexer_segment_test_CFLAGS = $(AM_CFLAGS)
 
 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)
+       $(CAIRO_LIBS)
 
 EXTRA_DIST += \
        tests/coverage.sh \
@@ -224,6 +254,7 @@ TESTSUITE_AT = \
        tests/data/datasheet-test.at \
        tests/data/format-guesser.at \
        tests/data/por-file.at \
+       tests/data/sys-file-reader.at \
        tests/data/sys-file.at \
        tests/language/command.at \
        tests/language/control/do-if.at \
@@ -233,6 +264,7 @@ TESTSUITE_AT = \
        tests/language/data-io/add-files.at \
        tests/language/data-io/data-list.at \
        tests/language/data-io/data-reader.at \
+       tests/language/data-io/dataset.at \
        tests/language/data-io/file-handle.at \
        tests/language/data-io/get-data-gnm.at \
        tests/language/data-io/get-data-psql.at \
@@ -241,11 +273,13 @@ TESTSUITE_AT = \
        tests/language/data-io/inpt-pgm.at \
        tests/language/data-io/list.at \
        tests/language/data-io/match-files.at \
+       tests/language/data-io/print-space.at \
        tests/language/data-io/print.at \
        tests/language/data-io/save.at \
        tests/language/data-io/save-translate.at \
        tests/language/data-io/update.at \
        tests/language/dictionary/attributes.at \
+       tests/language/dictionary/formats.at \
        tests/language/dictionary/missing-values.at \
        tests/language/dictionary/mrsets.at \
        tests/language/dictionary/rename-variables.at \
@@ -257,8 +291,11 @@ TESTSUITE_AT = \
        tests/language/dictionary/weight.at \
        tests/language/expressions/evaluate.at \
        tests/language/expressions/parse.at \
+       tests/language/lexer/command-name.at \
        tests/language/lexer/lexer.at \
        tests/language/lexer/q2c.at \
+       tests/language/lexer/scan.at \
+       tests/language/lexer/segment.at \
        tests/language/lexer/variable-parser.at \
        tests/language/stats/aggregate.at \
        tests/language/stats/autorecode.at \
@@ -271,12 +308,15 @@ TESTSUITE_AT = \
        tests/language/stats/frequencies.at \
        tests/language/stats/npar.at \
        tests/language/stats/oneway.at \
+       tests/language/stats/quick-cluster.at \
        tests/language/stats/rank.at \
        tests/language/stats/regression.at \
        tests/language/stats/reliability.at \
        tests/language/stats/roc.at \
        tests/language/stats/sort-cases.at \
        tests/language/stats/t-test.at \
+       tests/language/utilities/cache.at \
+       tests/language/utilities/cd.at \
        tests/language/utilities/date.at \
        tests/language/utilities/insert.at \
        tests/language/utilities/permissions.at \
@@ -289,6 +329,7 @@ TESTSUITE_AT = \
        tests/language/xforms/select-if.at \
        tests/libpspp/abt.at \
        tests/libpspp/bt.at \
+       tests/libpspp/encoding-guesser.at \
        tests/libpspp/float-format.at \
        tests/libpspp/heap.at \
        tests/libpspp/hmap.at \
@@ -306,8 +347,10 @@ TESTSUITE_AT = \
        tests/libpspp/string-set.at \
        tests/libpspp/stringi-set.at \
        tests/libpspp/tower.at \
+       tests/libpspp/u8-istream.at \
        tests/math/moments.at \
        tests/math/randist.at \
+       tests/output/ascii.at \
        tests/output/charts.at \
        tests/output/output.at \
        tests/output/paper-size.at \
@@ -317,6 +360,7 @@ TESTSUITE_AT = \
 
 TESTSUITE = $(srcdir)/tests/testsuite
 DISTCLEANFILES += tests/atconfig tests/atlocal $(TESTSUITE)
+AUTOTEST_PATH = tests/data:tests/language/lexer:tests/libpspp:tests/output:src/ui/terminal
 
 $(srcdir)/tests/testsuite.at: tests/testsuite.in tests/automake.mk
        cp $< $@
@@ -327,7 +371,7 @@ EXTRA_DIST += tests/testsuite.at
 
 CHECK_LOCAL += tests_check
 tests_check: tests/atconfig tests/atlocal $(TESTSUITE) $(check_PROGRAMS)
-       $(SHELL) '$(TESTSUITE)' -C tests AUTOTEST_PATH=tests/data:tests/libpspp:tests/output:src/ui/terminal $(TESTSUITEFLAGS)
+       $(SHELL) '$(TESTSUITE)' -C tests AUTOTEST_PATH=$(AUTOTEST_PATH) $(TESTSUITEFLAGS)
 
 CLEAN_LOCAL += tests_clean
 tests_clean:
@@ -336,7 +380,7 @@ tests_clean:
 AUTOM4TE = $(SHELL) $(srcdir)/build-aux/missing --run autom4te
 AUTOTEST = $(AUTOM4TE) --language=autotest
 $(TESTSUITE): package.m4 $(srcdir)/tests/testsuite.at $(TESTSUITE_AT) 
-       $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
+       $(AUTOTEST) -I '$(srcdir)' $@.at | sed 's/@<00A0>@/ /g' > $@.tmp
        mv $@.tmp $@
 
 # The `:;' works around a Bash 3.2 bug when the output is not writeable.
@@ -350,3 +394,51 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
          echo 'm4_define([AT_PACKAGE_BUGREPORT], [$(PACKAGE_BUGREPORT)])' && \
          echo 'm4_define([AT_PACKAGE_URL],       [$(PACKAGE_URL)])'; \
        } >'$(srcdir)/package.m4'
+\f
+# valgrind support for Autotest testsuite
+
+valgrind_wrappers = \
+       tests/valgrind/datasheet-test \
+       tests/valgrind/command-name-test \
+       tests/valgrind/scan-test \
+       tests/valgrind/segment-test \
+       tests/valgrind/abt-test \
+       tests/valgrind/bt-test \
+       tests/valgrind/encoding-guesser-test \
+       tests/valgrind/heap-test \
+       tests/valgrind/hmap-test \
+       tests/valgrind/hmapx-test \
+       tests/valgrind/i18n-test \
+       tests/valgrind/ll-test \
+       tests/valgrind/llx-test \
+       tests/valgrind/range-map-test \
+       tests/valgrind/range-set-test \
+       tests/valgrind/sparse-array-test \
+       tests/valgrind/sparse-xarray-test \
+       tests/valgrind/str-test \
+       tests/valgrind/string-map-test \
+       tests/valgrind/stringi-map-test \
+       tests/valgrind/string-set-test \
+       tests/valgrind/stringi-set-test \
+       tests/valgrind/tower-test \
+       tests/valgrind/u8-istream-test \
+       tests/valgrind/render-test \
+       tests/valgrind/pspp
+
+$(valgrind_wrappers): tests/valgrind-wrapper.in
+       @test -d tests/valgrind || mkdir tests/valgrind
+       sed -e 's,[@]wrap_program[@],$@,' \
+               $(top_srcdir)/tests/valgrind-wrapper.in > $@.tmp
+       chmod +x $@.tmp
+       mv $@.tmp $@
+CLEANFILES += $(valgrind_wrappers)
+EXTRA_DIST += tests/valgrind-wrapper.in
+
+VALGRIND = $(SHELL) $(abs_top_builddir)/libtool --mode=execute valgrind --log-file=valgrind.%p --leak-check=full --num-callers=20
+check-valgrind: all tests/atconfig tests/atlocal $(TESTSUITE) $(valgrind_wrappers)
+       $(SHELL) '$(TESTSUITE)' -C tests VALGRIND='$(VALGRIND)' AUTOTEST_PATH='tests/valgrind:$(AUTOTEST_PATH)' -d $(TESTSUITEFLAGS)
+       @echo
+       @echo '--------------------------------'
+       @echo 'Valgrind output is in:'
+       @echo 'tests/testsuite.dir/*/valgrind.*'
+       @echo '--------------------------------'
index bfdf9ef5026e3a1f5787929e9f8d0e68b0b2e771..cfe965c5146aa6b9e1fdf18ec336b726716ffa40 100644 (file)
@@ -3413,7 +3413,7 @@ AT_CLEANUP
 
 AT_SETUP([binary and hexadecimal input (IB, PIB, and PIBHEX formats)])
 AT_CHECK([$PERL -e 'print pack "n", $_ foreach 0...65535' > binhex-in.data])
-AT_CHECK([wc -c < binhex-in.data], [0], [131072
+AT_CHECK([[wc -c < binhex-in.data | sed 's/[   ]//g']], [0], [131072
 ])
 AT_DATA([binhex-in.sps], [dnl
 SET RIB=MSBFIRST.
@@ -3434,7 +3434,7 @@ AT_CLEANUP
 
 AT_SETUP([BCD input (P and PK formats)])
 AT_CHECK([$PERL -e 'print pack "n", $_ foreach 0...65535' > bcd-in.data])
-AT_CHECK([wc -c < bcd-in.data], [0], [131072
+AT_CHECK([[wc -c < bcd-in.data | sed 's/[      ]//g']], [0], [131072
 ])
 AT_DATA([bcd-in.sps], [dnl
 SET ERRORS=NONE.
@@ -3454,7 +3454,7 @@ AT_CLEANUP
 
 AT_SETUP([legacy input (N and Z formats)])
 AT_CHECK([$PERL -e 'print pack "n", $_ foreach 0...65535' > legacy-in.data])
-AT_CHECK([wc -c < legacy-in.data], [0], [131072
+AT_CHECK([[wc -c < legacy-in.data | sed 's/[   ]//g']], [0], [131072
 ])
 AT_DATA([legacy-in.sps], [dnl
 SET ERRORS=NONE.
@@ -3500,23 +3500,23 @@ PRINT OUTFILE='wkday.out'/ALL.
 EXECUTE.
 ])
 AT_CHECK([pspp -O format=csv wkday.sps], [0], [dnl
-wkday.sps:20.1-2: warning: Data for variable wkday2 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.2: warning: Data for variable wkday2 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-3: warning: Data for variable wkday3 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.3: warning: Data for variable wkday3 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-4: warning: Data for variable wkday4 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.4: warning: Data for variable wkday4 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-5: warning: Data for variable wkday5 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.5: warning: Data for variable wkday5 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-6: warning: Data for variable wkday6 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.6: warning: Data for variable wkday6 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-7: warning: Data for variable wkday7 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.7: warning: Data for variable wkday7 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-8: warning: Data for variable wkday8 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.8: warning: Data for variable wkday8 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-9: warning: Data for variable wkday9 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.9: warning: Data for variable wkday9 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 
-wkday.sps:20.1-10: warning: Data for variable wkday10 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
+wkday.sps:20.1-20.10: warning: Data for variable wkday10 is not valid as format WKDAY: Unrecognized weekday name.  At least the first two letters of an English weekday name must be specified.
 ])
 AT_CHECK([cat wkday.out], [0], [dnl
   .  .  .  .  .  .  .  .  . @&t@
@@ -3595,51 +3595,51 @@ PRINT OUTFILE='month.out'/ALL.
 EXECUTE.
 ])
 AT_CHECK([pspp -O format=csv month.sps], [0], [dnl
-month.sps:15.1-4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:15.1-10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:15.1-15.10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-3: warning: Data for variable month3 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.3: warning: Data for variable month3 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:26.1-10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:26.1-26.10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-3: warning: Data for variable month3 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.3: warning: Data for variable month3 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.4: warning: Data for variable month4 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.5: warning: Data for variable month5 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.6: warning: Data for variable month6 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.7: warning: Data for variable month7 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.8: warning: Data for variable month8 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.9: warning: Data for variable month9 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 
-month.sps:39.1-10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
+month.sps:39.1-39.10: warning: Data for variable month10 is not valid as format MONTH: Unrecognized month format.  Months may be specified as Arabic or Roman numerals or as at least 3 letters of their English names.
 ])
 AT_CHECK([cat month.out], [0], [dnl
    .   .   .   .   .   .   .   . @&t@
index 9a41a3b5fd4cdc1c5dc204d01b6fe0d5ad3fb3f4..7fcf8b154e52ce2eb0d6e064093a22e791faaee1 100644 (file)
@@ -218,6 +218,42 @@ sub increment {
 AT_CHECK([$PERL num-out-compare.pl $PSPP_NUM_OUT_COMPARE_FLAGS expout.inexact output.inexact])
 AT_CLEANUP
 
+AT_SETUP([non-ASCII custom currency formats])
+AT_DATA([data-out.sps], [dnl
+SET CCA='«,¥,€,»'.
+SHOW CCA.
+DATA LIST LIST NOTABLE/x.
+PRINT/x (F8.2) x (CCA10.2).
+EXECUTE.
+BEGIN DATA.
+1
+-1
+1.5
+-1.5
+.75
+1.5e10
+-1.5e10
+END DATA.
+])
+AT_CHECK([pspp -O format=csv data-out.sps], [0], [dnl
+"data-out.sps:2: note: SHOW: CCA is «,¥,€,»."
+
+1.00   ¥1.00€ @&t@
+
+-1.00  «¥1.00€»
+
+1.50   ¥1.50€ @&t@
+
+-1.50  «¥1.50€»
+
+.75    ¥.75€ @&t@
+
+1.5E+010 ¥2E+010€ @&t@
+
+-2E+010«¥2E+010€»
+])
+AT_CLEANUP
+
 AT_SETUP([binary and hexadecimal output])
 AT_DATA([binhex-out.sps], [dnl
 SET ERRORS=NONE.
@@ -14009,11 +14045,12 @@ print outfile='month-out.out'/x(month40).
 execute.
 ])
 AT_CHECK([pspp -O format=csv month-out.sps], [1], [stdout])
-AT_CHECK([sed '/^$/d' stdout | sort | uniq -c], [0], [dnl
-     38 error: Month number 0.000000 is not between 1 and 12.
-     38 error: Month number 0.500000 is not between 1 and 12.
-     38 error: Month number 0.900000 is not between 1 and 12.
-     38 error: Month number 13.000000 is not between 1 and 12.
+AT_CHECK([[sed '/^$/d' stdout | sort | uniq -c | sed 's/^[     ]*//']], [0],
+[dnl
+38 error: Month number 0.000000 is not between 1 and 12.
+38 error: Month number 0.500000 is not between 1 and 12.
+38 error: Month number 0.900000 is not between 1 and 12.
+38 error: Month number 13.000000 is not between 1 and 12.
 ])
 AT_CHECK([cat month-out.out], [0], [dnl
    .
@@ -14924,11 +14961,12 @@ end repeat.
 execute.
 ])
 AT_CHECK([pspp -O format=csv wkday-out.sps], [1], [stdout])
-AT_CHECK([sed '/^$/d' stdout | sort | uniq -c], [0], [dnl
-     39 error: Weekday number 0.000000 is not between 1 and 7.
-     39 error: Weekday number 0.500000 is not between 1 and 7.
-     39 error: Weekday number 0.900000 is not between 1 and 7.
-     39 error: Weekday number 8.000000 is not between 1 and 7.
+AT_CHECK([[sed '/^$/d' stdout | sort | uniq -c | sed 's/^[     ]*//']], [0],
+[dnl
+39 error: Weekday number 0.000000 is not between 1 and 7.
+39 error: Weekday number 0.500000 is not between 1 and 7.
+39 error: Weekday number 0.900000 is not between 1 and 7.
+39 error: Weekday number 8.000000 is not between 1 and 7.
 ])
 AT_CHECK([cat wkday-out.out], [0], [dnl
   .
diff --git a/tests/data/sack.c b/tests/data/sack.c
new file mode 100644 (file)
index 0000000..ace153c
--- /dev/null
@@ -0,0 +1,499 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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 <float.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
+
+#include "gl/error.h"
+#include "gl/md5.h"
+#include "gl/intprops.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+
+struct buffer
+  {
+    uint8_t *data;
+    size_t size;
+    size_t allocated;
+  };
+
+static void buffer_put (struct buffer *, const void *, size_t);
+static void *buffer_put_uninit (struct buffer *, size_t);
+
+enum token_type
+  {
+    T_EOF,
+    T_INTEGER,
+    T_FLOAT,
+    T_STRING,
+    T_SEMICOLON,
+    T_ASTERISK,
+    T_LPAREN,
+    T_RPAREN,
+    T_I8,
+    T_S,
+    T_COUNT
+  };
+
+static enum token_type token;
+static unsigned long int tok_integer;
+static double tok_float;
+static char *tok_string;
+static size_t tok_strlen, tok_allocated;
+
+/* --be, --le: Integer and floating-point formats. */
+static enum float_format float_format = FLOAT_IEEE_DOUBLE_BE;
+static enum integer_format integer_format = INTEGER_MSB_FIRST;
+
+/* Input file and current position. */
+static FILE *input;
+static const char *input_file_name;
+static int line_number;
+
+static void PRINTF_FORMAT (1, 2)
+fatal (const char *message, ...)
+{
+  va_list args;
+
+  fprintf (stderr, "%s:%d: ", input_file_name, line_number);
+  va_start (args, message);
+  vfprintf (stderr, message, args);
+  va_end (args);
+  putc ('\n', stderr);
+
+  exit (EXIT_FAILURE);
+}
+
+static void
+add_char (int c)
+{
+  if (tok_strlen >= tok_allocated)
+    tok_string = x2realloc (tok_string, &tok_allocated);
+
+  tok_string[tok_strlen++] = c;
+}
+
+static void
+get_token (void)
+{
+  int c;
+
+  do
+    {
+      c = getc (input);
+      if (c == '#')
+        {
+          while ((c = getc (input)) != '\n' && c != EOF)
+            continue;
+        }
+      if (c == '\n')
+        line_number++;
+    }
+  while (isspace (c) || c == '<' || c == '>');
+
+  tok_strlen = 0;
+  if (c == EOF)
+    {
+      if (token == T_EOF)
+        fatal ("unexpected end of input");
+      token = T_EOF;
+    }
+  else if (isdigit (c) || c == '-')
+    {
+      char *tail;
+
+      do
+        {
+          add_char (c);
+          c = getc (input);
+        }
+      while (isdigit (c) || isalpha (c) || c == '.');
+      add_char ('\0');
+      ungetc (c, input);
+
+      errno = 0;
+      if (strchr (tok_string, '.') == NULL)
+        {
+          token = T_INTEGER;
+          tok_integer = strtoul (tok_string, &tail, 0);
+        }
+      else
+        {
+          token = T_FLOAT;
+          tok_float = strtod (tok_string, &tail);
+        }
+      if (errno || *tail)
+        fatal ("invalid numeric syntax");
+    }
+  else if (c == '"')
+    {
+      token = T_STRING;
+      while ((c = getc (input)) != '"')
+        {
+          if (c == '\n')
+            fatal ("new-line inside string");
+          add_char (c);
+        }
+    }
+  else if (c == ';')
+    token = T_SEMICOLON;
+  else if (c == '*')
+    token = T_ASTERISK;
+  else if (c == '(')
+    token = T_LPAREN;
+  else if (c == ')')
+    token = T_RPAREN;
+  else if (isalpha (c))
+    {
+      do
+        {
+          add_char (c);
+          c = getc (input);
+        }
+      while (isdigit (c) || isalpha (c) || c == '.');
+      add_char ('\0');
+      ungetc (c, input);
+
+      if (!strcmp (tok_string, "i8"))
+        token = T_I8;
+      else if (tok_string[0] == 's')
+        {
+          token = T_S;
+          tok_integer = atoi (tok_string + 1);
+        }
+      else if (!strcmp (tok_string, "SYSMIS"))
+        {
+          token = T_FLOAT;
+          tok_float = -DBL_MAX;
+        }
+      else if (!strcmp (tok_string, "LOWEST"))
+        {
+          token = T_FLOAT;
+          tok_float = float_get_lowest ();
+        }
+      else if (!strcmp (tok_string, "HIGHEST"))
+        {
+          token = T_FLOAT;
+          tok_float = DBL_MAX;
+        }
+      else if (!strcmp (tok_string, "ENDIAN"))
+        {
+          token = T_INTEGER;
+          tok_integer = integer_format == INTEGER_MSB_FIRST ? 1 : 2;
+        }
+      else if (!strcmp (tok_string, "COUNT"))
+        token = T_COUNT;
+      else
+        fatal ("invalid token `%s'", tok_string);
+    }
+  else
+    fatal ("invalid input byte `%c'", c);
+}
+
+static void
+buffer_put (struct buffer *buffer, const void *data, size_t n)
+{
+  memcpy (buffer_put_uninit (buffer, n), data, n);
+}
+
+static void *
+buffer_put_uninit (struct buffer *buffer, size_t n)
+{
+  buffer->size += n;
+  if (buffer->size > buffer->allocated)
+    {
+      buffer->allocated = buffer->size * 2;
+      buffer->data = xrealloc (buffer->data, buffer->allocated);
+    }
+  return &buffer->data[buffer->size - n];
+}
+
+static void
+usage (void)
+{
+  printf ("\
+%s, SAv Construction Kit\n\
+usage: %s [OPTIONS] INPUT\n\
+\nOptions:\n\
+  --be     big-endian output format (default)\n\
+  --le     little-endian output format\n\
+  --help   print this help message and exit\n\
+\n\
+The input is a sequence of data items, each followed by a semicolon.\n\
+Each data item is converted to the output format and written on\n\
+stdout.  A data item is one of the following\n\
+\n\
+  - An integer in decimal, in hexadecimal prefixed by 0x, or in octal\n\
+    prefixed by 0.  Output as a 32-bit binary integer.\n\
+\n\
+  - A floating-point number.  Output in 64-bit IEEE 754 format.\n\
+\n\
+  - A string enclosed in double quotes.  Output literally.  There is\n\
+    no syntax for \"escapes\".  Strings may not contain new-lines.\n\
+\n\
+  - A literal of the form s<number> followed by a quoted string as\n\
+    above.  Output as the string's contents followed by enough spaces\n\
+    to fill up <number> bytes.  For example, s8 \"foo\" is output as\n\
+    the \"foo\" followed by 5 spaces.\n\
+\n\
+  - The literal \"i8\" followed by an integer.  Output as a single\n\
+    byte with the specified value.\n\
+\n\
+  - One of the literals SYSMIS, LOWEST, or HIGHEST.  Output as a\n\
+    64-bit IEEE 754 float of the appropriate PSPP value.\n\
+\n\
+  - The literal ENDIAN.  Output as a 32-bit binary integer, either\n\
+    with value 1 if --be is in effect or 2 if --le is in effect.\n\
+\n\
+  - A pair of parentheses enclosing a sequence of data items, each\n\
+    followed by a semicolon (the last semicolon is optional).\n\
+    Output as the enclosed data items in sequence.\n\
+\n\
+  - The literal COUNT followed by a sequence of parenthesized data\n\
+    items, as above.  Output as a 32-bit binary integer whose value\n\
+    is the number of bytes enclosed within the parentheses, followed\n\
+    by the enclosed data items themselves.\n\
+\n\
+optionally followed by an asterisk and a positive integer, which\n\
+specifies a repeat count for the data item.\n\
+\n\
+The md5sum of the data written to stdout is written to stderr as\n\
+16 hexadecimal digits followed by a new-line.\n",
+          program_name, program_name);
+  exit (EXIT_SUCCESS);
+}
+
+static const char *
+parse_options (int argc, char **argv)
+{
+  for (;;)
+    {
+      enum {
+        OPT_BE = UCHAR_MAX + 1,
+        OPT_LE,
+        OPT_HELP
+      };
+      static const struct option options[] =
+        {
+          {"be", no_argument, NULL, OPT_BE},
+          {"le", no_argument, NULL, OPT_LE},
+          {"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_BE:
+          float_format = FLOAT_IEEE_DOUBLE_BE;
+          integer_format = INTEGER_MSB_FIRST;
+          break;
+
+        case OPT_LE:
+          float_format = FLOAT_IEEE_DOUBLE_LE;
+          integer_format = INTEGER_LSB_FIRST;
+          break;
+
+        case OPT_HELP:
+          usage ();
+
+        case 0:
+          break;
+
+        case '?':
+          exit (EXIT_FAILURE);
+          break;
+
+        default:
+          NOT_REACHED ();
+        }
+
+    }
+
+  if (optind + 1 != argc)
+    error (1, 0, "exactly one non-option argument required; "
+           "use --help for help");
+  return argv[optind];
+}
+
+static void
+parse_data_item (struct buffer *output)
+{
+  size_t old_size = output->size;
+
+  if (token == T_INTEGER)
+    {
+      integer_put (tok_integer, integer_format,
+                   buffer_put_uninit (output, 4), 4);
+      get_token ();
+    }
+  else if (token == T_FLOAT)
+    {
+      float_convert (FLOAT_NATIVE_DOUBLE, &tok_float,
+                     float_format, buffer_put_uninit (output, 8));
+      get_token ();
+    }
+  else if (token == T_I8)
+    {
+      uint8_t byte;
+
+      get_token ();
+      do
+        {
+          if (token != T_INTEGER)
+            fatal ("integer expected after `i8'");
+          byte = tok_integer;
+          buffer_put (output, &byte, 1);
+          get_token ();
+        }
+      while (token == T_INTEGER);
+    }
+  else if (token == T_STRING)
+    {
+      buffer_put (output, tok_string, tok_strlen);
+      get_token ();
+    }
+  else if (token == T_S)
+    {
+      int n;
+
+      n = tok_integer;
+      get_token ();
+
+      if (token != T_STRING)
+        fatal ("string expected");
+      if (tok_strlen > n)
+        fatal ("%zu-byte string is longer than pad length %d",
+               tok_strlen, n);
+
+      buffer_put (output, tok_string, tok_strlen);
+      memset (buffer_put_uninit (output, n - tok_strlen), ' ',
+              n - tok_strlen);
+      get_token ();
+    }
+  else if (token == T_LPAREN)
+    {
+      get_token ();
+
+      while (token != T_RPAREN)
+        parse_data_item (output);
+
+      get_token ();
+    }
+  else if (token == T_COUNT)
+    {
+      buffer_put_uninit (output, 4);
+
+      get_token ();
+      if (token != T_LPAREN)
+        fatal ("`(' expected after COUNT");
+      get_token ();
+
+      while (token != T_RPAREN)
+        parse_data_item (output);
+      get_token ();
+
+      integer_put (output->size - old_size - 4, integer_format,
+                   output->data + old_size, 4);
+    }
+  else
+    fatal ("syntax error");
+
+  if (token == T_ASTERISK)
+    {
+      size_t n = output->size - old_size;
+      char *p;
+
+      get_token ();
+
+      if (token != T_INTEGER || tok_integer < 1)
+        fatal ("positive integer expected after `*'");
+      p = buffer_put_uninit (output, (tok_integer - 1) * n);
+      while (--tok_integer > 0)
+        {
+          memcpy (p, output->data + old_size, n);
+          p += n;
+        }
+
+      get_token ();
+    }
+
+  if (token == T_SEMICOLON)
+    get_token ();
+  else if (token != T_RPAREN)
+    fatal ("`;' expected");
+}
+
+int
+main (int argc, char **argv)
+{
+  struct buffer output;
+  uint8_t digest[16];
+  int i;
+
+  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);
+    }
+
+  if (isatty (STDOUT_FILENO))
+    error (1, 0, "not writing binary data to a terminal; redirect to a file");
+
+  output.data = NULL;
+  output.size = 0;
+  output.allocated = 0;
+
+  line_number = 1;
+  get_token ();
+  while (token != T_EOF)
+    parse_data_item (&output);
+
+  if (input != stdin)
+    fclose (input);
+
+  fwrite (output.data, output.size, 1, stdout);
+
+  md5_buffer ((const char *) output.data, output.size, digest);
+  for (i = 0; i < sizeof digest; i++)
+    fprintf (stderr, "%02x", digest[i]);
+  putc ('\n', stderr);
+
+  return 0;
+}
diff --git a/tests/data/sys-file-reader.at b/tests/data/sys-file-reader.at
new file mode 100644 (file)
index 0000000..cdf6366
--- /dev/null
@@ -0,0 +1,3263 @@
+AT_BANNER([system file reader - positive])
+
+AT_SETUP([variable labels and missing values])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+22; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted
+1; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52";
+"PSPP synthetic test file: "; i8 244; i8 245; i8 246; i8 248; s34 "";
+i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Numeric variable, variable label.
+2; 0; 1; 0; 0x050800 *2; s8 "NUM2";
+32; "Numeric variable 2's label ("; i8 249; i8 250; i8 251; ")";
+
+dnl Numeric variable, one missing value.
+2; 0; 0; 1; 0x050800 *2; s8 "NUM3";
+1.0;
+
+dnl Numeric variable, variable label and missing value.
+2; 0; 1; 1; 0x050800 *2; s8 "NUM4";
+30; "Another numeric variable label"; i8 0 * 2;
+1.0;
+
+dnl Numeric variable, two missing values.
+2; 0; 0; 2; 0x050800 *2; s8 "NUM5"; 1.0; 2.0;
+
+dnl Numeric variable, three missing values.
+2; 0; 0; 3; 0x050800 *2; s8 "NUM6"; 1.0; 2.0; 3.0;
+
+dnl Numeric variable, range of missing values.
+2; 0; 0; -2; 0x050800 *2; s8 "NUM7"; 1.0; 3.0;
+
+dnl Numeric variables, range of missing values plus discrete value.
+2; 0; 0; -3; 0x050800 *2; s8 "NUM8"; 1.0; 3.0; 5.0;
+2; 0; 0; -3; 0x050800 *2; s8 "NUM9"; 1.0; HIGHEST; -5.0;
+2; 0; 0; -3; 0x050800 *2; "NUM"; i8 192; i8 200; i8 204; i8 209; i8 210;
+LOWEST; 1.0; 5.0;
+
+dnl String variable, no label or missing values.
+2; 4; 0; 0; 0x010400 *2; s8 "STR1";
+
+dnl String variable, variable label.
+2; 4; 1; 0; 0x010400 *2; s8 "STR2";
+25; "String variable 2's label"; i8 0 * 3;
+
+dnl String variable, one missing value.
+2; 4; 0; 1; 0x010400 *2; s8 "STR3"; s8 "MISS";
+
+dnl String variable, variable label and missing value.
+2; 4; 1; 1; 0x010400 *2; s8 "STR4";
+29; "Another string variable label"; i8 0 * 3;
+s8 "OTHR";
+
+dnl String variable, two missing values.
+2; 4; 0; 2; 0x010400 *2; s8 "STR5"; s8 "MISS"; s8 "OTHR";
+
+dnl String variable, three missing values.
+2; 4; 0; 3; 0x010400 *2; s8 "STR6"; s8 "MISS"; s8 "OTHR"; s8 "MORE";
+
+dnl Long string variable, one missing value.
+2; 11; 0; 1; 0x010b00 *2; s8 "STR7"; "first8by";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Long string variable, value label.
+2; 25; 1; 0; 0x011900 *2; s8 "STR8"; 14; "25-byte string"; i8 0 * 2;
+( 2; -1; 0; 0; 0; 0; s8 ""; ) * 2;
+dnl Variable label fields on continuation records have been spotted in system
+dnl files created by "SPSS Power Macintosh Release 6.1".
+2; -1; 1; 0; 0; 0; s8 ""; 20; "dummy variable label";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Machine floating-point info record.
+7; 4; 8; 3; SYSMIS; HIGHEST; LOWEST;
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0; 2.0; 3.0; 4.0; 5.0; 6.0; 7.0; 8.0; 9.0; 10.0;
+s8 "abcd"; s8 "efgh"; s8 "ijkl"; s8 "mnop"; s8 "qrst"; s8 "uvwx";
+s16 "yzABCDEFGHI"; s32 "JKLMNOPQRSTUVWXYZ01234567";
+])
+for variant in \
+       "be 94338da4d8d44244d43f31e2ea4d0a6a" \
+       "le e3e7eefb984b81be5531b579293cb127"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY FILE LABEL.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+File label: PSPP synthetic test file: ôõöø
+
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Numeric variable 2's label (ùúû),,2
+,Format: F8.0,,
+num3,Format: F8.0,,3
+,Missing Values: 1,,
+num4,Another numeric variable label,,4
+,Format: F8.0,,
+,Missing Values: 1,,
+num5,Format: F8.0,,5
+,Missing Values: 1; 2,,
+num6,Format: F8.0,,6
+,Missing Values: 1; 2; 3,,
+num7,Format: F8.0,,7
+,Missing Values: 1 THRU 3,,
+num8,Format: F8.0,,8
+,Missing Values: 1 THRU 3; 5,,
+num9,Format: F8.0,,9
+,Missing Values: 1 THRU HIGHEST; -5,,
+numÀÈÌÑÒ,Format: F8.0,,10
+,Missing Values: LOWEST THRU 1; 5,,
+str1,Format: A4,,11
+str2,String variable 2's label,,12
+,Format: A4,,
+str3,Format: A4,,13
+,"Missing Values: ""MISS""",,
+str4,Another string variable label,,14
+,Format: A4,,
+,"Missing Values: ""OTHR""",,
+str5,Format: A4,,15
+,"Missing Values: ""MISS""; ""OTHR""",,
+str6,Format: A4,,16
+,"Missing Values: ""MISS""; ""OTHR""; ""MORE""",,
+str7,Format: A11,,17
+,"Missing Values: ""first8by""",,
+str8,25-byte string,,18
+,Format: A25,,
+
+Table: Data List
+num1,num2,num3,num4,num5,num6,num7,num8,num9,numÀÈÌÑÒ,str1,str2,str3,str4,str5,str6,str7,str8
+1,2,3,4,5,6,7,8,9,10,abcd,efgh,ijkl,mnop,qrst,uvwx,yzABCDEFGHI,JKLMNOPQRSTUVWXYZ01234567
+])
+done
+AT_CLEANUP
+
+AT_SETUP([unspecified number of variable positions])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+-1; dnl Nominal case size (unspecified)
+0; dnl Not compressed
+0; dnl Not weighted 
+1; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Numeric variable, variable label.
+2; 0; 1; 0; 0x050800 *2; s8 "NUM2";
+26; "Numeric variable 2's label"; i8 0 *2;
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0; 2.0; 
+])
+for variant in \
+       "be 413e7bc80a47fcd7e4c8020e8e120060" \
+       "le d7db9120b1ff28c83aa6fe9fc405d903"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Numeric variable 2's label,,2
+,Format: F8.0,,
+
+Table: Data List
+num1,num2
+1,2
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong number of variable positions but version 13])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+-1; dnl Nominal case size (unspecified)
+0; dnl Not compressed
+0; dnl Not weighted 
+1; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Numeric variable, variable label.
+2; 0; 1; 0; 0x050800 *2; s8 "NUM2";
+26; "Numeric variable 2's label"; i8 0 *2;
+
+dnl Machine integer info record (SPSS 13).
+7; 3; 4; 8; 13; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0; 2.0; 
+])
+for variant in \
+       "be 3d17aae7d99538dc73c5cb42692b1038" \
+       "le 8ad1000df598617d5258f323c882d749"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Numeric variable 2's label,,2
+,Format: F8.0,,
+
+Table: Data List
+num1,num2
+1,2
+])
+done
+AT_CLEANUP
+
+AT_SETUP([value labels])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+22; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+1; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM3";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM4";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM5";
+
+dnl String variables.
+2; 1; 0; 0; 0x010100 *2; s8 "STR1"; dnl index 6
+2; 2; 0; 0; 0x010200 *2; s8 "STR2"; dnl index 7
+2; 3; 0; 0; 0x010300 *2; s8 "STR3"; dnl index 8
+2; 4; 0; 0; 0x010400 *2; s8 "STR4"; dnl index 9
+2; 4; 0; 0; 0x010400 *2; s8 "STR5"; dnl index 10
+2; 6; 0; 0; 0x010600 *2; s8 "STR6"; dnl index 11
+2; 7; 0; 0; 0x010700 *2; s8 "STR7"; dnl index 12
+2; 8; 0; 0; 0x010800 *2; s8 "STR8"; dnl index 13
+2; 9; 0; 0; 0x010900 *2; "STR9"; i8 230; s3 ""; dnl index 14
+2; -1; 0; 0; 0; 0; s8 "";
+2; 12; 0; 0; 0x010c00 *2; s8 "STR12"; dnl index 16
+2; -1; 0; 0; 0; 0; s8 "";
+2; 16; 0; 0; 0x011000 *2; s8 "STR16"; dnl index 18
+2; -1; 0; 0; 0; 0; s8 "";
+2; 17; 0; 0; 0x011100 *2; s8 "STR17"; dnl index 20
+( 2; -1; 0; 0; 0; 0; s8 ""; ) * 2;
+
+dnl One value label for NUM1.
+3; 1; 1.0; i8 17; i8 238; i8 228; i8 232; i8 237; s19 " (in Russian)"; 4; 1; 1;
+
+dnl Two value labels for NUM2, as a single pair of type 3 and type 4 records.
+3; 2; 1.0; i8 3; s7 "one"; 2.0; i8 3; s7 "two"; 4; 1; 2;
+
+dnl Two value labels for NUM3, as two pairs of type 3 and type 4 records.
+3; 1; 3.0; i8 5; s7 "three"; 4; 1; 3;
+3; 1; 4.0; i8 4; s7 "four"; 4; 1; 3;
+
+dnl Two common value labels for NUM4 and NUM5, plus two different ones for each.
+3; 1; 5.0; i8 4; s7 "five"; 4; 1; 4;
+3; 1; 6.0; i8 3; s7 "six"; 4; 1; 5;
+3; 2; 7.0; i8 5; s7 "seven"; 8.0; i8 5; s7 "eight"; 4; 2; 4; 5;
+3; 1; 9.0; i8 4; s7 "nine"; 4; 1; 4;
+3; 1; 10.0; i8 3; s7 "ten"; 4; 1; 5;
+
+dnl One value label for STR1.
+3; 1; s8 "a"; i8 19; s23 "value label for `a'"; 4; 1; 6;
+
+dnl Two value labels for STR2, as a single pair of type 3 and type 4 records.
+3; 2;
+s8 "bc"; i8 20; s23 "value label for `bc'";
+s8 "de"; i8 20; s23 "value label for `de'";
+4; 1; 7;
+
+dnl Two value labels for STR3, as two pairs of type 3 and type 4 records.
+3; 1; s8 "fgh"; i8 21; s23 "value label for `fgh'"; 4; 1; 8;
+3; 1; s8 "ijk"; i8 21; s23 "value label for `ijk'"; 4; 1; 8;
+
+dnl Two common value labels for STR4 and STR5, plus two different ones for each.
+3; 1; s8 "lmno"; i8 22; s23 "value label for `lmno'"; 4; 1; 9;
+3; 1; s8 "pqrs"; i8 22; s23 "value label for `pqrs'"; 4; 1; 10;
+3; 2;
+s8 "tuvw"; i8 22; s23 "value label for `tuvw'";
+s8 "xyzA"; i8 22; s23 "value label for `xyzA'";
+4; 2; 9; 10;
+3; 1; s8 "BCDE"; i8 22; s23 "value label for `BCDE'"; 4; 1; 9;
+3; 1; s8 "FGHI"; i8 22; s23 "value label for `FGHI'"; 4; 1; 10;
+
+dnl One value label for STR6, STR7, STR8.
+3; 1; s8 "JKLMNO"; i8 24; s31 "value label for `JKLMNO'"; 4; 1; 11;
+3; 1; s8 "JKLMNOP"; i8 25; s31 "value label for `JKLMNOP'"; 4; 1; 12;
+3; 1; s8 "JKLMNOPQ"; i8 26; s31 "value label for `JKLMNOPQ'"; 4; 1; 13;
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1251;
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1251";
+
+7; 21; 1; COUNT (
+dnl One value label for STR9ж,
+COUNT("STR9"; i8 230); 9; 1; COUNT("RSTUVWXYZ"); COUNT("value label for `RSTUVWXYZ'");
+
+dnl Two value labels for STR12.
+COUNT("STR12"); 12; 2;
+COUNT("0123456789ab"); COUNT("value label for `0123456789ab'");
+COUNT("cdefghijklmn"); COUNT("value label for `cdefghijklmn'");
+
+dnl Three value labels for STR16.
+COUNT("STR16"); 16; 3;
+COUNT("opqrstuvwxyzABCD"); COUNT("value label for `opqrstuvwxyzABCD'");
+COUNT("EFGHIJKLMNOPQRST"); COUNT("value label for `EFGHIJKLMNOPQRST'");
+COUNT("UVWXYZ0123456789"); COUNT("value label for `UVWXYZ0123456789' with Cyrillic letters: `"; i8 244; i8 245; i8 246; "'");
+
+dnl One value label for STR17.
+COUNT("STR17"); 17; 1;
+COUNT("abcdefghijklmnopq"); COUNT("value label for `abcdefghijklmnopq'");
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be b27d766d8a5ad9e901c8b244591a5942" \
+       "le eb2e93f3cc29acd605b80e6c3af25ba6"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+num1,Format: F8.0,,1
+,1,один (in Russian),
+num2,Format: F8.0,,2
+,1,one,
+,2,two,
+num3,Format: F8.0,,3
+,3,three,
+,4,four,
+num4,Format: F8.0,,4
+,5,five,
+,7,seven,
+,8,eight,
+,9,nine,
+num5,Format: F8.0,,5
+,6,six,
+,7,seven,
+,8,eight,
+,10,ten,
+str1,Format: A1,,6
+,a,value label for `a',
+str2,Format: A2,,7
+,bc,value label for `bc',
+,de,value label for `de',
+str3,Format: A3,,8
+,fgh,value label for `fgh',
+,ijk,value label for `ijk',
+str4,Format: A4,,9
+,BCDE,value label for `BCDE',
+,lmno,value label for `lmno',
+,tuvw,value label for `tuvw',
+,xyzA,value label for `xyzA',
+str5,Format: A4,,10
+,FGHI,value label for `FGHI',
+,pqrs,value label for `pqrs',
+,tuvw,value label for `tuvw',
+,xyzA,value label for `xyzA',
+str6,Format: A6,,11
+,JKLMNO,value label for `JKLMNO',
+str7,Format: A7,,12
+,JKLMNOP,value label for `JKLMNOP',
+str8,Format: A8,,13
+,JKLMNOPQ,value label for `JKLMNOPQ',
+str9ж,Format: A9,,14
+,RSTUVWXYZ,value label for `RSTUVWXYZ',
+str12,Format: A12,,15
+,0123456789ab,value label for `0123456789ab',
+,cdefghijklmn,value label for `cdefghijklmn',
+str16,Format: A16,,16
+,EFGHIJKLMNOPQRST,value label for `EFGHIJKLMNOPQRST',
+,UVWXYZ0123456789,value label for `UVWXYZ0123456789' with Cyrillic letters: `фхц',
+,opqrstuvwxyzABCD,value label for `opqrstuvwxyzABCD',
+str17,Format: A17,,17
+,abcdefghijklmnopq,value label for `abcdefghijklmnopq',
+])
+done
+AT_CLEANUP
+
+AT_SETUP([documents])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+1; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+1; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Document record.
+6; 5;
+s80 "First line of documents";
+s80 "Second line of documents";
+"abb"; i8 233; " appliqu"; i8 233; " attach"; i8 233; " blas"; i8 233; " caf"; i8 233; " canap"; i8 233; " clich"; i8 233; " consomm"; i8 233;
+s25 "";
+s80 "";
+s80 "Last line of documents";
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0;
+])
+for variant in \
+       "be 3555f74f3e714a3a703de7df56ce6d24" \
+       "le ede5a0f805a1aab096ea86abf677ff34"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DOCUMENTS.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([cat pspp.csv], [0], [dnl
+Documents in the active dataset:
+
+First line of documents
+
+Second line of documents
+
+abbé appliqué attaché blasé café canapé cliché consommé
+
+
+
+Last line of documents
+
+Table: Data List
+num1
+1
+])
+done
+AT_CLEANUP
+
+AT_SETUP([multiple response sets])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+16; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+0; dnl No cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl $a
+2; 0; 0; 0; 0x050800 *2; i8 0x82; i8 0xa0; s6 "";
+2; 0; 0; 0; 0x050800 *2; s8 "B";
+2; 0; 0; 0; 0x050800 *2; s8 "C";
+
+dnl $b
+2; 0; 0; 0; 0x050800 *2; s8 "D";
+2; 0; 0; 0; 0x050800 *2; s8 "E";
+2; 0; 0; 0; 0x050800 *2; s8 "F";
+2; 0; 0; 0; 0x050800 *2; s8 "G";
+
+dnl $c
+2; 4; 0; 0; 0x010400 *2; s8 "H";
+2; 4; 0; 0; 0x010400 *2; s8 "I";
+2; 4; 0; 0; 0x010400 *2; s8 "J";
+
+dnl $d
+2; 0; 0; 0; 0x050800 *2; s8 "K";
+2; 0; 0; 0; 0x050800 *2; s8 "L";
+2; 0; 0; 0; 0x050800 *2; s8 "M";
+
+dnl $e
+2; 6; 0; 0; 0x010600 *2; s8 "N";
+2; 6; 0; 0; 0x010600 *2; s8 "O";
+2; 6; 0; 0; 0x010600 *2; s8 "P";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 932;
+
+7; 7; 1;
+COUNT(
+  "$a=C 10 my mcgroup "; i8 0x82; i8 0xa0; " b c"; i8 10;
+  "$b=D2 55 0  g e f d"; i8 10;
+  "$c=D4 "; i8 0x82; i8 0xcd; i8 0x82; i8 0xa2; " 10 mdgroup #2 h i j"; i8 10);
+
+7; 19; 1;
+COUNT(
+  "$d=E 1 2 34 13 third mdgroup k l m"; i8 10;
+  "$e=E 11 6 choice 0  n o p"; i8 10);
+
+dnl Character encoding record.
+7; 20; 1; 9; "shift_jis";
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be fdf260a05220e08c748967dcb90d8b15" \
+       "le 4c9b0c0636bc0aa0cc16684c8188d1c7"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+MRSETS /DISPLAY NAME=ALL.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Multiple Response Sets
+Name,Variables,Details
+$a,"あ
+b
+c
+","Multiple category set
+Label: my mcgroup
+"
+$b,"g
+e
+f
+d
+","Multiple dichotomy set
+Counted value: 55
+Category label source: Variable labels
+"
+$c,"h
+i
+j
+","Multiple dichotomy set
+Label: mdgroup #2
+Label source: Provided by user
+Counted value: `はい'
+Category label source: Variable labels
+"
+$d,"k
+l
+m
+","Multiple dichotomy set
+Label: third mdgroup
+Label source: Provided by user
+Counted value: 34
+Category label source: Value labels of counted value
+"
+$e,"n
+o
+p
+","Multiple dichotomy set
+Label source: First variable label among variables
+Counted value: `choice'
+Category label source: Value labels of counted value
+"
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable display parameters, without width])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+19; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+0; dnl No cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "A";
+2; 0; 0; 0; 0x050800 *2; s8 "B";
+2; 0; 0; 0; 0x050800 *2; s8 "C";
+2; 0; 0; 0; 0x050800 *2; s8 "D";
+
+dnl Short string variables.
+2; 3; 0; 0; 0x010300 *2; s8 "H";
+2; 3; 0; 0; 0x010300 *2; s8 "I";
+2; 3; 0; 0; 0x010300 *2; s8 "J";
+2; 3; 0; 0; 0x010300 *2; s8 "K";
+
+dnl Long string variables.
+2; 9; 0; 0; 0x010900 *2; s8 "L";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 10; 0; 0; 0x010a00 *2; s8 "M";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 17; 0; 0; 0x011100 *2; s8 "N";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 2;
+2; 25; 0; 0; 0x011900 *2; s8 "O";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 3;
+
+dnl Variable display parameters
+7; 11; 4; 24;
+1; 0;
+2; 0;
+3; 0;
+1; 1;
+2; 1;
+3; 1;
+1; 2;
+2; 2;
+3; 2;
+0; 0;
+0; 1;
+0; 2;
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be c130d9345080579b8862b360924edbfa" \
+       "le 6fde96f5a7c7386bff6cca049cd84d6a"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([cat pspp.csv], [0], [dnl
+Variable,Description,,Position
+a,Format: F8.0,,1
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+b,Format: F8.0,,2
+,Measure: Ordinal,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+c,Format: F8.0,,3
+,Measure: Scale,,
+,Display Alignment: Left,,
+,Display Width: 8,,
+d,Format: F8.0,,4
+,Measure: Nominal,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+h,Format: A3,,5
+,Measure: Ordinal,,
+,Display Alignment: Right,,
+,Display Width: 3,,
+i,Format: A3,,6
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 3,,
+j,Format: A3,,7
+,Measure: Nominal,,
+,Display Alignment: Center,,
+,Display Width: 3,,
+k,Format: A3,,8
+,Measure: Ordinal,,
+,Display Alignment: Center,,
+,Display Width: 3,,
+l,Format: A9,,9
+,Measure: Scale,,
+,Display Alignment: Center,,
+,Display Width: 9,,
+m,Format: A10,,10
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 10,,
+n,Format: A17,,11
+,Measure: Nominal,,
+,Display Alignment: Right,,
+,Display Width: 17,,
+o,Format: A25,,12
+,Measure: Nominal,,
+,Display Alignment: Center,,
+,Display Width: 25,,
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable display parameters, with width])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+19; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+0; dnl No cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "A";
+2; 0; 0; 0; 0x050800 *2; s8 "B";
+2; 0; 0; 0; 0x050800 *2; s8 "C";
+2; 0; 0; 0; 0x050800 *2; s8 "D";
+
+dnl Short string variables.
+2; 3; 0; 0; 0x010300 *2; s8 "H";
+2; 3; 0; 0; 0x010300 *2; s8 "I";
+2; 3; 0; 0; 0x010300 *2; s8 "J";
+2; 3; 0; 0; 0x010300 *2; s8 "K";
+
+dnl Long string variables.
+2; 9; 0; 0; 0x010900 *2; s8 "L";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 10; 0; 0; 0x010a00 *2; s8 "M";
+2; -1; 0; 0; 0; 0; s8 "";
+2; 17; 0; 0; 0x011100 *2; s8 "N";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 2;
+2; 25; 0; 0; 0x011900 *2; s8 "O";
+( 2; -1; 0; 0; 0; 0; s8 "" ) * 3;
+
+dnl Variable display parameters
+7; 11; 4; 36;
+1; 1; 0;
+2; 2; 0;
+3; 3; 0;
+1; 4; 1;
+2; 5; 1;
+3; 6; 1;
+1; 7; 2;
+2; 8; 2;
+3; 9; 2;
+0; 10; 0;
+0; 11; 1;
+0; 12; 2;
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 3ace75689a0b7faa9360936bbfe26055" \
+       "le 6e93f35d19a9882eb53ffb1b067ef7cd"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([cat pspp.csv], [0], [dnl
+Variable,Description,,Position
+a,Format: F8.0,,1
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 1,,
+b,Format: F8.0,,2
+,Measure: Ordinal,,
+,Display Alignment: Left,,
+,Display Width: 2,,
+c,Format: F8.0,,3
+,Measure: Scale,,
+,Display Alignment: Left,,
+,Display Width: 3,,
+d,Format: F8.0,,4
+,Measure: Nominal,,
+,Display Alignment: Right,,
+,Display Width: 4,,
+h,Format: A3,,5
+,Measure: Ordinal,,
+,Display Alignment: Right,,
+,Display Width: 5,,
+i,Format: A3,,6
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 6,,
+j,Format: A3,,7
+,Measure: Nominal,,
+,Display Alignment: Center,,
+,Display Width: 7,,
+k,Format: A3,,8
+,Measure: Ordinal,,
+,Display Alignment: Center,,
+,Display Width: 8,,
+l,Format: A9,,9
+,Measure: Scale,,
+,Display Alignment: Center,,
+,Display Width: 9,,
+m,Format: A10,,10
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 10,,
+n,Format: A17,,11
+,Measure: Nominal,,
+,Display Alignment: Right,,
+,Display Width: 11,,
+o,Format: A25,,12
+,Measure: Nominal,,
+,Display Alignment: Center,,
+,Display Width: 12,,
+])
+done
+AT_CLEANUP
+
+AT_SETUP([long variable names])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+7; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+0; dnl No cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVARI";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_A";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_B";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_C";
+2; 0; 0; 0; 0x050800 *2; "CO"; i8 214; "RDINA";
+2; 0; 0; 0; 0x050800 *2; "CO"; i8 214; "RDI_A";
+2; 0; 0; 0; 0x050800 *2; "CO"; i8 214; "RDI_B";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Machine floating-point info record.
+7; 4; 8; 3; SYSMIS; HIGHEST; LOWEST;
+
+dnl Long variable names.
+7; 13; 1; COUNT (
+"LONGVARI=LongVariableName1"; i8 9;
+"LONGVA_A=LongVariableName2"; i8 9;
+"LONGVA_B=LongVariableName3"; i8 9;
+"LONGVA_C=LongVariableName4"; i8 9;
+"CO"; i8 214; "RDINA=Co"; i8 246; "rdinate_X"; i8 9;
+"CO"; i8 214; "RDI_A=Co"; i8 246; "rdinate_Y"; i8 9;
+"CO"; i8 214; "RDI_B=Co"; i8 246; "rdinate_Z";
+);
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 8ea5a72f3ae6e732371e92a7719c3951" \
+       "le 02bcf02cf08b1e8fc80a858101ae22fc"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+LongVariableName1,Format: F8.0,,1
+LongVariableName2,Format: F8.0,,2
+LongVariableName3,Format: F8.0,,3
+LongVariableName4,Format: F8.0,,4
+Coördinate_X,Format: F8.0,,5
+Coördinate_Y,Format: F8.0,,6
+Coördinate_Z,Format: F8.0,,7
+])
+done
+AT_CLEANUP
+
+AT_SETUP([very long strings])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+109; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+1; dnl No cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl 256-byte string.
+2; 255; 0; 0; 0x01FF00 *2; "S"; i8 201; s6 "Q256";
+(2; -1; 0; 0; 0; 0; s8 "") * 31;
+2; 4; 0; 0; 0x010400 *2; "S"; i8 201; "Q256_1";
+
+dnl 600-byte string.
+2; 255; 0; 0; 0x01FF00 *2; s8 "STR600";
+(2; -1; 0; 0; 0; 0; s8 "") * 31;
+2; 255; 0; 0; 0x01FF00 *2; s8 "STR600_1";
+(2; -1; 0; 0; 0; 0; s8 "") * 31;
+2; 96; 0; 0; 0x016000 *2; s8 "STR600_2";
+(2; -1; 0; 0; 0; 0; s8 "") * 11;
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Very long string record.
+7; 14; 1; COUNT (
+"S"; i8 201; "Q256=00256"; i8 0; i8 9;
+"STR600=00600"; i8 0; i8 9;
+);
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#" * 4;
+"abcdefgh";
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#" * 9;
+"abcdefghijklmnopqrstuvwxyzABCDEF";
+])
+for variant in \
+       "be 844a4704f669dfe292482e587d690133" \
+       "le b76025f602bdff6a42c1e0795a8b62ff"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+sÉq256,Format: A256,,1
+str600,Format: A600,,2
+
+Table: Data List
+sÉq256,str600
+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@a,abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#abcdefghijklmnopqrstuvwxyz
+])
+done
+AT_CLEANUP
+
+AT_SETUP([data file and variable attributes])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+2; dnl Nominal case size
+0; dnl Not compressed
+0; dnl Not weighted 
+0; dnl 1 case.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Variables.
+2; 0; 0; 0; 0x050800 *2; s8 "FIRSTVAR";
+2; 0; 0; 0; 0x050800 *2; s8 "SECONDVA";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; ENDIAN; 1252;
+
+dnl Long variable names.
+7; 13; 1; COUNT (
+"FIRSTVAR=FirstVariable"; i8 9;
+"SECONDVA=S"; i8 233; "condVariable"; i8 9;
+);
+
+dnl Data file attributes record.
+7; 17; 1; COUNT (
+"Attr1('Value1'"; i8 10; "''d"; i8 233; "claration''"; i8 10; ")";
+"S"; i8 233; "condAttr('123'"; i8 10; "'456'"; i8 10; ")";
+);
+
+dnl Variable attributes record.
+7; 18; 1; COUNT (
+"FirstVariable:";
+  "ad"; i8 232; "le('23'"; i8 10; "'34'"; i8 10; ")";
+  "bert('123'"; i8 10; ")";
+"/S"; i8 233; "condVariable:";
+  "xyzzy('quux'"; i8 10; ")";
+);
+
+
+dnl Character encoding record.
+7; 20; 1; 12; "windows-1252";
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be c7cae57af35662acec3b945abcf7927c" \
+       "le eb6b4ab9c27bfa0daa49bf2770bccb70"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY ATTRIBUTES.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([cat pspp.csv], [0],
+[[Variable,Description,
+FirstVariable,Custom attributes:,
+,bert,123
+,adèle[1],23
+,adèle[2],34
+SécondVariable,Custom attributes:,
+,xyzzy,quux
+
+Table: Custom data file attributes.
+Attribute,Value
+SécondAttr[1],123
+SécondAttr[2],456
+Attr1[1],Value1
+Attr1[2],'déclaration'
+]])
+done
+AT_CLEANUP
+
+AT_SETUP([compressed data])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+6; dnl Nominal case size
+1; dnl Not compressed
+0; dnl Not weighted 
+-1; dnl Unspecified number of cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR4";
+2; 8; 0; 0; 0x010800 *2; s8 "STR8";
+2; 15; 0; 0; 0x010f00 *2; s8 "STR15";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Compressed data.
+i8 1 100 254 253 254 253; i8 255 251; "abcdefgh"; s8 "0123";
+i8 253 253 253 254; i8 101 102 253 253; s8 "jklm"; s8 "nopqrstu";
+s8 "vwxyzABC"; s8 "DEFG"; s8 "HIJKLMNO";
+i8 254 253 252 0 0 0 0 0; s8 "PQRSTUVW";
+
+])
+for variant in \
+       "be c0670e436b068f45710b98f6f7d01dc5" \
+       "le 2e43a7f8861df4e714a192dfb3c8b2f4"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Format: F8.0,,2
+str4,Format: A4,,3
+str8,Format: A8,,4
+str15,Format: A15,,5
+
+Table: Data List
+num1,num2,str4,str8,str15
+-99,0,,abcdefgh,0123   @&t@
+.,151,jklm,nopqrstu,vwxyzABC       @&t@
+1,2,DEFG,HIJKLMNO,PQRSTUV
+])
+done
+AT_CLEANUP
+
+AT_SETUP([compressed data, zero bias])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+6; dnl Nominal case size
+1; dnl Not compressed
+0; dnl Not weighted 
+-1; dnl Unspecified number of cases.
+0.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR4";
+2; 8; 0; 0; 0x010800 *2; s8 "STR8";
+2; 15; 0; 0; 0x010f00 *2; s8 "STR15";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Compressed data.
+i8 1 100 254 253 254 253; i8 255 251; "abcdefgh"; s8 "0123";
+i8 253 253 253 254; i8 101 102 253 253; s8 "jklm"; s8 "nopqrstu";
+s8 "vwxyzABC"; s8 "DEFG"; s8 "HIJKLMNO";
+i8 254 253 252 0 0 0 0 0; s8 "PQRSTUVW";
+
+])
+for variant in \
+       "be 2f0d25704ee497ae833213a3e4ff5e8b" \
+       "le 49f68a9e1ba02a2f7e9166686a0db9d9"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps], [0])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Format: F8.0,,2
+str4,Format: A4,,3
+str8,Format: A8,,4
+str15,Format: A15,,5
+
+Table: Data List
+num1,num2,str4,str8,str15
+1,100,,abcdefgh,0123   @&t@
+.,251,jklm,nopqrstu,vwxyzABC       @&t@
+101,102,DEFG,HIJKLMNO,PQRSTUV
+])
+done
+AT_CLEANUP
+
+AT_SETUP([compressed data, other bias])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+6; dnl Nominal case size
+1; dnl Not compressed
+0; dnl Not weighted 
+-1; dnl Unspecified number of cases.
+50.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR4";
+2; 8; 0; 0; 0x010800 *2; s8 "STR8";
+2; 15; 0; 0; 0x010f00 *2; s8 "STR15";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Compressed data.
+i8 1 100 254 253 254 253; i8 255 251; "abcdefgh"; s8 "0123";
+i8 253 253 253 254; i8 101 102 253 253; s8 "jklm"; s8 "nopqrstu";
+s8 "vwxyzABC"; s8 "DEFG"; s8 "HIJKLMNO";
+i8 254 253 252 0 0 0 0 0; s8 "PQRSTUVW";
+
+])
+for variant in \
+       "be 668b85e3dee0797883e9933a096b8c18" \
+       "le 5e7a9c4e88cd2dbc2322943da663868e"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+LIST.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps], [0], 
+    [warning: `sys-file.sav' near offset 0x54: Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format.
+])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0], [dnl
+"warning: `sys-file.sav' near offset 0x54: Compression bias is not the usual value of 100, or system file uses unrecognized floating-point format."
+
+Variable,Description,,Position
+num1,Format: F8.0,,1
+num2,Format: F8.0,,2
+str4,Format: A4,,3
+str8,Format: A8,,4
+str15,Format: A15,,5
+
+Table: Data List
+num1,num2,str4,str8,str15
+-49,50,,abcdefgh,0123   @&t@
+.,201,jklm,nopqrstu,vwxyzABC       @&t@
+51,52,DEFG,HIJKLMNO,PQRSTUV
+])
+done
+AT_CLEANUP
+\f
+AT_BANNER([system file reader - negative])
+
+AT_SETUP([misplaced type 4 record])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Type 4 record.
+>>4<<;
+])
+for variant in \
+       "be 6e0bb549fff1fd1af333d51b8a6e0f43" \
+       "le 7b62734edcee2a1689c463f2866d11b8"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xd4: Misplaced type 4 record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad record type])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Type 8 record (not a valid type).
+>>8<<;
+])
+for variant in \
+       "be dc8f078c23046ee7db74ec1003178a11" \
+       "le dc7f111642f0629f4370630fd092eee3"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xd4: Unrecognized record type 8.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong number of variable positions])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; >>2<<; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be c57e91aa426f61813c3ad91ea3a56dda" \
+       "le 5d1a6c114b135b219473c8ad5bb44bda"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], 
+   [warning: `sys-file.sav': File header claims 2 variable positions but 1 were read from file.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable name may not begin with `#'])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 >>"$UM1"<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be decb7ac6defa1ab3cc7a386d1843c1ae" \
+       "le 5279b6275633bac55d167faebccfdb14"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xb4: Invalid variable name `$UM1'.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable name may not be reserved word])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 >>"TO"<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 57e6ad709668bbf538e2efee4af49916" \
+       "le 523f14b611efa380bbadf7a16ea43fed"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xb4: Invalid variable name `TO'.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable width must be between 0 and 255])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl String variable with invalid width 256.
+2; 256; 0; 0; 0x050800 *2; s8 "VAR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 170bb18589ba264a0ed2d57b41fe77e1" \
+       "le 9528b4b5936ef5630bbd3bdd60a123c3"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xb4: Bad width 256 for variable VAR1.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([duplicate variable name])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "VAR1";
+2; 0; 0; 0; 0x050800 *2; s8 "VAR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be d8f5fd768ab1d641f9330a4840c71343" \
+       "le f01e123d384cdaa7c2f7fc4791325ebf"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xd4: Duplicate variable name `VAR1'.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable label indicator not 0 or 1])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; >>2<<; 0; 0x050800 *2; s8 "VAR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 3c5ff8d8f146457a385ca92d3d23ca8a" \
+       "le 37e9f956d321ae57b0bf7fe2384e892b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xb4: Variable label indicator field is not 0 or 1.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([invalid numeric missing value indicator])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; >>-1<<; 0x050800 *2; s8 "VAR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be d1d0d4aedf9f053452c4b1e658ade5e2" \
+       "le df697575499fe12921185a3d23a5d61d"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   ["error: `sys-file.sav' near offset 0xb4: Numeric missing value indicator field is not -3, -2, 0, 1, 2, or 3."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([invalid string missing value indicator])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl String variable.
+2; 8; 0; >>4<<; 0x010800 *2; s8 "VAR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be f833033be7b102fae19159989f62faa6" \
+       "le 9704ba828bb7a36ef0262838f6b7936b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   ["error: `sys-file.sav' near offset 0xb4: String missing value indicator field is not 0, 1, 2, or 3."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing string continuation record])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl String variable.
+2; 10; 0; 0; 0x010a00 *2; s8 "VAR1";
+>>2; 0; 0; 0; 0x050800 *2; s8 "VAR2";<<
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be c8f9ad2b2acd2918055e2b78c1e0b4b8" \
+       "le 1afab4d6aee90a6fe8d2dbf229e06409"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0xb4: Missing string continuation record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([invalid variable format])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 4; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, invalid format types.
+dnl No warning is issued for type 0 because it has been observed in real
+dnl system files.
+2; 0; 0; 0; >>0xff0800; 0<<; s8 "NUM1";
+
+dnl Numeric variable, string formats.
+2; 0; 0; 0; >>0x010800<<; >>0x021000<<; s8 "VAR1";
+
+dnl String variable, numeric formats.
+2; 4; 0; 0; >>0x050800<<; >>0x110a01<<; s8 "STR1";
+
+dnl String variable, wrong width formats.
+2; 4; 0; 0; >>0x010800<<; >>0x020400<<; s8 "STR2";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be c6ef5d8fded46443aba89adfafe15cad" \
+       "le fccaf1764c973892f2d5adbcc2c36fb7"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xc0: Variable NUM1 with width 0 has invalid print format 0xff0800.
+
+warning: `sys-file.sav' near offset 0xe0: Variable VAR1 with width 0 has invalid print format 0x10800.
+
+warning: `sys-file.sav' near offset 0xe4: Variable VAR1 with width 0 has invalid write format 0x21000.
+
+warning: `sys-file.sav' near offset 0x100: Variable STR1 with width 4 has invalid print format 0x50800.
+
+warning: `sys-file.sav' near offset 0x104: Variable STR1 with width 4 has invalid write format 0x110a01.
+
+warning: `sys-file.sav' near offset 0x120: Variable STR2 with width 4 has invalid print format 0x10800.
+
+warning: `sys-file.sav' near offset 0x124: Variable STR2 with width 4 has invalid write format 0x20400.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([weighting variable must be numeric])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; >>2<<; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 82d30105e46c4896c24f9dcec26c4749" \
+       "le 32e235119be70050eb78bf4186a5a046"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav': Weighting variable must be numeric (not string variable `STR1').
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad weighting variable index])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; >>3<<; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR1";
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be cd9af924ff20bc75834aa2c696254c97" \
+       "le cbe0f2f514f5e95f27644d0b4314bc78"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0x4c: Variable index 3 not in valid range 1...2.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variable index is long string contination])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; >>3<<; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Long string variable.
+2; 9; 0; 0; 0x010900 *2; s8 "STR1";
+(2; -1; 0; 0; 0; 0; s8 "");
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 0c395354df56ea5ff374aafcc535d633" \
+       "le d977f684ea9d4648ed40f8c6dddde9f7"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0x4c: Variable index 3 refers to long string continuation.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([multiple documents records])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Two document records.
+(6; 1; s80 "One line of documents") >>* 2<<;
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0;
+])
+for variant in \
+       "be 18aa3348a216ed494efe28285b348fa8" \
+       "le 19b21522bcef1dcc60af328f923f307e"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0x12c: Duplicate type 6 (document) record.
+])
+done
+AT_CLEANUP
+
+
+AT_SETUP([empty document record])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Empty document record.
+6; >>0<<;
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Data.
+1.0;
+])
+for variant in \
+       "be d8ef29c1b97f9ed226cbd938c9c49b6e" \
+       "le f6a560c5b62e2c472429d85294f36e61"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xd4: Number of document lines (0) must be greater than 0 and less than 26843545.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([extension record too large])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Too-large extension record.
+7; 3; >>0xfffff000 * 2<<;
+])
+for variant in \
+       "be 5a6679dc41ac349b0b73fc430937c05c" \
+       "le d4769c7f650cfbf160e0386d0d33be04"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xd8: Record type 7 subtype 3 too large.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([unknown extension record])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Unknown extension record type.
+7; 30; 1; 1; i8 0;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be ac8395e27677408189bcb8655e56cc0e" \
+       "le e308bfcd51f1e3c28d7379c29271f9d6"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+"warning: `sys-file.sav' near offset 0xd8: Unrecognized record type 7, subtype 30.  Please send a copy of this file, and the syntax which created it to bug-gnu-pspp@gnu.org."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad machine integer info size])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine integer info record.
+7; 3; 4; >>9<<; 1; 2; 3; -1; 1; 1; ENDIAN; 1252; >>1234<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 21ec84826886b0a266d1360f8279d769" \
+       "le 15dcba7b2b89b7d8a21ebcc872f515af"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [ignore])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+"warning: `sys-file.sav' near offset 0xd8: Record type 7, subtype 3 has bad count 9 (expected 8)."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad machine integer info float format])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; >>2<<; 1; ENDIAN; 1252;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be d510ed28278649eee997fb6881a4c04f" \
+       "le fbf1eca561a4e243b7ae844ed1677035"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [ignore])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xd8: Floating-point representation indicated by system file (2) differs from expected (1).
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad machine integer info endianness])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine integer info record.
+7; 3; 4; 8; 1; 2; 3; -1; 1; 1; >>3<<; 1252;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 855123d16d5e1560b91d60753dad79ad 1" \
+       "le d6626b4fa2e46a91f26c2fc609b2f1e0 2"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK_UNQUOTED([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: \`sys-file.sav' near offset 0xd8: Integer format indicated by system file (3) differs from expected ($[3]).
+
+Variable,Description,,Position
+num1,Format: F8.0,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+])
+done
+AT_CLEANUP
+
+
+AT_SETUP([bad machine floating-point info size])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine floating-point info record.
+7; 4; 8; >>4<<; SYSMIS; HIGHEST; LOWEST; 0.0;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 29c9a173638fbb8bb1efe1176c4d670f" \
+       "le 5cb49eb1084e5b9cd573a54705ff86a7"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [ignore])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+"warning: `sys-file.sav' near offset 0xd8: Record type 7, subtype 4 has bad count 4 (expected 3)."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong special floating point values])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Machine floating-point info record.
+7; 4; 8; 3; >>0.0<<; >>1.0<<; >>2.0<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 1e7452d9bb0a2397bf6084a25437514e" \
+       "le f59f9a83f723cde1611869ff6d91d325"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: File specifies unexpected value 0 as SYSMIS.
+
+warning: `sys-file.sav' near offset 0xd8: File specifies unexpected value 1 as HIGHEST.
+
+warning: `sys-file.sav' near offset 0xd8: File specifies unexpected value 2 as LOWEST.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad mrsets name])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("a=C");
+7; 19; 1; COUNT("xyz=D");
+
+999; 0;
+])
+for variant in \
+       "be 15a9bf44d0cd6186a60629b77079c5a5" \
+       "le 161c99aca5e7a3684df096137e72ce5b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: `a' does not begin with `$' at offset 2 in MRSETS record.
+
+warning: `sys-file.sav' near offset 0xeb: `xyz' does not begin with `$' at offset 4 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing space after C in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=Cx");
+
+999; 0;
+])
+for variant in \
+       "be c5e5656ba3d74c3a967850f29ad89970" \
+       "le 29f110509c3d6893a7d21ae2d66aad9d"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Missing space following `C' at offset 4 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing space after E in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=Ex");
+
+999; 0;
+])
+for variant in \
+       "be a9e1dc63e2524882a5e3d2949a2da9d4" \
+       "le ac709ca1928f65f47a8c8efdd9454b50"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Missing space following `E' at offset 4 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([unexpected label source in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=E 2");
+
+999; 0;
+])
+for variant in \
+       "be 8c710e85a0a1609d0d03dec80aaf5f94" \
+       "le 4682440b82f22d4bd2ac56afb7fa3152"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Unexpected label source value `2' following `E' at offset 7 in MRSETS record.
+
+warning: `sys-file.sav' near offset 0xd8: Expecting digit at offset 7 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad type character in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=");
+
+999; 0;
+])
+for variant in \
+       "be fc5e5200d8f56b9a5a713e4a95313a3b" \
+       "le 578a61e8a06b20216612f566c2050879"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+"warning: `sys-file.sav' near offset 0xd8: Missing `C', `D', or `E' at offset 3 in MRSETS record."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad counted string length in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=Dx");
+
+999; 0;
+])
+for variant in \
+       "be 23d0e2f65c7c5f93bbedcc0f2b260c69" \
+       "le c3860c1d80e08842264948056e72c0db"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Expecting digit at offset 4 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing space in counted string in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=D1x");
+
+999; 0;
+])
+for variant in \
+       "be c9ce001723763e0698878b7e43a887e8" \
+       "le e258a1e4491d5a1d1e7d2272ef631a22"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Expecting space at offset 5 in MRSETS record.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([counted string too long in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=D4 abc");
+
+999; 0;
+])
+for variant in \
+       "be 196d1266fa0e8e315769dcbe3130e3df" \
+       "le 23df1ba7b77a26da8ce1c2cfbcaadce0"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: 4-byte string starting at offset 6 exceeds record length 9.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing space after counted string in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=D3 abcx");
+
+999; 0;
+])
+for variant in \
+       "be 86314bb0bbdfad48c10af8b8d8106d6e" \
+       "le 2b8d05ff501ca78e51f7110ce88a2364"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Expecting space at offset 9 following 3-byte string.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing newline after variable name in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=C 0  NUM1");
+
+999; 0;
+])
+for variant in \
+       "be cea939cf3e6a5f88cb45e8fa871c5e13" \
+       "le 52135afec082f50f37eafacadbb2cd65"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Missing new-line parsing variable names at offset 14 in MRSETS record.
+
+warning: `sys-file.sav' near offset 0xd8: MRSET $a has only 1 variables.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([duplicate variable name in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=C 0  NUM1 NUM1"; i8 10);
+
+999; 0;
+])
+for variant in \
+       "be 4b1b5fa2dc22cf0afdd35422290b0a29" \
+       "le e4304b57976440a036f25f8dd8ac1404"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Duplicate variable name NUM1 at offset 18 in MRSETS record.
+
+warning: `sys-file.sav' near offset 0xd8: MRSET $a has only 1 variables.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([mixed variable types in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 8; 0; 0; 0x010800 *2; s8 "STR1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=C 0  NUM1 STR1"; i8 10);
+
+999; 0;
+])
+for variant in \
+       "be 0f130e967e4097823f85b8711eb20727" \
+       "le 4dc987b4303fd115f1cae9be3963acc9"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xf8: MRSET $a contains both string and numeric variables.
+
+warning: `sys-file.sav' near offset 0xf8: MRSET $a has only 1 variables.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing newline after variable name in mrsets])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=C 0  NUM1"; i8 10);
+
+999; 0;
+])
+for variant in \
+       "be 3a891e0a467afb3d622629c70f329ada" \
+       "le 432998ec08370510411af4f5207c015e"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: MRSET $a has only 1 variables.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([only one variable in mrset])
+AT_KEYWORDS([sack synthetic system file negative multiple response])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Multiple response sets.
+7; 7; 1; COUNT("$a=C 0  NUM1"; i8 10);
+
+999; 0;
+])
+for variant in \
+       "be 3a891e0a467afb3d622629c70f329ada" \
+       "le 432998ec08370510411af4f5207c015e"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: MRSET $a has only 1 variables.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong display parameter size])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Display parameters record.
+7; 11; >>8<<; 2; 1.0; 1.0;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 7c0f1ae47ae11e37d435c4abaceca226" \
+       "le c29d05a1f8f15ed2201f31f8b787aaa0"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+"warning: `sys-file.sav' near offset 0xd8: Record type 7, subtype 11 has bad size 8 (expected 4)."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong display parameter count])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Display parameters record.
+7; 11; 4; >>4<<; 1; 1; 2; 2;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 372b57e73c69b05047b60bf6c596e2a1" \
+       "le 2a550d8c5ceae4de7ced77df66e49d0f"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Extension 11 has bad count 4 (for 1 variables).
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong display measurement level])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Display parameters record.
+7; 11; 4; 2; >>4<<; 0;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be d43e7616b03743339f37292dec6c2204" \
+       "le 821533c29a070cefdd8f07f4e1741d2a"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Invalid variable display parameters for variable 0 (NUM1).  Default parameters substituted.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([wrong display alignment])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable, no label or missing values.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Display parameters record.
+7; 11; 4; 2; 1; >>-1<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be c54bc48b5767e2ec3a9ef31df790cb7c" \
+       "le a4d8b14af64221abe83adb417d110e10"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xd8: Invalid variable display parameters for variable 0 (NUM1).  Default parameters substituted.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad variable name in variable/value pair])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVARI";
+
+dnl Long variable names.
+7; 13; 1; COUNT (>>"xyzzy"<<);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be b67b6e3c1900e5a9cc691055008f0447" \
+       "le 26cc52e601f830f9087a0ea2bd9527df"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xde: Dictionary record refers to unknown variable xyzzy.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([duplicate long variable name])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 4; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVARI";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_A";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_B";
+2; 0; 0; 0; 0x050800 *2; s8 "LONGVA_C";
+
+dnl Long variable names.
+7; 13; 1; COUNT (
+"LONGVARI=_Invalid"; i8 9;
+"LONGVA_A=LongVariableName"; i8 9;
+"LONGVA_B=LONGVARIABLENAME"; i8 9;
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 9b4b4daa00084d984efb8f889bcb727c" \
+       "le c1b1470d5cd615106e9ae507c9948d8e"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0x138: Long variable mapping from LONGVARI to invalid variable name `_Invalid'.
+
+warning: `sys-file.sav' near offset 0x138: Duplicate long variable name `LONGVARIABLENAME'.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad very long string length])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Very long string map.
+7; 14; 1; COUNT (
+"NUM1=00000"; i8 0; i8 9;
+"NUM1=00255"; i8 0; i8 9;
+"NUM1=00256"; i8 0; i8 9;
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 1309d8d9fb24bcf08952dce9b0f39a94" \
+       "le 94a39de88f8034001b3e467c4cc04d0f"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+warning: `sys-file.sav' near offset 0xd8: NUM1 listed as string of invalid length 00000 in very long string record.
+
+"warning: `sys-file.sav' near offset 0xd8: NUM1 listed in very long string record with width 00255, which requires only one segment."
+
+error: `sys-file.sav' near offset 0xd8: Very long string NUM1 overflows dictionary.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad very long string segment width])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 255; 0; 0; 0x01ff00 *2; s8 "STR1";
+(2; -1; 0; 0; 0; 0; s8 "") * 31;
+2; >>9<<; 0; 0; 0x010900 *2; s8 "STR1_A";
+>>2; -1; 0; 0; 0; 0; s8 "";<<
+
+dnl Very long string map.
+7; 14; 1; COUNT (
+"STR1=00256"; i8 0; i8 9;
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 1d09a44a46859e6eda28e053dd4b7a8b" \
+       "le 63b9ac0b3953f3e0d5ee248ebe257794"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0x4f8: Very long string with width 256 has segment 1 of width 9 (expected 4).
+])
+done
+AT_CLEANUP
+
+AT_SETUP([too many value labels])
+dnl Skip the test if multiplying a small number by INT32_MAX would not
+dnl cause an overflow in size_t.
+AT_SKIP_IF([test $SIZEOF_SIZE_T -gt 4])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+3; >>0x7fffffff<<;
+])
+for variant in \
+       "be 975b2668dde395ddf619977958b37412" \
+       "le 0c14aa278cfc2a4b801f91c14321f03b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xd4: Invalid number of labels 2147483647.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing type 4 record])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Value label with missing type 4 record.
+3; 1; 1.0; i8 3; s7 "one";
+
+dnl End of dictionary.
+>>999; 0<<;
+])
+for variant in \
+       "be 5e1286ac92e3f25ff98492bc5019d608" \
+       "le b33c12f776bbcaa43aa3bfdd4799e0c0"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xe8: Variable index record (type 4) does not immediately follow value label record (type 3) as it should.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([value label with no associated variables])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variable.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Value label with no variables.
+3; 1; 1.0; i8 3; s7 "one"; 4; >>0<<;
+])
+for variant in \
+       "be b0dcec30a936cbcad21c4f3d6fe10fcf" \
+       "le 3b9fdfce5c8c248048232fd6eac018e3"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xec: Number of variables associated with a value label (0) is not between 1 and the number of variables (1).
+])
+done
+AT_CLEANUP
+
+AT_SETUP([type 4 record names long string variable])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Long string variable.
+2; 9; 0; 0; 0x010900 *2; s8 "STR1";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Value label that names long string variable.
+3; 1; s8 "xyzzy"; i8 3; s7 "one"; 4; 1; >>1<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 14053a4f09de4c7c4c55281534dd66f4" \
+       "le 8a61cc994c659fd66307d2f0fd64ce20"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [ignore])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+error: `sys-file.sav' near offset 0xf4: Value labels may not be added to long string variables (e.g. STR1) using records types 3 and 4.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([variables for value label must all be same type])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 6; 0; 0; 0x010600 *2; s8 "STR1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Value label that names numeric and string variables.
+3; 1; s8 "xyzzy"; i8 3; s7 "one"; 4; 2; >>1; 2<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be 7577c456726a88f52bbef63a8b47bf1a" \
+       "le 3ba5c6af9ad0ae5cc88f9f63e726e414"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [ignore])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], [dnl
+"error: `sys-file.sav' near offset 0xf4: Variables associated with value label are not all of identical type.  Variable STR1 is string, but variable NUM1 is numeric."
+])
+done
+AT_CLEANUP
+
+AT_SETUP([duplicate value labels type])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 6; 0; 0; 0x010600 *2; s8 "STR1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+
+dnl Duplicate value labels.
+3; 1; s8 "xyzzy"; i8 3; s7 "one"; 4; 2; >>1; 1<<;
+3; 1; 1.0; i8 3; s7 "one"; 4; 2; >>2; 2<<;
+
+dnl End of dictionary.
+999; 0;
+])
+for variant in \
+       "be ef0f5b2ebddb5a3bfcda16c93a2508f4" \
+       "le c00e27abd9a6c06bf29a108d7220435a"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xf4: Duplicate value label for `xyzzy ' on STR1.
+
+warning: `sys-file.sav' near offset 0x11c: Duplicate value label for 1 on NUM1.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([missing attribute value])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 0; 0; 0; 0x050800 *2; s8 "FIRSTVAR";
+
+dnl Data file attributes record.
+7; 17; 1; COUNT (
+"Attr1("
+);
+
+dnl Variable attributes record.
+7; 18; 1; COUNT (
+"FIRSTVAR:";
+  "fred('23'"; i8 10
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 0fc71f5e3cdb6b7f2dd73d011d4885c2" \
+       "le e519b44715400156a2bfe648eb5cff34"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xdf: Error parsing attribute value Attr1[[1]].
+
+warning: `sys-file.sav' near offset 0x102: Error parsing attribute value fred[[2]].
+])
+done
+AT_CLEANUP
+
+AT_SETUP([unquoted attribute value])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 1; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 0; 0; 0; 0x050800 *2; s8 "FIRSTVAR";
+
+dnl Data file attributes record.
+7; 17; 1; COUNT (
+"Attr1(value"; i8 10;
+")"
+);
+
+dnl Variable attributes record.
+7; 18; 1; COUNT (
+"FIRSTVAR:";
+  "fred(23"; i8 10; ")"
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be 33dba37c2247e63c04bb74a7b472293d" \
+       "le 041025a9d9d9e21a7fabd90ba7341934"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0xe4: Attribute value Attr1[[1]] is not quoted: value.
+
+warning: `sys-file.sav' near offset 0x106: Attribute value fred[[1]] is not quoted: 23.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([bad variable name in long string value label])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 3; 1; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 14; 0; 0; 0x010e00 *2; s8 "STR14";
+2; -1; 0; 0; 0; 0; s8 "";
+
+7; 21; 1; COUNT (
+dnl No variable named STR9.
+COUNT(>>"STR9"<<); 9;
+1; COUNT("RSTUVWXYZ"); COUNT("value label for `RSTUVWXYZ'");
+
+dnl NUM1 is numeric.
+COUNT(>>"NUM1"<<); 0;
+1; COUNT("xyz"); COUNT("value label for 1.0");
+
+dnl Wrong width for STR14.
+COUNT("STR14"); >>9<<;
+1; COUNT("RSTUVWXYZ"); COUNT("value label for `RSTUVWXYZ'");
+
+dnl Wrong width for value.
+COUNT("STR14"); 14;
+1; COUNT(>>"RSTUVWXYZ"<<); COUNT("value label for `RSTUVWXYZ'");
+
+dnl Duplicate value label.
+COUNT("STR14"); 14; 2;
+COUNT("abcdefghijklmn"); COUNT("value label for `abcdefghijklmn'");
+>>COUNT("abcdefghijklmn"); COUNT("another value label for `abcdefghijklmn'")<<;
+);
+
+dnl Dictionary termination record.
+999; 0;
+])
+for variant in \
+       "be cf2e883dadb00e2c6404c09ea0a4e388" \
+       "le 89c340faf0a7e4a8c834f9687684c091"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [0], [dnl
+warning: `sys-file.sav' near offset 0x128: Ignoring long string value record for unknown variable STR9.
+
+warning: `sys-file.sav' near offset 0x164: Ignoring long string value record for numeric variable NUM1.
+
+warning: `sys-file.sav' near offset 0x193: Ignoring long string value record for variable STR14 because the record's width (9) does not match the variable's width (14).
+
+"warning: `sys-file.sav' near offset 0x1d4: Ignoring long string value 0 for variable str14, with width 14, that has bad value width 9."
+
+warning: `sys-file.sav' near offset 0x259: Duplicate value label for `abcdefghijklmn' on str14.
+])
+done
+AT_CLEANUP
+
+AT_SETUP([fewer data records than indicated by file header])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 0; 0; >>5<<; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl Data.
+999; 0;
+1.0; 2.0;
+3.0; 4.0;
+5.0; 6.0;
+7.0; 8.0;
+dnl Missing record here.
+])
+for variant in \
+       "be 6ee097c3934055d0c4564641636f4b5a" \
+       "le ae03fe1b888091d6938b5a436d44ac60"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+LIST.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: Error reading case from file `sys-file.sav'.
+
+Table: Data List
+num1,num2
+1,2
+3,4
+5,6
+7,8
+])
+done
+AT_CLEANUP
+
+AT_SETUP([partial data record between variables])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 0; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl Data.
+999; 0;
+1.0; 2.0;
+3.0;
+])
+for variant in \
+       "be 4bcc085d7d8f0f09c6a4ba8064ffe61c" \
+       "le 7387fc5edd2740aff92c30ca688d6d9b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+LIST.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0x110: File ends in partial case.
+
+Table: Data List
+num1,num2
+1,2
+])
+done
+AT_CLEANUP
+
+AT_SETUP([partial data record within long string])
+AT_KEYWORDS([sack synthetic system file negative])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; 2; 0; 0; -1; 100.0; "01 Jan 11"; "20:53:52"; s64 ""; i8 0 *3;
+
+dnl Numeric variables.
+2; 14; 0; 0; 0x010e00 *2; s8 "STR14";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Data.
+999; 0;
+s14 "one data item";
+s8 "partial";
+])
+for variant in \
+       "be 4a9e84f9e679afb7bb71acd0bb7eab89" \
+       "le 30752606f14ee2deec2854e8e6de4b3b"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+LIST.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0x10e: Unexpected end of file.
+
+Table: Data List
+str14
+one data item @&t@
+])
+done
+AT_CLEANUP
+
+AT_SETUP([partial compressed data record])
+AT_KEYWORDS([sack synthetic system file positive])
+AT_DATA([sys-file.sack], [dnl
+dnl File header.
+"$FL2"; s60 "$(#) SPSS DATA FILE PSPP synthetic test file";
+2; dnl Layout code
+6; dnl Nominal case size
+1; dnl Compressed
+0; dnl Not weighted 
+-1; dnl Unspecified number of cases.
+100.0; dnl Bias.
+"01 Jan 11"; "20:53:52"; s64 "PSPP synthetic test file";
+i8 0 *3;
+
+dnl Numeric variables.
+2; 0; 0; 0; 0x050800 *2; s8 "NUM1";
+2; 0; 0; 0; 0x050800 *2; s8 "NUM2";
+
+dnl String variable.
+2; 4; 0; 0; 0x010400 *2; s8 "STR4";
+2; 8; 0; 0; 0x010800 *2; s8 "STR8";
+2; 15; 0; 0; 0x010f00 *2; s8 "STR15";
+2; -1; 0; 0; 0; 0; s8 "";
+
+dnl Dictionary termination record.
+999; 0;
+
+dnl Compressed data.
+i8 1 100 254 253 254 253; i8 255 251; "abcdefgh"; s8 "0123";
+])
+for variant in \
+       "be ef01b16e2e397d979a3a7d20725ebe6d" \
+       "le 51f7a61e9bc68992469d16c55d6ecd88"
+do
+  set $variant
+  AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
+])
+  AT_DATA([sys-file.sps], [GET FILE='sys-file.sav'.
+LIST.
+])
+  AT_CHECK([pspp -O format=csv sys-file.sps], [1], 
+   [error: `sys-file.sav' near offset 0x190: File ends in partial case.
+
+Table: Data List
+num1,num2,str4,str8,str15
+-99,0,,abcdefgh,0123   @&t@
+])
+done
+AT_CLEANUP
+
index 721578e6a0aadf23048adaa846ba6ce35ca41502..5975e0f3b7326c4e44e8141d735d64c418648b97 100644 (file)
@@ -55,14 +55,13 @@ GET FILE='com.sav'.
 LIST.
 ])
 AT_CHECK([pspp -o pspp.csv sysfile.sps])
-dnl Make sure file really was compressd.
-AT_CHECK([dd if=com.sav bs=1 skip=72 count=4 2> /dev/null | od | sed '1q' > com.txt])
-dnl Allow big- or little-endian format.
+dnl Make sure file really was compressd, allowing big- or little-endian format.
+AT_CHECK([dd if=com.sav bs=1 skip=72 count=4 2> /dev/null > com.sav.subset])
+od com.sav.subset
 AT_CHECK(
-  [(echo '0000000 000000 000001' | diff com.txt -) ||
-   (echo '0000000 000001 000000' | diff com.txt -)], [0],
+  [(printf '\000\000\000\001' | cmp -l com.sav.subset -) ||
+   (printf '\001\000\000\000' | cmp -l com.sav.subset -)], [0],
   [ignore])
-AT_CAPTURE_FILE([com.txt])
 AT_CLEANUP
 
 AT_SETUP([overwriting system file])
@@ -380,3 +379,78 @@ d,Format: A32767,,4
 
 VLS_WRITE([UNCOMPRESSED])
 VLS_WRITE([COMPRESSED])
+
+dnl This test writes non-ASCII characters to most of the string fields in
+dnl a .sav file and demonstrates that they are properly read back in.
+dnl XXX mrsets tests are missing.
+AT_SETUP([system file character encoding])
+AT_CHECK([supports_encodings windows-1252])
+AT_DATA([save.sps], [dnl
+SET LOCALE='windows-1252'.
+DATA LIST LIST NOTABLE /àéîöçxyzabc * roué (A9) croûton (A1000).
+FILE LABEL 'clientèle confrère cortège crèche'.
+DOCUMENT coördinate smörgåsbord
+épée séance soufflé soirée
+jalapeño vicuña.
+VALUE LABEL
+      /àéîöçxyzabc 1 'éclair élan'
+      /roué 'abcdefghi' 'sauté précis'.
+VARIABLE LABEL
+      roué 'Provençal soupçon'.
+DATAFILE ATTRIBUTE
+      ATTRIBUTE=Furtwängler('kindergärtner').
+VARIABLE ATTRIBUTE
+      VARIABLES=àéîöçxyzabc
+      ATTRIBUTE=Atatürk('Düsseldorf Gewürztraminer').
+BEGIN DATA.
+1 a x
+2 b y
+3 c z
+END DATA.
+SAVE OUTFILE='foo.sav'.
+])
+AT_CHECK([pspp -O format=csv save.sps])
+AT_DATA([get.sps], [dnl
+GET FILE='foo.sav'.
+DISPLAY FILE LABEL.
+DISPLAY DOCUMENTS.
+DISPLAY DICTIONARY.
+])
+AT_CHECK([pspp -o pspp.csv get.sps])
+AT_CHECK([[sed 's/(Entered [^)]*)/(Entered <date>)/' pspp.csv]], [0], [dnl
+File label: clientèle confrère cortège crèche
+
+Documents in the active dataset:
+
+DOCUMENT coördinate smörgåsbord
+
+épée séance soufflé soirée
+
+jalapeño vicuña.
+
+(Entered <date>)
+
+Variable,Description,,Position
+àéîöçxyzabc,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,1.00,éclair élan,
+,Custom attributes:,,
+,Atatürk,Düsseldorf Gewürztraminer,
+roué,Provençal soupçon,,2
+,Format: A9,,
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 9,,
+,abcdefghi,sauté précis,
+croûton,Format: A1000,,3
+,Measure: Nominal,,
+,Display Alignment: Left,,
+,Display Width: 32,,
+
+Table: Custom data file attributes.
+Attribute,Value
+Furtwängler,kindergärtner
+])
+AT_CLEANUP
diff --git a/tests/dissect-sysfile.c b/tests/dissect-sysfile.c
deleted file mode 100644 (file)
index fda3b38..0000000
+++ /dev/null
@@ -1,1441 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2008, 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 <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <data/val-type.h>
-#include <libpspp/compiler.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/misc.h>
-
-#include "error.h"
-#include "minmax.h"
-#include "progname.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-#define VAR_NAME_LEN 64
-
-struct sfm_reader
-  {
-    const char *file_name;
-    FILE *file;
-
-    int n_variable_records, n_variables;
-
-    int *var_widths;
-    size_t n_var_widths, allocated_var_widths;
-
-    enum integer_format integer_format;
-    enum float_format float_format;
-
-    bool compressed;
-    double bias;
-  };
-
-static void read_header (struct sfm_reader *);
-static void read_variable_record (struct sfm_reader *);
-static void read_value_label_record (struct sfm_reader *);
-static void read_document_record (struct sfm_reader *);
-static void read_extension_record (struct sfm_reader *);
-static void read_machine_integer_info (struct sfm_reader *,
-                                       size_t size, size_t count);
-static void read_machine_float_info (struct sfm_reader *,
-                                     size_t size, size_t count);
-static void read_mrsets (struct sfm_reader *, size_t size, size_t count);
-static void read_display_parameters (struct sfm_reader *,
-                                     size_t size, size_t count);
-static void read_long_var_name_map (struct sfm_reader *r,
-                                    size_t size, size_t count);
-static void read_long_string_map (struct sfm_reader *r,
-                                  size_t size, size_t count);
-static void read_datafile_attributes (struct sfm_reader *r,
-                                      size_t size, size_t count);
-static void read_variable_attributes (struct sfm_reader *r,
-                                      size_t size, size_t count);
-static void read_ncases64 (struct sfm_reader *, size_t size, size_t count);
-static void read_character_encoding (struct sfm_reader *r,
-                                      size_t size, size_t count);
-static void read_long_string_value_labels (struct sfm_reader *r,
-                                           size_t size, size_t count);
-static void read_unknown_extension (struct sfm_reader *,
-                                    size_t size, size_t count);
-static void read_compressed_data (struct sfm_reader *);
-
-static struct text_record *open_text_record (
-  struct sfm_reader *, size_t size);
-static void close_text_record (struct text_record *);
-static bool read_variable_to_value_pair (struct text_record *,
-                                         char **key, char **value);
-static char *text_tokenize (struct text_record *, int delimiter);
-static bool text_match (struct text_record *text, int c);
-static const char *text_parse_counted_string (struct text_record *);
-static size_t text_pos (const struct text_record *);
-
-static void usage (int exit_code);
-static void sys_warn (struct sfm_reader *, const char *, ...)
-     PRINTF_FORMAT (2, 3);
-static void sys_error (struct sfm_reader *, const char *, ...)
-     PRINTF_FORMAT (2, 3)
-     NO_RETURN;
-
-static void read_bytes (struct sfm_reader *, void *, size_t);
-static bool try_read_bytes (struct sfm_reader *, void *, size_t);
-static int read_int (struct sfm_reader *);
-static int64_t read_int64 (struct sfm_reader *);
-static double read_float (struct sfm_reader *);
-static void read_string (struct sfm_reader *, char *, size_t);
-static void skip_bytes (struct sfm_reader *, size_t);
-static void trim_spaces (char *);
-
-int
-main (int argc, char *argv[])
-{
-  struct sfm_reader r;
-  int i;
-
-  set_program_name (argv[0]);
-  if (argc < 2)
-    usage (EXIT_FAILURE);
-
-  for (i = 1; i < argc; i++) 
-    {
-      int rec_type;
-
-      r.file_name = argv[i];
-      r.file = fopen (r.file_name, "rb");
-      if (r.file == NULL)
-        error (EXIT_FAILURE, errno, "error opening `%s'", r.file_name);
-      r.n_variable_records = 0;
-      r.n_variables = 0;
-      r.n_var_widths = 0;
-      r.allocated_var_widths = 0;
-      r.var_widths = 0;
-      r.compressed = false;
-
-      if (argc > 2)
-        printf ("Reading \"%s\":\n", r.file_name);
-      
-      read_header (&r);
-      while ((rec_type = read_int (&r)) != 999)
-        {
-          switch (rec_type)
-            {
-            case 2:
-              read_variable_record (&r);
-              break;
-
-            case 3:
-              read_value_label_record (&r);
-              break;
-
-            case 4:
-              sys_error (&r, _("Misplaced type 4 record."));
-
-            case 6:
-              read_document_record (&r);
-              break;
-
-            case 7:
-              read_extension_record (&r);
-              break;
-
-            default:
-              sys_error (&r, _("Unrecognized record type %d."), rec_type);
-            }
-        }
-      printf ("%08llx: end-of-dictionary record "
-              "(first byte of data at %08llx)\n",
-              (long long int) ftello (r.file),
-              (long long int) ftello (r.file) + 4);
-
-      if (r.compressed)
-        read_compressed_data (&r);
-
-      fclose (r.file);
-    }
-  
-  return 0;
-}
-
-static void
-read_header (struct sfm_reader *r)
-{
-  char rec_type[5];
-  char eye_catcher[61];
-  uint8_t raw_layout_code[4];
-  int32_t layout_code;
-  int32_t nominal_case_size;
-  int32_t compressed;
-  int32_t weight_index;
-  int32_t ncases;
-  uint8_t raw_bias[8];
-  char creation_date[10];
-  char creation_time[9];
-  char file_label[65];
-
-  read_string (r, rec_type, sizeof rec_type);
-  read_string (r, eye_catcher, sizeof eye_catcher);
-
-  if (strcmp ("$FL2", rec_type) != 0)
-    sys_error (r, _("This is not an SPSS system file."));
-
-  /* Identify integer format. */
-  read_bytes (r, raw_layout_code, sizeof raw_layout_code);
-  if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
-                          &r->integer_format)
-       && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
-                             &r->integer_format))
-      || (r->integer_format != INTEGER_MSB_FIRST
-          && r->integer_format != INTEGER_LSB_FIRST))
-    sys_error (r, _("This is not an SPSS system file."));
-  layout_code = integer_get (r->integer_format,
-                             raw_layout_code, sizeof raw_layout_code);
-
-  nominal_case_size = read_int (r);
-  compressed = read_int (r);
-  weight_index = read_int (r);
-  ncases = read_int (r);
-
-  r->compressed = compressed != 0;
-
-  /* Identify floating-point format and obtain compression bias. */
-  read_bytes (r, raw_bias, sizeof raw_bias);
-  if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
-    {
-      sys_warn (r, _("Compression bias is not the usual "
-                     "value of 100, or system file uses unrecognized "
-                     "floating-point format."));
-      if (r->integer_format == INTEGER_MSB_FIRST)
-        r->float_format = FLOAT_IEEE_DOUBLE_BE;
-      else
-        r->float_format = FLOAT_IEEE_DOUBLE_LE;
-    }
-  r->bias = float_get_double (r->float_format, raw_bias);
-
-  read_string (r, creation_date, sizeof creation_date);
-  read_string (r, creation_time, sizeof creation_time);
-  read_string (r, file_label, sizeof file_label);
-  trim_spaces (file_label);
-  skip_bytes (r, 3);
-
-  printf ("File header record:\n");
-  printf ("\t%17s: %s\n", "Product name", eye_catcher);
-  printf ("\t%17s: %"PRId32"\n", "Layout code", layout_code);
-  printf ("\t%17s: %"PRId32"\n", "Compressed", compressed);
-  printf ("\t%17s: %"PRId32"\n", "Weight index", weight_index);
-  printf ("\t%17s: %"PRId32"\n", "Number of cases", ncases);
-  printf ("\t%17s: %g\n", "Compression bias", r->bias);
-  printf ("\t%17s: %s\n", "Creation date", creation_date);
-  printf ("\t%17s: %s\n", "Creation time", creation_time);
-  printf ("\t%17s: \"%s\"\n", "File label", file_label);
-}
-
-static const char *
-format_name (int format)
-{
-  switch ((format >> 16) & 0xff)
-    {
-    case 1: return "A";
-    case 2: return "AHEX";
-    case 3: return "COMMA";
-    case 4: return "DOLLAR";
-    case 5: return "F";
-    case 6: return "IB";
-    case 7: return "PIBHEX";
-    case 8: return "P";
-    case 9: return "PIB";
-    case 10: return "PK";
-    case 11: return "RB";
-    case 12: return "RBHEX";
-    case 15: return "Z";
-    case 16: return "N";
-    case 17: return "E";
-    case 20: return "DATE";
-    case 21: return "TIME";
-    case 22: return "DATETIME";
-    case 23: return "ADATE";
-    case 24: return "JDATE";
-    case 25: return "DTIME";
-    case 26: return "WKDAY";
-    case 27: return "MONTH";
-    case 28: return "MOYR";
-    case 29: return "QYR";
-    case 30: return "WKYR";
-    case 31: return "PCT";
-    case 32: return "DOT";
-    case 33: return "CCA";
-    case 34: return "CCB";
-    case 35: return "CCC";
-    case 36: return "CCD";
-    case 37: return "CCE";
-    case 38: return "EDATE";
-    case 39: return "SDATE";
-    default: return "invalid";
-    }
-}
-
-/* Reads a variable (type 2) record from R and adds the
-   corresponding variable to DICT.
-   Also skips past additional variable records for long string
-   variables. */
-static void
-read_variable_record (struct sfm_reader *r)
-{
-  int width;
-  int has_variable_label;
-  int missing_value_code;
-  int print_format;
-  int write_format;
-  char name[9];
-
-  printf ("%08llx: variable record #%d\n",
-          (long long int) ftello (r->file), r->n_variable_records++);
-
-  width = read_int (r);
-  has_variable_label = read_int (r);
-  missing_value_code = read_int (r);
-  print_format = read_int (r);
-  write_format = read_int (r);
-  read_string (r, name, sizeof name);
-  name[strcspn (name, " ")] = '\0';
-
-  if (width >= 0)
-    r->n_variables++;
-
-  if (r->n_var_widths >= r->allocated_var_widths)
-    r->var_widths = x2nrealloc (r->var_widths, &r->allocated_var_widths,
-                                sizeof *r->var_widths);
-  r->var_widths[r->n_var_widths++] = width;
-
-  printf ("\tWidth: %d (%s)\n",
-          width,
-          width > 0 ? "string"
-          : width == 0 ? "numeric"
-          : "long string continuation record");
-  printf ("\tVariable label: %d\n", has_variable_label);
-  printf ("\tMissing values code: %d (%s)\n", missing_value_code,
-          (missing_value_code == 0 ? "no missing values"
-           : missing_value_code == 1 ? "one missing value"
-           : missing_value_code == 2 ? "two missing values"
-           : missing_value_code == 3 ? "three missing values"
-           : missing_value_code == -2 ? "one missing value range"
-           : missing_value_code == -3 ? "one missing value, one range"
-           : "bad value"));
-  printf ("\tPrint format: %06x (%s%d.%d)\n",
-          print_format, format_name (print_format),
-          (print_format >> 8) & 0xff, print_format & 0xff);
-  printf ("\tWrite format: %06x (%s%d.%d)\n",
-          write_format, format_name (write_format),
-          (write_format >> 8) & 0xff, write_format & 0xff);
-  printf ("\tName: %s\n", name);
-
-  /* Get variable label, if any. */
-  if (has_variable_label != 0 && has_variable_label != 1)
-    sys_error (r, _("Variable label indicator field is not 0 or 1."));
-  if (has_variable_label == 1)
-    {
-      long long int offset = ftello (r->file);
-      size_t len, read_len;
-      char label[255 + 1];
-
-      len = read_int (r);
-
-      /* Read up to 255 bytes of label. */
-      read_len = MIN (sizeof label - 1, len);
-      read_string (r, label, read_len + 1);
-      printf("\t%08llx Variable label: \"%s\"\n", offset, label);
-
-      /* Skip unread label bytes. */
-      skip_bytes (r, len - read_len);
-
-      /* Skip label padding up to multiple of 4 bytes. */
-      skip_bytes (r, ROUND_UP (len, 4) - len);
-    }
-
-  /* Set missing values. */
-  if (missing_value_code != 0)
-    {
-      int i;
-
-      printf ("\t%08llx Missing values:", (long long int) ftello (r->file));
-      if (!width)
-        {
-          if (missing_value_code < -3 || missing_value_code > 3
-              || missing_value_code == -1)
-            sys_error (r, _("Numeric missing value indicator field is not "
-                            "-3, -2, 0, 1, 2, or 3."));
-          if (missing_value_code < 0)
-            {
-              double low = read_float (r);
-              double high = read_float (r);
-              printf (" %g...%g", low, high);
-              missing_value_code = -missing_value_code - 2;
-            }
-          for (i = 0; i < missing_value_code; i++)
-            printf (" %g", read_float (r));
-        }
-      else if (width > 0)
-        {
-          if (missing_value_code < 1 || missing_value_code > 3)
-            sys_error (r, _("String missing value indicator field is not "
-                            "0, 1, 2, or 3."));
-          for (i = 0; i < missing_value_code; i++)
-            {
-              char string[9];
-              read_string (r, string, sizeof string);
-              printf (" \"%s\"", string);
-            }
-        }
-      putchar ('\n');
-    }
-}
-
-static void
-print_untyped_value (struct sfm_reader *r, char raw_value[8])
-{
-  int n_printable;
-  double value;
-
-  value = float_get_double (r->float_format, raw_value);
-  for (n_printable = 0; n_printable < sizeof raw_value; n_printable++)
-    if (!isprint (raw_value[n_printable]))
-      break;
-
-  printf ("%g/\"%.*s\"", value, n_printable, raw_value);
-}
-
-/* Reads value labels from sysfile R and inserts them into the
-   associated dictionary. */
-static void
-read_value_label_record (struct sfm_reader *r)
-{
-  int label_cnt, var_cnt;
-  int i;
-
-  printf ("%08llx: value labels record\n", (long long int) ftello (r->file));
-
-  /* Read number of labels. */
-  label_cnt = read_int (r);
-  for (i = 0; i < label_cnt; i++)
-    {
-      char raw_value[8];
-      unsigned char label_len;
-      size_t padded_len;
-      char label[256];
-
-      read_bytes (r, raw_value, sizeof raw_value);
-
-      /* Read label length. */
-      read_bytes (r, &label_len, sizeof label_len);
-      padded_len = ROUND_UP (label_len + 1, 8);
-
-      /* Read label, padding. */
-      read_bytes (r, label, padded_len - 1);
-      label[label_len] = 0;
-
-      printf ("\t");
-      print_untyped_value (r, raw_value);
-      printf (": \"%s\"\n", label);
-    }
-
-  /* Now, read the type 4 record that has the list of variables
-     to which the value labels are to be applied. */
-
-  /* Read record type of type 4 record. */
-  if (read_int (r) != 4)
-    sys_error (r, _("Variable index record (type 4) does not immediately "
-                    "follow value label record (type 3) as it should."));
-
-  /* Read number of variables associated with value label from type 4
-     record. */
-  printf ("\t%08llx: apply to variables", (long long int) ftello (r->file));
-  var_cnt = read_int (r);
-  for (i = 0; i < var_cnt; i++)
-    printf (" #%d", read_int (r));
-  putchar ('\n');
-}
-
-static void
-read_document_record (struct sfm_reader *r)
-{
-  int n_lines;
-  int i;
-
-  printf ("%08llx: document record\n", (long long int) ftello (r->file));
-  n_lines = read_int (r);
-  printf ("\t%d lines of documents\n", n_lines);
-
-  for (i = 0; i < n_lines; i++)
-    {
-      char line[81];
-      printf ("\t%08llx: ", (long long int) ftello (r->file));
-      read_string (r, line, sizeof line);
-      trim_spaces (line);
-      printf ("line %d: \"%s\"\n", i, line);
-    }
-}
-
-static void
-read_extension_record (struct sfm_reader *r)
-{
-  long long int offset = ftello (r->file);
-  int subtype = read_int (r);
-  size_t size = read_int (r);
-  size_t count = read_int (r);
-  size_t bytes = size * count;
-
-  printf ("%08llx: Record 7, subtype %d, size=%zu, count=%zu\n",
-          offset, subtype, size, count);
-
-  switch (subtype)
-    {
-    case 3:
-      read_machine_integer_info (r, size, count);
-      return;
-
-    case 4:
-      read_machine_float_info (r, size, count);
-      return;
-
-    case 5:
-      /* Variable sets information.  We don't use these yet.
-         They only apply to GUIs; see VARSETS on the APPLY
-         DICTIONARY command in SPSS documentation. */
-      break;
-
-    case 6:
-      /* DATE variable information.  We don't use it yet, but we
-         should. */
-      break;
-
-    case 7:
-    case 19:
-      read_mrsets (r, size, count);
-      return;
-
-    case 11:
-      read_display_parameters (r, size, count);
-      return;
-
-    case 13:
-      read_long_var_name_map (r, size, count);
-      return;
-
-    case 14:
-      read_long_string_map (r, size, count);
-      return;
-
-    case 16:
-      read_ncases64 (r, size, count);
-      return;
-
-    case 17:
-      read_datafile_attributes (r, size, count);
-      return;
-
-    case 18:
-      read_variable_attributes (r, size, count);
-      return;
-
-    case 20:
-      read_character_encoding (r, size, count);
-      return;
-
-    case 21:
-      read_long_string_value_labels (r, size, count);
-      return;
-
-    default:
-      sys_warn (r, _("Unrecognized record type 7, subtype %d."), subtype);
-      read_unknown_extension (r, size, count);
-      return;
-    }
-
-  skip_bytes (r, bytes);
-}
-
-static void
-read_machine_integer_info (struct sfm_reader *r, size_t size, size_t count)
-{
-  long long int offset = ftello (r->file);
-  int version_major = read_int (r);
-  int version_minor = read_int (r);
-  int version_revision = read_int (r);
-  int machine_code = read_int (r);
-  int float_representation = read_int (r);
-  int compression_code = read_int (r);
-  int integer_representation = read_int (r);
-  int character_code = read_int (r);
-
-  printf ("%08llx: machine integer info\n", offset);
-  if (size != 4 || count != 8)
-    sys_error (r, _("Bad size (%zu) or count (%zu) field on record type 7, "
-                    "subtype 3."),
-                size, count);
-
-  printf ("\tVersion: %d.%d.%d\n",
-          version_major, version_minor, version_revision);
-  printf ("\tMachine code: %d\n", machine_code);
-  printf ("\tFloating point representation: %d (%s)\n",
-          float_representation,
-          float_representation == 1 ? "IEEE 754"
-          : float_representation == 2 ? "IBM 370"
-          : float_representation == 3 ? "DEC VAX"
-          : "unknown");
-  printf ("\tCompression code: %d\n", compression_code);
-  printf ("\tEndianness: %d (%s)\n", integer_representation,
-          integer_representation == 1 ? "big"
-          : integer_representation == 2 ? "little" : "unknown");
-  printf ("\tCharacter code: %d\n", character_code);
-}
-
-/* Read record type 7, subtype 4. */
-static void
-read_machine_float_info (struct sfm_reader *r, size_t size, size_t count)
-{
-  long long int offset = ftello (r->file);
-  double sysmis = read_float (r);
-  double highest = read_float (r);
-  double lowest = read_float (r);
-
-  printf ("%08llx: machine float info\n", offset);
-  if (size != 8 || count != 3)
-    sys_error (r, _("Bad size (%zu) or count (%zu) on extension 4."),
-               size, count);
-
-  printf ("\tsysmis: %g\n", sysmis);
-  if (sysmis != SYSMIS)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
-              sysmis, "SYSMIS");
-
-  printf ("\thighest: %g\n", highest);
-  if (highest != HIGHEST)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
-              highest, "HIGHEST");
-
-  printf ("\tlowest: %g\n", lowest);
-  if (lowest != LOWEST)
-    sys_warn (r, _("File specifies unexpected value %g as %s."),
-              lowest, "LOWEST");
-}
-
-/* Read record type 7, subtype 7. */
-static void
-read_mrsets (struct sfm_reader *r, size_t size, size_t count)
-{
-  struct text_record *text;
-
-  printf ("%08llx: multiple response sets\n",
-          (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
-  for (;;)
-    {
-      const char *name;
-      enum { MRSET_MC, MRSET_MD } type;
-      bool cat_label_from_counted_values = false;
-      bool label_from_var_label = false;
-      const char *counted;
-      const char *label;
-      const char *variables;
-
-      name = text_tokenize (text, '=');
-      if (name == NULL)
-        break;
-
-      if (text_match (text, 'C'))
-        {
-          type = MRSET_MC;
-          counted = NULL;
-          if (!text_match (text, ' '))
-            {
-              sys_warn (r, "missing space following 'C' at offset %zu "
-                        "in mrsets record", text_pos (text));
-              break;
-            }
-        }
-      else if (text_match (text, 'D'))
-        {
-          type = MRSET_MD;
-        }
-      else if (text_match (text, 'E'))
-        {
-          char *number;
-
-          type = MRSET_MD;
-          cat_label_from_counted_values = true;
-
-          if (!text_match (text, ' '))
-            {
-              sys_warn (r, _("Missing space following `%c' at offset %zu "
-                             "in MRSETS record"), 'E', text_pos (text));
-              break;
-            }
-
-          number = text_tokenize (text, ' ');
-          if (!strcmp (number, "11"))
-            label_from_var_label = true;
-          else if (strcmp (number, "1"))
-            sys_warn (r, _("Unexpected label source value `%s' "
-                           "following `E' at offset %zu in MRSETS record"),
-                      number, text_pos (text));
-
-        }
-      else
-        {
-          sys_warn (r, "missing `C', `D', or `E' at offset %zu "
-                    "in mrsets record", text_pos (text));
-          break;
-        }
-
-      if (type == MRSET_MD)
-        {
-          counted = text_parse_counted_string (text);
-          if (counted == NULL)
-            break;
-        }
-
-      label = text_parse_counted_string (text);
-      if (label == NULL)
-        break;
-
-      variables = text_tokenize (text, '\n');
-      if (variables == NULL)
-        {
-          sys_warn (r, "missing variable names following label "
-                    "at offset %zu in mrsets record", text_pos (text));
-          break;
-        }
-
-      printf ("\t\"%s\": multiple %s set",
-              name, type == MRSET_MC ? "category" : "dichotomy");
-      if (counted != NULL)
-        printf (", counted value \"%s\"", counted);
-      if (cat_label_from_counted_values)
-        printf (", category labels from counted values");
-      if (label[0] != '\0')
-        printf (", label \"%s\"", label);
-      if (label_from_var_label)
-        printf (", label from variable label");
-      printf(", variables \"%s\"\n", variables);
-    }
-  close_text_record (text);
-}
-
-/* Read record type 7, subtype 11. */
-static void
-read_display_parameters (struct sfm_reader *r, size_t size, size_t count)
-{
-  size_t n_vars;
-  bool includes_width;
-  size_t i;
-
-  printf ("%08llx: variable display parameters\n",
-          (long long int) ftello (r->file));
-  if (size != 4)
-    {
-      sys_warn (r, _("Bad size %zu on extension 11."), size);
-      skip_bytes (r, size * count);
-      return;
-    }
-
-  n_vars = r->n_variables;
-  if (count == 3 * n_vars)
-    includes_width = true;
-  else if (count == 2 * n_vars)
-    includes_width = false;
-  else
-    {
-      sys_warn (r, _("Extension 11 has bad count %zu (for %zu variables)."),
-                count, n_vars);
-      skip_bytes (r, size * count);
-      return;
-    }
-
-  for (i = 0; i < n_vars; ++i)
-    {
-      int measure = read_int (r);
-      int width = includes_width ? read_int (r) : 0;
-      int align = read_int (r);
-
-      printf ("\tVar #%zu: measure=%d (%s)", i, measure,
-              (measure == 1 ? "nominal"
-               : measure == 2 ? "ordinal"
-               : measure == 3 ? "scale"
-               : "invalid"));
-      if (includes_width)
-        printf (", width=%d", width);
-      printf (", align=%d (%s)\n", align,
-              (align == 0 ? "left"
-               : align == 1 ? "right"
-               : align == 2 ? "centre"
-               : "invalid"));
-    }
-}
-
-/* Reads record type 7, subtype 13, which gives the long name
-   that corresponds to each short name.  */
-static void
-read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count)
-{
-  struct text_record *text;
-  char *var;
-  char *long_name;
-
-  printf ("%08llx: long variable names (short => long)\n",
-          (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
-  while (read_variable_to_value_pair (text, &var, &long_name))
-    printf ("\t%s => %s\n", var, long_name);
-  close_text_record (text);
-}
-
-/* Reads record type 7, subtype 14, which gives the real length
-   of each very long string.  Rearranges DICT accordingly. */
-static void
-read_long_string_map (struct sfm_reader *r, size_t size, size_t count)
-{
-  struct text_record *text;
-  char *var;
-  char *length_s;
-
-  printf ("%08llx: very long strings (variable => length)\n",
-          (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
-  while (read_variable_to_value_pair (text, &var, &length_s))
-    printf ("\t%s => %d\n", var, atoi (length_s));
-  close_text_record (text);
-}
-
-static bool
-read_attributes (struct sfm_reader *r, struct text_record *text,
-                 const char *variable)
-{
-  const char *key;
-  int index;
-
-  for (;;) 
-    {
-      key = text_tokenize (text, '(');
-      if (key == NULL)
-        return true;
-  
-      for (index = 1; ; index++)
-        {
-          /* Parse the value. */
-          const char *value = text_tokenize (text, '\n');
-          if (value == NULL) 
-            {
-              sys_warn (r, _("%s: Error parsing attribute value %s[%d]"),
-                        variable, key, index);
-              return false;
-            }
-          if (strlen (value) < 2
-              || value[0] != '\'' || value[strlen (value) - 1] != '\'')
-            sys_warn (r, _("%s: Attribute value %s[%d] is not quoted: %s"),
-                      variable, key, index, value);
-          else
-            printf ("\t%s: %s[%d] = \"%.*s\"\n",
-                    variable, key, index, (int) strlen (value) - 2, value + 1);
-
-          /* Was this the last value for this attribute? */
-          if (text_match (text, ')'))
-            break;
-        }
-
-      if (text_match (text, '/'))
-        return true; 
-    }
-}
-
-/* Read extended number of cases record. */
-static void
-read_ncases64 (struct sfm_reader *r, size_t size, size_t count)
-{
-  int64_t unknown, ncases64;
-
-  if (size != 8)
-    {
-      sys_warn (r, _("Bad size %zu for extended number of cases."), size);
-      skip_bytes (r, size * count);
-      return;
-    }
-  if (count != 2)
-    {
-      sys_warn (r, _("Bad count %zu for extended number of cases."), size);
-      skip_bytes (r, size * count);
-      return;
-    }
-  unknown = read_int64 (r);
-  ncases64 = read_int64 (r);
-  printf ("%08llx: extended number of cases: "
-          "unknown=%"PRId64", ncases64=%"PRId64"\n",
-          (long long int) ftello (r->file), unknown, ncases64);
-}
-
-static void
-read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count) 
-{
-  struct text_record *text;
-  
-  printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
-  read_attributes (r, text, "datafile");
-  close_text_record (text);
-}
-
-static void
-read_character_encoding (struct sfm_reader *r, size_t size, size_t count)
-{
-  long long int posn =  ftello (r->file);
-  char *encoding = xcalloc (size, count + 1);
-  read_string (r, encoding, count + 1);
-
-  printf ("%08llx: Character Encoding: %s\n", posn, encoding);
-}
-
-static void
-read_long_string_value_labels (struct sfm_reader *r, size_t size, size_t count)
-{
-  long long int start = ftello (r->file);
-
-  printf ("%08llx: long string value labels\n", start);
-  while (ftello (r->file) - start < size * count)
-    {
-      long long posn = ftello (r->file);
-      char var_name[VAR_NAME_LEN + 1];
-      int var_name_len;
-      int n_values;
-      int width;
-      int i;
-
-      /* Read variable name. */
-      var_name_len = read_int (r);
-      if (var_name_len > VAR_NAME_LEN)
-        sys_error (r, _("Variable name length in long string value label "
-                        "record (%d) exceeds %d-byte limit."),
-                   var_name_len, VAR_NAME_LEN);
-      read_string (r, var_name, var_name_len + 1);
-
-      /* Read width, number of values. */
-      width = read_int (r);
-      n_values = read_int (r);
-
-      printf ("\t%08llx: %s, width %d, %d values\n",
-              posn, var_name, width, n_values);
-
-      /* Read values. */
-      for (i = 0; i < n_values; i++)
-       {
-          char *value;
-          int value_length;
-
-          char *label;
-         int label_length;
-
-          posn = ftello (r->file);
-
-          /* Read value. */
-          value_length = read_int (r);
-          value = xmalloc (value_length + 1);
-          read_string (r, value, value_length + 1);
-
-          /* Read label. */
-          label_length = read_int (r);
-          label = xmalloc (label_length + 1);
-          read_string (r, label, label_length + 1);
-
-          printf ("\t\t%08llx: \"%s\" (%d bytes) => \"%s\" (%d bytes)\n",
-                  posn, value, value_length, label, label_length);
-
-          free (value);
-          free (label);
-       }
-    }
-}
-
-static void
-hex_dump (size_t offset, const void *buffer_, size_t buffer_size)
-{
-  const uint8_t *buffer = buffer_;
-
-  while (buffer_size > 0)
-    {
-      size_t n = MIN (buffer_size, 16);
-      size_t i;
-
-      printf ("%04zx", offset);
-      for (i = 0; i < 16; i++)
-        {
-          if (i < n)
-            printf ("%c%02x", i == 8 ? '-' : ' ', buffer[i]);
-          else
-            printf ("   ");
-        }
-
-      printf (" |");
-      for (i = 0; i < 16; i++)
-        {
-          unsigned char c = i < n ? buffer[i] : ' ';
-          putchar (isprint (c) ? c : '.');
-        }
-      printf ("|\n");
-
-      offset += n;
-      buffer += n;
-      buffer_size -= n;
-    }
-}
-
-/* Reads and prints any type 7 record that we don't understand. */
-static void
-read_unknown_extension (struct sfm_reader *r, size_t size, size_t count)
-{
-  unsigned char *buffer;
-  size_t i;
-
-  if (size == 0 || count > 65536 / size)
-    skip_bytes (r, size * count);
-  else if (size != 1)
-    {
-      buffer = xmalloc (size);
-      for (i = 0; i < count; i++)
-        {
-          read_bytes (r, buffer, size);
-          hex_dump (i * size, buffer, size);
-        }
-      free (buffer);
-    }
-  else
-    {
-      buffer = xmalloc (count);
-      read_bytes (r, buffer, count);
-      if (memchr (buffer, 0, count) == 0)
-        for (i = 0; i < count; i++)
-          {
-            unsigned char c = buffer[i];
-
-            if (c == '\\')
-              printf ("\\\\");
-            else if (c == '\n' || isprint (c))
-              putchar (c);
-            else
-              printf ("\\%02x", c);
-          }
-      else
-        hex_dump (0, buffer, count);
-      free (buffer);
-    }
-}
-
-static void
-read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) 
-{
-  struct text_record *text;
-  
-  printf ("%08llx: variable attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
-  for (;;) 
-    {
-      const char *variable = text_tokenize (text, ':');
-      if (variable == NULL || !read_attributes (r, text, variable))
-        break; 
-    }
-  close_text_record (text);
-}
-
-static void
-read_compressed_data (struct sfm_reader *r)
-{
-  enum { N_OPCODES = 8 };
-  uint8_t opcodes[N_OPCODES];
-  long long int opcode_ofs;
-  int opcode_idx;
-  int case_num;
-  int i;
-
-  read_int (r);
-  printf ("\n%08llx: compressed data:\n", (long long int) ftello (r->file));
-
-  opcode_idx = N_OPCODES;
-  opcode_ofs = 0;
-  case_num = 0;
-  for (case_num = 0; ; case_num++)
-    {
-      printf ("%08llx: case %d's uncompressible data begins\n",
-              (long long int) ftello (r->file), case_num);
-      for (i = 0; i < r->n_var_widths; )
-        {
-          int width = r->var_widths[i];
-          char raw_value[8];
-          int opcode;
-
-          if (opcode_idx >= N_OPCODES)
-            {
-              opcode_ofs = ftello (r->file);
-              if (i == 0)
-                {
-                  if (!try_read_bytes (r, opcodes, 8))
-                    return;
-                }
-              else
-                read_bytes (r, opcodes, 8);
-              opcode_idx = 0;
-            }
-          opcode = opcodes[opcode_idx];
-          printf ("%08llx: variable %d: opcode %d: ",
-                  opcode_ofs + opcode_idx, i, opcode);
-
-          switch (opcode)
-            {
-            default:
-              printf ("%g", opcode - r->bias);
-              if (width != 0)
-                printf (", but this is a string variable (width=%d)", width);
-              printf ("\n");
-              i++;
-              break;
-
-            case 0:
-              printf ("ignored padding\n");
-              break;
-
-            case 252:
-              printf ("end of data\n");
-              return;
-
-            case 253:
-              read_bytes (r, raw_value, 8);
-              printf ("uncompressible data: ");
-              print_untyped_value (r, raw_value);
-              printf ("\n");
-              i++;
-              break;
-
-            case 254:
-              printf ("spaces");
-              if (width == 0)
-                printf (", but this is a numeric variable");
-              printf ("\n");
-              i++;
-              break;
-
-            case 255:
-              printf ("SYSMIS");
-              if (width != 0)
-                printf (", but this is a string variable (width=%d)", width);
-              printf ("\n");
-              i++;
-              break;
-            }
-
-          opcode_idx++;
-        }
-    }
-}
-\f
-/* Helpers for reading records that consist of structured text
-   strings. */
-
-/* State. */
-struct text_record
-  {
-    struct sfm_reader *reader;  /* Reader. */
-    char *buffer;               /* Record contents. */
-    size_t size;                /* Size of buffer. */
-    size_t pos;                 /* Current position in buffer. */
-  };
-
-/* Reads SIZE bytes into a text record for R,
-   and returns the new text record. */
-static struct text_record *
-open_text_record (struct sfm_reader *r, size_t size)
-{
-  struct text_record *text = xmalloc (sizeof *text);
-  char *buffer = xmalloc (size + 1);
-  read_bytes (r, buffer, size);
-  buffer[size] = '\0';
-  text->reader = r;
-  text->buffer = buffer;
-  text->size = size;
-  text->pos = 0;
-  return text;
-}
-
-/* Closes TEXT and frees its storage.
-   Not really needed, because the pool will free the text record anyway,
-   but can be used to free it earlier. */
-static void
-close_text_record (struct text_record *text)
-{
-  free (text->buffer);
-  free (text);
-}
-
-static char *
-text_tokenize (struct text_record *text, int delimiter)
-{
-  size_t start = text->pos;
-  while (text->pos < text->size
-         && text->buffer[text->pos] != delimiter
-         && text->buffer[text->pos] != '\0')
-    text->pos++;
-  if (text->pos == text->size)
-    return NULL;
-  text->buffer[text->pos++] = '\0';
-  return &text->buffer[start];
-}
-
-static bool
-text_match (struct text_record *text, int c) 
-{
-  if (text->pos < text->size && text->buffer[text->pos] == c) 
-    {
-      text->pos++;
-      return true;
-    }
-  else
-    return false;
-}
-
-/* Reads a integer value expressed in decimal, then a space, then a string that
-   consists of exactly as many bytes as specified by the integer, then a space,
-   from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
-   buffer (so the caller should not free the string). */
-static const char *
-text_parse_counted_string (struct text_record *text)
-{
-  size_t start;
-  size_t n;
-  char *s;
-
-  start = text->pos;
-  n = 0;
-  while (isdigit ((unsigned char) text->buffer[text->pos]))
-    n = (n * 10) + (text->buffer[text->pos++] - '0');
-  if (start == text->pos)
-    {
-      sys_error (text->reader, "expecting digit at offset %zu in record",
-                 text->pos);
-      return NULL;
-    }
-
-  if (!text_match (text, ' '))
-    {
-      sys_error (text->reader, "expecting space at offset %zu in record",
-                 text->pos);
-      return NULL;
-    }
-
-  if (text->pos + n > text->size)
-    {
-      sys_error (text->reader, "%zu-byte string starting at offset %zu "
-                 "exceeds record length %zu", n, text->pos, text->size);
-      return NULL;
-    }
-
-  s = &text->buffer[text->pos];
-  if (s[n] != ' ')
-    {
-      sys_error (text->reader, "expecting space at offset %zu following "
-                 "%zu-byte string", text->pos + n, n);
-      return NULL;
-    }
-  s[n] = '\0';
-  text->pos += n + 1;
-  return s;
-}
-
-/* Reads a variable=value pair from TEXT.
-   Looks up the variable in DICT and stores it into *VAR.
-   Stores a null-terminated value into *VALUE. */
-static bool
-read_variable_to_value_pair (struct text_record *text,
-                             char **key, char **value)
-{
-  *key = text_tokenize (text, '=');
-  *value = text_tokenize (text, '\t');
-  if (!*key || !*value)
-    return false;
-
-  while (text->pos < text->size
-         && (text->buffer[text->pos] == '\t'
-             || text->buffer[text->pos] == '\0'))
-    text->pos++;
-  return true;
-}
-
-/* Returns the current byte offset inside the TEXT's string. */
-static size_t
-text_pos (const struct text_record *text)
-{
-  return text->pos;
-}
-\f
-static void
-usage (int exit_code)
-{
-  printf ("usage: %s SYSFILE...\n"
-          "where each SYSFILE is the name of a system file\n",
-          program_name);
-  exit (exit_code);
-}
-
-/* Displays a corruption message. */
-static void
-sys_msg (struct sfm_reader *r, const char *format, va_list args)
-{
-  printf ("\"%s\" near offset 0x%llx: ",
-          r->file_name, (long long int) ftello (r->file));
-  vprintf (format, args);
-  putchar ('\n');
-}
-
-/* Displays a warning for the current file position. */
-static void
-sys_warn (struct sfm_reader *r, const char *format, ...)
-{
-  va_list args;
-
-  va_start (args, format);
-  sys_msg (r, format, args);
-  va_end (args);
-}
-
-/* Displays an error for the current file position,
-   marks it as in an error state,
-   and aborts reading it using longjmp. */
-static void
-sys_error (struct sfm_reader *r, const char *format, ...)
-{
-  va_list args;
-
-  va_start (args, format);
-  sys_msg (r, format, args);
-  va_end (args);
-
-  exit (EXIT_FAILURE);
-}
-\f
-/* Reads BYTE_CNT bytes into BUF.
-   Returns true if exactly BYTE_CNT bytes are successfully read.
-   Aborts if an I/O error or a partial read occurs.
-   If EOF_IS_OK, then an immediate end-of-file causes false to be
-   returned; otherwise, immediate end-of-file causes an abort
-   too. */
-static inline bool
-read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
-                     void *buf, size_t byte_cnt)
-{
-  size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
-  if (bytes_read == byte_cnt)
-    return true;
-  else if (ferror (r->file))
-    sys_error (r, _("System error: %s."), strerror (errno));
-  else if (!eof_is_ok || bytes_read != 0)
-    sys_error (r, _("Unexpected end of file."));
-  else
-    return false;
-}
-
-/* Reads BYTE_CNT into BUF.
-   Aborts upon I/O error or if end-of-file is encountered. */
-static void
-read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
-{
-  read_bytes_internal (r, false, buf, byte_cnt);
-}
-
-/* Reads BYTE_CNT bytes into BUF.
-   Returns true if exactly BYTE_CNT bytes are successfully read.
-   Returns false if an immediate end-of-file is encountered.
-   Aborts if an I/O error or a partial read occurs. */
-static bool
-try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
-{
-  return read_bytes_internal (r, true, buf, byte_cnt);
-}
-
-/* Reads a 32-bit signed integer from R and returns its value in
-   host format. */
-static int
-read_int (struct sfm_reader *r)
-{
-  uint8_t integer[4];
-  read_bytes (r, integer, sizeof integer);
-  return integer_get (r->integer_format, integer, sizeof integer);
-}
-
-/* Reads a 64-bit signed integer from R and returns its value in
-   host format. */
-static int64_t
-read_int64 (struct sfm_reader *r)
-{
-  uint8_t integer[8];
-  read_bytes (r, integer, sizeof integer);
-  return integer_get (r->integer_format, integer, sizeof integer);
-}
-
-/* Reads a 64-bit floating-point number from R and returns its
-   value in host format. */
-static double
-read_float (struct sfm_reader *r)
-{
-  uint8_t number[8];
-  read_bytes (r, number, sizeof number);
-  return float_get_double (r->float_format, number);
-}
-
-/* Reads exactly SIZE - 1 bytes into BUFFER
-   and stores a null byte into BUFFER[SIZE - 1]. */
-static void
-read_string (struct sfm_reader *r, char *buffer, size_t size)
-{
-  assert (size > 0);
-  read_bytes (r, buffer, size - 1);
-  buffer[size - 1] = '\0';
-}
-
-/* Skips BYTES bytes forward in R. */
-static void
-skip_bytes (struct sfm_reader *r, size_t bytes)
-{
-  while (bytes > 0)
-    {
-      char buffer[1024];
-      size_t chunk = MIN (sizeof buffer, bytes);
-      read_bytes (r, buffer, chunk);
-      bytes -= chunk;
-    }
-}
-
-static void
-trim_spaces (char *s)
-{
-  char *end = strchr (s, '\0');
-  while (end > s && end[-1] == ' ')
-    end--;
-  *end = '\0';
-}
index 1bd6ccf2ebc1fc22d4de85bc1c1bb4621945d456..8d65b6fb8c2998bd14a27ee8d5f4d9f9b2174587 100644 (file)
@@ -7,9 +7,9 @@ DATA rubbish.
 EXECUTE.
 ])
 AT_CHECK([pspp -O format=csv command.sps], [1], [dnl
-command.sps:1: error: Unknown command DATA RUBBISH.
+command.sps:1: error: Unknown command `DATA rubbish'.
 
-command.sps:2: error: EXECUTE: EXECUTE is allowed only after the active file has been defined.
+command.sps:2: error: EXECUTE: EXECUTE is allowed only after the active dataset has been defined.
 ])
 AT_CLEANUP
 
index a0b29d93a10a6ee83d4ab1b00dcb7f5778412e76..4421ba6b715fbf2641b602d004ea4b3f23eca68b 100644 (file)
@@ -1,6 +1,95 @@
 AT_BANNER([DO REPEAT])
 
-AT_SETUP([DO REPEAT -- ordinary])
+AT_SETUP([DO REPEAT -- simple])
+AT_DATA([do-repeat.sps], [dnl
+INPUT PROGRAM.
+STRING y(A1).
+DO REPEAT xval = 1 2 3 / yval = 'a' 'b' 'c' / var = a b c.
+COMPUTE x=xval.
+COMPUTE y=yval.
+COMPUTE var=xval.
+END CASE.
+END REPEAT.
+END FILE.
+END INPUT PROGRAM.
+LIST.
+])
+AT_CHECK([pspp -o pspp.csv do-repeat.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Data List
+y,x,a,b,c
+a,1.00,1.00,.  ,.  @&t@
+b,2.00,.  ,2.00,.  @&t@
+c,3.00,.  ,.  ,3.00
+])
+AT_CLEANUP
+
+AT_SETUP([DO REPEAT -- containing BEGIN DATA])
+AT_DATA([do-repeat.sps], [dnl
+DO REPEAT offset = 1 2 3.
+DATA LIST NOTABLE /x 1-2.
+BEGIN DATA.
+10
+20
+30
+END DATA.
+COMPUTE x = x + offset.
+LIST.
+END REPEAT.
+])
+AT_CHECK([pspp -o pspp.csv do-repeat.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Data List
+x
+11
+21
+31
+
+Table: Data List
+x
+12
+22
+32
+
+Table: Data List
+x
+13
+23
+33
+])
+AT_CLEANUP
+
+AT_SETUP([DO REPEAT -- dummy vars not expanded in include files])
+AT_DATA([include.sps], [dnl
+COMPUTE y = y + x + 10.
+])
+AT_DATA([do-repeat.sps], [dnl
+INPUT PROGRAM.
+COMPUTE x = 0.
+COMPUTE y = 0.
+END CASE.
+END FILE.
+END INPUT PROGRAM.
+
+DO REPEAT x = 1 2 3.
+INCLUDE 'include.sps'.
+END REPEAT.
+
+LIST.
+])
+AT_CHECK([pspp -o pspp.csv do-repeat.sps], [0], [dnl
+do-repeat.sps:8: warning: DO REPEAT: Dummy variable name `x' hides dictionary variable `x'.
+])
+AT_CHECK([cat pspp.csv], [0], [dnl
+do-repeat.sps:8: warning: DO REPEAT: Dummy variable name `x' hides dictionary variable `x'.
+
+Table: Data List
+x,y
+.00,30.00
+])
+AT_CLEANUP
+
+AT_SETUP([DO REPEAT -- nested])
 AT_DATA([do-repeat.sps], [dnl
 DATA LIST NOTABLE /a 1.
 BEGIN DATA.
@@ -55,13 +144,7 @@ AT_DATA([do-repeat.sps], [dnl
 DATA LIST NOTABLE /x 1.
 DO REPEAT y = 1 TO 10.
 ])
-AT_CHECK([pspp -o pspp.csv do-repeat.sps], [1], [dnl
-error: DO REPEAT: DO REPEAT without END REPEAT.
-error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
-])
-AT_CHECK([cat pspp.csv], [0], [dnl
-error: DO REPEAT: DO REPEAT without END REPEAT.
-
-error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
+AT_CHECK([pspp -O format=csv do-repeat.sps], [1], [dnl
+error: DO REPEAT: Syntax error at end of input: expecting `END'.
 ])
 AT_CLEANUP
index dba2a4a12e182a0d14cd0db555ffcfb4389c54d0..b0582c6c47a7fd141395c41cc85a05a7aa22f958 100644 (file)
@@ -49,7 +49,7 @@ B,F8.0
 C,F8.0
 D,F8.0
 
-data-list.pspp:3.9-13: warning: Data for variable D is not valid as format F: Number followed by garbage.
+data-list.pspp:3.9-3.13: warning: Data for variable D is not valid as format F: Number followed by garbage.
 
 Table: Data List
 A,B,C,D
@@ -160,9 +160,9 @@ end data.
 list.
 ])
 AT_CHECK([pspp -O format=csv data-list.pspp], [0], [dnl
-data-list.pspp:8.1-3: warning: Data for variable count is not valid as format F: Field contents are not numeric.
+data-list.pspp:8.1-8.3: warning: Data for variable count is not valid as format F: Field contents are not numeric.
 
-data-list.pspp:11.1-3: warning: Data for variable count is not valid as format F: Field contents are not numeric.
+data-list.pspp:11.1-11.3: warning: Data for variable count is not valid as format F: Field contents are not numeric.
 
 Table: Data List
 start,end,count
index f00a42c44dffd56b3ee547845863a45a9bce6e76..a6a5f360aeb06f6142d148cd57f54a50a00ae7b1 100644 (file)
@@ -65,6 +65,7 @@ AT_CLEANUP
 
 m4_define([DATA_READER_BINARY], 
   [AT_SETUP([read and write files with $1])
+$3
    AT_DATA([input.txt], [dnl
 07-22-2007
 10-06-2007
@@ -204,13 +205,15 @@ DATA_READER_BINARY([MODE=360 /RECFORM=FIXED /LRECL=32],
        $out .= ' ' x ($lrecl - length ($out));
        length ($out) == 32 or die;
        print +a2e ($out);
-   }])
+   }],
+  [AT_CHECK([supports_encodings EBCDIC-US])])
 
 DATA_READER_BINARY([MODE=360 /RECFORM=VARIABLE],
   [for $_ (@data) {
        push (@records, pack ("n xx", length ($_) + 4) . a2e ($_));
    }
-   dump_records ();])
+   dump_records ();],
+  [AT_CHECK([supports_encodings EBCDIC-US])])
 
 DATA_READER_BINARY([MODE=360 /RECFORM=SPANNED],
   [[for my $line (@data) {
@@ -229,4 +232,5 @@ DATA_READER_BINARY([MODE=360 /RECFORM=SPANNED],
                 pack ("nCx", length ($r[$i]) + 4, $scc) . a2e ($r[$i]));
        }
    }
-   dump_records ();]])
+   dump_records ();]],
+  [AT_CHECK([supports_encodings EBCDIC-US])])
diff --git a/tests/language/data-io/dataset.at b/tests/language/data-io/dataset.at
new file mode 100644 (file)
index 0000000..7d5e928
--- /dev/null
@@ -0,0 +1,302 @@
+AT_BANNER([DATASET commands])
+
+AT_SETUP([DATASET COPY])
+AT_DATA([dataset.pspp], [dnl
+DATASET NAME initial.
+DATA LIST NOTABLE /x 1.
+COMPUTE x = x + 1.
+DATASET COPY clone.
+BEGIN DATA.
+1
+2
+3
+4
+5
+END DATA.
+
+NEW FILE.
+DATA LIST NOTABLE /y 1.
+BEGIN DATA.
+6
+7
+8
+END DATA.
+LIST.
+DATASET DISPLAY.
+
+DATASET ACTIVATE clone.
+DATASET DISPLAY.
+LIST.
+
+DATASET ACTIVATE initial.
+DATASET DISPLAY.
+LIST.
+
+COMPUTE z=y.
+DATASET COPY clone.
+
+DATASET ACTIVATE clone.
+LIST.
+DATASET COPY clone.
+DATASET DISPLAY.
+
+DATASET CLOSE initial.
+DATASET DISPLAY.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
+Table: Data List
+y
+6
+7
+8
+
+Table: Open datasets.
+Dataset
+clone
+initial (active dataset)
+
+Table: Open datasets.
+Dataset
+clone (active dataset)
+initial
+
+Table: Data List
+x
+2
+3
+4
+5
+6
+
+Table: Open datasets.
+Dataset
+clone
+initial (active dataset)
+
+Table: Data List
+y
+6
+7
+8
+
+Table: Data List
+y,z
+6,6.00
+7,7.00
+8,8.00
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+initial
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+])
+AT_CLEANUP
+
+AT_SETUP([DATASET DECLARE])
+AT_DATA([dataset.pspp], [dnl
+DATASET DECLARE second.
+DATASET DISPLAY.
+DATA LIST NOTABLE/x 1.
+BEGIN DATA.
+1
+END DATA.
+LIST.
+DATASET ACTIVATE second.
+DATASET DISPLAY.
+LIST.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+second
+
+Table: Data List
+x
+1
+
+Table: Open datasets.
+Dataset
+second (active dataset)
+
+dataset.pspp:10: error: LIST: LIST is allowed only after the active dataset has been defined.
+])
+AT_CLEANUP
+
+AT_SETUP([DATASET NAME deletes duplicate name])
+AT_DATA([dataset.pspp], [dnl
+DATASET NAME a.
+DATASET DECLARE b.
+DATASET DECLARE c.
+DATASET DISPLAY.
+
+DATASET NAME b.
+DATASET NAME c.
+DATASET DISPLAY.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
+Table: Open datasets.
+Dataset
+a (active dataset)
+b
+c
+
+Table: Open datasets.
+Dataset
+c (active dataset)
+])
+AT_CLEANUP
+
+AT_SETUP([DATASET ACTIVATE deletes unnamed dataset])
+AT_DATA([dataset.pspp], [dnl
+DATASET DECLARE x.
+DATASET DISPLAY.
+
+DATASET ACTIVATE x.
+DATASET DISPLAY.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+x
+
+Table: Open datasets.
+Dataset
+x (active dataset)
+])
+AT_CLEANUP
+
+AT_SETUP([DATASET ACTIVATE executes pending transformations])
+AT_DATA([dataset.pspp], [dnl
+DATASET NAME one.
+DATASET DECLARE another.
+DATASET DISPLAY.
+
+DATA LIST NOTABLE /x 1.
+PRINT/x.
+DATASET ACTIVATE another.
+BEGIN DATA.
+1
+2
+3
+4
+5
+END DATA.
+
+LIST.
+
+DATASET ACTIVATE one.
+LIST.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [1], [dnl
+Table: Open datasets.
+Dataset
+another
+one (active dataset)
+
+1 @&t@
+
+2 @&t@
+
+3 @&t@
+
+4 @&t@
+
+5 @&t@
+
+dataset.pspp:16: error: LIST: LIST is allowed only after the active dataset has been defined.
+
+Table: Data List
+x
+1
+2
+3
+4
+5
+])
+AT_CLEANUP
+
+AT_SETUP([DATASET CLOSE])
+AT_DATA([dataset.pspp], [dnl
+DATASET DISPLAY
+DATASET CLOSE *.
+DATASET DISPLAY.
+
+DATASET NAME this.
+DATASET DISPLAY.
+DATASET CLOSE this.
+DATASET DISPLAY.
+
+DATASET NAME this.
+DATASET DISPLAY.
+DATASET CLOSE *.
+DATASET DISPLAY.
+
+DATASET DECLARE that.
+DATASET DECLARE theother.
+DATASET DECLARE yetanother.
+DATASET DISPLAY.
+DATASET CLOSE ALL.
+DATASET DISPLAY.
+
+DATASET NAME this.
+DATASET DECLARE that.
+DATASET DECLARE theother.
+DATASET DECLARE yetanother.
+DATASET DISPLAY.
+DATASET CLOSE ALL.
+DATASET DISPLAY.
+])
+AT_CHECK([pspp -O format=csv dataset.pspp], [0], [dnl
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+
+Table: Open datasets.
+Dataset
+this (active dataset)
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+
+Table: Open datasets.
+Dataset
+this (active dataset)
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+that
+theother
+yetanother
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+
+Table: Open datasets.
+Dataset
+that
+theother
+this (active dataset)
+yetanother
+
+Table: Open datasets.
+Dataset
+unnamed dataset (active dataset)
+])
+AT_CLEANUP
index e4c6ae374bd4133be56ca67ac32843bb52d084b4..4418974701233658dd5531635391977994eba4b9 100644 (file)
@@ -113,7 +113,7 @@ AT_CLEANUP
 AT_SETUP([GET DATA /TYPE=TXT with multiple records per case])
 AT_DATA([get-data.sps], [dnl
 get data /type=txt /file=inline /arrangement=fixed /fixcase=3 /variables=
-       /1 start 0-19 adate
+       /1 start 0-19 adate8
        /2 end 0-19 adate
        /3 count 0-2 f.
 begin data.
@@ -133,9 +133,9 @@ AT_CHECK([pspp -o pspp.csv get-data.sps])
 AT_CHECK([cat pspp.csv], [0], [dnl
 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
+07/22/07,10/06/2007,321
+********,08/26/1789,4
+01/01/72,12/31/1999,682
 ])
 AT_CLEANUP
 
index a519b67fe3592583790a15e5ef6c929be2f2c5ff..b9a187f292034cb872516de81ea61862e1fb5c6a 100644 (file)
@@ -58,8 +58,6 @@ dnl We use stdin here, because the bug seems to manifest itself only in
 dnl interactive mode.
 AT_CHECK([echo "GET /FILE='nonexistent.sav'." | pspp -O format=csv], [1], [dnl
 error: An error occurred while opening `nonexistent.sav': No such file or directory.
-
--:1: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 ])
 AT_CLEANUP
 
index 7f2e143594144d0c7798ee1a990c1c5d0dd17258..f048d3743fd44f881561354a3951929550c7849b 100644 (file)
@@ -13,10 +13,6 @@ END INPUT PROGRAM.
 ])
 AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
 input-program.sps:3: error: BEGIN DATA: BEGIN DATA is not allowed inside INPUT PROGRAM.
-
-input-program.sps:4: error: Syntax error at `123456789': expecting command name.
-
-input-program.sps:5: error: Unknown command END DATA.
 ])
 AT_CLEANUP
 
@@ -32,6 +28,6 @@ END INPUT PROGRAM.
 DESCRIPTIVES x.
 ])
 AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
-error: DESCRIPTIVES: Syntax error at end of file: expecting `BEGIN'.
+error: DESCRIPTIVES: Syntax error at end of input: expecting `BEGIN'.
 ])
 AT_CLEANUP
index f8b3bb5c3bb6323eda932692a6a81aed6a68003c..4beeceed1f78779ef473c85202b5f62e44f7f32d 100644 (file)
@@ -84,6 +84,50 @@ Case Number,avar,bvar
 ])
 AT_CLEANUP
 
+# Checks for a crash when LIST did not include the variables from SPLIT
+# FILE in the same positions (bug #30684).
+AT_SETUP([LIST with split file])
+AT_DATA([data.txt], [dnl
+a 1
+a 2
+a 3
+b 1
+c 4
+c 5
+])
+AT_DATA([list.sps], [dnl
+DATA LIST LIST NOTABLE FILE='data.txt'/s (a1) n.
+SPLIT FILE BY s.
+LIST n.
+])
+AT_CHECK([pspp -o pspp.csv list.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Variable,Value,Label
+s,a,
+
+Table: Data List
+n
+1.00
+2.00
+3.00
+
+Variable,Value,Label
+s,b,
+
+Table: Data List
+n
+1.00
+
+Variable,Value,Label
+s,c,
+
+Table: Data List
+n
+4.00
+5.00
+])
+AT_CLEANUP
+
 AT_SETUP([LIST lots of variables])
 AT_DATA([data.txt], [dnl
 767532466348513789073483106409
index 2cca5213a942ba80222515df4d0e5a6e60428e52..ce429a81e8f9b696cf78eec0bb626012c52c1597 100644 (file)
@@ -134,8 +134,8 @@ a,b,c,d,e,f
 ])
 AT_CLEANUP
 
-dnl Test bug handling TABLE from active file found by John Darrington.
-AT_SETUP([MATCH FILES bug with TABLE from active file])
+dnl Test bug handling TABLE from active dataset found by John Darrington.
+AT_SETUP([MATCH FILES bug with TABLE from active dataset])
 AT_DATA([match-files.sps], [dnl
 DATA LIST LIST NOTABLE /x * y *.
 BEGIN DATA
diff --git a/tests/language/data-io/print-space.at b/tests/language/data-io/print-space.at
new file mode 100644 (file)
index 0000000..e2bd2ee
--- /dev/null
@@ -0,0 +1,93 @@
+AT_BANNER([PRINT SPACE])
+
+AT_SETUP([PRINT SPACE without arguments])
+AT_DATA([print-space.sps], [dnl
+DATA LIST NOTABLE/x 1.
+BEGIN DATA.
+1
+2
+END DATA.
+PRINT/x.
+PRINT SPACE.
+EXECUTE.
+])
+AT_CHECK([pspp -O format=csv print-space.sps], [0], [dnl
+1 @&t@
+
+
+
+2 @&t@
+
+
+])
+AT_CLEANUP
+
+AT_SETUP([PRINT SPACE with number])
+AT_DATA([print-space.sps], [dnl
+DATA LIST NOTABLE/x 1.
+BEGIN DATA.
+1
+2
+END DATA.
+PRINT/x.
+PRINT SPACE 2.
+EXECUTE.
+])
+AT_CHECK([pspp -O format=csv print-space.sps], [0], [dnl
+1 @&t@
+
+
+
+
+
+2 @&t@
+
+
+
+
+])
+AT_CLEANUP
+
+AT_SETUP([PRINT SPACE to file])
+AT_CAPTURE_FILE([output.txt])
+AT_DATA([print-space.sps], [dnl
+DATA LIST NOTABLE/x 1.
+BEGIN DATA.
+1
+2
+END DATA.
+PRINT OUTFILE='output.txt'/x.
+PRINT SPACE OUTFILE='output.txt'.
+EXECUTE.
+])
+AT_CHECK([pspp -O format=csv print-space.sps])
+AT_CHECK([cat output.txt], [0], [dnl
+ 1 @&t@
+ @&t@
+ 2 @&t@
+ @&t@
+])
+AT_CLEANUP
+
+AT_SETUP([PRINT SPACE to file with number])
+AT_CAPTURE_FILE([output.txt])
+AT_DATA([print-space.sps], [dnl
+DATA LIST NOTABLE/x 1.
+BEGIN DATA.
+1
+2
+END DATA.
+PRINT OUTFILE='output.txt'/x.
+PRINT SPACE OUTFILE='output.txt' 2.
+EXECUTE.
+])
+AT_CHECK([pspp -O format=csv print-space.sps])
+AT_CHECK([cat output.txt], [0], [dnl
+ 1 @&t@
+ @&t@
+ @&t@
+ 2 @&t@
+ @&t@
+ @&t@
+])
+AT_CLEANUP
index 9381d7da4547e7706fde4453d37bf366c3bbc46b..71259e0c68dc8566c8b84824c948f4c8d7647a07 100644 (file)
@@ -172,7 +172,7 @@ PRINT F8.2
 LIST.
 ])
 AT_CHECK([pspp -O format=csv print.sps], [1], [dnl
-print.sps:7: error: PRINT: Syntax error at `F8.2': expecting a valid subcommand.
+print.sps:7.7-7.10: error: PRINT: Syntax error at `F8.2': expecting a valid subcommand.
 
 Table: Data List
 a,b
diff --git a/tests/language/dictionary/formats.at b/tests/language/dictionary/formats.at
new file mode 100644 (file)
index 0000000..d3c2e65
--- /dev/null
@@ -0,0 +1,80 @@
+AT_BANNER([FORMATS])
+
+AT_SETUP([FORMATS positive tests])
+AT_DATA([formats.sps], [dnl
+DATA LIST LIST /a b c * x (A1) y (A2) z (A3).
+DISPLAY VARIABLES.
+FORMATS /a (COMMA10) b (N4).
+DISPLAY VARIABLES.
+FORMATS c (E8.1) x (A1) /y (AHEX4) z (A3).
+DISPLAY VARIABLES.
+])
+AT_CHECK([pspp -o pspp.csv formats.sps])
+AT_CHECK([grep -E -v 'Measure|Display' pspp.csv], [0], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+a,F8.0
+b,F8.0
+c,F8.0
+x,A1
+y,A2
+z,A3
+
+Variable,Description,,Position
+a,Format: F8.2,,1
+b,Format: F8.2,,2
+c,Format: F8.2,,3
+x,Format: A1,,4
+y,Format: A2,,5
+z,Format: A3,,6
+
+Variable,Description,,Position
+a,Format: COMMA10.0,,1
+b,Format: N4.0,,2
+c,Format: F8.2,,3
+x,Format: A1,,4
+y,Format: A2,,5
+z,Format: A3,,6
+
+Variable,Description,,Position
+a,Format: COMMA10.0,,1
+b,Format: N4.0,,2
+c,Format: E8.1,,3
+x,Format: A1,,4
+y,Format: AHEX4,,5
+z,Format: A3,,6
+])
+AT_CLEANUP
+
+AT_SETUP([FORMATS negative tests])
+AT_DATA([formats.sps], [dnl
+DATA LIST LIST /a b c * x (A1) y (A2) z (A3).
+FORMATS a (E6.1).
+FORMATS a y (F4).
+FORMATS x (A2).
+FORMATS y (AHEX2).
+FORMATS x y (A2).
+])
+AT_CHECK([pspp -O format=csv formats.sps], [1], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+a,F8.0
+b,F8.0
+c,F8.0
+x,A1
+y,A2
+z,A3
+
+"formats.sps:2: error: FORMATS: Output format E6.1 specifies 1 decimal place, but the given width does not allow for any decimals."
+
+formats.sps:3: error: FORMATS: a and y are not the same type.  All variables in this variable list must be of the same type.  y will be omitted from the list.
+
+formats.sps:4: error: FORMATS: String variable with width 1 is not compatible with format A2.
+
+formats.sps:5: error: FORMATS: String variable with width 2 is not compatible with format AHEX2.
+
+formats.sps:6: error: FORMATS: x and y are string variables with different widths.  All variables in this variable list must have the same width.  y will be omitted from the list.
+
+formats.sps:6: error: FORMATS: String variable with width 1 is not compatible with format A2.
+])
+AT_CLEANUP
index df2aeebe3d4392683c05ad3f4f6d5576c0dd9642..75254462aa0ea3bc39cffec96897b3cd9a7ea15a 100644 (file)
@@ -63,7 +63,7 @@ missing-values.sps:5: error: MISSING VALUES: Missing values provided are too lon
 
 missing-values.sps:8: error: MISSING VALUES: Truncating missing value to maximum acceptable length (8 bytes).
 
-missing-values.sps:11: error: MISSING VALUES: Syntax error at `THRU': expecting string.
+missing-values.sps:11.26-11.29: error: MISSING VALUES: Syntax error at `THRU': expecting string.
 
 missing-values.sps:11: error: MISSING VALUES: THRU is not a variable name.
 
index 4eb021446a04163467c69abf74735130baa55426..04abfc7d4be373d24f0a0d7f19a57ba2c71ec952 100644 (file)
@@ -185,7 +185,7 @@ d
 ","Multiple category set
 "
 
-mrsets.sps:50: note: MRSETS: The active file dictionary does not contain any multiple response sets.
+mrsets.sps:50: note: MRSETS: The active dataset dictionary does not contain any multiple response sets.
 ])
 AT_CLEANUP
 
index 14a53fafcf5cf5ec5b07b43b7a9f2122e5abebfd..923c3a29c7c34c685002dbb08e9c6fdba7a174c5 100644 (file)
@@ -17,7 +17,8 @@ AT_CHECK(
   [sed -e '/^Created:,/d' \
        -e '/^Endian:,/d' \
        -e '/^Integer Format:,/d' \
-       -e '/^Real Format:,/d' pspp.csv],
+       -e '/^Real Format:,/d' \
+       -e '/^Charset:,/d' pspp.csv],
   [0], [dnl
 Table: Reading free-form data from INLINE.
 Variable,Format
@@ -31,7 +32,6 @@ Cases:,3
 Type:,System File
 Weight:,Not weighted.
 Mode:,Compression on.
-Charset:,Unknown
 
 Variable,Description,,Position
 x,Format: F8.2,,1
index c6c48db4f0847b92e81cab3291b601acccbb19f0..4c9f43976d52b69a70e9f3db7d5f280dfb8584e9 100644 (file)
@@ -1,5 +1,100 @@
 AT_BANNER([VALUE LABELS])
 
+AT_SETUP([VALUE LABELS date formats])
+AT_DATA([value-labels.sps], [dnl
+DATA LIST LIST NOTABLE /ad (adate10) dt (datetime20).
+VALUE LABELS ad 'july 10, 1982' 'label 1'
+                '1-2-93' 'label 2'
+                '5-4-2003' 'label 3'
+            /dt '12 Apr 2011 06:09:56' 'label 4'.
+DISPLAY DICTIONARY.
+])
+AT_CHECK([pspp -O format=csv value-labels.sps], [0], [dnl
+Variable,Description,,Position
+ad,Format: ADATE10,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,07/10/1982,label 1,
+,01/02/1993,label 2,
+,05/04/2003,label 3,
+dt,Format: DATETIME20.0,,2
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,12-APR-2011 06:09:56,label 4,
+])
+AT_CLEANUP
+
+AT_SETUP([VALUE LABELS with new-line])
+AT_DATA([value-labels.sps], [dnl
+DATA LIST LIST NOTABLE /x.
+VALUE LABELS x 1 'one' 2 'first line\nsecond line' 3 'three'.
+BEGIN DATA.
+1
+2
+3
+END DATA.
+DISPLAY DICTIONARY.
+FREQUENCIES x/STAT=NONE.
+])
+AT_CHECK([pspp -O format=csv value-labels.sps], [0], [dnl
+Variable,Description,,Position
+x,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,1.00,one,
+,2.00,first line\nsecond line,
+,3.00,three,
+
+Table: x
+Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
+one,1.00,1,33.33,33.33,33.33
+"first line
+second line",2.00,1,33.33,33.33,66.67
+three,3.00,1,33.33,33.33,100.00
+Total,,3,100.0,100.0,
+])
+AT_CLEANUP
+
+AT_SETUP([VALUE LABELS with new-line in system file])
+AT_DATA([save.sps], [dnl
+DATA LIST LIST NOTABLE /x.
+VALUE LABELS x 1 'one' 2 'first line\nsecond line' 3 'three'.
+BEGIN DATA.
+1
+2
+3
+END DATA.
+SAVE OUTFILE='value-labels.sav'.
+])
+AT_CHECK([pspp -O format=csv save.sps])
+AT_DATA([get.sps], [dnl
+GET FILE='value-labels.sav'.
+DISPLAY DICTIONARY.
+FREQUENCIES x/STAT=NONE.
+])
+AT_CHECK([pspp -O format=csv get.sps], [0], [dnl
+Variable,Description,,Position
+x,Format: F8.2,,1
+,Measure: Scale,,
+,Display Alignment: Right,,
+,Display Width: 8,,
+,1.00,one,
+,2.00,first line\nsecond line,
+,3.00,three,
+
+Table: x
+Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
+one,1.00,1,33.33,33.33,33.33
+"first line
+second line",2.00,1,33.33,33.33,66.67
+three,3.00,1,33.33,33.33,100.00
+Total,,3,100.0,100.0,
+])
+AT_CLEANUP
+
 dnl Tests for a bug which caused VALUE LABELS to 
 dnl crash when given invalid syntax.
 AT_SETUP([VALUE LABELS invalid syntax bug])
index 0eb55bc72d0d22dfa61f367c0d59b7ea74deecc2..40226924d7f5e78929780e11e5ed5e8083bb312b 100644 (file)
@@ -146,6 +146,6 @@ Range,,76.000
 Minimum,,18.000
 Maximum,,94.000
 Sum,,23006.00
-Percentiles,50 (Median),29
+Percentiles,50 (Median),28
 ])
 AT_CLEANUP
index 4a8324ed661436e833ec6f295b990b6620f50714..e56a3a457e53c46d4a6905d95c8521c355891556 100644 (file)
@@ -10,7 +10,12 @@ DEBUG EVALUATE m4_argn(4, check)/[]m4_car(check).
    AT_CAPTURE_FILE([evaluate.sps])
    m4_pushdef([i], [2])
    AT_CHECK([pspp --testing-mode --error-file=- --no-output evaluate.sps], 
-     [m4_if(m4_bregexp([m4_foreach([check], [m4_shift($@)], [m4_argn(3, check)])], [error:]), [-1], [0], [1])],
+     [m4_if(m4_bregexp([m4_foreach([check], [m4_shift($@)], [m4_argn(3, check)])], [error:]), [-1], [0], [1])], 
+     [stdout])
+   # Use sed to transform "file:line.column:" into plain "file:line:",
+   # because column numbers change between opt and noopt versions.
+   AT_CHECK([[sed 's/\(evaluate.sps:[0-9]\{1,\}\)\.[0-9]\{1,\}:/\1:/' stdout]],
+     [0],
      [m4_foreach([check], [m4_shift($@)],
         [m4_define([i], m4_incr(i))dnl
 m4_if(m4_argn(3, check), [], [], [evaluate.sps:[]i[]: m4_argn(3, check)
@@ -281,10 +286,10 @@ dnl Make sure >= token can't be split:
   [['asdfj   ' ne 'asdf'], [true]],
 dnl <> token can't be split:
   [[1 < > 1], [error],
-   [error: DEBUG EVALUATE: Syntax error at `GT'.]],
+   [error: DEBUG EVALUATE: Syntax error at `>'.]],
 dnl # ~= token can't be split:
   [[1 ~ = 1], [error],
-   [error: DEBUG EVALUATE: Syntax error at `NOT': expecting end of command.]])
+   [error: DEBUG EVALUATE: Syntax error at `~': expecting end of command.]])
 
 CHECK_EXPR_EVAL([exp lg10 ln sqrt abs mod mod10 rnd trunc],
   [[exp(10)], [22026.47]],
@@ -1281,7 +1286,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.date(date.mdy(10,7,1943) + time.hms(2,57,52)) / 86400], [131845.00]],
   [[xdate.date(date.mdy(3,17,1992) + time.hms(16,45,44)) / 86400], [149539.00]],
   [[xdate.date(date.mdy(2,25,1996) + time.hms(21,30,57)) / 86400], [150979.00]],
-  [[xdate.date(date.mdy(9,29,41) + time.hms(4,25,9)) / 86400], [131107.00]],
+  [[xdate.date(date.mdy(9,29,1941) + time.hms(4,25,9)) / 86400], [131107.00]],
   [[xdate.date(date.mdy(4,19,43) + time.hms(6,49,27)) / 86400], [131674.00]],
   [[xdate.date(date.mdy(10,7,43) + time.hms(2,57,52)) / 86400], [131845.00]],
   [[xdate.date(date.mdy(3,17,92) + time.hms(16,45,44)) / 86400], [149539.00]],
@@ -1305,7 +1310,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.hour(date.mdy(10,7,1943) + time.hms(2,57,52))], [2.00]],
   [[xdate.hour(date.mdy(3,17,1992) + time.hms(16,45,44))], [16.00]],
   [[xdate.hour(date.mdy(2,25,1996) + time.hms(21,30,57))], [21.00]],
-  [[xdate.hour(date.mdy(9,29,41) + time.hms(4,25,9))], [4.00]],
+  [[xdate.hour(date.mdy(9,29,1941) + time.hms(4,25,9))], [4.00]],
   [[xdate.hour(date.mdy(4,19,43) + time.hms(6,49,27))], [6.00]],
   [[xdate.hour(date.mdy(10,7,43) + time.hms(2,57,52))], [2.00]],
   [[xdate.hour(date.mdy(3,17,92) + time.hms(16,45,44))], [16.00]],
@@ -1331,7 +1336,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.jday(date.mdy(10,7,1943) + time.hms(2,57,52))], [280.00]],
   [[xdate.jday(date.mdy(3,17,1992) + time.hms(16,45,44))], [77.00]],
   [[xdate.jday(date.mdy(2,25,1996) + time.hms(21,30,57))], [56.00]],
-  [[xdate.jday(date.mdy(9,29,41) + time.hms(4,25,9))], [272.00]],
+  [[xdate.jday(date.mdy(9,29,1941) + time.hms(4,25,9))], [272.00]],
   [[xdate.jday(date.mdy(4,19,43) + time.hms(6,49,27))], [109.00]],
   [[xdate.jday(date.mdy(10,7,43) + time.hms(2,57,52))], [280.00]],
   [[xdate.jday(date.mdy(3,17,92) + time.hms(16,45,44))], [77.00]],
@@ -1355,7 +1360,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.mday(date.mdy(10,7,1943) + time.hms(2,57,52))], [7.00]],
   [[xdate.mday(date.mdy(3,17,1992) + time.hms(16,45,44))], [17.00]],
   [[xdate.mday(date.mdy(2,25,1996) + time.hms(21,30,57))], [25.00]],
-  [[xdate.mday(date.mdy(9,29,41) + time.hms(4,25,9))], [29.00]],
+  [[xdate.mday(date.mdy(9,29,1941) + time.hms(4,25,9))], [29.00]],
   [[xdate.mday(date.mdy(4,19,43) + time.hms(6,49,27))], [19.00]],
   [[xdate.mday(date.mdy(10,7,43) + time.hms(2,57,52))], [7.00]],
   [[xdate.mday(date.mdy(3,17,92) + time.hms(16,45,44))], [17.00]],
@@ -1376,7 +1381,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.minute(date.mdy(10,7,1943) + time.hms(2,57,52))], [57.00]],
   [[xdate.minute(date.mdy(3,17,1992) + time.hms(16,45,44))], [45.00]],
   [[xdate.minute(date.mdy(2,25,1996) + time.hms(21,30,57))], [30.00]],
-  [[xdate.minute(date.mdy(9,29,41) + time.hms(4,25,9))], [25.00]],
+  [[xdate.minute(date.mdy(9,29,1941) + time.hms(4,25,9))], [25.00]],
   [[xdate.minute(date.mdy(4,19,43) + time.hms(6,49,27))], [49.00]],
   [[xdate.minute(date.mdy(10,7,43) + time.hms(2,57,52))], [57.00]],
   [[xdate.minute(date.mdy(3,17,92) + time.hms(16,45,44))], [45.00]],
@@ -1397,7 +1402,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.month(date.mdy(10,7,1943) + time.hms(2,57,52))], [10.00]],
   [[xdate.month(date.mdy(3,17,1992) + time.hms(16,45,44))], [3.00]],
   [[xdate.month(date.mdy(2,25,1996) + time.hms(21,30,57))], [2.00]],
-  [[xdate.month(date.mdy(9,29,41) + time.hms(4,25,9))], [9.00]],
+  [[xdate.month(date.mdy(9,29,1941) + time.hms(4,25,9))], [9.00]],
   [[xdate.month(date.mdy(4,19,43) + time.hms(6,49,27))], [4.00]],
   [[xdate.month(date.mdy(10,7,43) + time.hms(2,57,52))], [10.00]],
   [[xdate.month(date.mdy(3,17,92) + time.hms(16,45,44))], [3.00]],
@@ -1418,7 +1423,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.quarter(date.mdy(10,7,1943) + time.hms(2,57,52))], [4.00]],
   [[xdate.quarter(date.mdy(3,17,1992) + time.hms(16,45,44))], [1.00]],
   [[xdate.quarter(date.mdy(2,25,1996) + time.hms(21,30,57))], [1.00]],
-  [[xdate.quarter(date.mdy(9,29,41) + time.hms(4,25,9))], [3.00]],
+  [[xdate.quarter(date.mdy(9,29,1941) + time.hms(4,25,9))], [3.00]],
   [[xdate.quarter(date.mdy(4,19,43) + time.hms(6,49,27))], [2.00]],
   [[xdate.quarter(date.mdy(10,7,43) + time.hms(2,57,52))], [4.00]],
   [[xdate.quarter(date.mdy(3,17,92) + time.hms(16,45,44))], [1.00]],
@@ -1439,7 +1444,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.second(date.mdy(10,7,1943) + time.hms(2,57,52))], [52.00]],
   [[xdate.second(date.mdy(3,17,1992) + time.hms(16,45,44))], [44.00]],
   [[xdate.second(date.mdy(2,25,1996) + time.hms(21,30,57))], [57.00]],
-  [[xdate.second(date.mdy(9,29,41) + time.hms(4,25,9))], [9.00]],
+  [[xdate.second(date.mdy(9,29,1941) + time.hms(4,25,9))], [9.00]],
   [[xdate.second(date.mdy(4,19,43) + time.hms(6,49,27))], [27.00]],
   [[xdate.second(date.mdy(10,7,43) + time.hms(2,57,52))], [52.00]],
   [[xdate.second(date.mdy(3,17,92) + time.hms(16,45,44))], [44.00]],
@@ -1460,7 +1465,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.tday(date.mdy(10,7,1943) + time.hms(2,57,52))], [131845.00]],
   [[xdate.tday(date.mdy(3,17,1992) + time.hms(16,45,44))], [149539.00]],
   [[xdate.tday(date.mdy(2,25,1996) + time.hms(21,30,57))], [150979.00]],
-  [[xdate.tday(date.mdy(9,29,41) + time.hms(4,25,9))], [131107.00]],
+  [[xdate.tday(date.mdy(9,29,1941) + time.hms(4,25,9))], [131107.00]],
   [[xdate.tday(date.mdy(4,19,43) + time.hms(6,49,27))], [131674.00]],
   [[xdate.tday(date.mdy(10,7,43) + time.hms(2,57,52))], [131845.00]],
   [[xdate.tday(date.mdy(3,17,92) + time.hms(16,45,44))], [149539.00]],
@@ -1481,7 +1486,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.time(date.mdy(10,7,1943) + time.hms(2,57,52))], [10672.00]],
   [[xdate.time(date.mdy(3,17,1992) + time.hms(16,45,44))], [60344.00]],
   [[xdate.time(date.mdy(2,25,1996) + time.hms(21,30,57))], [77457.00]],
-  [[xdate.time(date.mdy(9,29,41) + time.hms(4,25,9))], [15909.00]],
+  [[xdate.time(date.mdy(9,29,1941) + time.hms(4,25,9))], [15909.00]],
   [[xdate.time(date.mdy(4,19,43) + time.hms(6,49,27))], [24567.00]],
   [[xdate.time(date.mdy(10,7,43) + time.hms(2,57,52))], [10672.00]],
   [[xdate.time(date.mdy(3,17,92) + time.hms(16,45,44))], [60344.00]],
@@ -1502,7 +1507,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.week(date.mdy(10,7,1943) + time.hms(2,57,52))], [40.00]],
   [[xdate.week(date.mdy(3,17,1992) + time.hms(16,45,44))], [11.00]],
   [[xdate.week(date.mdy(2,25,1996) + time.hms(21,30,57))], [8.00]],
-  [[xdate.week(date.mdy(9,29,41) + time.hms(4,25,9))], [39.00]],
+  [[xdate.week(date.mdy(9,29,1941) + time.hms(4,25,9))], [39.00]],
   [[xdate.week(date.mdy(4,19,43) + time.hms(6,49,27))], [16.00]],
   [[xdate.week(date.mdy(10,7,43) + time.hms(2,57,52))], [40.00]],
   [[xdate.week(date.mdy(3,17,92) + time.hms(16,45,44))], [11.00]],
@@ -1523,7 +1528,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.wkday(date.mdy(10,7,1943))], [5.00]],
   [[xdate.wkday(date.mdy(3,17,1992))], [3.00]],
   [[xdate.wkday(date.mdy(2,25,1996))], [1.00]],
-  [[xdate.wkday(date.mdy(9,29,41))], [2.00]],
+  [[xdate.wkday(date.mdy(9,29,1941))], [2.00]],
   [[xdate.wkday(date.mdy(4,19,43))], [2.00]],
   [[xdate.wkday(date.mdy(10,7,43))], [5.00]],
   [[xdate.wkday(date.mdy(3,17,92))], [3.00]],
@@ -1544,7 +1549,7 @@ CHECK_EXPR_EVAL([xdate],
   [[xdate.year(date.mdy(10,7,1943) + time.hms(2,57,52))], [1943.00]],
   [[xdate.year(date.mdy(3,17,1992) + time.hms(16,45,44))], [1992.00]],
   [[xdate.year(date.mdy(2,25,1996) + time.hms(21,30,57))], [1996.00]],
-  [[xdate.year(date.mdy(9,29,41) + time.hms(4,25,9))], [1941.00]],
+  [[xdate.year(date.mdy(9,29,1941) + time.hms(4,25,9))], [1941.00]],
   [[xdate.year(date.mdy(4,19,43) + time.hms(6,49,27))], [1943.00]],
   [[xdate.year(date.mdy(10,7,43) + time.hms(2,57,52))], [1943.00]],
   [[xdate.year(date.mdy(3,17,92) + time.hms(16,45,44))], [1992.00]],
@@ -1565,8 +1570,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(4,19,1943), date.mdy(10,7,1943), 'years')], [0.00]],
   [[datediff(date.mdy(10,7,1943), date.mdy(3,17,1992), 'years')], [-48.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(2,25,1996), 'years')], [-3.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(2,25,1996), 'years')], [-54.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(4,19,43), 'years')], [-1.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(2,25,1996), 'years')], [-54.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(4,19,43), 'years')], [-1.00]],
   [[datediff(date.mdy(4,19,43), date.mdy(10,7,43), 'years')], [0.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(3,17,92), 'years')], [-48.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(2,25,96), 'years')], [-3.00]],
@@ -1588,8 +1593,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(4,19,1943), date.mdy(10,7,1943), 'quarters')], [-1.00]],
   [[datediff(date.mdy(10,7,1943), date.mdy(3,17,1992), 'quarters')], [-193.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(2,25,1996), 'quarters')], [-15.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(2,25,1996), 'quarters')], [-217.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(4,19,43), 'quarters')], [-6.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(2,25,1996), 'quarters')], [-217.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(4,19,43), 'quarters')], [-6.00]],
   [[datediff(date.mdy(4,19,43), date.mdy(10,7,43), 'quarters')], [-1.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(3,17,92), 'quarters')], [-193.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(2,25,96), 'quarters')], [-15.00]],
@@ -1611,8 +1616,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(4,19,1943), date.mdy(10,7,1943), 'months')], [-5.00]],
   [[datediff(date.mdy(10,7,1943), date.mdy(3,17,1992), 'months')], [-581.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(2,25,1996), 'months')], [-47.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(2,25,1996), 'months')], [-652.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(4,19,43), 'months')], [-18.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(2,25,1996), 'months')], [-652.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(4,19,43), 'months')], [-18.00]],
   [[datediff(date.mdy(4,19,43), date.mdy(10,7,43), 'months')], [-5.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(3,17,92), 'months')], [-581.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(2,25,96), 'months')], [-47.00]],
@@ -1634,8 +1639,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(4,19,1943), date.mdy(10,7,1943), 'weeks')], [-24.00]],
   [[datediff(date.mdy(10,7,1943), date.mdy(3,17,1992), 'weeks')], [-2527.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(2,25,1996), 'weeks')], [-205.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(2,25,1996), 'weeks')], [-2838.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(4,19,43), 'weeks')], [-81.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(2,25,1996), 'weeks')], [-2838.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(4,19,43), 'weeks')], [-81.00]],
   [[datediff(date.mdy(4,19,43), date.mdy(10,7,43), 'weeks')], [-24.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(3,17,92), 'weeks')], [-2527.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(2,25,96), 'weeks')], [-205.00]],
@@ -1657,8 +1662,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(4,19,1943), date.mdy(10,7,1943), 'days')], [-171.00]],
   [[datediff(date.mdy(10,7,1943), date.mdy(3,17,1992), 'days')], [-17694.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(2,25,1996), 'days')], [-1440.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(2,25,1996), 'days')], [-19872.00]],
-  [[datediff(date.mdy(9,29,41), date.mdy(4,19,43), 'days')], [-567.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(2,25,1996), 'days')], [-19872.00]],
+  [[datediff(date.mdy(9,29,1941), date.mdy(4,19,43), 'days')], [-567.00]],
   [[datediff(date.mdy(4,19,43), date.mdy(10,7,43), 'days')], [-171.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(3,17,92), 'days')], [-17694.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(2,25,96), 'days')], [-1440.00]],
@@ -1680,8 +1685,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(10,7,1943), date.mdy(4,19,1943), 'years')], [0.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(10,7,1943), 'years')], [48.00]],
   [[datediff(date.mdy(2,25,1996), date.mdy(3,17,1992), 'years')], [3.00]],
-  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,41), 'years')], [54.00]],
-  [[datediff(date.mdy(4,19,43), date.mdy(9,29,41), 'years')], [1.00]],
+  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,1941), 'years')], [54.00]],
+  [[datediff(date.mdy(4,19,43), date.mdy(9,29,1941), 'years')], [1.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(4,19,43), 'years')], [0.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(10,7,43), 'years')], [48.00]],
   [[datediff(date.mdy(2,25,96), date.mdy(3,17,92), 'years')], [3.00]],
@@ -1703,8 +1708,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(10,7,1943), date.mdy(4,19,1943), 'months')], [5.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(10,7,1943), 'months')], [581.00]],
   [[datediff(date.mdy(2,25,1996), date.mdy(3,17,1992), 'months')], [47.00]],
-  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,41), 'months')], [652.00]],
-  [[datediff(date.mdy(4,19,43), date.mdy(9,29,41), 'months')], [18.00]],
+  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,1941), 'months')], [652.00]],
+  [[datediff(date.mdy(4,19,43), date.mdy(9,29,1941), 'months')], [18.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(4,19,43), 'months')], [5.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(10,7,43), 'months')], [581.00]],
   [[datediff(date.mdy(2,25,96), date.mdy(3,17,92), 'months')], [47.00]],
@@ -1726,8 +1731,8 @@ CHECK_EXPR_EVAL([datediff],
   [[datediff(date.mdy(10,7,1943), date.mdy(4,19,1943), 'quarters')], [1.00]],
   [[datediff(date.mdy(3,17,1992), date.mdy(10,7,1943), 'quarters')], [193.00]],
   [[datediff(date.mdy(2,25,1996), date.mdy(3,17,1992), 'quarters')], [15.00]],
-  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,41), 'quarters')], [217.00]],
-  [[datediff(date.mdy(4,19,43), date.mdy(9,29,41), 'quarters')], [6.00]],
+  [[datediff(date.mdy(2,25,1996), date.mdy(9,29,1941), 'quarters')], [217.00]],
+  [[datediff(date.mdy(4,19,43), date.mdy(9,29,1941), 'quarters')], [6.00]],
   [[datediff(date.mdy(10,7,43), date.mdy(4,19,43), 'quarters')], [1.00]],
   [[datediff(date.mdy(3,17,92), date.mdy(10,7,43), 'quarters')], [193.00]],
   [[datediff(date.mdy(2,25,96), date.mdy(3,17,92), 'quarters')], [15.00]],
index 7ebc5dc15dbcf263c20560d0405328b2152060a3..df8192b28ed74d0d7978231b54052c34ddfe78b9 100644 (file)
@@ -18,6 +18,6 @@ END IF.
 AT_CHECK([pspp -O format=csv parse.sps], [1], [dnl
 parse.sps:10: error: IF: Unknown identifier y.
 
-parse.sps:10: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
+parse.sps:11: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 ])
 AT_CLEANUP
diff --git a/tests/language/lexer/command-name-test.c b/tests/language/lexer/command-name-test.c
new file mode 100644 (file)
index 0000000..d63b8a2
--- /dev/null
@@ -0,0 +1,149 @@
+/* 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 <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "language/lexer/command-name.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+
+static char **commands, **strings;
+static size_t n_commands, n_strings;
+
+static void parse_options (int argc, char **argv);
+static void usage (void) NO_RETURN;
+
+int
+main (int argc, char *argv[])
+{
+  size_t i;
+
+  set_program_name (argv[0]);
+  parse_options (argc, argv);
+
+  for (i = 0; i < n_strings; i++)
+    {
+      const char *string = strings[i];
+      struct command_matcher cm;
+      const char *best;
+      size_t j;
+
+      if (i > 0)
+        putchar ('\n');
+      printf ("string=\"%s\":\n", string);
+      for (j = 0; j < n_commands; j++)
+        {
+          const char *command = commands[j];
+          int missing_words;
+          bool match, exact;
+
+          match = command_match (ss_cstr (command), ss_cstr (string),
+                                 &exact, &missing_words);
+          printf ("\tcommand=\"%s\" match=%s",
+                  command, match ? "yes" : "no");
+          if (match)
+            printf (" exact=%s missing_words=%d",
+                    exact ? "yes" : "no", missing_words);
+          putchar ('\n');
+        }
+
+      command_matcher_init (&cm, ss_cstr (string));
+      for (j = 0; j < n_commands; j++)
+        command_matcher_add (&cm, ss_cstr (commands[j]), commands[j]);
+      best = command_matcher_get_match (&cm);
+      printf ("match: %s, missing_words=%d\n",
+              best ? best : "none", command_matcher_get_missing_words (&cm));
+      command_matcher_destroy (&cm);
+    }
+
+  return 0;
+}
+
+static void
+parse_options (int argc, char **argv)
+{
+  int breakpoint;
+
+  for (;;)
+    {
+      static const struct option options[] =
+        {
+          {"help", no_argument, NULL, 'h'},
+          {NULL, 0, NULL, 0},
+        };
+
+      int c = getopt_long (argc, argv, "h", options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'h':
+          usage ();
+
+        case 0:
+          break;
+
+        case '?':
+          exit (EXIT_FAILURE);
+          break;
+
+        default:
+          NOT_REACHED ();
+        }
+
+    }
+
+  for (breakpoint = optind; ; breakpoint++)
+    if (breakpoint >= argc)
+      error (1, 0, "missing ',' on command line; use --help for help");
+    else if (!strcmp (argv[breakpoint], ","))
+      break;
+
+  commands = &argv[optind];
+  n_commands = breakpoint - optind;
+
+  strings = &argv[breakpoint + 1];
+  n_strings = argc - (breakpoint + 1);
+
+  if (n_commands == 0 || n_strings == 0)
+    error (1, 0, "must specify at least one command and one string; "
+           "use --help for help");
+}
+
+static void
+usage (void)
+{
+  printf ("\
+%s, to match PSPP command names\n\
+usage: %s [OPTIONS] COMMAND... , STRING...\n\
+\n\
+Options:\n\
+  -h, --help          print this help message\n",
+          program_name, program_name);
+  exit (EXIT_SUCCESS);
+}
diff --git a/tests/language/lexer/command-name.at b/tests/language/lexer/command-name.at
new file mode 100644 (file)
index 0000000..e0ecd59
--- /dev/null
@@ -0,0 +1,234 @@
+AT_BANNER([command name matching])
+\f
+AT_SETUP([single words])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test DESCRIPTIVES , DESCRIPTIVESX DESCRIPTIVES descr Des DEX DE '' 'DESCRIPTIVES MORE' 'DESCRIPTIVES@<00A0>@MORE'],
+  [0], [dnl
+string="DESCRIPTIVESX":
+       command="DESCRIPTIVES" match=no
+match: none, missing_words=0
+
+string="DESCRIPTIVES":
+       command="DESCRIPTIVES" match=yes exact=yes missing_words=0
+match: DESCRIPTIVES, missing_words=0
+
+string="descr":
+       command="DESCRIPTIVES" match=yes exact=no missing_words=0
+match: DESCRIPTIVES, missing_words=0
+
+string="Des":
+       command="DESCRIPTIVES" match=yes exact=no missing_words=0
+match: DESCRIPTIVES, missing_words=0
+
+string="DEX":
+       command="DESCRIPTIVES" match=no
+match: none, missing_words=0
+
+string="DE":
+       command="DESCRIPTIVES" match=no
+match: none, missing_words=0
+
+string="":
+       command="DESCRIPTIVES" match=yes exact=yes missing_words=1
+match: none, missing_words=1
+
+string="DESCRIPTIVES MORE":
+       command="DESCRIPTIVES" match=yes exact=yes missing_words=-1
+match: DESCRIPTIVES, missing_words=-1
+
+string="DESCRIPTIVES@<00A0>@MORE":
+       command="DESCRIPTIVES" match=yes exact=yes missing_words=-1
+match: DESCRIPTIVES, missing_words=-1
+])
+AT_CLEANUP
+\f
+AT_SETUP([two words without prefix match])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test 'DO IF' 'DO REPEAT' , 'DO@<00A0>@IF' 'DO REPEAT' 'DO REP' 'DO OTHER' 'D IF' 'DO I' DO],
+  [0], [dnl
+string="DO@<00A0>@IF":
+       command="DO IF" match=yes exact=yes missing_words=0
+       command="DO REPEAT" match=no
+match: DO IF, missing_words=0
+
+string="DO REPEAT":
+       command="DO IF" match=no
+       command="DO REPEAT" match=yes exact=yes missing_words=0
+match: DO REPEAT, missing_words=0
+
+string="DO REP":
+       command="DO IF" match=no
+       command="DO REPEAT" match=yes exact=no missing_words=0
+match: DO REPEAT, missing_words=0
+
+string="DO OTHER":
+       command="DO IF" match=no
+       command="DO REPEAT" match=no
+match: none, missing_words=0
+
+string="D IF":
+       command="DO IF" match=no
+       command="DO REPEAT" match=no
+match: none, missing_words=0
+
+string="DO I":
+       command="DO IF" match=no
+       command="DO REPEAT" match=no
+match: none, missing_words=0
+
+string="DO":
+       command="DO IF" match=yes exact=yes missing_words=1
+       command="DO REPEAT" match=yes exact=yes missing_words=1
+match: none, missing_words=1
+])
+AT_CLEANUP
+\f
+AT_SETUP([two words with prefix match])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test GET 'GET DATA' , GET 'GET TYPE' 'GET DAT' 'GET DATA'],
+  [0], [dnl
+string="GET":
+       command="GET" match=yes exact=yes missing_words=0
+       command="GET DATA" match=yes exact=yes missing_words=1
+match: none, missing_words=1
+
+string="GET TYPE":
+       command="GET" match=yes exact=yes missing_words=-1
+       command="GET DATA" match=no
+match: GET, missing_words=-1
+
+string="GET DAT":
+       command="GET" match=yes exact=yes missing_words=-1
+       command="GET DATA" match=yes exact=no missing_words=0
+match: GET DATA, missing_words=0
+
+string="GET DATA":
+       command="GET" match=yes exact=yes missing_words=-1
+       command="GET DATA" match=yes exact=yes missing_words=0
+match: GET DATA, missing_words=0
+])
+AT_CLEANUP
+\f
+AT_SETUP([ambiguous single-word names])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test CASEPLOT CASESTOVARS , CAS Case CaseP CaseS], [0],
+  [dnl
+string="CAS":
+       command="CASEPLOT" match=yes exact=no missing_words=0
+       command="CASESTOVARS" match=yes exact=no missing_words=0
+match: none, missing_words=0
+
+string="Case":
+       command="CASEPLOT" match=yes exact=no missing_words=0
+       command="CASESTOVARS" match=yes exact=no missing_words=0
+match: none, missing_words=0
+
+string="CaseP":
+       command="CASEPLOT" match=yes exact=no missing_words=0
+       command="CASESTOVARS" match=no
+match: CASEPLOT, missing_words=0
+
+string="CaseS":
+       command="CASEPLOT" match=no
+       command="CASESTOVARS" match=yes exact=no missing_words=0
+match: CASESTOVARS, missing_words=0
+])
+AT_CLEANUP
+
+AT_SETUP([ambiguous two-word names])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test VARCOMP VARSTOCASES 'VARIABLE ATTRIBUTE' , VAR VARC VARS VARI 'VAR@<00A0>@ATT'],
+  [0], [dnl
+string="VAR":
+       command="VARCOMP" match=yes exact=no missing_words=0
+       command="VARSTOCASES" match=yes exact=no missing_words=0
+       command="VARIABLE ATTRIBUTE" match=yes exact=no missing_words=1
+match: none, missing_words=1
+
+string="VARC":
+       command="VARCOMP" match=yes exact=no missing_words=0
+       command="VARSTOCASES" match=no
+       command="VARIABLE ATTRIBUTE" match=no
+match: VARCOMP, missing_words=0
+
+string="VARS":
+       command="VARCOMP" match=no
+       command="VARSTOCASES" match=yes exact=no missing_words=0
+       command="VARIABLE ATTRIBUTE" match=no
+match: VARSTOCASES, missing_words=0
+
+string="VARI":
+       command="VARCOMP" match=no
+       command="VARSTOCASES" match=no
+       command="VARIABLE ATTRIBUTE" match=yes exact=no missing_words=1
+match: none, missing_words=1
+
+string="VAR@<00A0>@ATT":
+       command="VARCOMP" match=yes exact=no missing_words=-1
+       command="VARSTOCASES" match=yes exact=no missing_words=-1
+       command="VARIABLE ATTRIBUTE" match=yes exact=no missing_words=0
+match: VARIABLE ATTRIBUTE, missing_words=0
+])
+AT_CLEANUP
+\f
+AT_SETUP([numbers and punctuation])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test T-TEST 2SLS LIST , T-TEST 'T - Test' 2SLS '2 SLS' List],
+  [0], [dnl
+string="T-TEST":
+       command="T-TEST" match=yes exact=yes missing_words=0
+       command="2SLS" match=no
+       command="LIST" match=no
+match: T-TEST, missing_words=0
+
+string="T - Test":
+       command="T-TEST" match=yes exact=yes missing_words=0
+       command="2SLS" match=no
+       command="LIST" match=no
+match: T-TEST, missing_words=0
+
+string="2SLS":
+       command="T-TEST" match=no
+       command="2SLS" match=yes exact=yes missing_words=0
+       command="LIST" match=no
+match: 2SLS, missing_words=0
+
+string="2 SLS":
+       command="T-TEST" match=no
+       command="2SLS" match=yes exact=yes missing_words=0
+       command="LIST" match=no
+match: 2SLS, missing_words=0
+
+string="List":
+       command="T-TEST" match=no
+       command="2SLS" match=no
+       command="LIST" match=yes exact=yes missing_words=0
+match: LIST, missing_words=0
+])
+AT_CLEANUP
+\f
+AT_SETUP([off by more than one word])
+AT_KEYWORDS([command name matching])
+AT_CHECK([command-name-test 'a@<00A0>@b c' , a 'a b' 'a b c' 'a@<00A0>@b c d' 'a b c@<00A0>@d e'],
+  [0], [dnl
+string="a":
+       command="a@<00A0>@b c" match=yes exact=yes missing_words=2
+match: none, missing_words=1
+
+string="a b":
+       command="a@<00A0>@b c" match=yes exact=yes missing_words=1
+match: none, missing_words=1
+
+string="a b c":
+       command="a@<00A0>@b c" match=yes exact=yes missing_words=0
+match: a@<00A0>@b c, missing_words=0
+
+string="a@<00A0>@b c d":
+       command="a@<00A0>@b c" match=yes exact=yes missing_words=-1
+match: a@<00A0>@b c, missing_words=-1
+
+string="a b c@<00A0>@d e":
+       command="a@<00A0>@b c" match=yes exact=yes missing_words=-2
+match: a@<00A0>@b c, missing_words=-2
+])
+AT_CLEANUP
index 2c1dfc93b850d01446692dfa48425292ead089d2..08c146447fbed1964843a9544efec6f63b9292e2 100644 (file)
@@ -18,3 +18,46 @@ a
 2.00
 ])
 AT_CLEANUP
+
+AT_SETUP([lexer properly reports scan errors])
+AT_DATA([lexer.sps], [dnl
+x'123'
+x'1x'
+u''
+u'012345678'
+u'd800'
+u'110000'
+'foo
+'very long unterminated string that be ellipsized in its error message
+1e .x
+`
+�
+])
+AT_CHECK([pspp -O format=csv lexer.sps], [1], [dnl
+"lexer.sps:1.1-1.6: error: Syntax error at `x'123'': String of hex digits has 3 characters, which is not a multiple of 2."
+
+lexer.sps:2.1-2.5: error: Syntax error at `x'1x'': `x' is not a valid hex digit.
+
+"lexer.sps:3.1-3.3: error: Syntax error at `u''': Unicode string contains 0 bytes, which is not in the valid range of 1 to 8 bytes."
+
+"lexer.sps:4.1-4.12: error: Syntax error at `u'012345678'': Unicode string contains 9 bytes, which is not in the valid range of 1 to 8 bytes."
+
+lexer.sps:5.1-5.7: error: Syntax error at `u'd800'': U+D800 is not a valid Unicode code point.
+
+lexer.sps:6.1-6.9: error: Syntax error at `u'110000'': U+110000 is not a valid Unicode code point.
+
+lexer.sps:7.1-7.4: error: Syntax error at `'foo': Unterminated string constant.
+
+lexer.sps:8.1-8.70: error: Syntax error at `'very long unterminated string that be ellipsized in its err...': Unterminated string constant.
+
+lexer.sps:9.1-9.2: error: Syntax error at `1e': Missing exponent following `1e'.
+
+lexer.sps:9.4: error: Syntax error at `.': Unexpected `.' in middle of command.
+
+lexer.sps:9: error: Unknown command `x'.
+
+lexer.sps:10.1: error: Syntax error at ``': Bad character ``' in input.
+
+lexer.sps:11.1: error: Syntax error at `�': Bad character U+FFFD in input.
+])
+AT_CLEANUP
index eeeed8d73f8dd3d12b3ae560e72c616640bd269f..6ba3f7ab126065d6932507efc42fa68a5223dca3 100644 (file)
@@ -16,7 +16,7 @@ CROSSTABS.
 AT_CHECK([pspp -O format=csv q2c.sps], [1], [dnl
 q2c.sps:8: error: EXAMINE: VARIABLES subcommand must be given.
 
-q2c.sps:9: error: ONEWAY: Syntax error at end of command: expecting variable name.
+q2c.sps:9.7: error: ONEWAY: Syntax error at end of command: expecting variable name.
 
 q2c.sps:10: error: CROSSTABS: TABLES subcommand must be given.
 ])
diff --git a/tests/language/lexer/scan-test.c b/tests/language/lexer/scan-test.c
new file mode 100644 (file)
index 0000000..a56dfd7
--- /dev/null
@@ -0,0 +1,217 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/misc.h"
+#include "language/lexer/scan.h"
+#include "language/lexer/token.h"
+
+#include "gl/error.h"
+#include "gl/ftoastr.h"
+#include "gl/progname.h"
+#include "gl/read-file.h"
+#include "gl/xalloc.h"
+
+/* -a/--auto, -b/--batch, -i/--interactive: syntax mode. */
+static enum segmenter_mode mode = SEG_MODE_AUTO;
+
+static const char *parse_options (int argc, char **argv);
+static void usage (void) NO_RETURN;
+
+int
+main (int argc, char *argv[])
+{
+  struct segment
+    {
+      enum segment_type type;
+      struct substring string;
+    };
+
+  size_t offset;
+  const char *file_name;
+  char *input;
+  struct segmenter s;
+  struct segment *segs;
+  size_t n_segs, allocated_segs;
+  size_t length;
+  size_t i;
+  int n;
+
+  set_program_name (argv[0]);
+  file_name = parse_options (argc, argv);
+
+  /* Read from stdin into 'input'.  Ensure that 'input' ends in a new-line
+     followed by a null byte. */
+  input = (!strcmp (file_name, "-")
+           ? fread_file (stdin, &length)
+           : read_file (file_name, &length));
+  if (input == NULL)
+    error (EXIT_FAILURE, errno, "reading %s failed", file_name);
+  input = xrealloc (input, length + 3);
+  if (length == 0 || input[length - 1] != '\n')
+    input[length++] = '\n';
+  input[length++] = '\0';
+
+  segs = NULL;
+  n_segs = allocated_segs = 0;
+
+  segmenter_init (&s, mode);
+  for (offset = 0; offset < length; offset += n)
+    {
+      enum segment_type type;
+
+      n = segmenter_push (&s, input + offset, length - offset, &type);
+      assert (n >= 0);
+      assert (offset + n <= length);
+
+      if (n_segs >= allocated_segs)
+        segs = x2nrealloc (segs, &allocated_segs, sizeof *segs);
+
+      segs[n_segs].type = type;
+      segs[n_segs].string.string = input + offset;
+      segs[n_segs].string.length = n;
+      n_segs++;
+    }
+
+  for (i = 0; i < n_segs; )
+    {
+      enum scan_result result;
+      struct scanner scanner;
+      struct token token;
+      int saved = -1;
+
+      scanner_init (&scanner, &token);
+      do
+        {
+          struct segment *seg;
+
+          assert (i < n_segs);
+
+          seg = &segs[i++];
+          result = scanner_push (&scanner, seg->type, seg->string, &token);
+          if (result == SCAN_SAVE)
+            saved = i;
+        }
+      while (result == SCAN_MORE || result == SCAN_SAVE);
+
+      if (result == SCAN_BACK)
+        {
+          assert (saved >= 0);
+          i = saved;
+        }
+
+      printf ("%s", scan_type_to_string (token.type));
+      if (token.number != 0.0)
+        {
+          char s[DBL_BUFSIZE_BOUND];
+
+          dtoastr (s, sizeof s, 0, 0, token.number);
+          printf (" %s", s);
+        }
+      if (token.string.string != NULL || token.string.length > 0)
+        printf (" \"%.*s\"", (int) token.string.length, token.string.string);
+      printf ("\n");
+
+      token_destroy (&token);
+    }
+
+  free (input);
+
+  return 0;
+}
+
+static const char *
+parse_options (int argc, char **argv)
+{
+  for (;;)
+    {
+      static const struct option options[] =
+        {
+          {"auto", no_argument, NULL, 'a'},
+          {"batch", no_argument, NULL, 'b'},
+          {"interactive", no_argument, NULL, 'i'},
+          {"help", no_argument, NULL, 'h'},
+          {NULL, 0, NULL, 0},
+        };
+
+      int c = getopt_long (argc, argv, "abih", options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'a':
+          mode = SEG_MODE_AUTO;
+          break;
+
+        case 'b':
+          mode = SEG_MODE_BATCH;
+          break;
+
+        case 'i':
+          mode = SEG_MODE_INTERACTIVE;
+          break;
+
+        case 'h':
+          usage ();
+
+        case 0:
+          break;
+
+        case '?':
+          exit (EXIT_FAILURE);
+          break;
+
+        default:
+          NOT_REACHED ();
+        }
+
+    }
+
+  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 breaking PSPP syntax into tokens\n\
+usage: %s [OPTIONS] INPUT\n\
+\n\
+Options:\n\
+  -1, --one-segment   feed one segment at a time\n\
+  -a, --auto          use \"auto\" syntax mode\n\
+  -b, --batch         use \"batch\" syntax mode\n\
+  -i, --interactive   use \"interactive\" syntax mode (default)\n\
+  -v, --verbose       include rows and column numbers in output\n\
+  -h, --help          print this help message\n",
+          program_name, program_name);
+  exit (EXIT_SUCCESS);
+}
diff --git a/tests/language/lexer/scan.at b/tests/language/lexer/scan.at
new file mode 100644 (file)
index 0000000..50ee123
--- /dev/null
@@ -0,0 +1,818 @@
+AT_BANNER([syntax scanning])
+m4_define([PSPP_CHECK_SCAN],
+  [AT_CHECK([scan-test $1 input], [0], [expout])])
+\f
+AT_SETUP([identifiers])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+a aB i5 $x @efg @@. #.# .x _z.
+abcd. abcd.
+QRSTUV./* end of line comment */
+QrStUv./* end of line comment */ @&t@
+WXYZ. /* unterminated end of line comment
+�. /* U+FFFD is not valid in an identifier
+])
+AT_DATA([expout], [dnl
+ID "a"
+SKIP
+ID "aB"
+SKIP
+ID "i5"
+SKIP
+ID "$x"
+SKIP
+ID "@efg"
+SKIP
+ID "@@."
+SKIP
+ID "#.#"
+SKIP
+UNEXPECTED_DOT
+ID "x"
+SKIP
+UNEXPECTED_CHAR 95
+ID "z"
+ENDCMD
+SKIP
+ID "abcd."
+SKIP
+ID "abcd"
+ENDCMD
+SKIP
+ID "QRSTUV"
+ENDCMD
+SKIP
+SKIP
+ID "QrStUv"
+ENDCMD
+SKIP
+SKIP
+SKIP
+ID "WXYZ"
+ENDCMD
+SKIP
+SKIP
+SKIP
+UNEXPECTED_CHAR 65533
+ENDCMD
+SKIP
+SKIP
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([reserved words])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+and or not eq ge gt le lt ne all by to with
+AND OR NOT EQ GE GT LE LT NE ALL BY TO WITH
+andx orx notx eqx gex gtx lex ltx nex allx byx tox withx
+and. with.
+])
+AT_DATA([expout], [dnl
+AND
+SKIP
+OR
+SKIP
+NOT
+SKIP
+EQ
+SKIP
+GE
+SKIP
+GT
+SKIP
+LE
+SKIP
+LT
+SKIP
+NE
+SKIP
+ALL
+SKIP
+BY
+SKIP
+TO
+SKIP
+WITH
+SKIP
+AND
+SKIP
+OR
+SKIP
+NOT
+SKIP
+EQ
+SKIP
+GE
+SKIP
+GT
+SKIP
+LE
+SKIP
+LT
+SKIP
+NE
+SKIP
+ALL
+SKIP
+BY
+SKIP
+TO
+SKIP
+WITH
+SKIP
+ID "andx"
+SKIP
+ID "orx"
+SKIP
+ID "notx"
+SKIP
+ID "eqx"
+SKIP
+ID "gex"
+SKIP
+ID "gtx"
+SKIP
+ID "lex"
+SKIP
+ID "ltx"
+SKIP
+ID "nex"
+SKIP
+ID "allx"
+SKIP
+ID "byx"
+SKIP
+ID "tox"
+SKIP
+ID "withx"
+SKIP
+ID "and."
+SKIP
+WITH
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([punctuation])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+~ & | = >= > <= < ~= <> ( ) , - + * / [[ ]] **
+~&|=>=><=<~=<>(),-+*/[[]]**
+])
+AT_DATA([expout], [dnl
+NOT
+SKIP
+AND
+SKIP
+OR
+SKIP
+EQUALS
+SKIP
+GE
+SKIP
+GT
+SKIP
+LE
+SKIP
+LT
+SKIP
+NE
+SKIP
+NE
+SKIP
+LPAREN
+SKIP
+RPAREN
+SKIP
+COMMA
+SKIP
+DASH
+SKIP
+PLUS
+SKIP
+ASTERISK
+SKIP
+SLASH
+SKIP
+LBRACK
+SKIP
+RBRACK
+SKIP
+EXP
+SKIP
+NOT
+AND
+OR
+EQUALS
+GE
+GT
+LE
+LT
+NE
+NE
+LPAREN
+RPAREN
+COMMA
+DASH
+PLUS
+ASTERISK
+SLASH
+LBRACK
+RBRACK
+EXP
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([numbers])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+0 1 01 001. 1.
+123. /* comment 1 */ /* comment 2 */
+.1 0.1 00.1 00.10
+5e1 6E-1 7e+1 6E+01 6e-03
+.3E1 .4e-1 .5E+1 .6e+01 .7E-03
+1.23e1 45.6E-1 78.9e+1 99.9E+01 11.2e-03
+. 1e e1 1e+ 1e-
+])
+AT_DATA([expout], [dnl
+POS_NUM
+SKIP
+POS_NUM 1
+SKIP
+POS_NUM 1
+SKIP
+POS_NUM 1
+SKIP
+POS_NUM 1
+ENDCMD
+SKIP
+POS_NUM 123
+ENDCMD
+SKIP
+SKIP
+SKIP
+SKIP
+SKIP
+ENDCMD
+POS_NUM 1
+SKIP
+POS_NUM 0.1
+SKIP
+POS_NUM 0.1
+SKIP
+POS_NUM 0.1
+SKIP
+POS_NUM 50
+SKIP
+POS_NUM 0.6
+SKIP
+POS_NUM 70
+SKIP
+POS_NUM 60
+SKIP
+POS_NUM 0.006
+SKIP
+ENDCMD
+POS_NUM 30
+SKIP
+POS_NUM 0.04
+SKIP
+POS_NUM 5
+SKIP
+POS_NUM 6
+SKIP
+POS_NUM 0.0007
+SKIP
+POS_NUM 12.3
+SKIP
+POS_NUM 4.56
+SKIP
+POS_NUM 789
+SKIP
+POS_NUM 999
+SKIP
+POS_NUM 0.0112
+SKIP
+ENDCMD
+SKIP
+EXPECTED_EXPONENT "1e"
+SKIP
+ID "e1"
+SKIP
+EXPECTED_EXPONENT "1e+"
+SKIP
+EXPECTED_EXPONENT "1e-"
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([strings])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+'x' "y" 'abc'
+'Don''t' "Can't" 'Won''t'
+"""quoted""" '"quoted"'
+'' "" '''' """"
+'missing end quote
+"missing double quote
+'x' + "y"
++ 'z' +
+'a' /* abc */ + "b" /*
++ 'c' +/* */"d"/* */+'e'
+'foo'
++          /* special case: + in column 0 would ordinarily start a new command
+'bar'
+'foo'
+ +
+'bar'
+'foo'
++
+
+'bar'
+
++
+x"4142"+'5152'
+"4142"+
+x'5152'
+x"4142"
++u'304a'
+"�あいうえお"
+"abc"+U"FFFD"+u'3048'+"xyz"
+])
+AT_DATA([expout], [dnl
+STRING "x"
+SKIP
+STRING "y"
+SKIP
+STRING "abc"
+SKIP
+STRING "Don't"
+SKIP
+STRING "Can't"
+SKIP
+STRING "Won't"
+SKIP
+STRING ""quoted""
+SKIP
+STRING ""quoted""
+SKIP
+STRING ""
+SKIP
+STRING ""
+SKIP
+STRING "'"
+SKIP
+STRING """
+SKIP
+EXPECTED_QUOTE
+SKIP
+EXPECTED_QUOTE
+SKIP
+STRING "xyzabcde"
+SKIP
+STRING "foobar"
+SKIP
+STRING "foobar"
+SKIP
+STRING "foo"
+SKIP
+PLUS
+SKIP
+ENDCMD
+SKIP
+STRING "bar"
+SKIP
+ENDCMD
+SKIP
+PLUS
+SKIP
+STRING "AB5152"
+SKIP
+STRING "4142QR"
+SKIP
+STRING "ABお"
+SKIP
+STRING "�あいうえお"
+SKIP
+STRING "abc�えxyz"
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([@%:@! construct])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+#! /usr/bin/pspp
+#! /usr/bin/pspp
+])
+AT_DATA([expout], [dnl
+SKIP
+SKIP
+ID "#"
+UNEXPECTED_CHAR 33
+SKIP
+SLASH
+ID "usr"
+SLASH
+ID "bin"
+SLASH
+ID "pspp"
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([* and COMMENT commands])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+* Comment commands "don't
+have to contain valid tokens.
+
+** Check ambiguity with ** token.
+****************.
+
+comment keyword works too.
+COMM also.
+com is ambiguous with COMPUTE.
+
+   * Comment need not start at left margin.
+
+* Comment ends with blank line
+
+next command.
+
+])
+AT_DATA([expout], [dnl
+SKIP
+SKIP
+SKIP
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+SKIP
+ENDCMD
+SKIP
+SKIP
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+SKIP
+ENDCMD
+SKIP
+SKIP
+ENDCMD
+SKIP
+ID "com"
+SKIP
+ID "is"
+SKIP
+ID "ambiguous"
+SKIP
+WITH
+SKIP
+ID "COMPUTE"
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+SKIP
+SKIP
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+SKIP
+SKIP
+ENDCMD
+SKIP
+ID "next"
+SKIP
+ID "command"
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([DOCUMENT command])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+DOCUMENT one line.
+DOC more
+    than
+        one
+            line.
+docu
+first.paragraph
+isn't parsed as tokens
+
+second paragraph.
+])
+AT_DATA([expout], [dnl
+ID "DOCUMENT"
+STRING "DOCUMENT one line."
+ENDCMD
+ENDCMD
+SKIP
+ID "DOCUMENT"
+STRING "DOC more"
+SKIP
+STRING "    than"
+SKIP
+STRING "        one"
+SKIP
+STRING "            line."
+ENDCMD
+ENDCMD
+SKIP
+ID "DOCUMENT"
+STRING "docu"
+SKIP
+STRING "first.paragraph"
+SKIP
+STRING "isn't parsed as tokens"
+SKIP
+STRING ""
+SKIP
+STRING "second paragraph."
+ENDCMD
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([TITLE, SUBTITLE, FILE LABEL commands])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+title/**/'Quoted string title'.
+tit /*
+"Quoted string on second line".
+sub "Quoted string subtitle"
+ .
+
+TITL /* Not a */ quoted string title.
+SUBT Not a quoted string /* subtitle
+
+FIL label isn't quoted.
+FILE
+  lab 'is quoted'.
+FILE /*
+/**/  lab not quoted here either
+
+])
+AT_DATA([expout], [dnl
+ID "title"
+SKIP
+STRING "Quoted string title"
+ENDCMD
+SKIP
+ID "tit"
+SKIP
+SKIP
+SKIP
+STRING "Quoted string on second line"
+ENDCMD
+SKIP
+ID "sub"
+SKIP
+STRING "Quoted string subtitle"
+SKIP
+SKIP
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+ID "TITL"
+SKIP
+STRING "/* Not a */ quoted string title"
+ENDCMD
+SKIP
+ID "SUBT"
+SKIP
+STRING "Not a quoted string /* subtitle"
+SKIP
+ENDCMD
+SKIP
+ID "FIL"
+SKIP
+ID "label"
+SKIP
+STRING "isn't quoted"
+ENDCMD
+SKIP
+ID "FILE"
+SKIP
+SKIP
+ID "lab"
+SKIP
+STRING "is quoted"
+ENDCMD
+SKIP
+ID "FILE"
+SKIP
+SKIP
+SKIP
+SKIP
+SKIP
+ID "lab"
+SKIP
+STRING "not quoted here either"
+SKIP
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([BEGIN DATA command])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+begin data.
+123
+xxx
+end data.
+
+BEG /**/ DAT /*
+5 6 7 /* x
+
+end  data
+end data
+.
+])
+AT_DATA([expout], [dnl
+ID "begin"
+SKIP
+ID "data"
+ENDCMD
+SKIP
+STRING "123"
+SKIP
+STRING "xxx"
+SKIP
+ID "end"
+SKIP
+ID "data"
+ENDCMD
+SKIP
+ENDCMD
+SKIP
+ID "BEG"
+SKIP
+SKIP
+SKIP
+ID "DAT"
+SKIP
+SKIP
+SKIP
+STRING "5 6 7 /* x"
+SKIP
+STRING ""
+SKIP
+STRING "end  data"
+SKIP
+ID "end"
+SKIP
+ID "data"
+SKIP
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([DO REPEAT command])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+do repeat x=a b c
+          y=d e f.
+  do repeat a=1 thru 5.
+another command.
+second command
++ third command.
+end /* x */ /* y */ repeat print.
+end
+ repeat.
+])
+AT_DATA([expout], [dnl
+ID "do"
+SKIP
+ID "repeat"
+SKIP
+ID "x"
+EQUALS
+ID "a"
+SKIP
+ID "b"
+SKIP
+ID "c"
+SKIP
+SKIP
+ID "y"
+EQUALS
+ID "d"
+SKIP
+ID "e"
+SKIP
+ID "f"
+ENDCMD
+SKIP
+STRING "  do repeat a=1 thru 5."
+SKIP
+STRING "another command."
+SKIP
+STRING "second command"
+SKIP
+STRING "+ third command."
+SKIP
+STRING "end /* x */ /* y */ repeat print."
+SKIP
+ID "end"
+SKIP
+SKIP
+ID "repeat"
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-i])
+AT_CLEANUP
+\f
+AT_SETUP([batch mode])
+AT_KEYWORDS([scan])
+AT_DATA([input], [dnl
+first command
+     another line of first command
++  second command
+third command
+
+fourth command.
+   fifth command.
+])
+AT_DATA([expout], [dnl
+ID "first"
+SKIP
+ID "command"
+SKIP
+SKIP
+ID "another"
+SKIP
+ID "line"
+SKIP
+ID "of"
+SKIP
+ID "first"
+SKIP
+ID "command"
+SKIP
+ENDCMD
+SKIP
+ID "second"
+SKIP
+ID "command"
+SKIP
+ENDCMD
+ID "third"
+SKIP
+ID "command"
+SKIP
+ENDCMD
+SKIP
+ID "fourth"
+SKIP
+ID "command"
+ENDCMD
+SKIP
+SKIP
+ID "fifth"
+SKIP
+ID "command"
+ENDCMD
+SKIP
+STOP
+])
+PSPP_CHECK_SCAN([-b])
+AT_CLEANUP
diff --git a/tests/language/lexer/segment-test.c b/tests/language/lexer/segment-test.c
new file mode 100644 (file)
index 0000000..64243c8
--- /dev/null
@@ -0,0 +1,318 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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 <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistr.h>
+
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/misc.h"
+#include "language/lexer/segment.h"
+
+#include "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/progname.h"
+#include "gl/read-file.h"
+#include "gl/xalloc.h"
+
+/* -a/--auto, -b/--batch, -i/--interactive: syntax mode. */
+static enum segmenter_mode mode = SEG_MODE_AUTO;
+
+/* -v, --verbose: Print row and column information. */
+static bool verbose;
+
+/* -1, --one-byte: Feed in one byte at a time? */
+static bool one_byte;
+
+static const char *parse_options (int argc, char **argv);
+static void usage (void) NO_RETURN;
+
+int
+main (int argc, char *argv[])
+{
+  size_t offset, line_number, line_offset;
+  const char *file_name;
+  char *input;
+  struct segmenter s;
+  size_t length;
+  int prev_type;
+
+  set_program_name (argv[0]);
+  file_name = parse_options (argc, argv);
+
+  /* Read from stdin into 'input'.  Ensure that 'input' ends in a new-line
+     followed by a null byte. */
+  input = (!strcmp (file_name, "-")
+           ? fread_file (stdin, &length)
+           : read_file (file_name, &length));
+  if (input == NULL)
+    error (EXIT_FAILURE, errno, "reading %s failed", file_name);
+  input = xrealloc (input, length + 3);
+  if (length == 0 || input[length - 1] != '\n')
+    input[length++] = '\n';
+  input[length++] = '\0';
+
+  segmenter_init (&s, mode);
+
+  line_number = 1;
+  line_offset = 0;
+  prev_type = -1;
+  for (offset = 0; offset < length; )
+    {
+      enum segment_type type;
+      const char *type_name, *p;
+      int n;
+
+      if (one_byte)
+        {
+          int n_newlines = 0;
+          int i;
+
+          for (i = 0; i <= length - offset; i++)
+            {
+              /* Make a copy to ensure that segmenter_push() isn't actually
+                 looking ahead. */
+              char *copy;
+
+              if (i > 0 && input[offset + i - 1] == '\n')
+                n_newlines++;
+
+              copy = xmemdup (input + offset, i);
+              n = segmenter_push (&s, copy, i, &type);
+              free (copy);
+
+              if (n >= 0)
+                break;
+            }
+          assert (n_newlines <= 2);
+        }
+      else
+        n = segmenter_push (&s, input + offset, length - offset, &type);
+
+      if (n < 0)
+        error (EXIT_FAILURE, 0, "segmenter_push returned -1 at offset %zu",
+               offset);
+      assert (offset + n <= length);
+
+      if (type == SEG_NEWLINE)
+        assert ((n == 1 && input[offset] == '\n')
+                || (n == 2
+                    && input[offset] == '\r' && input[offset + 1] == '\n'));
+      else
+        assert (memchr (&input[offset], '\n', n) == NULL);
+
+      if (!verbose)
+        {
+          if (prev_type != SEG_SPACES && prev_type != -1
+              && type == SEG_SPACES && n == 1 && input[offset] == ' ')
+            {
+              printf ("    space\n");
+              offset++;
+              prev_type = -1;
+              continue;
+            }
+        }
+      if (prev_type != -1)
+        putchar ('\n');
+      prev_type = type;
+
+      if (verbose)
+        printf ("%2zu:%2zu: ", line_number, offset - line_offset);
+
+      type_name = segment_type_to_string (type);
+      for (p = type_name; *p != '\0'; p++)
+        putchar (tolower ((unsigned char) *p));
+      if (n > 0)
+        {
+          int i;
+
+          for (i = MIN (15, strlen (type_name)); i < 16; i++)
+            putchar (' ');
+          for (i = 0; i < n; )
+            {
+              const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
+              ucs4_t uc;
+              int mblen;
+
+              mblen = u8_mbtoucr (&uc, u_input + (offset + i), n - i);
+              if (mblen < 0)
+                {
+                  int j;
+
+                  mblen = u8_mbtouc (&uc, u_input + (offset + i), n - i);
+                  putchar ('<');
+                  for (j = 0; j < mblen; j++)
+                    {
+                      if (j > 0)
+                        putchar (' ');
+                      printf ("%02x", input[offset + i + j]);
+                    }
+                  putchar ('>');
+                }
+              else
+                {
+                  switch (uc)
+                    {
+                    case ' ':
+                      printf ("_");
+                      break;
+
+                    case '_':
+                      printf ("\\_");
+                      break;
+
+                    case '\\':
+                      printf ("\\\\");
+                      break;
+
+                    case '\t':
+                      printf ("\\t");
+                      break;
+
+                    case '\r':
+                      printf ("\\r");
+                      break;
+
+                    case '\n':
+                      printf ("\\n");
+                      break;
+
+                    case '\v':
+                      printf ("\\v");
+                      break;
+
+                    default:
+                      if (uc < 0x20 || uc == 0x00a0)
+                        printf ("<U+%04X>", uc);
+                      else
+                        fwrite (input + offset + i, 1, mblen, stdout);
+                      break;
+                    }
+                }
+
+              i += mblen;
+            }
+        }
+
+      offset += n;
+      if (type == SEG_NEWLINE)
+        {
+          enum prompt_style prompt;
+
+          line_number++;
+          line_offset = offset;
+
+          prompt = segmenter_get_prompt (&s);
+          printf (" (%s)\n", prompt_style_to_string (prompt));
+        }
+    }
+  putchar ('\n');
+
+  free (input);
+
+  return 0;
+}
+
+static const char *
+parse_options (int argc, char **argv)
+{
+  for (;;)
+    {
+      static const struct option options[] =
+        {
+          {"one-byte", no_argument, NULL, '1'},
+          {"auto", no_argument, NULL, 'a'},
+          {"batch", no_argument, NULL, 'b'},
+          {"interactive", no_argument, NULL, 'i'},
+          {"verbose", no_argument, NULL, 'v'},
+          {"help", no_argument, NULL, 'h'},
+          {NULL, 0, NULL, 0},
+        };
+
+      int c = getopt_long (argc, argv, "1abivh", options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case '1':
+          one_byte = true;
+          break;
+
+        case 'a':
+          mode = SEG_MODE_AUTO;
+          break;
+
+        case 'b':
+          mode = SEG_MODE_BATCH;
+          break;
+
+        case 'i':
+          mode = SEG_MODE_INTERACTIVE;
+          break;
+
+        case 'v':
+          verbose = true;
+          break;
+
+        case 'h':
+          usage ();
+
+        case 0:
+          break;
+
+        case '?':
+          exit (EXIT_FAILURE);
+          break;
+
+        default:
+          NOT_REACHED ();
+        }
+
+    }
+
+  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 breaking PSPP syntax into lexical segments\n\
+usage: %s [OPTIONS] INPUT\n\
+\n\
+Options:\n\
+  -1, --one-byte      feed one byte at a time\n\
+  -a, --auto          use \"auto\" syntax mode\n\
+  -b, --batch         use \"batch\" syntax mode\n\
+  -i, --interactive   use \"interactive\" syntax mode (default)\n\
+  -v, --verbose       include rows and column numbers in output\n\
+  -h, --help          print this help message\n",
+          program_name, program_name);
+  exit (EXIT_SUCCESS);
+}
diff --git a/tests/language/lexer/segment.at b/tests/language/lexer/segment.at
new file mode 100644 (file)
index 0000000..e1dd0b5
--- /dev/null
@@ -0,0 +1,1070 @@
+AT_BANNER([syntax segmentation])
+m4_define([PSPP_CHECK_SEGMENT],
+  [AT_CHECK([segment-test $1 input], [0], [expout])
+   AT_CHECK([segment-test -1 $1 input], [0], [expout])])
+\f
+AT_SETUP([identifiers])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+a ab abc abcd
+A AB ABC ABCD
+aB aBC aBcD
+$x $y $z
+grève@<00A0>@Ângstrom@<00A0>@poté
+#a #b #c ## #d
+@efg @ @@. @#@ @&t@
+## # #12345 #.#
+f@#_.#6
+GhIjK
+.x 1y _z
+])
+AT_DATA([expout], [dnl
+identifier      a    space
+identifier      ab    space
+identifier      abc    space
+identifier      abcd
+newline         \n (later)
+
+identifier      A    space
+identifier      AB    space
+identifier      ABC    space
+identifier      ABCD
+newline         \n (later)
+
+identifier      aB    space
+identifier      aBC    space
+identifier      aBcD
+newline         \n (later)
+
+identifier      $x    space
+identifier      $y    space
+identifier      $z
+newline         \n (later)
+
+identifier      grève
+spaces          <U+00A0>
+identifier      Ângstrom
+spaces          <U+00A0>
+identifier      poté
+newline         \n (later)
+
+identifier      #a    space
+identifier      #b    space
+identifier      #c    space
+identifier      ##    space
+identifier      #d
+newline         \n (later)
+
+identifier      @efg    space
+identifier      @    space
+identifier      @@.    space
+identifier      @#@    space
+newline         \n (later)
+
+identifier      ##    space
+identifier      #    space
+identifier      #12345    space
+identifier      #.#
+newline         \n (later)
+
+identifier      f@#\_.#6
+newline         \n (later)
+
+identifier      GhIjK
+newline         \n (later)
+
+start_command   .
+identifier      x    space
+number          1
+identifier      y    space
+unexpected_char \_
+identifier      z
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([identifiers that end in '.'])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+abcd. abcd.
+ABCD. ABCD.
+aBcD. aBcD. @&t@
+$y. $z. あいうえお.
+#c. #d..
+@@. @@....
+#.#.
+#abcd.
+.
+. @&t@
+LMNOP. @&t@
+QRSTUV./* end of line comment */
+qrstuv. /* end of line comment */
+QrStUv./* end of line comment */ @&t@
+wxyz./* unterminated end of line comment
+WXYZ. /* unterminated end of line comment
+WxYz./* unterminated end of line comment @&t@
+])
+AT_DATA([expout], [dnl
+identifier      abcd.    space
+identifier      abcd
+end_command     .
+newline         \n (first)
+
+identifier      ABCD.    space
+identifier      ABCD
+end_command     .
+newline         \n (first)
+
+identifier      aBcD.    space
+identifier      aBcD
+end_command     .    space
+newline         \n (first)
+
+identifier      $y.    space
+identifier      $z.    space
+identifier      あいうえお
+end_command     .
+newline         \n (first)
+
+identifier      #c.    space
+identifier      #d.
+end_command     .
+newline         \n (first)
+
+identifier      @@.    space
+identifier      @@...
+end_command     .
+newline         \n (first)
+
+identifier      #.#
+end_command     .
+newline         \n (first)
+
+identifier      #abcd
+end_command     .
+newline         \n (first)
+
+start_command   .
+newline         \n (first)
+
+start_command   .    space
+newline         \n (first)
+
+identifier      LMNOP
+end_command     .    space
+newline         \n (first)
+
+identifier      QRSTUV
+end_command     .
+comment         /*_end_of_line_comment_*/
+newline         \n (first)
+
+identifier      qrstuv
+end_command     .    space
+comment         /*_end_of_line_comment_*/
+newline         \n (first)
+
+identifier      QrStUv
+end_command     .
+comment         /*_end_of_line_comment_*/    space
+newline         \n (first)
+
+identifier      wxyz
+end_command     .
+comment         /*_unterminated_end_of_line_comment
+newline         \n (first)
+
+identifier      WXYZ
+end_command     .    space
+comment         /*_unterminated_end_of_line_comment
+newline         \n (first)
+
+identifier      WxYz
+end_command     .
+comment         /*_unterminated_end_of_line_comment_
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([reserved words])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+and or not eq ge gt le lt ne all by to with
+AND OR NOT EQ GE GT LE LT NE ALL BY TO WITH
+andx orx notx eqx gex gtx lex ltx nex allx byx tox withx
+and. with.
+])
+AT_DATA([expout], [dnl
+reserved_word   and    space
+reserved_word   or    space
+reserved_word   not    space
+reserved_word   eq    space
+reserved_word   ge    space
+reserved_word   gt    space
+reserved_word   le    space
+reserved_word   lt    space
+reserved_word   ne    space
+reserved_word   all    space
+reserved_word   by    space
+reserved_word   to    space
+reserved_word   with
+newline         \n (later)
+
+reserved_word   AND    space
+reserved_word   OR    space
+reserved_word   NOT    space
+reserved_word   EQ    space
+reserved_word   GE    space
+reserved_word   GT    space
+reserved_word   LE    space
+reserved_word   LT    space
+reserved_word   NE    space
+reserved_word   ALL    space
+reserved_word   BY    space
+reserved_word   TO    space
+reserved_word   WITH
+newline         \n (later)
+
+identifier      andx    space
+identifier      orx    space
+identifier      notx    space
+identifier      eqx    space
+identifier      gex    space
+identifier      gtx    space
+identifier      lex    space
+identifier      ltx    space
+identifier      nex    space
+identifier      allx    space
+identifier      byx    space
+identifier      tox    space
+identifier      withx
+newline         \n (later)
+
+identifier      and.    space
+reserved_word   with
+end_command     .
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([punctuation])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+~ & | = >= > <= < ~= <> ( ) , - + * / [[ ]] **
+~&|=>=><=<~=<>(),-+*/[[]]**
+])
+AT_DATA([expout], [dnl
+punct           ~    space
+punct           &    space
+punct           |    space
+punct           =    space
+punct           >=    space
+punct           >    space
+punct           <=    space
+punct           <    space
+punct           ~=    space
+punct           <>    space
+punct           (    space
+punct           )    space
+punct           ,    space
+punct           -    space
+punct           +    space
+punct           *    space
+punct           /    space
+punct           [[    space
+punct           ]]    space
+punct           **
+newline         \n (later)
+
+punct           ~
+punct           &
+punct           |
+punct           =
+punct           >=
+punct           >
+punct           <=
+punct           <
+punct           ~=
+punct           <>
+punct           (
+punct           )
+punct           ,
+punct           -
+punct           +
+punct           *
+punct           /
+punct           [[
+punct           ]]
+punct           **
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([numbers])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+0 1 01 001. 1.
+123. /* comment 1 */ /* comment 2 */
+.1 0.1 00.1 00.10
+5e1 6E-1 7e+1 6E+01 6e-03
+.3E1 .4e-1 .5E+1 .6e+01 .7E-03
+1.23e1 45.6E-1 78.9e+1 99.9E+01 11.2e-03
+. 1e e1 1e+ 1e-
+])
+AT_DATA([expout], [dnl
+number          0    space
+number          1    space
+number          01    space
+number          001.    space
+number          1
+end_command     .
+newline         \n (first)
+
+number          123
+end_command     .    space
+comment         /*_comment_1_*/    space
+comment         /*_comment_2_*/
+newline         \n (first)
+
+start_command   .
+number          1    space
+number          0.1    space
+number          00.1    space
+number          00.10
+newline         \n (later)
+
+number          5e1    space
+number          6E-1    space
+number          7e+1    space
+number          6E+01    space
+number          6e-03
+newline         \n (later)
+
+start_command   .
+number          3E1    space
+number          .4e-1    space
+number          .5E+1    space
+number          .6e+01    space
+number          .7E-03
+newline         \n (later)
+
+number          1.23e1    space
+number          45.6E-1    space
+number          78.9e+1    space
+number          99.9E+01    space
+number          11.2e-03
+newline         \n (later)
+
+start_command   .    space
+expected_exponent 1e    space
+identifier      e1    space
+expected_exponent 1e+    space
+expected_exponent 1e-
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([strings])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+'x' "y" 'abc'
+'Don''t' "Can't" 'Won''t'
+"""quoted""" '"quoted"'
+'' ""
+'missing end quote
+"missing double quote
+x"4142" X'5152'
+u'fffd' U"041"
++ new command
++ /* comment */ 'string continuation'
++ /* also a punctuator on blank line
+- 'new command'
+])
+AT_DATA([expout], [dnl
+quoted_string   'x'    space
+quoted_string   "y"    space
+quoted_string   'abc'
+newline         \n (later)
+
+quoted_string   'Don''t'    space
+quoted_string   "Can't"    space
+quoted_string   'Won''t'
+newline         \n (later)
+
+quoted_string   """quoted"""    space
+quoted_string   '"quoted"'
+newline         \n (later)
+
+quoted_string   ''    space
+quoted_string   ""
+newline         \n (later)
+
+expected_quote  'missing_end_quote
+newline         \n (later)
+
+expected_quote  "missing_double_quote
+newline         \n (later)
+
+hex_string      x"4142"    space
+hex_string      X'5152'
+newline         \n (later)
+
+unicode_string  u'fffd'    space
+unicode_string  U"041"
+newline         \n (later)
+
+start_command   +    space
+identifier      new    space
+identifier      command
+newline         \n (later)
+
+punct           +    space
+comment         /*_comment_*/    space
+quoted_string   'string_continuation'
+newline         \n (later)
+
+punct           +    space
+comment         /*_also_a_punctuator_on_blank_line
+newline         \n (later)
+
+start_command   -    space
+quoted_string   'new_command'
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([@%:@! construct])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+#! /usr/bin/pspp
+title my title.
+#! /usr/bin/pspp
+])
+AT_DATA([expout], [dnl
+shbang          #!_/usr/bin/pspp
+newline         \n (first)
+
+identifier      title    space
+unquoted_string my_title
+end_command     .
+newline         \n (first)
+
+identifier      #
+unexpected_char !    space
+punct           /
+identifier      usr
+punct           /
+identifier      bin
+punct           /
+identifier      pspp
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([* and COMMENT commands])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+* Comment commands "don't
+have to contain valid tokens.
+
+** Check ambiguity with ** token.
+****************.
+
+comment keyword works too.
+COMM also.
+com is ambiguous with COMPUTE.
+
+   * Comment need not start at left margin.
+
+* Comment ends with blank line
+
+next command.
+
+])
+AT_DATA([expout], [dnl
+comment_command *_Comment_commands_"don't
+newline         \n (COMMENT)
+
+comment_command have_to_contain_valid_tokens
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+comment_command **_Check_ambiguity_with_**_token
+end_command     .
+newline         \n (first)
+
+comment_command ****************
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+comment_command comment_keyword_works_too
+end_command     .
+newline         \n (first)
+
+comment_command COMM_also
+end_command     .
+newline         \n (first)
+
+identifier      com    space
+identifier      is    space
+identifier      ambiguous    space
+reserved_word   with    space
+identifier      COMPUTE
+end_command     .
+newline         \n (first)
+
+separate_commands 
+newline         \n (first)
+
+spaces          ___
+comment_command *_Comment_need_not_start_at_left_margin
+end_command     .
+newline         \n (first)
+
+separate_commands 
+newline         \n (first)
+
+comment_command *_Comment_ends_with_blank_line
+newline         \n (COMMENT)
+
+separate_commands
+newline         \n (first)
+
+identifier      next    space
+identifier      command
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([DOCUMENT command])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+DOCUMENT one line.
+DOC more
+    than
+        one
+            line.
+docu
+first.paragraph
+isn't parsed as tokens
+
+second paragraph.
+])
+AT_DATA([expout], [dnl
+start_document
+document        DOCUMENT_one_line.
+end_command     
+separate_commands
+newline         \n (first)
+
+start_document
+document        DOC_more
+newline         \n (DOCUMENT)
+
+document        ____than
+newline         \n (DOCUMENT)
+
+document        ________one
+newline         \n (DOCUMENT)
+
+document        ____________line.
+end_command     
+separate_commands
+newline         \n (first)
+
+start_document
+document        docu
+newline         \n (DOCUMENT)
+
+document        first.paragraph
+newline         \n (DOCUMENT)
+
+document        isn't_parsed_as_tokens
+newline         \n (DOCUMENT)
+
+document
+newline         \n (DOCUMENT)
+
+document        second_paragraph.
+end_command     
+separate_commands
+newline         \n (first)
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([TITLE, SUBTITLE, FILE LABEL commands])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+title/**/'Quoted string title'.
+tit /*
+"Quoted string on second line".
+sub "Quoted string subtitle"
+ .
+
+TITL /* Not a */ quoted string title.
+SUBT Not a quoted string /* subtitle
+
+FIL label isn't quoted.
+FILE
+  lab 'is quoted'.
+FILE /*
+/**/  lab not quoted here either
+
+])
+AT_DATA([expout], [dnl
+identifier      title
+comment         /**/
+quoted_string   'Quoted_string_title'
+end_command     .
+newline         \n (first)
+
+identifier      tit    space
+comment         /*
+newline         \n (later)
+
+quoted_string   "Quoted_string_on_second_line"
+end_command     .
+newline         \n (first)
+
+identifier      sub    space
+quoted_string   "Quoted_string_subtitle"
+newline         \n (later)
+    space
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      TITL    space
+unquoted_string /*_Not_a_*/_quoted_string_title
+end_command     .
+newline         \n (first)
+
+identifier      SUBT    space
+unquoted_string Not_a_quoted_string_/*_subtitle
+newline         \n (later)
+
+separate_commands
+newline         \n (first)
+
+identifier      FIL    space
+identifier      label    space
+unquoted_string isn't_quoted
+end_command     .
+newline         \n (first)
+
+identifier      FILE
+newline         \n (later)
+
+spaces          __
+identifier      lab    space
+quoted_string   'is_quoted'
+end_command     .
+newline         \n (first)
+
+identifier      FILE    space
+comment         /*
+newline         \n (later)
+
+comment         /**/
+spaces          __
+identifier      lab    space
+unquoted_string not_quoted_here_either
+newline         \n (later)
+
+separate_commands
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([BEGIN DATA command])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+begin data.
+end data.
+
+begin data. /*
+123
+xxx
+end data.
+
+BEG /**/ DAT /*
+5 6 7 /* x
+
+end  data
+end data
+.
+
+begin
+ data.
+data
+end data.
+
+begin data "xxx".
+begin data 123.
+not data
+])
+AT_DATA([expout], [dnl
+identifier      begin    space
+identifier      data
+end_command     .
+newline         \n (data)
+
+identifier      end    space
+identifier      data
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      begin    space
+identifier      data
+end_command     .    space
+comment         /*
+newline         \n (data)
+
+inline_data     123
+newline         \n (data)
+
+inline_data     xxx
+newline         \n (data)
+
+identifier      end    space
+identifier      data
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      BEG    space
+comment         /**/    space
+identifier      DAT    space
+comment         /*
+newline         \n (data)
+
+inline_data     5_6_7_/*_x
+newline         \n (data)
+
+inline_data     
+newline         \n (data)
+
+inline_data     end__data
+newline         \n (data)
+
+identifier      end    space
+identifier      data
+newline         \n (later)
+
+start_command   .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      begin
+newline         \n (later)
+    space
+identifier      data
+end_command     .
+newline         \n (data)
+
+inline_data     data
+newline         \n (data)
+
+identifier      end    space
+identifier      data
+end_command     .
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      begin    space
+identifier      data    space
+quoted_string   "xxx"
+end_command     .
+newline         \n (first)
+
+identifier      begin    space
+identifier      data    space
+number          123
+end_command     .
+newline         \n (first)
+
+reserved_word   not    space
+identifier      data
+newline         \n (later)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([DO REPEAT command])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+do repeat x=a b c
+          y=d e f.
+  do repeat a=1 thru 5.
+another command.
+second command
++ third command.
+end /* x */ /* y */ repeat print.
+end
+ repeat.
+do
+  repeat #a=1.
+  inner command.
+end repeat.
+])
+AT_DATA([expout], [dnl
+identifier      do    space
+identifier      repeat    space
+identifier      x
+punct           =
+identifier      a    space
+identifier      b    space
+identifier      c
+newline         \n (later)
+
+spaces          __________
+identifier      y
+punct           =
+identifier      d    space
+identifier      e    space
+identifier      f
+end_command     .
+newline         \n (DO REPEAT)
+
+do_repeat_command __do_repeat_a=1_thru_5.
+newline         \n (DO REPEAT)
+
+do_repeat_command another_command.
+newline         \n (DO REPEAT)
+
+do_repeat_command second_command
+newline         \n (DO REPEAT)
+
+do_repeat_command +_third_command.
+newline         \n (DO REPEAT)
+
+do_repeat_command end_/*_x_*/_/*_y_*/_repeat_print.
+newline         \n (DO REPEAT)
+
+identifier      end
+newline         \n (later)
+    space
+identifier      repeat
+end_command     .
+newline         \n (first)
+
+identifier      do
+newline         \n (later)
+
+spaces          __
+identifier      repeat    space
+identifier      #a
+punct           =
+number          1
+end_command     .
+newline         \n (DO REPEAT)
+
+do_repeat_command __inner_command.
+newline         \n (DO REPEAT)
+
+identifier      end    space
+identifier      repeat
+end_command     .
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-i])
+AT_CLEANUP
+\f
+AT_SETUP([batch mode])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+first command
+     another line of first command
++  second command
+third command
+
+fourth command.
+   fifth command.
+])
+AT_DATA([expout], [dnl
+identifier      first    space
+identifier      command
+newline         \n (later)
+
+spaces          _____
+identifier      another    space
+identifier      line    space
+identifier      of    space
+identifier      first    space
+identifier      command
+newline         \n (later)
+
+start_command   +
+spaces          __
+identifier      second    space
+identifier      command
+newline         \n (later)
+
+start_command
+identifier      third    space
+identifier      command
+newline         \n (later)
+
+separate_commands
+newline         \n (first)
+
+identifier      fourth    space
+identifier      command
+end_command     .
+newline         \n (first)
+
+spaces          ___
+identifier      fifth    space
+identifier      command
+end_command     .
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-b])
+AT_CLEANUP
+\f
+AT_SETUP([auto mode])
+AT_KEYWORDS([segment])
+AT_DATA([input], [dnl
+command
+     another line of command
+2sls
++  another command
+another line of second command
+data list /x 1
+aggregate.
+print eject.
+twostep cluster
+
+
+fourth command.
+   fifth command.
+])
+AT_DATA([expout], [dnl
+identifier      command
+newline         \n (later)
+
+spaces          _____
+identifier      another    space
+identifier      line    space
+identifier      of    space
+identifier      command
+newline         \n (later)
+
+start_command
+number          2
+identifier      sls
+newline         \n (later)
+
+start_command   +
+spaces          __
+identifier      another    space
+identifier      command
+newline         \n (later)
+
+identifier      another    space
+identifier      line    space
+identifier      of    space
+identifier      second    space
+identifier      command
+newline         \n (later)
+
+start_command
+identifier      data    space
+identifier      list    space
+punct           /
+identifier      x    space
+number          1
+newline         \n (later)
+
+start_command
+identifier      aggregate
+end_command     .
+newline         \n (first)
+
+identifier      print    space
+identifier      eject
+end_command     .
+newline         \n (first)
+
+identifier      twostep    space
+identifier      cluster
+newline         \n (later)
+
+separate_commands
+newline         \n (first)
+
+separate_commands
+newline         \n (first)
+
+identifier      fourth    space
+identifier      command
+end_command     .
+newline         \n (first)
+
+spaces          ___
+identifier      fifth    space
+identifier      command
+end_command     .
+newline         \n (first)
+
+end             <U+0000>
+])
+PSPP_CHECK_SEGMENT([-a])
+AT_CLEANUP
index da078f84d1ff298bf4355bf774c21216416ce46f..ae7a38ad8376129af2cbb8d7ea392dd28c9ee91b 100644 (file)
@@ -4,7 +4,7 @@ dnl CHECK_AGGREGATE(OUTFILE, SORT, MISSING)
 dnl
 dnl Checks the AGGREGATE procedure with the specified combination of:
 dnl
-dnl - OUTFILE: One of "scratch", "active", or "external" according to
+dnl - OUTFILE: One of "dataset", "active", or "external" according to
 dnl   where AGGREGATE's output should be directed.
 dnl 
 dnl - SORT: Either "presorted" or "unsorted" according to whether
@@ -33,11 +33,12 @@ m4_define([CHECK_AGGREGATE], [
     [DATA LIST NOTABLE FILE='aggregate.data' /G N 1-2 S 3(a) W 4.
 WEIGHT BY w.
 MISSING VALUES n(4) s('4').
+m4_if([$1], [dataset], [DATASET DECLARE aggregate.])
 m4_if([$2], [presorted], [SORT CASES BY g.])
 AGGREGATE dnl
 m4_if([$1], [active], [OUTFILE=*],
       [$1], [external], [OUTFILE='aggregate.sys'],
-      [outfile=@%:@AGGREGATE]) dnl
+      [outfile=aggregate]) dnl
 m4_if([$2], [presorted], [/PRESORTED]) dnl
 m4_if([$3], [columnwise], [/MISSING=COLUMNWISE])
        /DOCUMENT
@@ -119,7 +120,7 @@ m4_if([$3], [columnwise], [/MISSING=COLUMNWISE])
        /NSUM = sum(n)
        /NSUMI = sum.(n).
 m4_if([$1], [external], [GET FILE='aggregate.sys'.],
-      [$1], [scratch], [GET FILE=@%:@AGGREGATE.])
+      [$1], [dataset], [DATASET ACTIVATE aggregate.])
 LIST.
 ])
   AT_CHECK([pspp -O format=csv aggregate.sps], [0], [stdout])
@@ -157,10 +158,10 @@ G,N,NI,NU,NUI,NFGT2,NFGT2I,SFGT2,SFGT2I,NFIN23,NFIN23I,SFIN23,SFIN23I,NFLT2,NFLT
 ])])
   AT_CLEANUP])
 
-CHECK_AGGREGATE([scratch], [presorted], [itemwise])
-CHECK_AGGREGATE([scratch], [presorted], [columnwise])
-CHECK_AGGREGATE([scratch], [unsorted], [itemwise])
-CHECK_AGGREGATE([scratch], [unsorted], [columnwise])
+CHECK_AGGREGATE([dataset], [presorted], [itemwise])
+CHECK_AGGREGATE([dataset], [presorted], [columnwise])
+CHECK_AGGREGATE([dataset], [unsorted], [itemwise])
+CHECK_AGGREGATE([dataset], [unsorted], [columnwise])
 CHECK_AGGREGATE([active], [presorted], [itemwise])
 CHECK_AGGREGATE([active], [presorted], [columnwise])
 CHECK_AGGREGATE([active], [unsorted], [itemwise])
@@ -283,9 +284,6 @@ AGGREGATE OUTFILE=* MODE=ADDVARIABLES
 
 AT_CHECK([pspp -O format=csv dup-variables.sps], [1],
 ["dup-variables.sps:24: error: AGGREGATE: Variable name N_BREAK is not unique within the aggregate file dictionary, which contains the aggregate variables and the break variables."
-
-dup-variables.sps:24: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 ])
 
-
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
index bd9d59f7c45dfaa2259e7abe15c2e0684b0728c5..7f5e6eb376aec3e421bc4f4490a791bb56083d14 100644 (file)
@@ -100,10 +100,10 @@ new,Format: F8.2,,3
 ,Measure: Scale,,
 ,Display Alignment: Right,,
 ,Display Width: 8,,
-,1,oojars,
-,2,oojimiflips,
-,3,thingummies,
-,4,widgets,
+,1.00,oojars,
+,2.00,oojimiflips,
+,3.00,thingummies,
+,4.00,widgets,
 ])
 
 AT_CLEANUP
index e464d84631b4fd65940cf554d6e27d56c8c7210e..eb511ced68140f966d28ade35971fedac373f0a6 100644 (file)
@@ -299,7 +299,7 @@ END DATA.
 LIST.
 
 
-CROSSTABS TABLES  x by y by z.
+CROSSTABS TABLES  x BY y BY z/STATISTICS=ALL.
 ]])
 AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
   [[Table: Reading 1 record from INLINE.
@@ -340,5 +340,125 @@ Total,,4.0,1.0,5.0
 ,6,1.0,.0,1.0
 ,9,1.0,.0,1.0
 Total,,3.0,1.0,4.0
+
+Table: Chi-square tests.
+z,Statistic,Value,df,Asymp. Sig. (2-tailed)
+1,Pearson Chi-Square,5.00,4,.29
+,Likelihood Ratio,5.00,4,.29
+,Linear-by-Linear Association,.01,1,.94
+,N of Valid Cases,5,,
+2,Pearson Chi-Square,4.00,3,.26
+,Likelihood Ratio,4.50,3,.21
+,Linear-by-Linear Association,1.58,1,.21
+,N of Valid Cases,4,,
+
+Table: Symmetric measures.
+z,Category,Statistic,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+1,Nominal by Nominal,Phi,1.00,,,
+,,Cramer's V,1.00,,,
+,,Contingency Coefficient,.71,,,
+,Ordinal by Ordinal,Kendall's tau-b,.00,.32,.00,
+,,Kendall's tau-c,.00,.32,.00,
+,,Gamma,.00,.50,.00,
+,,Spearman Correlation,.00,.22,.00,
+,Interval by Interval,Pearson's R,.04,.22,.18,
+,N of Valid Cases,,5,,,
+2,Nominal by Nominal,Phi,1.00,,,
+,,Cramer's V,1.00,,,
+,,Contingency Coefficient,.71,,,
+,Ordinal by Ordinal,Kendall's tau-b,-.71,.20,-1.73,
+,,Kendall's tau-c,-.75,.43,-1.73,
+,,Gamma,-1.00,.00,-1.73,
+,,Spearman Correlation,-.77,.17,-6.77,
+,Interval by Interval,Pearson's R,-.73,.18,-5.49,
+,N of Valid Cases,,4,,,
+
+Table: Directional measures.
+z,Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
+1,Nominal by Nominal,Lambda,Symmetric,.40,.28,1.02,
+,,,x Dependent,.25,NaN,1.12,
+,,,y Dependent,1.00,NaN,1.12,
+,,Goodman and Kruskal tau,x Dependent,.25,,,
+,,,y Dependent,1.00,,,
+,,Uncertainty Coefficient,Symmetric,.47,.18,1.51,
+,,,x Dependent,.31,.15,2.02,
+,,,y Dependent,1.00,.00,2.02,
+,Ordinal by Ordinal,Somers' d,Symmetric,.00,.09,.00,
+,,,x Dependent,.00,.50,.00,
+,,,y Dependent,.00,.20,.00,
+,Nominal by Interval,Eta,x Dependent,.04,,,
+,,,y Dependent,1.00,,,
+2,Nominal by Nominal,Lambda,Symmetric,.50,.25,1.51,
+,,,x Dependent,.33,NaN,1.15,
+,,,y Dependent,1.00,NaN,1.15,
+,,Goodman and Kruskal tau,x Dependent,.33,,,
+,,,y Dependent,1.00,,,
+,,Uncertainty Coefficient,Symmetric,.58,.17,1.56,
+,,,x Dependent,.41,.17,2.36,
+,,,y Dependent,1.00,.00,2.36,
+,Ordinal by Ordinal,Somers' d,Symmetric,-.67,.04,-1.73,
+,,,x Dependent,-1.00,.00,-1.73,
+,,,y Dependent,-.50,.29,-1.73,
+,Nominal by Interval,Eta,x Dependent,.73,,,
+,,,y Dependent,1.00,,,
+]])
+AT_CLEANUP
+
+
+
+AT_SETUP([CROSSTABS descending sort order])
+AT_DATA([crosstabs-descending.sps],
+  [[DATA LIST NOTABLE LIST /x * y *.
+BEGIN DATA.
+2 2
+2 2
+3 1
+4 1
+3 2
+3 2
+END DATA.
+
+CROSSTABS
+        /TABLES= x BY y
+       /FORMAT = DVALUE.
+]])
+
+AT_CHECK([pspp -O format=csv crosstabs-descending.sps], [0],
+  [[Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,6,100.0%,0,0.0%,6,100.0%
+
+Table: x * y [count].
+,y,,
+x,2.00,1.00,Total
+4.00,.0,1.0,1.0
+3.00,2.0,1.0,3.0
+2.00,2.0,.0,2.0
+Total,4.0,2.0,6.0
 ]])
 AT_CLEANUP
+
+# Bug #31260.
+AT_SETUP([CROSSTABS crash when all cases missing])
+AT_DATA([crosstabs.sps], [dnl
+DATA LIST LIST NOTABLE /X1 X2.
+BEGIN DATA.
+1 1
+END DATA.
+
+MISSING VALUES x2 (1).
+
+CROSSTABS /TABLES= X1 by X2.
+])
+AT_CHECK([pspp -O format=csv crosstabs.sps], [0], [dnl
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+X1 * X2,0,0.0%,1,100.0%,1,100.0%
+
+crosstabs.sps:8: warning: CROSSTABS: Crosstabulation X1 * X2 contained no non-missing cases.
+])
+AT_CLEANUP
index cfd992a59d34282f08e40cd11922b5f4d96d9367..9eae09e8364e974c447f4be8505abd9190323788 100644 (file)
@@ -70,7 +70,7 @@ Total,,4,100.0,100.0,
 AT_CLEANUP
 
 # Tests for a bug where PSPP would crash when a FREQUENCIES command
-# was used with the HTML output driver..
+# was used with the HTML output driver.
 AT_SETUP([FREQUENCIES HTML output crash])
 AT_DATA([frequencies.sps],
   [data list free /v1 v2.
@@ -105,7 +105,7 @@ AT_CHECK([test -s pspp.html])
 AT_CLEANUP
 
 # Tests for a bug which crashed PSPP when a piechart with too many
-# segments was requested..
+# segments was requested.
 AT_SETUP([FREQUENCIES pie chart crash])
 AT_DATA([frequencies.sps],
   [data list list /x * w *.
@@ -130,9 +130,7 @@ frequencies /x /format=notable /statistics=none
 ])
 # Cannot use the CSV driver for this because it does not output charts
 # at all.
-AT_CHECK([pspp frequencies.sps], [0],
-  [DATA LIST
-
+AT_CHECK([pspp frequencies.sps], [0], [dnl
 Reading free-form data from INLINE.
 +--------+------+
 |Variable|Format|
@@ -140,17 +138,36 @@ Reading free-form data from INLINE.
 |x       |F8.0  |
 |w       |F8.0  |
 +--------+------+
+])
+AT_CLEANUP
 
-BEGIN DATA
+# Tests for a bug which crashed PSPP when the median and a histogram
+# were both requested.
+AT_SETUP([FREQUENCIES median with histogram crash])
+AT_DATA([frequencies.sps], [dnl
+data list list notable /x.
+begin data.
+1
+end data.
 
-WEIGHT
+frequencies /x /histogram /STATISTICS=median.
+])
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: x
+Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
+,1.00,1,100.00,100.00,100.00
+Total,,1,100.0,100.0,
 
-FREQUENCIES
+Table: x
+N,Valid,1
+,Missing,0
+S.E. Kurt,,.00
+,50 (Median),1.00
 ])
 AT_CLEANUP
 
 # Tests for a bug which caused FREQUENCIES following TEMPORARY to
-# crash (bug #11492)..
+# crash (bug #11492).
 AT_SETUP([FREQUENCIES crash after TEMPORARY])
 AT_DATA([frequencies.sps],
   [DATA LIST LIST /SEX (A1) X *.
@@ -419,6 +436,47 @@ Percentiles,0,1.00
 ])
 AT_CLEANUP
 
+dnl Data for this test case from Fabio Bordignon <bordignon@demos.it>.
+AT_SETUP([FREQUENCIES enhanced percentiles, weighted (3)])
+AT_DATA([frequencies.sps],
+  [DATA LIST LIST notable /X * F *.
+BEGIN DATA.
+1 7
+2 16
+3 12
+4 5
+END DATA.
+
+WEIGHT BY f.
+
+FREQUENCIES 
+       VAR=x
+       /PERCENTILES = 0 25 50 75 100.
+])
+AT_CHECK([pspp -O format=csv frequencies.sps], [0], [dnl
+Table: X
+Value Label,Value,Frequency,Percent,Valid Percent,Cum Percent
+,1.00,7.00,17.50,17.50,17.50
+,2.00,16.00,40.00,40.00,57.50
+,3.00,12.00,30.00,30.00,87.50
+,4.00,5.00,12.50,12.50,100.00
+Total,,40.00,100.0,100.0,
+
+Table: X
+N,Valid,40.00
+,Missing,.00
+Mean,,2.38
+Std Dev,,.93
+Minimum,,1.00
+Maximum,,4.00
+Percentiles,0,1.00
+,25,2.00
+,50 (Median),2.00
+,75,3.00
+,100,4.00
+])
+AT_CLEANUP
+
 AT_SETUP([FREQUENCIES enhanced percentiles, weighted, missing values])
 AT_DATA([frequencies.sps],
   [DATA LIST LIST notable /X * F *.
index 83701276644f5e3deb5f1537f1032007163ead52..57193c00685249db3f24bbbbf8e064bc6144a422 100644 (file)
@@ -610,7 +610,9 @@ npar tests
        .
 ])
 AT_CHECK([pspp -o pspp.csv npar.sps])
-AT_CHECK([cat pspp.csv], [0], [dnl
+dnl Some machines return .313 instead of .312 for the Point Probability
+dnl (see bug #31611).
+AT_CHECK([sed 's/\.313$/.312/' pspp.csv], [0], [dnl
 Table: Frequencies
 ,,N
 height - age,Negative Differences,1
@@ -789,4 +791,305 @@ df,,2,2,
 Asymp. Sig.,,.041,.041,
 ])
 
-AT_CLEANUP
\ No newline at end of file
+AT_CLEANUP
+
+
+
+AT_SETUP([NPAR TESTS Runs])
+AT_DATA([npar-runs.sps], [dnl
+set format F11.4.
+data list notable list /score * w *.
+begin data
+4     6
+.     4
+4     3 
+3    20 
+2    29 
+1    42 
+6    18 
+5     7 
+6    78 
+5    10 
+6    46 
+5     5 
+6    17 
+5     1 
+6    11 
+4     2 
+3     7 
+2     6 
+1    10 
+4    13 
+3    22 
+3    11 
+2    24 
+1    18 
+4     4 
+3    12 
+2    10 
+1    25 
+4     4 
+3     7 
+2     3 
+1     4 
+4     2 
+3     3 
+2     2 
+1     4 
+end data.
+
+weight by w.
+
+npar tests
+       /runs (MEDIAN) = score
+       /runs (MEAN) = score
+       /runs (MODE) = score 
+       .
+])
+
+AT_CHECK([pspp -o pspp.csv npar-runs.sps])
+
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Runs Test
+,score
+Test Value (median),3.0000
+Cases < Test Value,177.0000
+Cases >= Test Value,309.0000
+Total Cases,486.0000
+Number of Runs,12
+Z,-20.9931
+Asymp. Sig. (2-tailed),.0000
+
+Table: Runs Test
+,score
+Test Value (mean),3.6379
+Cases < Test Value,259.0000
+Cases >= Test Value,227.0000
+Total Cases,486.0000
+Number of Runs,12
+Z,-21.0650
+Asymp. Sig. (2-tailed),.0000
+
+Table: Runs Test
+,score
+Test Value (mode),6.0000
+Cases < Test Value,316.0000
+Cases >= Test Value,170.0000
+Total Cases,486.0000
+Number of Runs,11
+Z,-21.0742
+Asymp. Sig. (2-tailed),.0000
+])
+
+AT_CLEANUP
+
+
+AT_SETUP([NPAR TESTS Friedman])
+AT_DATA([npar-friedman.sps], [dnl
+set format F15.4.
+data list notable list /x * y * z.
+begin data
+9.5 6.5        8.1
+8.0 6.0        6.0
+7.0 6.5        4.2
+9.5 5.0        7.3
+9.0 7.0 6.2
+8.5 6.9        6.5
+7.5 8.0        6.5
+6.0 8.0        3.1
+5.0 6.0        4.9
+7.5 7.5        6.2
+end data.
+
+npar tests
+     /friedman = x y z.
+])
+
+AT_CHECK([pspp -o pspp.csv npar-friedman.sps])
+
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Ranks
+,Mean Rank
+x,2.6500
+y,2.1000
+z,1.2500
+
+Table: Test Statistics
+N,10
+Chi-Square,10.4737
+df,2
+Asymp. Sig.,.0053
+])
+
+AT_CLEANUP
+
+
+
+AT_SETUP([NPAR TESTS Mann-Whitney])
+AT_DATA([npar-mann-whitney.sps], [dnl
+SET FORMAT     = F11.4
+
+data list notable list /height * sex (f1.0).
+begin data.
+201 1            
+84 1            
+83 1            
+94 1            
+88 0            
+99 0            
+55 0            
+69 0            
+86 1            
+79 1            
+91 0            
+201 0            
+88 1            
+85 1            
+82 1            
+88 0            
+75 0            
+99 0            
+81 0            
+72 1            
+89 1            
+92 1            
+80 0            
+82 0            
+76 0            
+65 0            
+85 0            
+76 1            
+145 1            
+24 1            
+end data.
+
+NPAR TESTS 
+     /M-W = height BY sex (0,1).
+])
+
+AT_CHECK([pspp -o pspp.csv npar-mann-whitney.sps])
+
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Ranks
+,N,,,Mean Rank,,Sum of Ranks,
+,0,1,Total,0,1,0,1
+height,15.0000,15.0000,30.0000,14.5333,16.4667,218.0000,247.0000
+
+Table: Test Statistics
+,Mann-Whitney U,Wilcoxon W,Z,Asymp. Sig. (2-tailed)
+height,98.0000,218.0000,-.6020,.5472
+])
+
+
+AT_CLEANUP
+
+
+AT_SETUP([NPAR TESTS Cochran])
+AT_DATA([npar-cochran.sps], [dnl
+set format f11.3.
+
+data list notable list /v1 * v2 * v3 * v4 * v5 * v6 * v7 *.
+begin data.
+2 1 1 2 1 1 2 
+2 2 2 2 1 1 1  
+1 1 2 2 1 1 2  
+2 2 2 2 1 1 2 
+2 1 2 1 1 2 1 
+1 2 2 1 1 1 1 
+1 2 2 2 2 2 2 
+2 2 1 2 1 1 1 
+1 2 1 2 1 1 2 
+end data.     
+
+npar tests 
+       /cochran = v1 to v7 .
+
+])
+
+AT_CHECK([pspp -o pspp.csv npar-cochran.sps])
+
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Frequencies
+,Value,
+,Success (2),Failure (1)
+v1,5,4
+v2,6,3
+v3,6,3
+v4,7,2
+v5,1,8
+v6,2,7
+v7,5,4
+
+Table: Test Statistics
+N,9
+Cochran's Q,12.735
+df,6
+Asymp. Sig.,.047
+])
+
+AT_CLEANUP
+
+
+
+AT_SETUP([NPAR TESTS Kendall])
+AT_DATA([npar-kendall.sps], [dnl
+SET FORMAT F14.3.
+
+data list notable list /v1 * v2 * v3
+begin data.
+ 7  7  2 
+ 5  6  5 
+ 8  6  4 
+ 5  7  4 
+ 5  4  4 
+ 8  6  5 
+ 6  3  5 
+ 7  6  5 
+ 8  5  5
+ .  2  2 
+ 5  4  5 
+ 3  4  4 
+ 5  1  2 
+ 5  2  1 
+ 7  6  5 
+ 6  3  4 
+ 6  6  6 
+ 5  4  5 
+ 4  3  4 
+ 9  1  1 
+ 6  2  1 
+ 3  7  8 
+ 6  3  4 
+ 4  4  4 
+ 5  4  3 
+ 6  5  2 
+ 4  4  8 
+ 4  6  4 
+ 6  5  5 
+ 7  8  6 
+ 5  3  5 
+end data.
+
+npar tests
+       /kendall = all
+       .
+])
+
+AT_CHECK([pspp -o pspp.csv npar-kendall.sps])
+
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Ranks
+,Mean Rank
+v1,2.500
+v2,1.817
+v3,1.683
+
+Table: Test Statistics
+N,30
+Kendall's W,.233
+Chi-Square,13.960
+df,2
+Asymp. Sig.,.001
+])
+
+AT_CLEANUP
index 1649e5ee457ba26a18cf831a9deea967f8976f5d..a0a3bafb745abeff97c97e06f8213a0bb328543c 100644 (file)
@@ -414,9 +414,9 @@ ONEWAY x y z by g
        /CONTRAST 2 -9 7  0
        .
 ])
-
-
-AT_CHECK([pspp -O format=csv multivar.sps], [0], 
+AT_CHECK([pspp -o pspp.csv multivar.sps])
+dnl Some machines return 3.88 instead of 3.87 below (see bug #31611).
+AT_CHECK([sed 's/^,Within Groups,3.88/,Within Groups,3.87/' pspp.csv], [0],
 [Table: Descriptives
 ,,,,,,95% Confidence Interval for Mean,,,
 ,,N,Mean,Std. Deviation,Std. Error,Lower Bound,Upper Bound,Minimum,Maximum
diff --git a/tests/language/stats/quick-cluster.at b/tests/language/stats/quick-cluster.at
new file mode 100644 (file)
index 0000000..ce28829
--- /dev/null
@@ -0,0 +1,74 @@
+AT_BANNER([QUICK CLUSTER])
+
+AT_SETUP([QUICK CLUSTER with small data set])
+AT_DATA([quick-cluster.sps], [dnl
+DATA LIST LIST /x y z.
+BEGIN DATA.
+22,2930,4099
+17,3350,4749
+22,2640,3799
+20, 3250,4816
+15,4080,7827
+4,5,4
+5,6,5
+6,7,6
+7,8,7
+8,9,8
+9,10,9
+END DATA.
+QUICK CLUSTER x y z
+  /CRITERIA=CLUSTER(2) MXITER(20).
+])
+AT_CHECK([pspp -o pspp.csv quick-cluster.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Reading free-form data from INLINE.
+Variable,Format
+x,F8.0
+y,F8.0
+z,F8.0
+
+Table: Final Cluster Centers
+,Cluster,
+,,
+,1,2
+,,
+x,6.50,19.20
+y,7.50,3250.00
+z,6.50,5058.00
+
+Table: Number of Cases in each Cluster
+Cluster,1,6
+,2,5
+Valid,,11
+])
+AT_CLEANUP
+
+AT_SETUP([QUICK CLUSTER with large data set])
+AT_DATA([quick-cluster.sps], [dnl
+input program.
+loop #i = 1 to 500000.
+compute x = 3.
+end case.
+end loop.
+end file.
+end input program.
+QUICK CLUSTER x /CRITERIA = CLUSTER(4) MXITER (100).
+])
+AT_CHECK([pspp -o pspp.csv quick-cluster.sps])
+AT_CHECK([cat pspp.csv], [0], [dnl
+Table: Final Cluster Centers
+,Cluster,,,
+,,,,
+,1,2,3,4
+,,,,
+x,.00,.00,.00,3.00
+
+Table: Number of Cases in each Cluster
+Cluster,1,0
+,2,0
+,3,0
+,4,500000
+Valid,,500000
+])
+AT_CLEANUP
+
index ac44189c25b3588446ffd9325c48d16b72ee69f1..6cb366849b88da1e6c7664593ee3c2043cb0a93e 100644 (file)
@@ -538,7 +538,7 @@ Variables Created By RANK
 
 x into Rx(RANK of x)
 
-rank.sps:14: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
+rank.sps:14: error: RANK: DEBUG XFORM FAIL transformation executed
 ])
 AT_CLEANUP
 
@@ -576,9 +576,9 @@ RANK x
  /RANK INTO foo  bar wiz.
 ])
 AT_CHECK([pspp -O format=csv rank.sps], [1], [dnl
-rank.sps:15: error: RANK: Syntax error at end of command: expecting `@{:@'.
+rank.sps:15.1: error: RANK: Syntax error at end of command: expecting `@{:@'.
 
-rank.sps:19: error: RANK: Syntax error at `d': expecting integer.
+rank.sps:19.11: error: RANK: Syntax error at `d': expecting integer.
 
 rank.sps:25: error: RANK: Variable x already exists.
 
index 11ce07fa7aa672f6a8cc6137084313d5f6749cd8..0ea3efc8a256aabf1bbe963e38d1d80cfa818d70 100644 (file)
@@ -38,7 +38,7 @@ Table: ANOVA
 
 Table: Coefficients
 ,,B,Std. Error,Beta,t,Significance
-,(Constant),2.19,2.36,.00,.93,.52
+,(Constant),2.19,2.36,.00,.93,.38
 ,v0,1.81,1.05,.17,1.72,.12
 ,v1,-3.43,.33,-1.03,-10.33,.00
 ,,,,,,
@@ -1585,7 +1585,7 @@ Table: ANOVA
 
 Table: Coefficients
 ,,B,Std. Error,Beta,t,Significance
-,(Constant),1.24,.42,.00,2.95,.21
+,(Constant),1.24,.42,.00,2.95,.00
 ,v1,1.37,.72,.05,1.89,.06
 ,,,,,,
 ])
index d06f2b2901e7ab33bb32111ee43b0b1c14369000..b000cb56ef36d24b5f2f0fd059a1757be04ad1ef 100644 (file)
@@ -46,7 +46,7 @@ m4_define([SORT_CASES_TEST],
    AT_CAPTURE_FILE([sort-cases.sps])
    AT_DATA([sort-cases.sps], [dnl
 DATA LIST LIST NOTABLE FILE='data.txt'/x y (F8).
-SORT BY x[]m4_if([$3], [], [], [/BUFFERS=$3]).
+SORT CASES BY x[]m4_if([$3], [], [], [/BUFFERS=$3]).
 PRINT OUTFILE='output.txt'/x y.
 EXECUTE.
 ])
@@ -80,3 +80,51 @@ SORT_CASES_TEST(10000, 5, 500)
 
 SORT_CASES_TEST(50000, 1)
 
+dnl Bug #33089 caused SORT CASES to delete filtered cases permanently.
+AT_SETUP([SORT CASES preserves filtered cases])
+AT_DATA([sort-cases.sps], [dnl
+DATA LIST FREE /x.
+BEGIN DATA.
+5 4 3 2 1 0
+END DATA.
+COMPUTE mod2 = MOD(x, 2).
+LIST.
+FILTER BY mod2.
+LIST.
+SORT CASES BY x.
+LIST.
+FILTER OFF.
+LIST.
+])
+AT_CHECK([pspp -O format=csv sort-cases.sps], [0], [dnl
+Table: Data List
+x,mod2
+5.00,1.00
+4.00,.00
+3.00,1.00
+2.00,.00
+1.00,1.00
+.00,.00
+
+Table: Data List
+x,mod2
+5.00,1.00
+3.00,1.00
+1.00,1.00
+
+Table: Data List
+x,mod2
+1.00,1.00
+3.00,1.00
+5.00,1.00
+
+Table: Data List
+x,mod2
+.00,.00
+1.00,1.00
+2.00,.00
+3.00,1.00
+4.00,.00
+5.00,1.00
+])
+AT_CLEANUP
index 80519fab2cc5566b52b73f72f65e1461f25cdce9..90b7ba9e594e7efc9c3d731af72402ed75323870 100644 (file)
@@ -1,4 +1,4 @@
-AT_BANNER([T-TEST])
+/AT_BANNER([T-TEST])
 
 AT_SETUP([T-TEST /PAIRS])
 AT_DATA([t-test.sps], [dnl
@@ -93,7 +93,7 @@ begin data.
 end data.
 
 
-t-test /MISSING=analysis /PAIRS a c with b d (PAIRED). 
+t-test /MISSING=analysis /PAIRS a c with b d (PAIRED) /CRITERIA=CIN(0.95)
 ])
 AT_CHECK([pspp -o missing.csv missing.sps])
 AT_CHECK([cat missing.csv], [0], [expout])
diff --git a/tests/language/utilities/cache.at b/tests/language/utilities/cache.at
new file mode 100644 (file)
index 0000000..2edda09
--- /dev/null
@@ -0,0 +1,8 @@
+AT_BANNER([CACHE])
+
+AT_SETUP([CACHE])
+AT_DATA([cache.sps], [dnl
+CACHE.
+])
+AT_CHECK([pspp -O format=csv cache.sps])
+AT_CLEANUP
diff --git a/tests/language/utilities/cd.at b/tests/language/utilities/cd.at
new file mode 100644 (file)
index 0000000..f56f1b8
--- /dev/null
@@ -0,0 +1,13 @@
+AT_BANNER([CD])
+
+AT_SETUP([CD])
+mkdir subdir
+AT_DATA([cd.sps], [dnl
+cd 'subdir'.
+host command=[['pwd > mydir']].
+])
+AT_CHECK([pspp -O format=csv cd.sps])
+AT_CAPTURE_FILE([subdir/mydir])
+AT_CHECK([sed 's,.*/,,' subdir/mydir], [0], [subdir
+])
+AT_CLEANUP
index e119f1033bc4a5794dc54c6f965a11d91ab59a86..8eaa72f7262e3f387d366901b2842035409371de 100644 (file)
@@ -3,13 +3,13 @@ AT_BANNER([INSERT])
 dnl Create a file "batch.sps" that is valid syntax only in batch mode.
 m4_define([CREATE_BATCH_SPS], 
   [AT_DATA([batch.sps], [dnl
-input program.
-+  loop #i = 1 to 5.
-+    compute z = #i
-+    end case.
-+  end loop
-end file.
-end input program.
+input program
+loop #i = 1 to 5
++  compute z = #i
++  end case
+end loop
+end file
+end input program
 ])])
 
 AT_SETUP([INSERT SYNTAX=INTERACTIVE])
@@ -17,15 +17,14 @@ CREATE_BATCH_SPS
 AT_DATA([insert.sps], [dnl
 INSERT 
   FILE='batch.sps'
-  SYNTAX=INTERACTIVE.
+  SYNTAX=interactive.
 LIST.
 ])
 AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl
-batch.sps:2: error: INPUT PROGRAM: Syntax error at `+': expecting command name.
-batch.sps:3: error: INPUT PROGRAM: Syntax error at `+': expecting command name.
-batch.sps:5: error: INPUT PROGRAM: Syntax error at `+': expecting command name.
-batch.sps:7: error: Input program did not create any variables.
-insert.sps:4: error: LIST: LIST is allowed only after the active file has been defined.
+batch.sps:2.1-2.4: error: INPUT PROGRAM: Syntax error at `loop': expecting end of command.
+batch.sps:3: error: COMPUTE: COMPUTE is allowed only after the active dataset has been defined or inside INPUT PROGRAM.
+batch.sps:4: error: END CASE: END CASE is allowed only inside INPUT PROGRAM.
+insert.sps:4: error: LIST: LIST is allowed only after the active dataset has been defined.
 ])
 AT_CLEANUP
 
@@ -66,7 +65,7 @@ END DATA.
 ])
 AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl
 Dir1/foo.sps:1: error: INSERT: Can't find `bar.sps' in include file search path.
-insert.sps:2: error: LIST: LIST is allowed only after the active file has been defined.
+insert.sps:2: error: LIST: LIST is allowed only after the active dataset has been defined.
 ])
 AT_CLEANUP
 
@@ -111,24 +110,22 @@ END DATA.
 * The following line is erroneous
 
 DISPLAY AKSDJ.
+LIST.
 ])])
 
 AT_SETUP([INSERT ERROR=STOP])
 CREATE_ERROR_SPS
 AT_DATA([insert.sps], [INSERT FILE='error.sps' ERROR=STOP.
-LIST.
 ])
 AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl
 error.sps:10: error: DISPLAY: AKSDJ is not a variable name.
 warning: Error encountered while ERROR=STOP is effective.
-error.sps:10: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
 ])
 AT_CLEANUP
 
 AT_SETUP([INSERT ERROR=CONTINUE])
 CREATE_ERROR_SPS
 AT_DATA([insert.sps], [INSERT FILE='error.sps' ERROR=CONTINUE.
-LIST.
 ])
 AT_CHECK([pspp -o pspp.csv insert.sps], [1], [dnl
 error.sps:10: error: DISPLAY: AKSDJ is not a variable name.
@@ -156,8 +153,8 @@ INSERT
 LIST.
 ])
 AT_CHECK([pspp -O format=csv insert.sps], [1], [dnl
-insert.sps:3: error: INSERT: Can't find `nonexistent' in include file search path.
+insert.sps:2: error: INSERT: Can't find `nonexistent' in include file search path.
 
-insert.sps:6: error: LIST: LIST is allowed only after the active file has been defined.
+insert.sps:6: error: LIST: LIST is allowed only after the active dataset has been defined.
 ])
 AT_CLEANUP
index 515bff5e6fdb6ee17512348c144551426ab59bb8..cd954f24bc4517f4c41d3ae64e05620ffd843ab8 100644 (file)
@@ -2,7 +2,7 @@ AT_BANNER([TITLE and related commands])
 
 AT_SETUP([FILE LABEL and (ADD) DOCUMENT])
 AT_DATA([file-label.sps], [dnl
-/* Set up a dummy active file in memory.
+/* Set up a dummy active dataset in memory.
 data list /X 1 Y 2.
 begin data.
 16
@@ -29,7 +29,7 @@ display file label.
 
 ADD DOCUMENT 'Line one' 'Line two'.
 
-/* Save the active file then get it and display the documents again.
+/* Save the active dataset then get it and display the documents again.
 save /OUTFILE='foo.save'.
 get /FILE='foo.save'.
 display documents.
@@ -64,7 +64,7 @@ Variable,Record,Columns,Format
 X,1,1-  1,F1.0
 Y,1,2-  2,F1.0
 
-Documents in the active file:
+Documents in the active dataset:
 
 document First line of a document
 
@@ -74,11 +74,9 @@ The last line should end with a period: .
 
 (Entered <date>)
 
-File label:
+File label: This is a test file label
 
-This is a test file label
-
-Documents in the active file:
+Documents in the active dataset:
 
 document First line of a document
 
@@ -94,11 +92,9 @@ Line two
 
 (Entered <date>)
 
-File label:
-
-This is a test file label
+File label: This is a test file label
 
-Documents in the active file:
+Documents in the active dataset:
 
 document First line of a document
 
@@ -118,7 +114,7 @@ document There should be another document now.
 
 (Entered <date>)
 
-Documents in the active file:
+Documents in the active dataset:
 
 document First line of a document
 
@@ -138,8 +134,6 @@ document There should be another document now.
 
 (Entered <date>)
 
-File label:
-
-This is a test file label
+File label: This is a test file label
 ])
 AT_CLEANUP
diff --git a/tests/libpspp/encoding-guesser-test.c b/tests/libpspp/encoding-guesser-test.c
new file mode 100644 (file)
index 0000000..a20607e
--- /dev/null
@@ -0,0 +1,102 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2011 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/encoding-guesser.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libpspp/i18n.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+
+static void
+usage (void)
+{
+  printf ("usage: %s [OTHER_ENCODING] [BUFSIZE] < INPUT\n"
+          "where OTHER_ENCODING is the fallback encoding (default taken\n"
+          "                     from the current locale)\n"
+          "  and BUFSIZE is the buffer size (default %d)\n",
+          program_name, ENCODING_GUESS_MIN);
+  exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char *encoding, *guess;
+  char *buffer;
+  int bufsize;
+  size_t n;
+  int i;
+
+  set_program_name (argv[0]);
+
+  i18n_init ();
+
+  encoding = NULL;
+  bufsize = 0;
+  for (i = 1; i < argc; i++)
+    {
+      const char *arg = argv[i];
+      if (!strcmp (arg, "--help"))
+        usage ();
+      else if (isdigit (arg[0]) && bufsize == 0)
+        {
+          bufsize = atoi (arg);
+          if (bufsize < ENCODING_GUESS_MIN)
+            error (1, 0, "buffer size %s is less than minimum size %d",
+                   arg, ENCODING_GUESS_MIN);
+        }
+      else if (!isdigit (arg[0]) && encoding == NULL)
+        encoding = arg;
+      else
+        error (1, 0, "bad syntax; use `%s --help' for help", program_name);
+    }
+
+  if (bufsize == 0)
+    bufsize = ENCODING_GUESS_MIN;
+
+  buffer = xmalloc (bufsize);
+
+  n = fread (buffer, 1, bufsize, stdin);
+  guess = encoding_guess_head_encoding (encoding, buffer, n);
+  if (!strcmp (guess, "ASCII") && encoding_guess_encoding_is_auto (encoding))
+    while (n > 0)
+      {
+        size_t n_ascii = encoding_guess_count_ascii (buffer, n);
+        if (n == n_ascii)
+          n = fread (buffer, 1, bufsize, stdin);
+        else
+          {
+            memmove (buffer, buffer + n_ascii, n - n_ascii);
+            n -= n_ascii;
+            n += fread (buffer + n, 1, bufsize - n, stdin);
+
+            guess = encoding_guess_tail_encoding (encoding, buffer, n);
+            break;
+          }
+      }
+  puts (guess);
+
+  return 0;
+}
diff --git a/tests/libpspp/encoding-guesser.at b/tests/libpspp/encoding-guesser.at
new file mode 100644 (file)
index 0000000..d63dc37
--- /dev/null
@@ -0,0 +1,143 @@
+AT_BANNER([encoding guesser])
+
+AT_SETUP([ASCII])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([echo string | encoding-guesser-test Auto,ISO-8859-1], [0], [ASCII
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-8])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf '\346\227\245\346\234\254\350\252\236\n' | encoding-guesser-test Auto,ISO-8859-1], [0], [UTF-8
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-8 starting with ASCII])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\346\227\245\346\234\254\350\252\236\n' | encoding-guesser-test Auto,ISO-8859-1 32], [0], [UTF-8
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-16 with big-endian byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\376\377' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-16 with little-endian byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\377\376' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-16BE])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\0e\0n\0t\0r\0\351\0e\0\n' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16BE
+])
+AT_CLEANUP
+
+dnl Unicode U+XX00 characters are confusing in UTF-16 because they look
+dnl likely to be of the opposite endianness, so this tests for proper handling.
+AT_SETUP([UTF-16BE starting with U+0100])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\1\0\0e\0n\0t\0r\0\351\0e\0\n' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16BE
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-16LE])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf 'e\0n\0t\0r\0\351\0e\0\n\0' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16LE
+])
+AT_CLEANUP
+
+dnl Unicode U+XX00 characters are confusing in UTF-16 because they look
+dnl likely to be of the opposite endianness, so this tests for proper handling.
+AT_SETUP([UTF-16LE starting with U+0100])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\0\1e\0n\0t\0r\0\351\0e\0\n\0' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-16LE
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-32 with big-endian byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\0\0\376\377' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-32
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-32 with little-endian byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\377\376\0\0' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-32
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-32BE])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf '\0\0\0e\0\0\0n\0\0\0t\0\0\0r\0\0\0\351\0\0\0e\0\0\0\n' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-32BE
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-32LE])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([printf 'e\0\0\0n\0\0\0t\0\0\0r\0\0\0\351\0\0\0e\0\0\0\n\0\0\0' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-32LE
+])
+AT_CLEANUP
+
+AT_SETUP([ISO-8859-1])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf 'entr\351e\n' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [ISO-8859-1
+])
+AT_CLEANUP
+
+AT_SETUP([GB-18030 with byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf '\204\061\225\063' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [GB-18030
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-EBCDIC with byte order mark])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf '\335\163\146\163' | encoding-guesser-test Auto,ISO-8859-1], 
+  [0], [UTF-EBCDIC
+])
+AT_CLEANUP
+
+AT_SETUP([EUC-JP as Auto,EUC-JP])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings EUC-JP])
+AT_CHECK([printf '\244\241 \244\242 \244\243 \244\244 \244\245 \244\246 \244\247 \244\250 \244\251 \244\252\n' | encoding-guesser-test Auto,EUC-JP],
+  [0], [EUC-JP
+])
+AT_CLEANUP
+
+AT_SETUP([EUC-JP starting with ASCII as Auto,EUC-JP])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings EUC-JP])
+AT_CHECK([printf 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \244\241 \244\242 \244\243 \244\244 \244\245 \244\246 \244\247 \244\250 \244\251 \244\252\n' | encoding-guesser-test Auto,EUC-JP 32],
+  [0], [EUC-JP
+])
+AT_CLEANUP
+
+AT_SETUP([UTF-8 with character split across input buffers])
+AT_KEYWORDS([encoding guesser])
+AT_CHECK([supports_encodings ISO-8859-1])
+AT_CHECK([printf '\343\201\201\343\201\202\343\201\203\343\201\204\343\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201\212\343\201\201\343\201\202\343\201\203\343\201\204\343\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201\212\n' | encoding-guesser-test Auto,ISO-8859-1 32],
+  [0], [UTF-8
+])
+AT_CLEANUP
index a00a353731c7928b9cfe8f1d269aff9dd5ea9d74..e84166c15f54c65f41af80fb0f719bd4189f36ea 100644 (file)
@@ -21,77 +21,78 @@ AT_DATA([float-format.txt], [dnl
 # x: hexadecimal digits
 
 # IEEE special values.
- 0 == isb(x'00000000')
-x('Infinity') == isb(x'7f800000')
-x('-Infinity') == isb(x'ff800000')
-x('NaN:') => isb(x'7f800001')          # NaN requires nonzero fraction.
-x('NaN:e000000000000000') == isb(x'7ff00000') == idb(x'7ffe000000000000')
-x('NaN:5a5a5e0000000000') == isb(x'7fad2d2f') == idb(x'7ff5a5a5e0000000')
-x('NaN:975612abcdef4000') == idb(x'7ff975612abcdef4')
-x('-NaN:e000000000000000') == isb(x'fff00000') == idb(x'fffe000000000000')
-x('-NaN:5a5a5e0000000000') == isb(x'ffad2d2f') == idb(x'fff5a5a5e0000000')
-x('-NaN:975612abcdef4000') == idb(x'fff975612abcdef4')
+ 0 == isb('00000000')
+x('Infinity') == isb('7f800000')
+x('-Infinity') == isb('ff800000')
+x('NaN:') => isb('7f800001')           # NaN requires nonzero fraction.
+x('NaN:e000000000000000') == isb('7ff00000') == idb('7ffe000000000000')
+x('NaN:5a5a5e0000000000') == isb('7fad2d2f') == idb('7ff5a5a5e0000000')
+x('NaN:975612abcdef4000') == idb('7ff975612abcdef4')
+x('-NaN:e000000000000000') == isb('fff00000') == idb('fffe000000000000')
+x('-NaN:5a5a5e0000000000') == isb('ffad2d2f') == idb('fff5a5a5e0000000')
+x('-NaN:975612abcdef4000') == idb('fff975612abcdef4')
 
 # PSPP special values.
-x('Missing') == isb(x'ff7fffff') == idb(x'ffefffffffffffff') == isl(x'ffff7fff') == idl(x'ffffffffffffefff') == vf(x'ffffffff') == vd(x'ffffffffffffffff') == vg(x'ffffffffffffffff') == zs(x'ffffffff') == zl(x'ffffffffffffffff')
-x('Lowest') == isb(x'ff7ffffe') == idb(x'ffeffffffffffffe') == isl(x'feff7fff') == idl(x'feffffffffffefff') == vf(x'fffffeff') == vd(x'fffffeffffffffff') == vg(x'fffffeffffffffff') == zs(x'fffffffe') == zl(x'fffffffffffffffe')
-x('Highest') == isb(x'7f7fffff') == idb(x'7fefffffffffffff') == isl(x'ffff7f7f') == idl(x'ffffffffffffef7f') == vf(x'ff7fffff') == vd(x'ffffffffff7fffff') == vg(x'ffffffffff7fffff') == zs(x'7fffffff') == zl(x'7fffffffffffffff')
+x('Missing') == isb('ff7fffff') == idb('ffefffffffffffff') == isl('ffff7fff') == idl('ffffffffffffefff') == vf('ffffffff') == vd('ffffffffffffffff') == vg('ffffffffffffffff') == zs('ffffffff') == zl('ffffffffffffffff')
+x('Lowest') == isb('ff7ffffe') == idb('ffeffffffffffffe') == isl('feff7fff') == idl('feffffffffffefff') == vf('fffffeff') == vd('fffffeffffffffff') == vg('fffffeffffffffff') == zs('fffffffe') == zl('fffffffffffffffe')
+x('Highest') == isb('7f7fffff') == idb('7fefffffffffffff') == isl('ffff7f7f') == idl('ffffffffffffef7f') == vf('ff7fffff') == vd('ffffffffff7fffff') == vg('ffffffffff7fffff') == zs('7fffffff') == zl('7fffffffffffffff')
 
 # From Wikipedia.
-0.15625 == isb(b'00111110001000000000000000000000')
--118.625 == isb(b'11000010111011010100000000000000')
+0.15625 == isb('3e200000')
+-118.625 == isb('c2ed4000')
 
 # http://www.psc.edu/general/software/packages/ieee/ieee.html
-x('NaN:0400000000000000') == isb(b'01111111100000100000000000000000')
-x('-NaN:2225540000000000') == isb(b'11111111100100010001001010101010')
-2 == isb(b'01000000000000000000000000000000')
-6.5 == isb(b'01000000110100000000000000000000')
--6.5 == isb(b'11000000110100000000000000000000')
-x('.4p-124') == isb(b'00000000100000000000000000000000')
-x('.2p-124') == isb(b'00000000010000000000000000000000')
+x('NaN:0400000000000000') == isb('7f820000')
+x('-NaN:2225540000000000') == isb('ff9112aa')
+2 == isb('40000000')
+6.5 == isb('40d00000')
+-6.5 == isb('c0d00000')
+x('.4p-124') == isb('00800000')
+x('.2p-124') == isb('00400000')
 
 # Using converter at http://babbage.cs.qc.edu/IEEE-754/Decimal.html
 # plus Emacs 'calc' to convert decimal to hexadecimal
-x('.7b74bc6a7ef9db23p8') => isb(x'42f6e979')           # 123.456
-x('.7b74bc6a7ef9db23p8') => idb(x'405edd2f1a9fbe77')
-x('.817427d2d4642004p-12') => isb(x'39017428')         # .0001234567
-x('.817427d2d4642004p-12') => idb(x'3f202e84fa5a8c84')
-x('.446c3b15f9926688p168') => isb(x'7f800000')         # 1e50; overflow
-x('.446c3b15f9926688p168') => idb(x'4a511b0ec57e649a')
+x('.7b74bc6a7ef9db23p8') => isb('42f6e979')            # 123.456
+x('.7b74bc6a7ef9db23p8') => idb('405edd2f1a9fbe77')
+x('.817427d2d4642004p-12') => isb('39017428')          # .0001234567
+x('.817427d2d4642004p-12') => idb('3f202e84fa5a8c84')
+x('.446c3b15f9926688p168') => isb('7f800000')          # 1e50; overflow
+x('.446c3b15f9926688p168') => idb('4a511b0ec57e649a')
 
 # From multiple editions of the z/Architecture Principles of Operation
 # manual.
-             1.0 == zs(x'41100000') == isb(x'3f800000')
-             0.5 == zs(x'40800000') == isb(x'3f000000')
-       x('.4p-4') == zs(x'3f400000') == isb(x'3c800000')
-               0 == zs(x'00000000') == isb(x'00000000')
-                    zs(x'80000000') == isb(x'80000000')
-             -15 == zs(x'c1f00000') == isb(x'c1700000')
-# x('.ffffffp252') == zs(x'7fffffff')
-      x('.3b4p8') == zs(x'423b4000')
-     x('.1p-256') == zs(x'00100000')
-     x('.4p-124') == zs(x'21400000') == isb(x'00800000')
-     x('.8p-148') == zs(x'1b800000') == isb(x'00000001')
-# x('.ffffffp128') == zs(x'60ffffff') == isb(x'7f7fffff')
-     x('.1p-256') == zs(x'00100000')
-     x('.1p-256') => isb(x'00000000')              # Underflow to zero.
- x('.ffffffp248') == zs(x'7effffff')
- x('.ffffffp248') => isb(x'7f800000')              # Overflow to +Infinity.
+             1.0 == zs('41100000') == isb('3f800000')
+             0.5 == zs('40800000') == isb('3f000000')
+       x('.4p-4') == zs('3f400000') == isb('3c800000')
+               0 == zs('00000000') == isb('00000000')
+                    zs('80000000') == isb('80000000')
+             -15 == zs('c1f00000') == isb('c1700000')
+# x('.ffffffp252') == zs('7fffffff')
+      x('.3b4p8') == zs('423b4000')
+     x('.1p-256') == zs('00100000')
+     x('.4p-124') == zs('21400000') == isb('00800000')
+     x('.8p-148') == zs('1b800000') == isb('00000001')
+# x('.ffffffp128') == zs('60ffffff') == isb('7f7fffff')
+     x('.1p-256') == zs('00100000')
+     x('.1p-256') => isb('00000000')              # Underflow to zero.
+ x('.ffffffp248') == zs('7effffff')
+ x('.ffffffp248') => isb('7f800000')              # Overflow to +Infinity.
 
-            x('.4p-1020') => zl(x'0000000000000000')     # Underflow to zero.
-            x('.4p-1020') == idb(x'0010000000000000')
-            x('.4p-1072') => zl(x'0000000000000000')     # Underflow to zero.
-            x('.4p-1072') => idb(x'0000000000000001')
-x('.fffffffffffff8p1024') => zl(x'7fffffffffffffff')     # Overflow to maxval.
-x('.fffffffffffff8p1024') => idb(x'7fefffffffffffff')
-            x('.1p-256') == zl(x'0010000000000000') == idb(x'2fb0000000000000')
- x('.ffffffffffffffp248') == zl(x'7effffffffffffff')
- x('.ffffffffffffffp248') => idb(x'4f70000000000000')  # Loses precision.
+            x('.4p-1020') => zl('0000000000000000')     # Underflow to zero.
+            x('.4p-1020') == idb('0010000000000000')
+            x('.4p-1072') => zl('0000000000000000')     # Underflow to zero.
+            x('.4p-1072') => idb('0000000000000001')
+x('.fffffffffffff8p1024') => zl('7fffffffffffffff')     # Overflow to maxval.
+x('.fffffffffffff8p1024') => idb('7fefffffffffffff')
+            x('.1p-256') == zl('0010000000000000') == idb('2fb0000000000000')
+ x('.ffffffffffffffp248') == zl('7effffffffffffff')
+ x('.ffffffffffffffp248') => idb('4f70000000000000')   # Loses precision.
 ])
 AT_CHECK(
   [sed 's/#.*//
 s/^[   ]*//
 s/[    ]*$//
+/^$/d
 s/^\(..*\)$/DEBUG FLOAT FORMAT \1./' < float-format.txt > float-format.sps])
 AT_CHECK([pspp --testing-mode -O format=csv float-format.sps])
 AT_CLEANUP
index f2bead96f78e6bd1412e2bc925c4bbbf43407b9d..b433756b0d21b2a1d9e455f1833de3b43eba006b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011 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 <stdlib.h>
+#include <string.h>
 
 #include "libpspp/i18n.h"
 
+#undef NDEBUG
+#include <assert.h>
+
 int
 main (int argc, char *argv[])
 {
-  char *s;
+  i18n_init ();
 
-  if (argc != 4)
+  if (argc == 5 && !strcmp (argv[1], "recode"))
+    {
+      const char *from = argv[2];
+      const char *to = argv[3];
+      const char *string = argv[4];
+      char *result = recode_string (to, from, string, -1);
+      puts (result);
+      assert (strlen (result) == recode_string_len (to, from, string, -1));
+      free (result);
+    }
+  else if (argc == 6 && !strcmp (argv[1], "concat"))
     {
-      fprintf (stderr,
-               "usage: %s FROM TO STRING\n"
-               "where FROM is the source encoding,\n"
-               "      TO is the target encoding,\n"
-               "      and STRING is the text to recode.\n",
-               argv[0]);
+      const char *head = argv[2];
+      const char *tail = argv[3];
+      const char *encoding = argv[4];
+      int max_len = atoi (argv[5]);
+      char *result;
+
+      result = utf8_encoding_concat (head, tail, encoding, max_len);
+      puts (result);
+
+      assert (strlen (result)
+              == utf8_encoding_concat_len (head, tail, encoding, max_len));
+
+      if (tail[0] == '\0')
+        {
+          char *result2 = utf8_encoding_trunc (head, encoding, max_len);
+          assert (!strcmp (result, result2));
+          assert (strlen (result2)
+                  == utf8_encoding_trunc_len (head, encoding, max_len));
+          free (result2);
+        }
+
+      free (result);
+    }
+  else
+    {
+      fprintf (stderr, "\
+usage: %s recode FROM TO STRING\n\
+where FROM is the source encoding,\n\
+      TO is the target encoding,\n\
+      and STRING is the text to recode.\n\
+\n\
+usage: %s concat HEAD TAIL ENCODING MAX_LEN\n\
+where HEAD is the first string to concatenate\n\
+      TAIL is the second string to concatenate\n\
+      ENCODING is the encoding in which to measure the result's length\n\
+      MAX_LEN is the maximum length of the result in ENCODING.\n",
+               argv[0], argv[0]);
       return EXIT_FAILURE;
     }
 
-  i18n_init ();
-  s = recode_string (argv[2], argv[1], argv[3], -1);
-  puts (s);
-  free (s);
+  i18n_done ();
 
   return 0;
 }
index ed29a7d69ca65cde5e28c23af21a1d80c3a2f737..421241e5db2f08b57cb766cf83b5c2bd9e16093a 100644 (file)
-AT_BANNER([i18n routines])
+AT_BANNER([i18n recoding])
 
-# CHECK_I18N([TITLE], [FROM-CODING], [TO-CODING], [FROM-TEXT], [TO-TEXT])
+m4_divert_push([PREPARE_TESTS])
+supports_encodings () {
+  case "$host" in
+    *-*-linux* | *-*-*-gnu*)
+      dnl GNU/Linux always has the encodings we want.  We can't ask
+      dnl config.charset about them because it has a special case here
+      dnl too and won't tell us.
+      return 0
+      ;;
+    *)
+      for encoding in "$@"; do
+       $SHELL $top_srcdir/gl/config.charset "$host" | grep '$2' || return 77
+      done
+      ;;
+  esac
+}
+m4_divert_pop([PREPARE_TESTS])
+
+# CHECK_I18N_RECODE([TITLE], [FROM-CODING], [TO-CODING],
+#                   [FROM-TEXT], [TO-TEXT])
 #
 # Converts FROM-TEXT from FROM-CODING to TO-CODING and checks that the result
-# is TO-TEXT.  The "printf" program is applied to both FROM-TEXT and TO-TEXT
-# to allow for backslash-escapes.  (Be aware that hex escapes are not portable;
-# use octal escapes instead.)
-m4_define([CHECK_I18N],
+# is TO-TEXT.  The "printf" program is applied to both FROM-TEXT and TO-TEXT to
+# allow for backslash-escapes.  (Hex escapes are not portable; use octal
+# escapes instead.)
+m4_define([CHECK_I18N_RECODE],
   [AT_SETUP([convert $1])
    AT_KEYWORDS([i18n])
 
    dnl Skip the test if this host doesn't know the source and target encodings.
-   AT_CHECK(
-     [case "$host" in
-        *-*-linux* | *-*-*-gnu*)
-          dnl GNU/Linux always has the encodings we want.  We can't ask
-         dnl config.charset about them because it has a special case here
-         dnl too and won't tell us.
-         ;;
-       *)
-          $SHELL $top_srcdir/gl/config.charset "$host" | grep '$2' || exit 77
-          $SHELL $top_srcdir/gl/config.charset "$host" | grep '$3' || exit 77
-          ;;
-      esac
-     ], [0], [ignore])
-   AT_CHECK_UNQUOTED([i18n-test '$2' '$3' `printf '$4'`], [0], [`printf '$5'`
+   AT_CHECK([supports_encodings '$2' '$3'])
+   AT_CHECK_UNQUOTED([i18n-test recode '$2' '$3' `printf '$4'`], [0], [`printf '$5'`
 ])
    AT_CLEANUP])
      
-CHECK_I18N([reflexively], [ASCII], [ASCII], [abc], [abc])
-CHECK_I18N([without any change], [ASCII], [UTF-8], [abc], [abc])
+CHECK_I18N_RECODE([reflexively], [ASCII], [ASCII], [abc], [abc])
+CHECK_I18N_RECODE([without any change], [ASCII], [UTF-8], [abc], [abc])
 
-CHECK_I18N([from ISO-8859-1 to UTF-8], [ISO-8859-1], [UTF-8],
-           [\242], [\302\242])
-CHECK_I18N([from UTF-8 to ISO-8859-1], [UTF-8], [ISO-8859-1],
-           [\302\242], [\242])
+CHECK_I18N_RECODE([from ISO-8859-1 to UTF-8], [ISO-8859-1], [UTF-8],
+                  [\242], [\302\242])
+CHECK_I18N_RECODE([from UTF-8 to ISO-8859-1], [UTF-8], [ISO-8859-1],
+                  [\302\242], [\242])
 
 # 0xc0 == 0300 is invalid in UTF-8
-CHECK_I18N([invalid UTF-8 to ISO-8859-1], [UTF-8], [ISO-8859-1],
-           [xy\300z], [xy?z])
+CHECK_I18N_RECODE([invalid UTF-8 to ISO-8859-1], [UTF-8], [ISO-8859-1],
+                  [xy\300z], [xy?z])
 # 0xc2 == 0302 is the first byte of a 2-byte UTF-8 sequence
-CHECK_I18N([truncated UTF-8 to ISO-8559-1], [UTF-8], [ISO-8859-1],
-           [xy\302], [xy?])
+CHECK_I18N_RECODE([truncated UTF-8 to ISO-8559-1], [UTF-8], [ISO-8859-1],
+                  [xy\302], [xy?])
 
 dnl The input to this test is 7 bytes long and the expected output is 9 bytes.
 dnl So it should exercise the E2BIG case 
-CHECK_I18N([from ISO-8859-1 to UTF-8 with overflow], [ISO-8859-1], [UTF-8],
-           [Tsch\374\337!], [Tsch\303\274\303\237!])
+CHECK_I18N_RECODE([from ISO-8859-1 to UTF-8 with overflow], 
+                  [ISO-8859-1], [UTF-8],
+                  [Tsch\374\337!], [Tsch\303\274\303\237!])
+
+AT_SETUP([convert unknown encoding])
+AT_KEYWORDS([i18n])
+AT_CHECK([i18n-test recode nonexistent1 nonexistent2 asdf], [0], [asdf
+],
+  [Warning: cannot create a converter for `nonexistent1' to `nonexistent2': Invalid argument
+])
+AT_CLEANUP
+\f
+AT_BANNER([i18n concatenation])
+
+# CHECK_I18N_CONCAT([HEAD], [TAIL], [ENCODING], [MAX-LEN], [ANSWER])
+#
+# Concatenates HEAD and TAIL, omitting as many characters from HEAD as needed
+# to make the result come out to no more than MAX-LEN bytes if it was expressed
+# in ENCODING, and checks that the answer matches ANSWER.  HEAD, TAIL, and
+# ANSWER are all in UTF-8.  The "printf" program is applied to HEAD, TAIL, and
+# ANSWER to allow for backslash-escapes.  (Hex escapes are not portable; use
+# octal escapes instead.)
+m4_define([CHECK_I18N_CONCAT],
+  [AT_SETUP([m4_if([$2], [], [truncate "$1" to $4 bytes in $3],
+                             [truncate "$1" + "$2" to $4 bytes in $3])])
+   AT_KEYWORDS([i18n])
+
+   dnl Skip the test if this host doesn't know the encoding.
+   AT_CHECK([supports_encodings '$3'])
+   AT_CHECK_UNQUOTED(
+     [i18n-test concat "`printf '$1'`" "`printf '$2'`" '$3' '$4'], [0],
+     [`printf '$5'`
+])
+   AT_CLEANUP])
+
+CHECK_I18N_CONCAT([abc], [], [UTF-8], [6], [abc])
+CHECK_I18N_CONCAT([], [xyz], [UTF-8], [6], [xyz])
+CHECK_I18N_CONCAT([], [], [UTF-8], [6], [])
+CHECK_I18N_CONCAT([abcdefghij], [], [UTF-8], [6], [abcdef])
+CHECK_I18N_CONCAT([], [tuvwxyz], [UTF-8], [6], [tuvwxyz])
+
+CHECK_I18N_CONCAT([abc], [xyz], [UTF-8], [6], [abcxyz])
+CHECK_I18N_CONCAT([abcd], [xyz], [UTF-8], [6], [abcxyz])
+CHECK_I18N_CONCAT([abc], [uvwxyz], [UTF-8], [6], [uvwxyz])
+
+# x in a box ( x⃞ ) is U+0078, U+20DE, 4 bytes in UTF-8, and one grapheme
+# cluster.
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [0], [y])
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [1], [y])
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [2], [y])
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [3], [y])
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [4], [y])
+CHECK_I18N_CONCAT([x\342\203\236], [y], [UTF-8], [5], [x\342\203\236y])
 
+# éèä is only 3 bytes in ISO-8859-1.
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [0], [xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [1], [xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [2], [xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [3], [xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [4], 
+                  [\303\251xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [5],
+                  [\303\251\303\250xyz])
+CHECK_I18N_CONCAT([\303\251\303\250\303\244], [xyz], [ISO-8859-1], [6],
+                  [\303\251\303\250\303\244xyz])
index 4ff7d3d841423201a10c3fa8d5727f0660e8ed68..9b5b966b6d9e32fb2c9a94ad78ac3596f3051f3d 100644 (file)
@@ -48,7 +48,7 @@ AT_CHECK([sparse-xarray-test$EXEEXT \
 AT_CLEANUP
 
 m4_define([SPARSE_XARRAY_ON_DISK],
-  [AT_SETUP([on-disk sparse_xarray])
+  [AT_SETUP([on-disk sparse_xarray max-memory-rows=$1])
    AT_CHECK([sparse-xarray-test$EXEEXT \
               --verbosity=0 --queue-limit=`sparse_xarray_queue_limit` \
                --columns=2 --max-rows=3 --max-memory-rows=$1 --values=2],
@@ -68,7 +68,7 @@ AT_CHECK([sparse-xarray-test$EXEEXT \
 AT_CLEANUP
 
 m4_define([SPARSE_XARRAY_COPY_DISK],
-  [AT_SETUP([copying between on-disk sparse_xarrays])
+  [AT_SETUP([copying between on-disk sparse_xarrays max-memory-rows=$1])
    AT_KEYWORDS([sparse_xarray])
    limit=`sparse_xarray_queue_limit`
    AT_CHECK([sparse-xarray-test$EXEEXT \
diff --git a/tests/libpspp/u8-istream-test.c b/tests/libpspp/u8-istream-test.c
new file mode 100644 (file)
index 0000000..ab1b717
--- /dev/null
@@ -0,0 +1,126 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 2011 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/u8-istream.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libpspp/i18n.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+#include "gl/xalloc.h"
+
+static void
+usage (void)
+{
+  printf ("usage: %s COMMAND [ARG]...\n"
+          "The available commands are:\n"
+          "  help\n"
+          "    print this usage message\n"
+          "  buffer-size\n"
+          "    print the buffer size, in bytes, on stdout\n"
+          "  read FILE ENCODING [OUTBUF]\n"
+          "    read FILE encoded in ENCODING (with output buffer size\n"
+          "    OUTBUF) and print it on stdout in UTF-8\n",
+          program_name);
+  exit (0);
+}
+
+static void
+cmd_read (int argc, char *argv[])
+{
+  struct u8_istream *is;
+  const char *encoding;
+  const char *filename;
+  int outbufsize;
+  char *buffer;
+
+  if (argc < 4 || argc > 5)
+    error (1, 0, "bad syntax for `%s' command; use `%s help' for help",
+           argv[1], program_name);
+
+  outbufsize = argc > 4 ? atoi (argv[4]) : 4096;
+  buffer = xmalloc (outbufsize);
+
+  filename = argv[2];
+  encoding = *argv[3] ? argv[3] : NULL;
+
+  is = (!strcmp(filename, "-")
+        ? u8_istream_for_fd (encoding, STDIN_FILENO)
+        : u8_istream_for_file (encoding, filename, O_RDONLY));
+  if (is == NULL)
+    error (1, errno, "u8_istream_open failed");
+
+  if (u8_istream_is_auto (is))
+    printf ("Auto mode\n");
+  else if (u8_istream_is_utf8 (is))
+    printf ("UTF-8 mode\n");
+
+  for (;;)
+    {
+      ssize_t n;
+
+      n = u8_istream_read (is, buffer, outbufsize);
+      if (n > 0)
+        fwrite (buffer, 1, n, stdout);
+      else if (n < 0)
+        error (1, errno, "u8_istream_read failed");
+      else
+        break;
+    }
+
+  if (u8_istream_is_auto (is))
+    printf ("Auto mode\n");
+  else if (u8_istream_is_utf8 (is))
+    printf ("UTF-8 mode\n");
+
+  if (!strcmp(filename, "-"))
+    u8_istream_free (is);
+  else
+    {
+      if (u8_istream_close (is) != 0)
+        error (1, errno, "u8_istream_close failed");
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  set_program_name (argv[0]);
+  i18n_init ();
+
+  if (argc < 2)
+    error (1, 0, "missing command name; use `%s help' for help", program_name);
+  else if (!strcmp(argv[1], "help") || !strcmp(argv[1], "--help"))
+    usage ();
+  else if (!strcmp(argv[1], "buffer-size"))
+    printf ("%d\n", U8_ISTREAM_BUFFER_SIZE);
+  else if (!strcmp(argv[1], "read"))
+    cmd_read (argc, argv);
+  else
+    error (1, 0, "unknown command `%s'; use `%s help' for help",
+           argv[1], program_name);
+
+  return 0;
+}
diff --git a/tests/libpspp/u8-istream.at b/tests/libpspp/u8-istream.at
new file mode 100644 (file)
index 0000000..2d8baa4
--- /dev/null
@@ -0,0 +1,142 @@
+AT_BANNER([u8_istream])
+
+AT_SETUP([read ASCII])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings ASCII])
+AT_CHECK([echo string | u8-istream-test read - ASCII], [0], [string
+])
+AT_CLEANUP
+
+AT_SETUP([read UTF-8])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([printf '\346\227\245\346\234\254\350\252\236\n' | u8-istream-test read - UTF-8], [0], [dnl
+UTF-8 mode
+日本語
+UTF-8 mode
+])
+AT_CLEANUP
+
+AT_SETUP([read EUC-JP])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings EUC-JP])
+AT_CHECK([printf '\244\241 \244\242 \244\243 \244\244 \244\245 \244\246 \244\247 \244\250 \244\251 \244\252\n' | u8-istream-test read - EUC-JP],
+  [0],
+  [ぁ あ ぃ い ぅ う ぇ え ぉ お
+])
+AT_CLEANUP
+
+AT_SETUP([read UTF-8 with character split across input buffers])
+AT_KEYWORDS([u8_istream])
+buffer_size=`u8-istream-test buffer-size`
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf '\343\201\201\343\201\202\343\201\203\343\201\204\343\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201\212\n') > input
+(echo "UTF-8 mode"
+ cat input
+ echo "UTF-8 mode") > expout
+AT_CHECK([u8-istream-test read input UTF-8 16], [0], [expout])
+AT_CLEANUP
+
+AT_SETUP([read UTF-8 with character split across output buffers])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([printf '\343\201\201\343\201\202\343\201\203\343\201\204\343\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201\212\n' | u8-istream-test read - UTF-8 16], [0], [dnl
+UTF-8 mode
+ぁあぃいぅうぇえぉお
+UTF-8 mode
+])
+AT_CLEANUP
+
+AT_SETUP([read UTF-8 with character split across input and output buffers])
+AT_KEYWORDS([u8_istream])
+buffer_size=`u8-istream-test buffer-size`
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf '\343\201\201\343\201\202\343\201\203\343\201\204\343\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201\212\n') > input
+(echo "UTF-8 mode"
+ cat input
+ echo "UTF-8 mode") > expout
+AT_CHECK([u8-istream-test read input UTF-8 16], [0], [expout])
+AT_CLEANUP
+
+AT_SETUP([read EUC-JP with character split across input buffers])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings EUC-JP])
+buffer_size=`u8-istream-test buffer-size`
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf '\244\241 \244\242 \244\243 \244\244 \244\245 \244\246 \244\247 '
+ printf '\244\250 \244\251 \244\252\n') > input
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf '\343\201\201\040\343\201\202\040\343\201\203\040\343\201\204\040'
+ printf '\343\201\205\040\343\201\206\040\343\201\207\040\343\201\210\040'
+ printf '\343\201\211\040\343\201\212\n') > expout
+AT_CHECK([u8-istream-test read input EUC-JP], [0], [expout])
+AT_CLEANUP
+
+AT_SETUP([read EUC-JP with character split across output buffers])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings EUC-JP])
+AT_CHECK([printf '\244\241\244\242\244\243\244\244\244\245\244\246\244\247\244\250\244\251\244\252\n' | u8-istream-test read - EUC-JP 16],
+  [0],
+  [ぁあぃいぅうぇえぉお
+])
+AT_CLEANUP
+
+AT_SETUP([read EUC-JP with character split across input and output buffers])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings EUC-JP])
+buffer_size=`u8-istream-test buffer-size`
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf 'xyz\244\241\244\242\244\243\244\244\244\245\244\246\244\247\244\250'
+ printf '\244\251\244\252\n') > input
+($PERL -e "print 'x' x ($buffer_size - 16)"
+ printf '\170\171\172\343\201\201\343\201\202\343\201\203\343\201\204\343'
+ printf '\201\205\343\201\206\343\201\207\343\201\210\343\201\211\343\201'
+ printf '\212\n') > expout
+AT_CHECK([u8-istream-test read input EUC-JP 16], [0], [expout])
+AT_CLEANUP
+
+AT_SETUP([read ASCII as Auto])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([echo string | u8-istream-test read - Auto], [0], [dnl
+Auto mode
+string
+Auto mode
+])
+AT_CLEANUP
+
+AT_SETUP([read UTF-8 as Auto])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([printf 'entr\303\251e\n' | u8-istream-test read - Auto], [0], [dnl
+Auto mode
+entrée
+UTF-8 mode
+])
+AT_CLEANUP
+
+AT_SETUP([read ISO-8859-1 as Auto,ISO-8859-1])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings ISO-8859-1])
+buffer_size=`u8-istream-test buffer-size`
+($PERL -e "print 'x' x int($buffer_size * 2.5)"; printf 'entr\351e\n') > input
+(echo "Auto mode"
+ $PERL -e "print 'x' x int($buffer_size * 2.5)"
+ printf 'entr\303\251e\n') > expout
+AT_CHECK([u8-istream-test read input Auto,ISO-8859-1], [0], [expout])
+AT_CLEANUP
+
+dnl UTF-16BE is not ASCII compatible so this doesn't start out in Auto mode.
+AT_SETUP([read UTF-16BE as Auto,UTF-16BE])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings UTF-16BE])
+AT_CHECK([printf '\0e\0n\0t\0r\0\351\0e\0\n' | u8-istream-test read - Auto,UTF-16BE], 
+  [0], [dnl
+entrée
+])
+AT_CLEANUP
+
+AT_SETUP([read EUC-JP as Auto,EUC-JP])
+AT_KEYWORDS([u8_istream])
+AT_CHECK([supports_encodings EUC-JP])
+AT_CHECK([printf 'entr\217\253\261e\n' | u8-istream-test read - Auto,EUC-JP], 
+  [0], [entrée
+])
+AT_CLEANUP
+
diff --git a/tests/output/ascii.at b/tests/output/ascii.at
new file mode 100644 (file)
index 0000000..df1263e
--- /dev/null
@@ -0,0 +1,585 @@
+AT_BANNER([ASCII driver -- rendering corner cases])
+
+AT_SETUP([ASCII driver overwriting single-width text])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [dnl
+## overwriting rest of line
+# plain
+0 0 0 abc
+1 0 0 BCD
+# emphasized over plain
+0 1 0 efg
+1 1 1 FGH
+# plain over emphasized
+0 2 1 ijk
+1 2 0 JKL
+# emphasized over emphasized
+0 3 1 mno
+1 3 1 NOP
+
+## overwriting partial line
+# plain
+0 5 0 abcdef
+0 5 0 A
+2 5 0 CDE
+# emphasized over plain
+0 6 0 ghijkl
+0 6 1 G
+2 6 1 IJK
+# plain over emphasized
+0 7 1 mnopqr
+0 7 0 M
+2 7 0 OPQ
+# emphasized over emphasized
+0 8 1 stuvwx
+0 8 1 S
+2 8 1 UVW
+
+## overwriting rest of line with double-width characters
+# plain
+0 10 0 kakiku
+2 10 0 きくけ
+# emphasized over plain
+0 11 0 kakiku
+2 11 1 きくけ
+# plain over emphasized
+0 12 1 kakiku
+2 12 0 きくけ
+# emphasized over emphasized
+0 13 1 kakiku
+2 13 1 きくけ
+
+## overwriting partial line with double-width characters
+# plain
+0 15 0 kakikukeko
+0 15 0 か
+4 15 0 くけ
+# emphasized over plain
+0 16 0 kakikukeko
+0 16 1 か
+4 16 1 くけ
+# plain over emphasized
+0 17 1 kakikukeko
+0 17 0 か
+4 17 0 くけ
+# emphasized over emphasized
+0 18 1 kakikukeko
+0 18 1 か
+4 18 1 くけ
+])
+AT_CHECK([render-test --draw-mode --emph=none input], [0], [dnl
+aBCD
+eFGH
+iJKL
+mNOP
+
+AbCDEf
+GhIJKl
+MnOPQr
+StUVWx
+
+kaきくけ
+kaきくけ
+kaきくけ
+kaきくけ
+
+かkiくけko
+かkiくけko
+かkiくけko
+かkiくけko
+])
+AT_CHECK([render-test --draw-mode --emph=bold input], [0], [dnl
+aBCD
+eF\bFG\bGH\bH
+i\biJKL
+m\bmN\bNO\bOP\bP
+
+AbCDEf
+G\bGhI\bIJ\bJK\bKl
+Mn\bnOPQr\br
+S\bSt\btU\bUV\bVW\bWx\bx
+
+kaきくけ
+kaき\bきく\bくけ\b
+k\bka\baきくけ
+k\bka\baき\bきく\bくけ\b
+
+かkiくけko
+か\bかkiく\bくけ\bけko
+かk\bki\biくけk\bko\bo
+か\bかk\bki\biく\bくけ\bけk\bko\bo
+])
+AT_CHECK([render-test --draw-mode --emph=underline input], [0], [dnl
+aBCD
+e_\bF_\bG_\bH
+_\biJKL
+_\bm_\bN_\bO_\bP
+
+AbCDEf
+_\bGh_\bI_\bJ_\bKl
+M_\bnOPQ_\br
+_\bS_\bt_\bU_\bV_\bW_\bx
+
+kaきくけ
+ka_\bき_\bく_\b
+_\bk_\baきくけ
+_\bk_\ba_\bき_\bく_\b
+
+かkiくけko
+_\bかki_\bく_\bけko
+か_\bk_\biくけ_\bk_\bo
+_\bか_\bk_\bi_\bく_\bけ_\bk_\bo
+])
+AT_CLEANUP
+
+AT_SETUP([ASCII driver overwriting double-width text])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [dnl
+## overwrite rest of line, aligned double-width over double-width
+# plain
+0 0 0 あいう
+2 0 0 きくけ
+# emphasized over plain
+0 1 0 あいう
+2 1 1 きくけ
+# plain over emphasized
+0 2 1 あいう
+2 2 0 きくけ
+# emphasized over emphasized
+0 3 1 あいう
+2 3 1 きくけ
+
+## overwrite rest of line, misaligned double-width over double-width
+# plain
+0 5 0 あいう
+3 5 0 きくけ
+# emphasized over plain
+0 6 0 あいう
+3 6 1 きくけ
+# plain over emphasized
+0 7 1 あいう
+3 7 0 きくけ
+# emphasized over emphasized
+0 8 1 あいう
+3 8 1 きくけ
+
+## overwrite partial line, aligned double-width over double-width
+# plain
+0 10 0 あいうえお
+0 10 0 か
+4 10 0 くけ
+# emphasized over plain
+0 11 0 あいうえお
+0 11 1 か
+4 11 1 くけ
+# plain over emphasized
+0 12 1 あいうえお
+0 12 0 か
+4 12 0 くけ
+# emphasized over emphasized
+0 13 1 あいうえお
+0 13 1 か
+4 13 1 くけ
+
+## overwrite partial line, misaligned double-width over double-width
+# plain
+0 15 0 あいうえおさ
+1 15 0 か
+5 15 0 くけ
+# emphasized over plain
+0 16 0 あいうえおさ
+1 16 1 か
+5 16 1 くけ
+# plain over emphasized
+0 17 1 あいうえおさ
+1 17 0 か
+5 17 0 くけ
+# emphasized over emphasized
+0 18 1 あいうえおさ
+1 18 1 か
+5 18 1 くけ
+
+## overwrite rest of line, aligned single-width over double-width
+# plain
+0 20 0 あいう
+2 20 0 kikuko
+# emphasized over plain
+0 21 0 あいう
+2 21 1 kikuko
+# plain over emphasized
+0 22 1 あいう
+2 22 0 kikuko
+# emphasized over emphasized
+0 23 1 あいう
+2 23 1 kikuko
+
+## overwrite rest of line, misaligned single-width over double-width
+# plain
+0 25 0 あいう
+3 25 0 kikuko
+# emphasized over plain
+0 26 0 あいう
+3 26 1 kikuko
+# plain over emphasized
+0 27 1 あいう
+3 27 0 kikuko
+# emphasized over emphasized
+0 28 1 あいう
+3 28 1 kikuko
+
+## overwrite partial line, aligned single-width over double-width
+# plain
+0 30 0 あいうえお
+0 30 0 ka
+4 30 0 kuke
+# emphasized over plain
+0 31 0 あいうえお
+0 31 1 ka
+4 31 1 kuke
+# plain over emphasized
+0 32 1 あいうえお
+0 32 0 ka
+4 32 0 kuke
+# emphasized over emphasized
+0 33 1 あいうえお
+0 33 1 ka
+4 33 1 kuke
+
+## overwrite partial line, misaligned single-width over double-width
+# plain
+0 35 0 あいうえおさ
+1 35 0 a
+5 35 0 kuke
+# emphasized over plain
+0 36 0 あいうえおさ
+1 36 1 a
+5 36 1 kuke
+# plain over emphasized
+0 37 1 あいうえおさ
+1 37 0 a
+5 37 0 kuke
+# emphasized over emphasized
+0 38 1 あいうえおさ
+1 38 1 a
+5 38 1 kuke
+])
+AT_CHECK([render-test --draw-mode --emph=none input], [0], [dnl
+あきくけ
+あきくけ
+あきくけ
+あきくけ
+
+あ?きくけ
+あ?きくけ
+あ?きくけ
+あ?きくけ
+
+かいくけお
+かいくけお
+かいくけお
+かいくけお
+
+?か??くけ?さ
+?か??くけ?さ
+?か??くけ?さ
+?か??くけ?さ
+
+あkikuko
+あkikuko
+あkikuko
+あkikuko
+
+あ?kikuko
+あ?kikuko
+あ?kikuko
+あ?kikuko
+
+kaいkukeお
+kaいkukeお
+kaいkukeお
+kaいkukeお
+
+?aい?kuke?さ
+?aい?kuke?さ
+?aい?kuke?さ
+?aい?kuke?さ
+])
+AT_CHECK([render-test --draw-mode --emph=bold input], [0], [dnl
+あきくけ
+あき\bきく\bくけ\b
+あ\bあきくけ
+あ\bあき\bきく\bくけ\b
+
+あ?きくけ
+あ?き\bきく\bくけ\b
+あ\bあ?きくけ
+あ\bあ?き\bきく\bくけ\b
+
+かいくけお
+か\bかいく\bくけ\bけお
+かい\bいくけお\b
+か\bかい\bいく\bくけ\bけお\b
+
+?か??くけ?さ
+?か\bか??く\bくけ\bけ?さ
+?か??くけ?さ\b
+?か\bか??く\bくけ\bけ?さ\b
+
+あkikuko
+あk\bki\bik\bku\buk\bko\bo
+あ\bあkikuko
+あ\bあk\bki\bik\bku\buk\bko\bo
+
+あ?kikuko
+あ?k\bki\bik\bku\buk\bko\bo
+あ\bあ?kikuko
+あ\bあ?k\bki\bik\bku\buk\bko\bo
+
+kaいkukeお
+k\bka\baいk\bku\buk\bke\beお
+kaい\bいkukeお\b
+k\bka\baい\bいk\bku\buk\bke\beお\b
+
+?aい?kuke?さ
+?a\baい?k\bku\buk\bke\be?さ
+?aい\bい?kuke?さ\b
+?a\baい\bい?k\bku\buk\bke\be?さ\b
+])
+AT_CHECK([render-test --draw-mode --emph=underline input], [0], [dnl
+あきくけ
+あ_\bき_\bく_\b
+_\bあきくけ
+_\bあ_\bき_\bく_\b
+
+あ?きくけ
+あ?_\bき_\bく_\b
+_\bあ?きくけ
+_\bあ?_\bき_\bく_\b
+
+かいくけお
+_\bかい_\bく_\bけお
+か_\bいくけ_\b
+_\bか_\bい_\bく_\bけ_\b
+
+?か??くけ?さ
+?_\bか??_\bく_\bけ?さ
+?か??くけ?_\b
+?_\bか??_\bく_\bけ?_\b
+
+あkikuko
+あ_\bk_\bi_\bk_\bu_\bk_\bo
+_\bあkikuko
+_\bあ_\bk_\bi_\bk_\bu_\bk_\bo
+
+あ?kikuko
+あ?_\bk_\bi_\bk_\bu_\bk_\bo
+_\bあ?kikuko
+_\bあ?_\bk_\bi_\bk_\bu_\bk_\bo
+
+kaいkukeお
+_\bk_\baい_\bk_\bu_\bk_\beお
+ka_\bいkuke_\b
+_\bk_\ba_\bい_\bk_\bu_\bk_\be_\b
+
+?aい?kuke?さ
+?_\baい?_\bk_\bu_\bk_\be?さ
+?a_\bい?kuke?_\b
+?_\ba_\bい?_\bk_\bu_\bk_\be?_\b
+])
+AT_CLEANUP
+
+AT_SETUP([ASCII driver overwriting combining characters])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [dnl
+## overwriting rest of line, ordinary over combining
+# plain
+0 0 0 àéî
+1 0 0 xyz
+# emphasized over plain
+0 1 0 àéî
+1 1 1 xyz
+# plain over emphasized
+0 2 1 àéî
+1 2 0 xyz
+# emphasized over emphasized
+0 3 1 àéî
+1 3 1 xyz
+
+## overwriting rest of line, combining over ordinary
+# plain
+0 5 0 xyz
+1 5 0 àéî
+# emphasized over plain
+0 6 0 xyz
+1 6 1 àéî
+# plain over emphasized
+0 7 1 xyz
+1 7 0 àéî
+# emphasized over emphasized
+0 8 1 xyz
+1 8 1 àéî
+
+## overwriting partial line, ordinary over combining
+# plain
+0 10 0 àéîo̧ũẙ
+0 10 0 a
+2 10 0 iou
+# emphasized over plain
+0 11 0 àéîo̧ũẙ
+0 11 1 a
+2 11 1 iou
+# plain over emphasized
+0 12 1 àéîo̧ũẙ
+0 12 0 a
+2 12 0 iou
+# emphasized over emphasized
+0 13 1 àéîo̧ũẙ
+0 13 1 a
+2 13 1 iou
+
+## overwriting partial line, combining over ordinary
+# plain
+0 15 0 aeiouy
+0 15 0 à
+2 15 0 îo̧ũ
+# emphasized over plain
+0 16 0 aeiouy
+0 16 1 à
+2 16 1 îo̧ũ
+# plain over emphasized
+0 17 1 aeiouy
+0 17 0 à
+2 17 0 îo̧ũ
+# emphasized over emphasized
+0 18 1 aeiouy
+0 18 1 à
+2 18 1 îo̧ũ
+])
+AT_CHECK([render-test --draw-mode --emph=none input], [0], [dnl
+àxyz
+àxyz
+àxyz
+àxyz
+
+xàéî
+xàéî
+xàéî
+xàéî
+
+aéiouẙ
+aéiouẙ
+aéiouẙ
+aéiouẙ
+
+àeîo̧ũy
+àeîo̧ũy
+àeîo̧ũy
+àeîo̧ũy
+])
+AT_CHECK([render-test --draw-mode --emph=bold input], [0], [dnl
+àxyz
+àx\bxy\byz\bz
+a\bàxyz
+a\bàx\bxy\byz\bz
+
+xàéî
+xa\bàe\béi\b
+x\bxàéî
+x\bxa\bàe\béi\b
+
+aéiouẙ
+a\baéi\bio\bou\buẙ
+ae\béiouy\b
+a\bae\béi\bio\bou\buy\b
+
+àeîo̧ũy
+a\bàei\bîo\bo̧u\bũy
+àe\beîo̧ũy\by
+a\bàe\bei\bîo\bo̧u\bũy\by
+])
+AT_CHECK([render-test --draw-mode --emph=underline input], [0], [dnl
+àxyz
+à_\bx_\by_\bz
+_\bàxyz
+_\bà_\bx_\by_\bz
+
+xàéî
+x_\bà_\bé_\b
+_\bxàéî
+_\bx_\bà_\bé_\b
+
+aéiouẙ
+_\baé_\bi_\bo_\buẙ
+a_\béiou_\b
+_\ba_\bé_\bi_\bo_\bu_\b
+
+àeîo̧ũy
+_\bàe_\bî_\bo̧_\bũy
+à_\beîo̧ũ_\by
+_\bà_\be_\bî_\bo̧_\bũ_\by
+])
+AT_CLEANUP
+
+AT_SETUP([ASCII driver Unicode box characters])
+AT_KEYWORDS([render rendering])
+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 --box=unicode input], [0], [dnl
+╭───┬─╮
+│abc│d│
+├─┬─┤e│
+│g│j│f│
+│h├─┴─┤
+│i│klm│
+╰─┴───╯
+])
+AT_CLEANUP
+
+AT_SETUP([ASCII driver syntax printback])
+AT_DATA([ascii.sps], [dnl
+SET PRINTBACK=ON.
+DATA LIST LIST /x * y * a (a23).
+BEGIN DATA.
+1 11 One
+2 22 Two
+3 33 Three
+END DATA.
+
+REGRESSION
+/VARIABLES= a
+/DEPENDENT= x y
+/STATISTICS=COEFF R ANOVA.
+])
+AT_CHECK([pspp ascii.sps], [1], [dnl
+SET PRINTBACK=ON.
+
+DATA LIST LIST /x * y * a (a23).
+
+Reading free-form data from INLINE.
++--------+------+
+|Variable|Format|
+#========#======#
+|x       |F8.0  |
+|y       |F8.0  |
+|a       |A23   |
++--------+------+
+
+BEGIN DATA.
+1 11 One
+2 22 Two
+3 33 Three
+END DATA.
+
+REGRESSION
+/VARIABLES= a
+/DEPENDENT= x y
+/STATISTICS=COEFF R ANOVA.
+
+ascii.sps:12: error: REGRESSION: REGRESSION requires numeric variables.
+])
+AT_CLEANUP
index e325dbb16d9ba35fae564bb2a9fb3b7327fb02f9..91fd76c4150ff0a778a0e0010770bd3700189aac 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011 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
@@ -25,6 +25,7 @@
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
 #include "libpspp/string-map.h"
+#include "output/ascii.h"
 #include "output/driver.h"
 #include "output/tab.h"
 #include "output/table-item.h"
 /* --transpose: Transpose the table before outputting? */
 static int transpose;
 
+/* --emphasis: ASCII driver emphasis option. */
+static char *emphasis;
+
+/* --box: ASCII driver box option. */
+static char *box;
+
+/* --draw-mode: special ASCII driver test mode. */
+static int draw_mode;
+
+/* ASCII driver, for ASCII driver test mode. */
+static struct output_driver *ascii_driver;
+
 static const char *parse_options (int argc, char **argv);
 static void usage (void) NO_RETURN;
 static struct table *read_table (FILE *);
+static void draw (FILE *);
 
 int
 main (int argc, char **argv)
 {
-  struct table *table;
   const char *input_file_name;
   FILE *input;
 
@@ -59,14 +72,24 @@ main (int argc, char **argv)
       if (input == NULL)
         error (1, errno, "%s: open failed", input_file_name);
     }
-  table = read_table (input);
+
+  if (!draw_mode)
+    {
+      struct table *table;
+
+      table = read_table (input);
+
+      if (transpose)
+        table = table_transpose (table);
+
+      table_item_submit (table_item_create (table, NULL));
+    }
+  else
+    draw (input);
+
   if (input != stdin)
     fclose (input);
 
-  if (transpose)
-    table = table_transpose (table);
-
-  table_item_submit (table_item_create (table, NULL));
   output_close ();
 
   return 0;
@@ -85,15 +108,22 @@ configure_drivers (int width, int length)
                             xasprintf ("%d", width));
   string_map_insert_nocopy (&options, xstrdup ("length"),
                             xasprintf ("%d", length));
+  if (emphasis != NULL)
+    string_map_insert (&options, "emphasis", emphasis);
+  if (box != NULL)
+    string_map_insert (&options, "box", box);
 
   /* Render to stdout. */
   string_map_clone (&tmp, &options);
-  driver = output_driver_create (&tmp);
+  ascii_driver = driver = output_driver_create (&tmp);
   if (driver == NULL)
     exit (EXIT_FAILURE);
   output_driver_register (driver);
   string_map_destroy (&tmp);
 
+  if (draw_mode)
+    return;
+
   /* Render to render.txt. */
   string_map_replace (&options, "output-file", "render.txt");
   driver = output_driver_create (&options);
@@ -116,6 +146,12 @@ configure_drivers (int width, int length)
   output_driver_register (driver);
 #endif
 
+  string_map_insert (&options, "output-file", "render.odt");
+  driver = output_driver_create (&options);
+  if (driver == NULL)
+    exit (EXIT_FAILURE);
+  output_driver_register (driver);
+
   string_map_destroy (&options);
 }
 
@@ -130,6 +166,8 @@ parse_options (int argc, char **argv)
       enum {
         OPT_WIDTH = UCHAR_MAX + 1,
         OPT_LENGTH,
+        OPT_EMPHASIS,
+        OPT_BOX,
         OPT_HELP
       };
       static const struct option options[] =
@@ -137,6 +175,9 @@ parse_options (int argc, char **argv)
           {"width", required_argument, NULL, OPT_WIDTH},
           {"length", required_argument, NULL, OPT_LENGTH},
           {"transpose", no_argument, &transpose, 1},
+          {"emphasis", required_argument, NULL, OPT_EMPHASIS},
+          {"box", required_argument, NULL, OPT_BOX},
+          {"draw-mode", no_argument, &draw_mode, 1},
           {"help", no_argument, NULL, OPT_HELP},
           {NULL, 0, NULL, 0},
         };
@@ -155,6 +196,14 @@ parse_options (int argc, char **argv)
           length = atoi (optarg);
           break;
 
+        case OPT_EMPHASIS:
+          emphasis = optarg;
+          break;
+
+        case OPT_BOX:
+          box = optarg;
+          break;
+
         case OPT_HELP:
           usage ();
 
@@ -185,7 +234,8 @@ 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",
+          "  --width=WIDTH   set page width in characters\n"
+          "  --length=LINE   set page length in lines\n",
           program_name, program_name);
   exit (EXIT_SUCCESS);
 }
@@ -298,3 +348,26 @@ read_table (FILE *stream)
 
   return &tab->table;
 }
+
+static void
+draw (FILE *stream)
+{
+  char buffer[1024];
+  int line = 0;
+
+  while (fgets (buffer, sizeof buffer, stream))
+    {
+      char text[sizeof buffer];
+      int emph;
+      int x, y;
+
+      line++;
+      if (strchr ("#\r\n", buffer[0]))
+        continue;
+
+      if (sscanf (buffer, "%d %d %d %[^\n]", &x, &y, &emph, text) != 4)
+        error (1, 0, "line %d has invalid format", line);
+
+      ascii_test_write (ascii_driver, text, x, y, emph ? TAB_EMPH : 0);
+    }
+}
index b9f8e62334b4ce66675f94cc45a3472a2093bc21..9821348adb62610ed5c77b22f4d20ff50ca04e48 100644 (file)
@@ -129,6 +129,7 @@ m4_define([RENDER_8X8_2],
 AT_BANNER([output rendering -- no page breaking])
 
 AT_SETUP([single cell])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [1 1
 abc
 ])
@@ -137,6 +138,7 @@ AT_CHECK([render-test input], [0], [abc
 AT_CLEANUP
 
 AT_SETUP([single cell with border])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [1 1
 @abc
 ])
@@ -148,6 +150,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([joined columns])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [2 2
 1*2 @abcdefg
 @hij
@@ -163,6 +166,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([3x3, joined rows and columns])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [3 3
 1*2 @abc
 2*1 @d\ne\nf
@@ -182,6 +186,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([6x6, joined rows and columns])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6
 AT_CHECK([render-test input], [0], [dnl
 +-+---+-+-+-+
@@ -201,6 +206,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([3 rows with many joined cells])
+AT_KEYWORDS([render rendering])
 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
@@ -219,6 +225,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([3 columns with many joined cells])
+AT_KEYWORDS([render rendering])
 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
@@ -270,6 +277,7 @@ s|cd|20|
 AT_CLEANUP
 
 AT_SETUP([joined rows])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [2 2
 2*1 @ab\ncd\nef
 @hij
@@ -284,7 +292,38 @@ AT_CHECK([render-test input], [0], [dnl
 ])
 AT_CLEANUP
 
+dnl This checks for bug #31346, a segmentation fault that surfaced
+dnl when two or more rows  had no unspanned cells and no rules.
+AT_SETUP([joined rows only, no rules])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [2 2
+2*1 ab\ncd\nef
+2*1 hij\nklm\nnop
+])
+AT_CHECK([render-test input], [0], [dnl
+ab hij
+cd klm
+ef nop
+])
+AT_CLEANUP
+
+AT_SETUP([joined columns only, no rules])
+AT_KEYWORDS([render rendering])
+AT_DATA([input], [2 2
+1*2 abc\ndef
+1*2 hij\nklm\nnop
+])
+AT_CHECK([render-test input], [0], [dnl
+abc
+def
+hij
+klm
+nop
+])
+AT_CLEANUP
+
 AT_SETUP([5 big narrow cells])
+AT_KEYWORDS([render rendering])
 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.
@@ -305,6 +344,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([9 big narrow cells])
+AT_KEYWORDS([render rendering])
 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.
@@ -335,9 +375,10 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([2 big cells with new-lines])
+AT_KEYWORDS([render rendering])
 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.
+@PSPP includes special support\nfor unknown numeric data values.\nMissing observations are assigned\na special value, called the\n``systemmissing 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
 +----------------------------------------------------------+------------------+
@@ -351,7 +392,7 @@ AT_CHECK([render-test input], [0], [dnl
 |                                                          |          assigned|
 |                                                          |  a special value,|
 |                                                          |        called the|
-|                                                          |  ``system-missing|
+|                                                          |  ``systemmissing|
 |                                                          |    value''.  This|
 |                                                          |``value'' actually|
 |                                                          |     indicates the|
@@ -365,6 +406,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([8x8 with many 2x2 joins])
+AT_KEYWORDS([render rendering])
 RENDER_8X8_2
 AT_CHECK([render-test input], [0],[dnl
 +---+---+----+----+
@@ -395,6 +437,7 @@ AT_CLEANUP
 AT_BANNER([output rendering -- horizontal page breaks])
 
 AT_SETUP([breaking row of many small cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 50
 m4_for([x], [1], [50], [1], [@x
@@ -411,6 +454,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking row of many small cells, with headers])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 54 2 2
 @ha
@@ -436,6 +480,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking row of many medium-size cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 50
 m4_for([x], [1], [50], [1], [@cell x
@@ -464,6 +509,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking row of many medium-size cells, with headers])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 52 1 1
 header1
@@ -500,6 +546,7 @@ header1|cell|cell|header2
 AT_CLEANUP
 
 AT_SETUP([breaking row of many big narrow cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 50
 m4_for([x], [1], [50], [1], [@This is cell x in a series of 50.
@@ -558,6 +605,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking 2 rows of many small cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [2 50
 m4_for([x], [1], [100], [1], [@x
@@ -578,6 +626,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking 3 rows with many joined cells])
+AT_KEYWORDS([render rendering])
 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
@@ -604,6 +653,7 @@ AT_CHECK([render-test input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([horz break 6x6, joined rows and columns])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6
 AT_CHECK([render-test --width=6 input], [0], [dnl
 +-+--
@@ -651,6 +701,7 @@ yz|s|
 AT_CLEANUP
 
 AT_SETUP([horz break 6x6, joined rows and columns, left header])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6([1 0 0 0])
 AT_CHECK([render-test --width=10 input], [0], [dnl
 +-+---+-+
@@ -684,6 +735,7 @@ AT_CHECK([render-test --width=10 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([horz break 6x6, joined rows and columns, right header])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6([0 1 0 0])
 AT_CHECK([render-test --width=10 input], [0], [dnl
 +-+---+-+
@@ -717,6 +769,7 @@ op|h|q|
 AT_CLEANUP
 
 AT_SETUP([breaking joined cells too wide for page])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [4 6
 1*6 @abc def ghi jkl
 1*3 @mno pqr
@@ -759,6 +812,7 @@ AT_CHECK([render-test --width=10 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking joined cells much too wide for page])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [4 6
 1*6 @abc def ghi jkl
 1*3 @mno pqr
@@ -813,6 +867,7 @@ qr|
 AT_CLEANUP
 
 AT_SETUP([breaking cell too wide for page, no border])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 1
 abcdefghijklmnopqrstuvwxyz
@@ -831,6 +886,7 @@ yz
 AT_CLEANUP
 
 AT_SETUP([breaking cell too wide for page, with border])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [1 1
 @abcdefghijklmnopqrstuvwxyz
@@ -867,6 +923,7 @@ xyz|
 AT_CLEANUP
 
 AT_SETUP([horz break 8x8 with many 2x2 joins])
+AT_KEYWORDS([render rendering])
 RENDER_8X8_2
 AT_CHECK([render-test --width=8 input], [0],[dnl
 +---+--
@@ -945,6 +1002,7 @@ AT_CLEANUP
 AT_BANNER([output rendering -- vertical page breaks])
 
 AT_SETUP([breaking column of many small cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [20 1
 m4_for([x], [1], [20], [1], [@x
@@ -1003,6 +1061,7 @@ AT_CHECK([render-test --length=10 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking column of many small cells, with headers])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [17 1 0 0 1 1
 @a
@@ -1067,6 +1126,7 @@ AT_CHECK([render-test --length=13 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([disabling too-big headers])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [17 1 0 0 1 1
 @a
@@ -1121,6 +1181,7 @@ AT_CHECK([render-test --length=10 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking column of many medium-size cells])
+AT_KEYWORDS([render rendering])
 AT_CAPTURE_FILE([input])
 AT_DATA([input], [20 1
 m4_for([x], [1], [20], [1], [@top x\ncell x\nbottom x
@@ -1229,6 +1290,7 @@ AT_CHECK([render-test --length 10 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking 3 columns with many joined cells])
+AT_KEYWORDS([render rendering])
 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
@@ -1298,6 +1360,7 @@ s|cd|20|
 AT_CLEANUP
 
 AT_SETUP([vert break 6x6, joined rows and columns])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6
 AT_CHECK([render-test --length=6 input], [0], [dnl
 +-+---+-+-+-+
@@ -1321,6 +1384,7 @@ AT_CHECK([render-test --length=6 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking joined cells too tall for page])
+AT_KEYWORDS([render rendering])
 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
@@ -1357,6 +1421,7 @@ AT_CHECK([render-test --transpose --length=6 input], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([breaking cell too tall for page, no border])
+AT_KEYWORDS([render rendering])
 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
@@ -1381,6 +1446,7 @@ QR STU
 AT_CLEANUP
 
 AT_SETUP([breaking cell too tall for page, with border])
+AT_KEYWORDS([render rendering])
 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
@@ -1418,6 +1484,7 @@ AT_CLEANUP
 AT_BANNER([output rendering -- double page breaks])
 
 AT_SETUP([double break 6x6, joined rows and columns])
+AT_KEYWORDS([render rendering])
 RENDER_WEAVE_6X6
 AT_CHECK([render-test --width=6 --length=6 input], [0], [dnl
 +-+--
@@ -1477,6 +1544,7 @@ yz|s|
 AT_CLEANUP
 
 AT_SETUP([double break 8x8, with joins, left and right headers])
+AT_KEYWORDS([render rendering])
 RENDER_8X8([1 1 0 0])
 AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
 +-+-+-+-+-+-+
@@ -1522,6 +1590,7 @@ AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([double break 8x8, with joins, top and bottom headers])
+AT_KEYWORDS([render rendering])
 RENDER_8X8([0 0 1 1])
 AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
 +-+-+-+-+-+-+
@@ -1577,6 +1646,7 @@ fg|h|
 AT_CLEANUP
 
 AT_SETUP([double break 8x8, with joins, all headers])
+AT_KEYWORDS([render rendering])
 RENDER_8X8([1 1 1 1])
 AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
 +-+-+-+-+-+-+
@@ -1632,6 +1702,7 @@ AT_CHECK([render-test input --width=14 --length=14], [0], [dnl
 AT_CLEANUP
 
 AT_SETUP([double break joined cells too big for page])
+AT_KEYWORDS([render rendering])
 AT_DATA([input], [7 7
 @a
 @b
@@ -1641,7 +1712,7 @@ AT_DATA([input], [7 7
 @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.
+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
@@ -1688,7 +1759,7 @@ ndling of|
 ariables.|
 NCLUDE is|
 set, then|
-r-missing|
+rmissing|
 alues are|
 ed in the|
 ions.  If|
@@ -1697,7 +1768,7 @@ E is set,|
 E is set,|
 ch is the|
  default,|
-r-missing|
+rmissing|
 alues are|
 excluded.|
          |
@@ -1708,3 +1779,28 @@ excluded.|
 ---------+
 ])
 AT_CLEANUP
+\f
+AT_BANNER([output rendering -- problematic procedures])
+
+dnl LIST used to put columns right up next to each other without any
+dnl intervening space, so this checks for regression.
+AT_SETUP([LIST puts space between columns])
+AT_KEYWORDS([render rendering])
+AT_DATA([list.sps], [dnl
+DATA LIST LIST NOTABLE /x y z (F1.0).
+BEGIN DATA.
+1 2 3
+4 5 6
+7 8 9
+END DATA.
+LIST.
+])
+AT_CHECK([pspp list.sps], [0], [dnl
+Data List
+x y z
+-----
+1 2 3
+4 5 6
+7 8 9
+])
+AT_CLEANUP
index 115f2a8d20e714f8b644f150df9c1c3c9609210c..308dd7711b219a317b0f09f0470fe523f10dc9f2 100644 (file)
@@ -56,11 +56,9 @@ DISPLAY DICTIONARY.
 SHOW WEIGHT.
 ])
 AT_CHECK([pspp -O format=csv dump-dict.sps], [0],
-  [File label:
+  [File label: My Dictionary
 
-My Dictionary
-
-Documents in the active file:
+Documents in the active dataset:
 
 These Documents
 
@@ -151,11 +149,9 @@ name,Format: A20,,2
 ,Display Alignment: Left,,
 ,Display Width: 20,,
 
-File label:
-
-This is the file label
+File label: This is the file label
 
-Documents in the active file:
+Documents in the active dataset:
 
 This is a document line
 
@@ -173,11 +169,9 @@ name,Format: A20,,2
 ,Display Alignment: Left,,
 ,Display Width: 20,,
 
-File label:
-
-This is the file label
+File label: This is the file label
 
-Documents in the active file:
+Documents in the active dataset:
 
 This is a document line
 
@@ -704,6 +698,8 @@ AT_CLEANUP
 
 AT_SETUP([Perl Pspp.t])
 AT_SKIP_IF([test "$WITH_PERL_MODULE" = no])
+# Skip this test if Perl's Text::Diff module is not installed.
+AT_CHECK([perl -MText::Diff -e '' || exit 77])
 AT_CHECK([RUN_PERL_MODULE $abs_top_builddir/perl-module/t/Pspp.t], [0],
   [[1..36
 ok 1 - use PSPP;
diff --git a/tests/stats/moments.sh b/tests/stats/moments.sh
deleted file mode 100755 (executable)
index a0a72c6..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#! /bin/sh
-
-# Tests calculation of moments.
-
-TEMPDIR=/tmp/pspp-tst-$$
-
-# ensure that top_builddir  are absolute
-if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
-if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
-top_builddir=`cd $top_builddir; pwd`
-PSPP=$top_builddir/src/ui/terminal/pspp$EXEEXT
-
-# ensure that top_srcdir is absolute
-top_srcdir=`cd $top_srcdir; pwd`
-
-STAT_CONFIG_PATH=$top_srcdir/config
-export STAT_CONFIG_PATH
-
-
-cleanup()
-{
-     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
-       echo "NOT cleaning $TEMPDIR" 
-       return ; 
-     fi
-     cd /
-     rm -rf $TEMPDIR
-}
-
-
-fail()
-{
-    echo $activity
-    echo FAILED
-    cleanup;
-    exit 1;
-}
-
-
-no_result()
-{
-    echo $activity
-    echo NO RESULT;
-    cleanup;
-    exit 2;
-}
-
-pass()
-{
-    cleanup;
-    exit 0;
-}
-
-mkdir -p $TEMPDIR
-
-cd $TEMPDIR
-activity="create one-pass moments list"
-sed -ne 's/#.*//;/^[   ]*$/!p' > $TEMPDIR/moments-list-1p <<'EOF'
-# Both the one-pass and two-pass algorithms should be 
-# able to cope properly with these.
-1 2 3 4 => W=4.000 M1=2.500 M2=1.667 M3=0.000 M4=-1.200
-1*5 2*5 3*5 4*5 => W=20.000 M1=2.500 M2=1.316 M3=0.000 M4=-1.401
-1*1 2*2 3*3 4*4 => W=10.000 M1=3.000 M2=1.111 M3=-0.712 M4=-0.450
-1*0 => W=0.000 M1=sysmis M2=sysmis M3=sysmis M4=sysmis
-1*1 => W=1.000 M1=1.000 M2=sysmis M3=sysmis M4=sysmis
-1*2 => W=2.000 M1=1.000 M2=0.000 M3=sysmis M4=sysmis
-1*3 => W=3.000 M1=1.000 M2=0.000 M3=sysmis M4=sysmis
-1*2 3 => W=3.000 M1=1.667 M2=1.333 M3=1.732 M4=sysmis
-1 1.00000001 => W=2.000 M1=1.000 M2=0.000 M3=sysmis M4=sysmis
-1000001 1000002 1000003 1000004 => W=4.000 M1=1000002.500 M2=1.667 M3=0.000 M4=-1.200
-EOF
-if [ $? -ne 0 ] ; then no_result ; fi
-
-cp $TEMPDIR/moments-list-1p $TEMPDIR/moments-list-2p
-sed -ne 's/#.*//;/^[   ]*$/!p' >> $TEMPDIR/moments-list-2p <<'EOF'
-# We used to have an example for which only the two-pass algorithm
-# produced reasonable results, but the provisional means algorithm
-# does better, so there aren't any extra tests here.
-EOF
-
-activity="create two-pass input file"
-sed < $TEMPDIR/moments-list-2p >> $TEMPDIR/moments-2p.stat \
-       -e 's#^\(.*\) => \(.*\)$#DEBUG MOMENTS/\1.#'
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="run two-pass program"
-$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"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/moments-list-2p $TEMPDIR/moments-2p.out
-diff -b $TEMPDIR/moments-list-2p $TEMPDIR/moments-2p.out
-if [ $? -ne 0 ] ; then fail ; fi
-
-activity="create input file"
-sed < $TEMPDIR/moments-list-1p >> $TEMPDIR/moments-1p.stat \
-       -e 's#^\(.*\) => \(.*\)$#DEBUG MOMENTS ONEPASS/\1.#'
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="run one-pass program"
-$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"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/moments-list-1p $TEMPDIR/moments-1p.out
-diff -b $TEMPDIR/moments-list-1p $TEMPDIR/moments-1p.out
-if [ $? -ne 0 ] ; then fail ; fi
-
-pass
diff --git a/tests/stats/percentiles-enhanced.sh b/tests/stats/percentiles-enhanced.sh
deleted file mode 100755 (executable)
index c69bacd..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-#! /bin/sh
-
-# Tests calculation of percentiles with the 
-# ENHANCED algorithm set.
-
-TEMPDIR=/tmp/pspp-tst-$$
-
-# ensure that top_builddir  are absolute
-if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
-if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
-top_builddir=`cd $top_builddir; pwd`
-PSPP=$top_builddir/src/ui/terminal/pspp$EXEEXT
-
-# ensure that top_srcdir is absolute
-top_srcdir=`cd $top_srcdir; pwd`
-
-STAT_CONFIG_PATH=$top_srcdir/config
-export STAT_CONFIG_PATH
-
-LANG=C
-export LANG
-
-
-cleanup()
-{
-     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
-       echo "NOT cleaning $TEMPDIR" 
-       return ; 
-     fi
-     cd /
-     rm -rf $TEMPDIR
-}
-
-
-fail()
-{
-    echo $activity
-    echo FAILED
-    cleanup;
-    exit 1;
-}
-
-
-no_result()
-{
-    echo $activity
-    echo NO RESULT;
-    cleanup;
-    exit 2;
-}
-
-pass()
-{
-    cleanup;
-    exit 0;
-}
-
-mkdir -p $TEMPDIR
-
-cd $TEMPDIR
-
-
-i=1;
-
-activity="create program $i"
-cat > $TEMPDIR/prog.sps <<EOF
-DATA LIST LIST notable /X * .
-BEGIN DATA.
-1 
-2 
-3 
-4 
-5
-END DATA.
-
-FREQUENCIES 
-       VAR=x
-       /PERCENTILES = 0 25 50 75 100
-
-EOF
-if [ $? -ne 0 ] ; then no_result; fi
-
-activity="run program $i"
-$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="compare output $i"
-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,
-
-Table: X
-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
-
-
-
-i=$[$i+1];
-
-activity="create program $i"
-cat > $TEMPDIR/prog.sps <<EOF
-DATA LIST LIST notable /X * F *.
-BEGIN DATA.
-1 2
-2 2
-3 2
-4 1
-4 1
-5 1
-5 1
-END DATA.
-
-WEIGHT BY f.
-
-FREQUENCIES 
-       VAR=x
-       /PERCENTILES = 0 25 50 75 100
-
-EOF
-if [ $? -ne 0 ] ; then no_result; fi
-
-
-activity="run program $i"
-$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="compare output $i"
-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,
-
-Table: X
-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
-
-
-
-i=$[$i+1];
-
-activity="create program $i"
-cat > $TEMPDIR/prog.sps <<EOF
-DATA LIST LIST notable /X * F *.
-BEGIN DATA.
-1 1
-3 2
-4 1
-5 1
-5 1
-END DATA.
-
-WEIGHT BY f.
-
-FREQUENCIES 
-       VAR=x
-       /PERCENTILES = 0 25 50 75 100
-
-EOF
-if [ $? -ne 0 ] ; then no_result; fi
-
-
-activity="run program $i"
-$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="compare output $i"
-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,
-
-Table: X
-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
-
-i=$[$i+1];
-
-activity="create program $i"
-cat > $TEMPDIR/prog.sps <<EOF
-DATA LIST LIST notable /X * F *.
-BEGIN DATA.
-1 1
-3 2
-4 1
-5 1
-5 1
-99 4
-END DATA.
-
-MISSING VALUE x (99.0) .
-WEIGHT BY f.
-
-FREQUENCIES 
-       VAR=x
-       /PERCENTILES = 0 25 50 75 100
-
-EOF
-if [ $? -ne 0 ] ; then no_result; fi
-
-
-activity="run program $i"
-$SUPERVISOR $PSPP -o pspp.csv $TEMPDIR/prog.sps
-if [ $? -ne 0 ] ; then no_result ; fi
-
-activity="compare output $i"
-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,
-
-Table: X
-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
-
-pass;
diff --git a/tests/valgrind-wrapper.in b/tests/valgrind-wrapper.in
new file mode 100755 (executable)
index 0000000..a60cd9e
--- /dev/null
@@ -0,0 +1,38 @@
+#! /bin/sh
+
+program=`basename "$0"`
+
+new_PATH=
+save_IFS=$IFS
+IFS=:
+found=no
+for dir in $PATH; do
+    IFS=$save_IFS
+    if test "X$dir" = X; then
+       dir=.
+    fi
+    if test -x "$dir/$program"; then
+       if test $found = no; then
+           found=yes
+           continue
+       else
+           if test "X$next_program" = X; then
+               next_program=$dir/$program
+           fi
+       fi
+    fi
+done
+IFS=$save_IFS
+
+if test $found = no; then
+    echo "$0: $program not found in PATH ($PATH)" >&2
+    exit 1
+elif test "X$next_program" = X; then
+    echo "$0: $program found only once in PATH ($PATH)" >&2
+    exit 1
+fi
+
+: ${VALGRIND:=libtool --mode=execute valgrind --log-file=valgrind.%p --leak-check=full --num-callers=20}
+exec $VALGRIND $next_program "$@"
+echo "$0: $VALGRIND $wrap_program $* failed" >&2
+exit 1
diff --git a/utilities/automake.mk b/utilities/automake.mk
new file mode 100644 (file)
index 0000000..ec4ccf2
--- /dev/null
@@ -0,0 +1,7 @@
+bin_PROGRAMS += utilities/pspp-dump-sav
+utilities_pspp_dump_sav_SOURCES = \
+       src/libpspp/integer-format.c \
+       src/libpspp/float-format.c \
+       utilities/pspp-dump-sav.c
+utilities_pspp_dump_sav_CPPFLAGS = $(AM_CPPFLAGS) -DINSTALLDIR=\"$(bindir)\"
+
diff --git a/utilities/pspp-dump-sav.c b/utilities/pspp-dump-sav.c
new file mode 100644 (file)
index 0000000..7cdd7d9
--- /dev/null
@@ -0,0 +1,1485 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2007, 2008, 2009, 2010, 2011 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 <getopt.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "data/val-type.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/misc.h"
+
+#include "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/progname.h"
+#include "gl/version-etc.h"
+#include "gl/xalloc.h"
+
+#define ID_MAX_LEN 64
+
+struct sfm_reader
+  {
+    const char *file_name;
+    FILE *file;
+
+    int n_variable_records, n_variables;
+
+    int *var_widths;
+    size_t n_var_widths, allocated_var_widths;
+
+    enum integer_format integer_format;
+    enum float_format float_format;
+
+    bool compressed;
+    double bias;
+  };
+
+static void read_header (struct sfm_reader *);
+static void read_variable_record (struct sfm_reader *);
+static void read_value_label_record (struct sfm_reader *);
+static void read_document_record (struct sfm_reader *);
+static void read_extension_record (struct sfm_reader *);
+static void read_machine_integer_info (struct sfm_reader *,
+                                       size_t size, size_t count);
+static void read_machine_float_info (struct sfm_reader *,
+                                     size_t size, size_t count);
+static void read_mrsets (struct sfm_reader *, size_t size, size_t count);
+static void read_display_parameters (struct sfm_reader *,
+                                     size_t size, size_t count);
+static void read_long_var_name_map (struct sfm_reader *r,
+                                    size_t size, size_t count);
+static void read_long_string_map (struct sfm_reader *r,
+                                  size_t size, size_t count);
+static void read_datafile_attributes (struct sfm_reader *r,
+                                      size_t size, size_t count);
+static void read_variable_attributes (struct sfm_reader *r,
+                                      size_t size, size_t count);
+static void read_ncases64 (struct sfm_reader *, size_t size, size_t count);
+static void read_character_encoding (struct sfm_reader *r,
+                                      size_t size, size_t count);
+static void read_long_string_value_labels (struct sfm_reader *r,
+                                           size_t size, size_t count);
+static void read_unknown_extension (struct sfm_reader *,
+                                    size_t size, size_t count);
+static void read_compressed_data (struct sfm_reader *, int max_cases);
+
+static struct text_record *open_text_record (
+  struct sfm_reader *, size_t size);
+static void close_text_record (struct text_record *);
+static bool read_variable_to_value_pair (struct text_record *,
+                                         char **key, char **value);
+static char *text_tokenize (struct text_record *, int delimiter);
+static bool text_match (struct text_record *text, int c);
+static const char *text_parse_counted_string (struct text_record *);
+static size_t text_pos (const struct text_record *);
+
+static void usage (void);
+static void sys_warn (struct sfm_reader *, const char *, ...)
+     PRINTF_FORMAT (2, 3);
+static void sys_error (struct sfm_reader *, const char *, ...)
+     PRINTF_FORMAT (2, 3)
+     NO_RETURN;
+
+static void read_bytes (struct sfm_reader *, void *, size_t);
+static bool try_read_bytes (struct sfm_reader *, void *, size_t);
+static int read_int (struct sfm_reader *);
+static int64_t read_int64 (struct sfm_reader *);
+static double read_float (struct sfm_reader *);
+static void read_string (struct sfm_reader *, char *, size_t);
+static void skip_bytes (struct sfm_reader *, size_t);
+static void trim_spaces (char *);
+
+int
+main (int argc, char *argv[])
+{
+  int max_cases = 0;
+  struct sfm_reader r;
+  int i;
+
+  set_program_name (argv[0]);
+
+  for (;;)
+    {
+      static const struct option long_options[] =
+        {
+          { "data",    optional_argument, NULL, 'd' },
+          { "help",    no_argument,       NULL, 'h' },
+          { "version", no_argument,       NULL, 'v' },
+          { NULL,      0,                 NULL, 0 },
+        };
+
+      int c;
+
+      c = getopt_long (argc, argv, "d::hv", long_options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'd':
+          max_cases = optarg ? atoi (optarg) : INT_MAX;
+          break;
+
+        case 'v':
+          version_etc (stdout, "pspp-dump-sav", PACKAGE_NAME, PACKAGE_VERSION,
+                       "Ben Pfaff", "John Darrington", NULL_SENTINEL);
+          exit (EXIT_SUCCESS);
+
+        case 'h':
+          usage ();
+          exit (EXIT_SUCCESS);
+
+        default:
+          exit (EXIT_FAILURE);
+        }
+    }
+
+  if (optind == argc)
+    error (1, 0, "at least one non-option argument is required; "
+           "use --help for help");
+
+  for (i = optind; i < argc; i++)
+    {
+      int rec_type;
+
+      r.file_name = argv[i];
+      r.file = fopen (r.file_name, "rb");
+      if (r.file == NULL)
+        error (EXIT_FAILURE, errno, "error opening `%s'", r.file_name);
+      r.n_variable_records = 0;
+      r.n_variables = 0;
+      r.n_var_widths = 0;
+      r.allocated_var_widths = 0;
+      r.var_widths = 0;
+      r.compressed = false;
+
+      if (argc - optind > 1)
+        printf ("Reading \"%s\":\n", r.file_name);
+      
+      read_header (&r);
+      while ((rec_type = read_int (&r)) != 999)
+        {
+          switch (rec_type)
+            {
+            case 2:
+              read_variable_record (&r);
+              break;
+
+            case 3:
+              read_value_label_record (&r);
+              break;
+
+            case 4:
+              sys_error (&r, "Misplaced type 4 record.");
+
+            case 6:
+              read_document_record (&r);
+              break;
+
+            case 7:
+              read_extension_record (&r);
+              break;
+
+            default:
+              sys_error (&r, "Unrecognized record type %d.", rec_type);
+            }
+        }
+      printf ("%08llx: end-of-dictionary record "
+              "(first byte of data at %08llx)\n",
+              (long long int) ftello (r.file),
+              (long long int) ftello (r.file) + 4);
+
+      if (r.compressed && max_cases > 0)
+        read_compressed_data (&r, max_cases);
+
+      fclose (r.file);
+    }
+  
+  return 0;
+}
+
+static void
+read_header (struct sfm_reader *r)
+{
+  char rec_type[5];
+  char eye_catcher[61];
+  uint8_t raw_layout_code[4];
+  int32_t layout_code;
+  int32_t nominal_case_size;
+  int32_t compressed;
+  int32_t weight_index;
+  int32_t ncases;
+  uint8_t raw_bias[8];
+  char creation_date[10];
+  char creation_time[9];
+  char file_label[65];
+
+  read_string (r, rec_type, sizeof rec_type);
+  read_string (r, eye_catcher, sizeof eye_catcher);
+
+  if (strcmp ("$FL2", rec_type) != 0)
+    sys_error (r, "This is not an SPSS system file.");
+
+  /* Identify integer format. */
+  read_bytes (r, raw_layout_code, sizeof raw_layout_code);
+  if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
+                          &r->integer_format)
+       && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
+                             &r->integer_format))
+      || (r->integer_format != INTEGER_MSB_FIRST
+          && r->integer_format != INTEGER_LSB_FIRST))
+    sys_error (r, "This is not an SPSS system file.");
+  layout_code = integer_get (r->integer_format,
+                             raw_layout_code, sizeof raw_layout_code);
+
+  nominal_case_size = read_int (r);
+  compressed = read_int (r);
+  weight_index = read_int (r);
+  ncases = read_int (r);
+
+  r->compressed = compressed != 0;
+
+  /* Identify floating-point format and obtain compression bias. */
+  read_bytes (r, raw_bias, sizeof raw_bias);
+  if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
+    {
+      sys_warn (r, "Compression bias is not the usual value of 100, or system "
+                "file uses unrecognized floating-point format.");
+      if (r->integer_format == INTEGER_MSB_FIRST)
+        r->float_format = FLOAT_IEEE_DOUBLE_BE;
+      else
+        r->float_format = FLOAT_IEEE_DOUBLE_LE;
+    }
+  r->bias = float_get_double (r->float_format, raw_bias);
+
+  read_string (r, creation_date, sizeof creation_date);
+  read_string (r, creation_time, sizeof creation_time);
+  read_string (r, file_label, sizeof file_label);
+  trim_spaces (file_label);
+  skip_bytes (r, 3);
+
+  printf ("File header record:\n");
+  printf ("\t%17s: %s\n", "Product name", eye_catcher);
+  printf ("\t%17s: %"PRId32"\n", "Layout code", layout_code);
+  printf ("\t%17s: %"PRId32"\n", "Compressed", compressed);
+  printf ("\t%17s: %"PRId32"\n", "Weight index", weight_index);
+  printf ("\t%17s: %"PRId32"\n", "Number of cases", ncases);
+  printf ("\t%17s: %g\n", "Compression bias", r->bias);
+  printf ("\t%17s: %s\n", "Creation date", creation_date);
+  printf ("\t%17s: %s\n", "Creation time", creation_time);
+  printf ("\t%17s: \"%s\"\n", "File label", file_label);
+}
+
+static const char *
+format_name (int format)
+{
+  switch ((format >> 16) & 0xff)
+    {
+    case 1: return "A";
+    case 2: return "AHEX";
+    case 3: return "COMMA";
+    case 4: return "DOLLAR";
+    case 5: return "F";
+    case 6: return "IB";
+    case 7: return "PIBHEX";
+    case 8: return "P";
+    case 9: return "PIB";
+    case 10: return "PK";
+    case 11: return "RB";
+    case 12: return "RBHEX";
+    case 15: return "Z";
+    case 16: return "N";
+    case 17: return "E";
+    case 20: return "DATE";
+    case 21: return "TIME";
+    case 22: return "DATETIME";
+    case 23: return "ADATE";
+    case 24: return "JDATE";
+    case 25: return "DTIME";
+    case 26: return "WKDAY";
+    case 27: return "MONTH";
+    case 28: return "MOYR";
+    case 29: return "QYR";
+    case 30: return "WKYR";
+    case 31: return "PCT";
+    case 32: return "DOT";
+    case 33: return "CCA";
+    case 34: return "CCB";
+    case 35: return "CCC";
+    case 36: return "CCD";
+    case 37: return "CCE";
+    case 38: return "EDATE";
+    case 39: return "SDATE";
+    default: return "invalid";
+    }
+}
+
+/* Reads a variable (type 2) record from R and adds the
+   corresponding variable to DICT.
+   Also skips past additional variable records for long string
+   variables. */
+static void
+read_variable_record (struct sfm_reader *r)
+{
+  int width;
+  int has_variable_label;
+  int missing_value_code;
+  int print_format;
+  int write_format;
+  char name[9];
+
+  printf ("%08llx: variable record #%d\n",
+          (long long int) ftello (r->file), r->n_variable_records++);
+
+  width = read_int (r);
+  has_variable_label = read_int (r);
+  missing_value_code = read_int (r);
+  print_format = read_int (r);
+  write_format = read_int (r);
+  read_string (r, name, sizeof name);
+  name[strcspn (name, " ")] = '\0';
+
+  if (width >= 0)
+    r->n_variables++;
+
+  if (r->n_var_widths >= r->allocated_var_widths)
+    r->var_widths = x2nrealloc (r->var_widths, &r->allocated_var_widths,
+                                sizeof *r->var_widths);
+  r->var_widths[r->n_var_widths++] = width;
+
+  printf ("\tWidth: %d (%s)\n",
+          width,
+          width > 0 ? "string"
+          : width == 0 ? "numeric"
+          : "long string continuation record");
+  printf ("\tVariable label: %d\n", has_variable_label);
+  printf ("\tMissing values code: %d (%s)\n", missing_value_code,
+          (missing_value_code == 0 ? "no missing values"
+           : missing_value_code == 1 ? "one missing value"
+           : missing_value_code == 2 ? "two missing values"
+           : missing_value_code == 3 ? "three missing values"
+           : missing_value_code == -2 ? "one missing value range"
+           : missing_value_code == -3 ? "one missing value, one range"
+           : "bad value"));
+  printf ("\tPrint format: %06x (%s%d.%d)\n",
+          print_format, format_name (print_format),
+          (print_format >> 8) & 0xff, print_format & 0xff);
+  printf ("\tWrite format: %06x (%s%d.%d)\n",
+          write_format, format_name (write_format),
+          (write_format >> 8) & 0xff, write_format & 0xff);
+  printf ("\tName: %s\n", name);
+
+  /* Get variable label, if any. */
+  if (has_variable_label != 0 && has_variable_label != 1)
+    sys_error (r, "Variable label indicator field is not 0 or 1.");
+  if (has_variable_label == 1)
+    {
+      long long int offset = ftello (r->file);
+      size_t len, read_len;
+      char label[255 + 1];
+
+      len = read_int (r);
+
+      /* Read up to 255 bytes of label. */
+      read_len = MIN (sizeof label - 1, len);
+      read_string (r, label, read_len + 1);
+      printf("\t%08llx Variable label: \"%s\"\n", offset, label);
+
+      /* Skip unread label bytes. */
+      skip_bytes (r, len - read_len);
+
+      /* Skip label padding up to multiple of 4 bytes. */
+      skip_bytes (r, ROUND_UP (len, 4) - len);
+    }
+
+  /* Set missing values. */
+  if (missing_value_code != 0)
+    {
+      int i;
+
+      printf ("\t%08llx Missing values:", (long long int) ftello (r->file));
+      if (!width)
+        {
+          if (missing_value_code < -3 || missing_value_code > 3
+              || missing_value_code == -1)
+            sys_error (r, "Numeric missing value indicator field is not "
+                       "-3, -2, 0, 1, 2, or 3.");
+          if (missing_value_code < 0)
+            {
+              double low = read_float (r);
+              double high = read_float (r);
+              printf (" %g...%g", low, high);
+              missing_value_code = -missing_value_code - 2;
+            }
+          for (i = 0; i < missing_value_code; i++)
+            printf (" %g", read_float (r));
+        }
+      else if (width > 0)
+        {
+          if (missing_value_code < 1 || missing_value_code > 3)
+            sys_error (r, "String missing value indicator field is not "
+                       "0, 1, 2, or 3.");
+          for (i = 0; i < missing_value_code; i++)
+            {
+              char string[9];
+              read_string (r, string, sizeof string);
+              printf (" \"%s\"", string);
+            }
+        }
+      putchar ('\n');
+    }
+}
+
+static void
+print_untyped_value (struct sfm_reader *r, char raw_value[8])
+{
+  int n_printable;
+  double value;
+
+  value = float_get_double (r->float_format, raw_value);
+  for (n_printable = 0; n_printable < sizeof raw_value; n_printable++)
+    if (!isprint (raw_value[n_printable]))
+      break;
+
+  printf ("%g/\"%.*s\"", value, n_printable, raw_value);
+}
+
+/* Reads value labels from sysfile R and inserts them into the
+   associated dictionary. */
+static void
+read_value_label_record (struct sfm_reader *r)
+{
+  int label_cnt, var_cnt;
+  int i;
+
+  printf ("%08llx: value labels record\n", (long long int) ftello (r->file));
+
+  /* Read number of labels. */
+  label_cnt = read_int (r);
+  for (i = 0; i < label_cnt; i++)
+    {
+      char raw_value[8];
+      unsigned char label_len;
+      size_t padded_len;
+      char label[256];
+
+      read_bytes (r, raw_value, sizeof raw_value);
+
+      /* Read label length. */
+      read_bytes (r, &label_len, sizeof label_len);
+      padded_len = ROUND_UP (label_len + 1, 8);
+
+      /* Read label, padding. */
+      read_bytes (r, label, padded_len - 1);
+      label[label_len] = 0;
+
+      printf ("\t");
+      print_untyped_value (r, raw_value);
+      printf (": \"%s\"\n", label);
+    }
+
+  /* Now, read the type 4 record that has the list of variables
+     to which the value labels are to be applied. */
+
+  /* Read record type of type 4 record. */
+  if (read_int (r) != 4)
+    sys_error (r, "Variable index record (type 4) does not immediately "
+               "follow value label record (type 3) as it should.");
+
+  /* Read number of variables associated with value label from type 4
+     record. */
+  printf ("\t%08llx: apply to variables", (long long int) ftello (r->file));
+  var_cnt = read_int (r);
+  for (i = 0; i < var_cnt; i++)
+    printf (" #%d", read_int (r));
+  putchar ('\n');
+}
+
+static void
+read_document_record (struct sfm_reader *r)
+{
+  int n_lines;
+  int i;
+
+  printf ("%08llx: document record\n", (long long int) ftello (r->file));
+  n_lines = read_int (r);
+  printf ("\t%d lines of documents\n", n_lines);
+
+  for (i = 0; i < n_lines; i++)
+    {
+      char line[81];
+      printf ("\t%08llx: ", (long long int) ftello (r->file));
+      read_string (r, line, sizeof line);
+      trim_spaces (line);
+      printf ("line %d: \"%s\"\n", i, line);
+    }
+}
+
+static void
+read_extension_record (struct sfm_reader *r)
+{
+  long long int offset = ftello (r->file);
+  int subtype = read_int (r);
+  size_t size = read_int (r);
+  size_t count = read_int (r);
+  size_t bytes = size * count;
+
+  printf ("%08llx: Record 7, subtype %d, size=%zu, count=%zu\n",
+          offset, subtype, size, count);
+
+  switch (subtype)
+    {
+    case 3:
+      read_machine_integer_info (r, size, count);
+      return;
+
+    case 4:
+      read_machine_float_info (r, size, count);
+      return;
+
+    case 5:
+      /* Variable sets information.  We don't use these yet.
+         They only apply to GUIs; see VARSETS on the APPLY
+         DICTIONARY command in SPSS documentation. */
+      break;
+
+    case 6:
+      /* DATE variable information.  We don't use it yet, but we
+         should. */
+      break;
+
+    case 7:
+    case 19:
+      read_mrsets (r, size, count);
+      return;
+
+    case 11:
+      read_display_parameters (r, size, count);
+      return;
+
+    case 13:
+      read_long_var_name_map (r, size, count);
+      return;
+
+    case 14:
+      read_long_string_map (r, size, count);
+      return;
+
+    case 16:
+      read_ncases64 (r, size, count);
+      return;
+
+    case 17:
+      read_datafile_attributes (r, size, count);
+      return;
+
+    case 18:
+      read_variable_attributes (r, size, count);
+      return;
+
+    case 20:
+      read_character_encoding (r, size, count);
+      return;
+
+    case 21:
+      read_long_string_value_labels (r, size, count);
+      return;
+
+    default:
+      sys_warn (r, "Unrecognized record type 7, subtype %d.", subtype);
+      read_unknown_extension (r, size, count);
+      return;
+    }
+
+  skip_bytes (r, bytes);
+}
+
+static void
+read_machine_integer_info (struct sfm_reader *r, size_t size, size_t count)
+{
+  long long int offset = ftello (r->file);
+  int version_major = read_int (r);
+  int version_minor = read_int (r);
+  int version_revision = read_int (r);
+  int machine_code = read_int (r);
+  int float_representation = read_int (r);
+  int compression_code = read_int (r);
+  int integer_representation = read_int (r);
+  int character_code = read_int (r);
+
+  printf ("%08llx: machine integer info\n", offset);
+  if (size != 4 || count != 8)
+    sys_error (r, "Bad size (%zu) or count (%zu) field on record type 7, "
+               "subtype 3.", size, count);
+
+  printf ("\tVersion: %d.%d.%d\n",
+          version_major, version_minor, version_revision);
+  printf ("\tMachine code: %d\n", machine_code);
+  printf ("\tFloating point representation: %d (%s)\n",
+          float_representation,
+          float_representation == 1 ? "IEEE 754"
+          : float_representation == 2 ? "IBM 370"
+          : float_representation == 3 ? "DEC VAX"
+          : "unknown");
+  printf ("\tCompression code: %d\n", compression_code);
+  printf ("\tEndianness: %d (%s)\n", integer_representation,
+          integer_representation == 1 ? "big"
+          : integer_representation == 2 ? "little" : "unknown");
+  printf ("\tCharacter code: %d\n", character_code);
+}
+
+/* Read record type 7, subtype 4. */
+static void
+read_machine_float_info (struct sfm_reader *r, size_t size, size_t count)
+{
+  long long int offset = ftello (r->file);
+  double sysmis = read_float (r);
+  double highest = read_float (r);
+  double lowest = read_float (r);
+
+  printf ("%08llx: machine float info\n", offset);
+  if (size != 8 || count != 3)
+    sys_error (r, "Bad size (%zu) or count (%zu) on extension 4.",
+               size, count);
+
+  printf ("\tsysmis: %g\n", sysmis);
+  if (sysmis != SYSMIS)
+    sys_warn (r, "File specifies unexpected value %g as %s.",
+              sysmis, "SYSMIS");
+
+  printf ("\thighest: %g\n", highest);
+  if (highest != HIGHEST)
+    sys_warn (r, "File specifies unexpected value %g as %s.",
+              highest, "HIGHEST");
+
+  printf ("\tlowest: %g\n", lowest);
+  if (lowest != LOWEST)
+    sys_warn (r, "File specifies unexpected value %g as %s.",
+              lowest, "LOWEST");
+}
+
+/* Read record type 7, subtype 7. */
+static void
+read_mrsets (struct sfm_reader *r, size_t size, size_t count)
+{
+  struct text_record *text;
+
+  printf ("%08llx: multiple response sets\n",
+          (long long int) ftello (r->file));
+  text = open_text_record (r, size * count);
+  for (;;)
+    {
+      const char *name;
+      enum { MRSET_MC, MRSET_MD } type;
+      bool cat_label_from_counted_values = false;
+      bool label_from_var_label = false;
+      const char *counted;
+      const char *label;
+      const char *variables;
+
+      name = text_tokenize (text, '=');
+      if (name == NULL)
+        break;
+
+      if (text_match (text, 'C'))
+        {
+          type = MRSET_MC;
+          counted = NULL;
+          if (!text_match (text, ' '))
+            {
+              sys_warn (r, "missing space following 'C' at offset %zu "
+                        "in mrsets record", text_pos (text));
+              break;
+            }
+        }
+      else if (text_match (text, 'D'))
+        {
+          type = MRSET_MD;
+        }
+      else if (text_match (text, 'E'))
+        {
+          char *number;
+
+          type = MRSET_MD;
+          cat_label_from_counted_values = true;
+
+          if (!text_match (text, ' '))
+            {
+              sys_warn (r, "Missing space following `%c' at offset %zu "
+                        "in MRSETS record", 'E', text_pos (text));
+              break;
+            }
+
+          number = text_tokenize (text, ' ');
+          if (!strcmp (number, "11"))
+            label_from_var_label = true;
+          else if (strcmp (number, "1"))
+            sys_warn (r, "Unexpected label source value `%s' "
+                      "following `E' at offset %zu in MRSETS record",
+                      number, text_pos (text));
+
+        }
+      else
+        {
+          sys_warn (r, "missing `C', `D', or `E' at offset %zu "
+                    "in mrsets record", text_pos (text));
+          break;
+        }
+
+      if (type == MRSET_MD)
+        {
+          counted = text_parse_counted_string (text);
+          if (counted == NULL)
+            break;
+        }
+
+      label = text_parse_counted_string (text);
+      if (label == NULL)
+        break;
+
+      variables = text_tokenize (text, '\n');
+      if (variables == NULL)
+        {
+          sys_warn (r, "missing variable names following label "
+                    "at offset %zu in mrsets record", text_pos (text));
+          break;
+        }
+
+      printf ("\t\"%s\": multiple %s set",
+              name, type == MRSET_MC ? "category" : "dichotomy");
+      if (counted != NULL)
+        printf (", counted value \"%s\"", counted);
+      if (cat_label_from_counted_values)
+        printf (", category labels from counted values");
+      if (label[0] != '\0')
+        printf (", label \"%s\"", label);
+      if (label_from_var_label)
+        printf (", label from variable label");
+      printf(", variables \"%s\"\n", variables);
+    }
+  close_text_record (text);
+}
+
+/* Read record type 7, subtype 11. */
+static void
+read_display_parameters (struct sfm_reader *r, size_t size, size_t count)
+{
+  size_t n_vars;
+  bool includes_width;
+  size_t i;
+
+  printf ("%08llx: variable display parameters\n",
+          (long long int) ftello (r->file));
+  if (size != 4)
+    {
+      sys_warn (r, "Bad size %zu on extension 11.", size);
+      skip_bytes (r, size * count);
+      return;
+    }
+
+  n_vars = r->n_variables;
+  if (count == 3 * n_vars)
+    includes_width = true;
+  else if (count == 2 * n_vars)
+    includes_width = false;
+  else
+    {
+      sys_warn (r, "Extension 11 has bad count %zu (for %zu variables.",
+                count, n_vars);
+      skip_bytes (r, size * count);
+      return;
+    }
+
+  for (i = 0; i < n_vars; ++i)
+    {
+      int measure = read_int (r);
+      int width = includes_width ? read_int (r) : 0;
+      int align = read_int (r);
+
+      printf ("\tVar #%zu: measure=%d (%s)", i, measure,
+              (measure == 1 ? "nominal"
+               : measure == 2 ? "ordinal"
+               : measure == 3 ? "scale"
+               : "invalid"));
+      if (includes_width)
+        printf (", width=%d", width);
+      printf (", align=%d (%s)\n", align,
+              (align == 0 ? "left"
+               : align == 1 ? "right"
+               : align == 2 ? "centre"
+               : "invalid"));
+    }
+}
+
+/* Reads record type 7, subtype 13, which gives the long name
+   that corresponds to each short name.  */
+static void
+read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count)
+{
+  struct text_record *text;
+  char *var;
+  char *long_name;
+
+  printf ("%08llx: long variable names (short => long)\n",
+          (long long int) ftello (r->file));
+  text = open_text_record (r, size * count);
+  while (read_variable_to_value_pair (text, &var, &long_name))
+    printf ("\t%s => %s\n", var, long_name);
+  close_text_record (text);
+}
+
+/* Reads record type 7, subtype 14, which gives the real length
+   of each very long string.  Rearranges DICT accordingly. */
+static void
+read_long_string_map (struct sfm_reader *r, size_t size, size_t count)
+{
+  struct text_record *text;
+  char *var;
+  char *length_s;
+
+  printf ("%08llx: very long strings (variable => length)\n",
+          (long long int) ftello (r->file));
+  text = open_text_record (r, size * count);
+  while (read_variable_to_value_pair (text, &var, &length_s))
+    printf ("\t%s => %d\n", var, atoi (length_s));
+  close_text_record (text);
+}
+
+static bool
+read_attributes (struct sfm_reader *r, struct text_record *text,
+                 const char *variable)
+{
+  const char *key;
+  int index;
+
+  for (;;) 
+    {
+      key = text_tokenize (text, '(');
+      if (key == NULL)
+        return true;
+  
+      for (index = 1; ; index++)
+        {
+          /* Parse the value. */
+          const char *value = text_tokenize (text, '\n');
+          if (value == NULL) 
+            {
+              sys_warn (r, "%s: Error parsing attribute value %s[%d]",
+                        variable, key, index);
+              return false;
+            }
+          if (strlen (value) < 2
+              || value[0] != '\'' || value[strlen (value) - 1] != '\'')
+            sys_warn (r, "%s: Attribute value %s[%d] is not quoted: %s",
+                      variable, key, index, value);
+          else
+            printf ("\t%s: %s[%d] = \"%.*s\"\n",
+                    variable, key, index, (int) strlen (value) - 2, value + 1);
+
+          /* Was this the last value for this attribute? */
+          if (text_match (text, ')'))
+            break;
+        }
+
+      if (text_match (text, '/'))
+        return true; 
+    }
+}
+
+/* Read extended number of cases record. */
+static void
+read_ncases64 (struct sfm_reader *r, size_t size, size_t count)
+{
+  int64_t unknown, ncases64;
+
+  if (size != 8)
+    {
+      sys_warn (r, "Bad size %zu for extended number of cases.", size);
+      skip_bytes (r, size * count);
+      return;
+    }
+  if (count != 2)
+    {
+      sys_warn (r, "Bad count %zu for extended number of cases.", size);
+      skip_bytes (r, size * count);
+      return;
+    }
+  unknown = read_int64 (r);
+  ncases64 = read_int64 (r);
+  printf ("%08llx: extended number of cases: "
+          "unknown=%"PRId64", ncases64=%"PRId64"\n",
+          (long long int) ftello (r->file), unknown, ncases64);
+}
+
+static void
+read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count) 
+{
+  struct text_record *text;
+  
+  printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file));
+  text = open_text_record (r, size * count);
+  read_attributes (r, text, "datafile");
+  close_text_record (text);
+}
+
+static void
+read_character_encoding (struct sfm_reader *r, size_t size, size_t count)
+{
+  long long int posn =  ftello (r->file);
+  char *encoding = xcalloc (size, count + 1);
+  read_string (r, encoding, count + 1);
+
+  printf ("%08llx: Character Encoding: %s\n", posn, encoding);
+}
+
+static void
+read_long_string_value_labels (struct sfm_reader *r, size_t size, size_t count)
+{
+  long long int start = ftello (r->file);
+
+  printf ("%08llx: long string value labels\n", start);
+  while (ftello (r->file) - start < size * count)
+    {
+      long long posn = ftello (r->file);
+      char var_name[ID_MAX_LEN + 1];
+      int var_name_len;
+      int n_values;
+      int width;
+      int i;
+
+      /* Read variable name. */
+      var_name_len = read_int (r);
+      if (var_name_len > ID_MAX_LEN)
+        sys_error (r, "Variable name length in long string value label "
+                   "record (%d) exceeds %d-byte limit.",
+                   var_name_len, ID_MAX_LEN);
+      read_string (r, var_name, var_name_len + 1);
+
+      /* Read width, number of values. */
+      width = read_int (r);
+      n_values = read_int (r);
+
+      printf ("\t%08llx: %s, width %d, %d values\n",
+              posn, var_name, width, n_values);
+
+      /* Read values. */
+      for (i = 0; i < n_values; i++)
+       {
+          char *value;
+          int value_length;
+
+          char *label;
+         int label_length;
+
+          posn = ftello (r->file);
+
+          /* Read value. */
+          value_length = read_int (r);
+          value = xmalloc (value_length + 1);
+          read_string (r, value, value_length + 1);
+
+          /* Read label. */
+          label_length = read_int (r);
+          label = xmalloc (label_length + 1);
+          read_string (r, label, label_length + 1);
+
+          printf ("\t\t%08llx: \"%s\" (%d bytes) => \"%s\" (%d bytes)\n",
+                  posn, value, value_length, label, label_length);
+
+          free (value);
+          free (label);
+       }
+    }
+}
+
+static void
+hex_dump (size_t offset, const void *buffer_, size_t buffer_size)
+{
+  const uint8_t *buffer = buffer_;
+
+  while (buffer_size > 0)
+    {
+      size_t n = MIN (buffer_size, 16);
+      size_t i;
+
+      printf ("%04zx", offset);
+      for (i = 0; i < 16; i++)
+        {
+          if (i < n)
+            printf ("%c%02x", i == 8 ? '-' : ' ', buffer[i]);
+          else
+            printf ("   ");
+        }
+
+      printf (" |");
+      for (i = 0; i < 16; i++)
+        {
+          unsigned char c = i < n ? buffer[i] : ' ';
+          putchar (isprint (c) ? c : '.');
+        }
+      printf ("|\n");
+
+      offset += n;
+      buffer += n;
+      buffer_size -= n;
+    }
+}
+
+/* Reads and prints any type 7 record that we don't understand. */
+static void
+read_unknown_extension (struct sfm_reader *r, size_t size, size_t count)
+{
+  unsigned char *buffer;
+  size_t i;
+
+  if (size == 0 || count > 65536 / size)
+    skip_bytes (r, size * count);
+  else if (size != 1)
+    {
+      buffer = xmalloc (size);
+      for (i = 0; i < count; i++)
+        {
+          read_bytes (r, buffer, size);
+          hex_dump (i * size, buffer, size);
+        }
+      free (buffer);
+    }
+  else
+    {
+      buffer = xmalloc (count);
+      read_bytes (r, buffer, count);
+      if (memchr (buffer, 0, count) == 0)
+        for (i = 0; i < count; i++)
+          {
+            unsigned char c = buffer[i];
+
+            if (c == '\\')
+              printf ("\\\\");
+            else if (c == '\n' || isprint (c))
+              putchar (c);
+            else
+              printf ("\\%02x", c);
+          }
+      else
+        hex_dump (0, buffer, count);
+      free (buffer);
+    }
+}
+
+static void
+read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) 
+{
+  struct text_record *text;
+  
+  printf ("%08llx: variable attributes\n", (long long int) ftello (r->file));
+  text = open_text_record (r, size * count);
+  for (;;) 
+    {
+      const char *variable = text_tokenize (text, ':');
+      if (variable == NULL || !read_attributes (r, text, variable))
+        break; 
+    }
+  close_text_record (text);
+}
+
+static void
+read_compressed_data (struct sfm_reader *r, int max_cases)
+{
+  enum { N_OPCODES = 8 };
+  uint8_t opcodes[N_OPCODES];
+  long long int opcode_ofs;
+  int opcode_idx;
+  int case_num;
+  int i;
+
+  read_int (r);
+  printf ("\n%08llx: compressed data:\n", (long long int) ftello (r->file));
+
+  opcode_idx = N_OPCODES;
+  opcode_ofs = 0;
+  case_num = 0;
+  for (case_num = 0; case_num < max_cases; case_num++)
+    {
+      printf ("%08llx: case %d's uncompressible data begins\n",
+              (long long int) ftello (r->file), case_num);
+      for (i = 0; i < r->n_var_widths; )
+        {
+          int width = r->var_widths[i];
+          char raw_value[8];
+          int opcode;
+
+          if (opcode_idx >= N_OPCODES)
+            {
+              opcode_ofs = ftello (r->file);
+              if (i == 0)
+                {
+                  if (!try_read_bytes (r, opcodes, 8))
+                    return;
+                }
+              else
+                read_bytes (r, opcodes, 8);
+              opcode_idx = 0;
+            }
+          opcode = opcodes[opcode_idx];
+          printf ("%08llx: variable %d: opcode %d: ",
+                  opcode_ofs + opcode_idx, i, opcode);
+
+          switch (opcode)
+            {
+            default:
+              printf ("%g", opcode - r->bias);
+              if (width != 0)
+                printf (", but this is a string variable (width=%d)", width);
+              printf ("\n");
+              i++;
+              break;
+
+            case 0:
+              printf ("ignored padding\n");
+              break;
+
+            case 252:
+              printf ("end of data\n");
+              return;
+
+            case 253:
+              read_bytes (r, raw_value, 8);
+              printf ("uncompressible data: ");
+              print_untyped_value (r, raw_value);
+              printf ("\n");
+              i++;
+              break;
+
+            case 254:
+              printf ("spaces");
+              if (width == 0)
+                printf (", but this is a numeric variable");
+              printf ("\n");
+              i++;
+              break;
+
+            case 255:
+              printf ("SYSMIS");
+              if (width != 0)
+                printf (", but this is a string variable (width=%d)", width);
+              printf ("\n");
+              i++;
+              break;
+            }
+
+          opcode_idx++;
+        }
+    }
+}
+\f
+/* Helpers for reading records that consist of structured text
+   strings. */
+
+/* State. */
+struct text_record
+  {
+    struct sfm_reader *reader;  /* Reader. */
+    char *buffer;               /* Record contents. */
+    size_t size;                /* Size of buffer. */
+    size_t pos;                 /* Current position in buffer. */
+  };
+
+/* Reads SIZE bytes into a text record for R,
+   and returns the new text record. */
+static struct text_record *
+open_text_record (struct sfm_reader *r, size_t size)
+{
+  struct text_record *text = xmalloc (sizeof *text);
+  char *buffer = xmalloc (size + 1);
+  read_bytes (r, buffer, size);
+  buffer[size] = '\0';
+  text->reader = r;
+  text->buffer = buffer;
+  text->size = size;
+  text->pos = 0;
+  return text;
+}
+
+/* Closes TEXT and frees its storage.
+   Not really needed, because the pool will free the text record anyway,
+   but can be used to free it earlier. */
+static void
+close_text_record (struct text_record *text)
+{
+  free (text->buffer);
+  free (text);
+}
+
+static char *
+text_tokenize (struct text_record *text, int delimiter)
+{
+  size_t start = text->pos;
+  while (text->pos < text->size
+         && text->buffer[text->pos] != delimiter
+         && text->buffer[text->pos] != '\0')
+    text->pos++;
+  if (start == text->pos)
+    return NULL;
+  text->buffer[text->pos++] = '\0';
+  return &text->buffer[start];
+}
+
+static bool
+text_match (struct text_record *text, int c) 
+{
+  if (text->pos < text->size && text->buffer[text->pos] == c) 
+    {
+      text->pos++;
+      return true;
+    }
+  else
+    return false;
+}
+
+/* Reads a integer value expressed in decimal, then a space, then a string that
+   consists of exactly as many bytes as specified by the integer, then a space,
+   from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
+   buffer (so the caller should not free the string). */
+static const char *
+text_parse_counted_string (struct text_record *text)
+{
+  size_t start;
+  size_t n;
+  char *s;
+
+  start = text->pos;
+  n = 0;
+  while (isdigit ((unsigned char) text->buffer[text->pos]))
+    n = (n * 10) + (text->buffer[text->pos++] - '0');
+  if (start == text->pos)
+    {
+      sys_error (text->reader, "expecting digit at offset %zu in record",
+                 text->pos);
+      return NULL;
+    }
+
+  if (!text_match (text, ' '))
+    {
+      sys_error (text->reader, "expecting space at offset %zu in record",
+                 text->pos);
+      return NULL;
+    }
+
+  if (text->pos + n > text->size)
+    {
+      sys_error (text->reader, "%zu-byte string starting at offset %zu "
+                 "exceeds record length %zu", n, text->pos, text->size);
+      return NULL;
+    }
+
+  s = &text->buffer[text->pos];
+  if (s[n] != ' ')
+    {
+      sys_error (text->reader, "expecting space at offset %zu following "
+                 "%zu-byte string", text->pos + n, n);
+      return NULL;
+    }
+  s[n] = '\0';
+  text->pos += n + 1;
+  return s;
+}
+
+/* Reads a variable=value pair from TEXT.
+   Looks up the variable in DICT and stores it into *VAR.
+   Stores a null-terminated value into *VALUE. */
+static bool
+read_variable_to_value_pair (struct text_record *text,
+                             char **key, char **value)
+{
+  *key = text_tokenize (text, '=');
+  *value = text_tokenize (text, '\t');
+  if (!*key || !*value)
+    return false;
+
+  while (text->pos < text->size
+         && (text->buffer[text->pos] == '\t'
+             || text->buffer[text->pos] == '\0'))
+    text->pos++;
+  return true;
+}
+
+/* Returns the current byte offset inside the TEXT's string. */
+static size_t
+text_pos (const struct text_record *text)
+{
+  return text->pos;
+}
+\f
+static void
+usage (void)
+{
+  printf ("\
+%s, a utility for dissecting system files.\n\
+Usage: %s [OPTION]... SYSFILE...\n\
+where each SYSFILE is the name of a system file.\n\
+\n\
+Options:\n\
+  --data[=MAXCASES]   print (up to MAXCASES cases of) compressed data\n\
+  --help              display this help and exit\n\
+  --version           output version information and exit\n",
+          program_name, program_name);
+}
+
+/* Displays a corruption message. */
+static void
+sys_msg (struct sfm_reader *r, const char *format, va_list args)
+{
+  printf ("\"%s\" near offset 0x%llx: ",
+          r->file_name, (long long int) ftello (r->file));
+  vprintf (format, args);
+  putchar ('\n');
+}
+
+/* Displays a warning for the current file position. */
+static void
+sys_warn (struct sfm_reader *r, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  sys_msg (r, format, args);
+  va_end (args);
+}
+
+/* Displays an error for the current file position,
+   marks it as in an error state,
+   and aborts reading it using longjmp. */
+static void
+sys_error (struct sfm_reader *r, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  sys_msg (r, format, args);
+  va_end (args);
+
+  exit (EXIT_FAILURE);
+}
+\f
+/* Reads BYTE_CNT bytes into BUF.
+   Returns true if exactly BYTE_CNT bytes are successfully read.
+   Aborts if an I/O error or a partial read occurs.
+   If EOF_IS_OK, then an immediate end-of-file causes false to be
+   returned; otherwise, immediate end-of-file causes an abort
+   too. */
+static inline bool
+read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
+                     void *buf, size_t byte_cnt)
+{
+  size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
+  if (bytes_read == byte_cnt)
+    return true;
+  else if (ferror (r->file))
+    sys_error (r, "System error: %s.", strerror (errno));
+  else if (!eof_is_ok || bytes_read != 0)
+    sys_error (r, "Unexpected end of file.");
+  else
+    return false;
+}
+
+/* Reads BYTE_CNT into BUF.
+   Aborts upon I/O error or if end-of-file is encountered. */
+static void
+read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
+{
+  read_bytes_internal (r, false, buf, byte_cnt);
+}
+
+/* Reads BYTE_CNT bytes into BUF.
+   Returns true if exactly BYTE_CNT bytes are successfully read.
+   Returns false if an immediate end-of-file is encountered.
+   Aborts if an I/O error or a partial read occurs. */
+static bool
+try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
+{
+  return read_bytes_internal (r, true, buf, byte_cnt);
+}
+
+/* Reads a 32-bit signed integer from R and returns its value in
+   host format. */
+static int
+read_int (struct sfm_reader *r)
+{
+  uint8_t integer[4];
+  read_bytes (r, integer, sizeof integer);
+  return integer_get (r->integer_format, integer, sizeof integer);
+}
+
+/* Reads a 64-bit signed integer from R and returns its value in
+   host format. */
+static int64_t
+read_int64 (struct sfm_reader *r)
+{
+  uint8_t integer[8];
+  read_bytes (r, integer, sizeof integer);
+  return integer_get (r->integer_format, integer, sizeof integer);
+}
+
+/* Reads a 64-bit floating-point number from R and returns its
+   value in host format. */
+static double
+read_float (struct sfm_reader *r)
+{
+  uint8_t number[8];
+  read_bytes (r, number, sizeof number);
+  return float_get_double (r->float_format, number);
+}
+
+/* Reads exactly SIZE - 1 bytes into BUFFER
+   and stores a null byte into BUFFER[SIZE - 1]. */
+static void
+read_string (struct sfm_reader *r, char *buffer, size_t size)
+{
+  assert (size > 0);
+  read_bytes (r, buffer, size - 1);
+  buffer[size - 1] = '\0';
+}
+
+/* Skips BYTES bytes forward in R. */
+static void
+skip_bytes (struct sfm_reader *r, size_t bytes)
+{
+  while (bytes > 0)
+    {
+      char buffer[1024];
+      size_t chunk = MIN (sizeof buffer, bytes);
+      read_bytes (r, buffer, chunk);
+      bytes -= chunk;
+    }
+}
+
+static void
+trim_spaces (char *s)
+{
+  char *end = strchr (s, '\0');
+  while (end > s && end[-1] == ' ')
+    end--;
+  *end = '\0';
+}