[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Pspp-cvs] pspp Smake configure.ac src/data/ChangeLog src/... [simpler-p
From: |
Ben Pfaff |
Subject: |
[Pspp-cvs] pspp Smake configure.ac src/data/ChangeLog src/... [simpler-proc] |
Date: |
Mon, 19 Mar 2007 21:36:26 +0000 |
CVSROOT: /cvsroot/pspp
Module name: pspp
Branch: simpler-proc
Changes by: Ben Pfaff <blp> 07/03/19 21:36:25
Modified files:
. : Smake configure.ac
src/data : ChangeLog any-reader.c any-reader.h
any-writer.c any-writer.h automake.mk case.c
case.h dictionary.c por-file-reader.c
por-file-reader.h por-file-writer.c
por-file-writer.h procedure.c procedure.h
scratch-handle.c scratch-handle.h
scratch-reader.c scratch-reader.h
scratch-writer.c scratch-writer.h settings.c
settings.h sys-file-reader.c sys-file-reader.h
sys-file-writer.c sys-file-writer.h
transformations.h value.h variable.c
src/language : command.c command.def
src/language/control: do-if.c
src/language/data-io: data-list.c data-reader.c get.c inpt-pgm.c
list.q
src/language/dictionary: apply-dictionary.c delete-variables.c
modify-variables.c sys-file-info.c
src/language/expressions: evaluate.c
src/language/lexer: variable-parser.c
src/language/stats: ChangeLog aggregate.c autorecode.c
binomial.c binomial.h chisquare.c
chisquare.h crosstabs.q descriptives.c
examine.q flip.c frequencies.q
npar-summary.c npar-summary.h npar.h npar.q
oneway.q rank.q regression.q sort-cases.c
sort-criteria.c sort-criteria.h t-test.q
src/language/tests: automake.mk
src/libpspp : alloc.c array.c deque.h
src/math : automake.mk levene.c levene.h sort.c sort.h
src/ui : automake.mk
src/ui/gui : automake.mk helper.c missing-val-dialog.c
psppire-case-file.c psppire-case-file.h
psppire-data-store.c psppire.c
sort-cases-dialog.c sort-cases-dialog.h
var-sheet.c
src/ui/terminal: automake.mk main.c
tests : automake.mk
tests/command : rank.sh
tests/libpspp : heap-test.c ll-test.c llx-test.c
Added files:
src/data : buffered-reader.c buffered-reader.h
case-tmpfile.c case-tmpfile.h casegrouper.c
casegrouper.h caseinit.c caseinit.h
casereader-private.h casereader.c casereader.h
casewindow.c casewindow.h casewriter-private.h
casewriter.c casewriter.h datasheet.c
datasheet.h
src/libpspp : count.h fat-array.h range-map.h range-set.h
sliding-window.h sparse-array.c sparse-array.h
src/math : merge.c merge.h ordering.c ordering.h
Log message:
Create simpler-proc branch.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pspp/Smake?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.49&r2=1.49.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/configure.ac?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.54&r2=1.54.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/ChangeLog?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.108&r2=1.108.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/any-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.7&r2=1.7.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/any-reader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/any-writer.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.7&r2=1.7.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/any-writer.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.15&r2=1.15.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.10&r2=1.10.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.9&r2=1.9.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/dictionary.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.32&r2=1.32.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/por-file-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.17&r2=1.17.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/por-file-reader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/por-file-writer.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.9&r2=1.9.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/por-file-writer.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/procedure.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.25&r2=1.25.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/procedure.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.12&r2=1.12.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-handle.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-handle.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-reader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-writer.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/scratch-writer.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/settings.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.6&r2=1.6.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/settings.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/sys-file-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.32&r2=1.32.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/sys-file-reader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.3&r2=1.3.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/sys-file-writer.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.22&r2=1.22.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/sys-file-writer.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/transformations.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/value.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.7&r2=1.7.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/variable.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.21&r2=1.21.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/buffered-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/buffered-reader.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casegrouper.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casegrouper.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/caseinit.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/caseinit.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader-private.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewindow.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewindow.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewriter-private.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewriter.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewriter.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/datasheet.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/datasheet.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/command.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.23&r2=1.23.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/command.def?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.14&r2=1.14.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/control/do-if.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.12&r2=1.12.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/data-io/data-list.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.30&r2=1.30.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/data-io/data-reader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.20&r2=1.20.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/data-io/get.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.29&r2=1.29.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/data-io/inpt-pgm.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.23&r2=1.23.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/data-io/list.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.24&r2=1.24.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/dictionary/apply-dictionary.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.13&r2=1.13.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/dictionary/delete-variables.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1&r2=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/dictionary/modify-variables.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.16&r2=1.16.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/dictionary/sys-file-info.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.22&r2=1.22.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/expressions/evaluate.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.18&r2=1.18.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/lexer/variable-parser.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.15&r2=1.15.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/ChangeLog?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.45&r2=1.45.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/aggregate.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.30&r2=1.30.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/autorecode.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.18&r2=1.18.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/binomial.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/binomial.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/chisquare.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.3&r2=1.3.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/chisquare.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/crosstabs.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.27&r2=1.27.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/descriptives.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.22&r2=1.22.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/examine.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.22&r2=1.22.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/flip.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.22&r2=1.22.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/frequencies.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.29&r2=1.29.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/npar-summary.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/npar-summary.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/npar.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/npar.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.3&r2=1.3.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/oneway.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.21&r2=1.21.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/rank.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.27&r2=1.27.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/regression.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.45&r2=1.45.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/sort-cases.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.8&r2=1.8.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/sort-criteria.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.7&r2=1.7.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/sort-criteria.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/stats/t-test.q?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.20&r2=1.20.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/language/tests/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/alloc.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/array.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.10&r2=1.10.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/deque.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1&r2=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/count.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/fat-array.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/range-map.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/range-set.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/sliding-window.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/sparse-array.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/libpspp/sparse-array.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/levene.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.9&r2=1.9.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/levene.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/sort.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.23&r2=1.23.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/sort.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/merge.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/merge.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/ordering.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/ordering.h?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.21&r2=1.21.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/helper.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.16&r2=1.16.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/missing-val-dialog.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.13&r2=1.13.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/psppire-case-file.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.17&r2=1.17.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/psppire-case-file.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.11&r2=1.11.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/psppire-data-store.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.33&r2=1.33.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/psppire.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.35&r2=1.35.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/sort-cases-dialog.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.6&r2=1.6.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/sort-cases-dialog.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/var-sheet.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.20&r2=1.20.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/terminal/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.14&r2=1.14.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/terminal/main.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.30&r2=1.30.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.27&r2=1.27.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/command/rank.sh?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.4&r2=1.4.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/libpspp/heap-test.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.2&r2=1.2.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/libpspp/ll-test.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/tests/libpspp/llx-test.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.5&r2=1.5.2.1
Patches:
Index: Smake
===================================================================
RCS file: /cvsroot/pspp/pspp/Smake,v
retrieving revision 1.49
retrieving revision 1.49.2.1
diff -u -b -r1.49 -r1.49.2.1
--- Smake 22 Feb 2007 11:26:36 -0000 1.49
+++ Smake 19 Mar 2007 21:36:24 -0000 1.49.2.1
@@ -55,6 +55,7 @@
vsnprintf \
xalloc \
xalloc-die \
+ xallocsa \
xsize \
xstrndup \
xvasprintf
Index: configure.ac
===================================================================
RCS file: /cvsroot/pspp/pspp/configure.ac,v
retrieving revision 1.54
retrieving revision 1.54.2.1
diff -u -b -r1.54 -r1.54.2.1
--- configure.ac 16 Feb 2007 19:24:25 -0000 1.54
+++ configure.ac 19 Mar 2007 21:36:24 -0000 1.54.2.1
@@ -9,12 +9,13 @@
dnl Checks for programs.
AC_GNU_SOURCE
AC_PROG_CC
-gl_EARLY
AM_PROG_CC_C_O
+gl_EARLY
AC_LIBTOOL_DLOPEN
AC_PROG_LIBTOOL
PSPP_ENABLE_WARNING(-Wdeclaration-after-statement)
+PSPP_ENABLE_WARNING(-Wno-missing-field-initializers)
AM_CONDITIONAL(cc_is_gcc, test x"$GCC" = x"yes" )
Index: src/data/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/ChangeLog,v
retrieving revision 1.108
retrieving revision 1.108.2.1
diff -u -b -r1.108 -r1.108.2.1
--- src/data/ChangeLog 19 Feb 2007 18:57:04 -0000 1.108
+++ src/data/ChangeLog 19 Mar 2007 21:36:24 -0000 1.108.2.1
@@ -1,3 +1,46 @@
+Fri Dec 22 13:56:08 2006 Ben Pfaff <address@hidden>
+
+ Simplify missing value handling.
+
+ * missing-values.h (enum mv_class): New type.
+ (enum mv_type): Moved definition into missing-values.c and renamed
+ each MV_* to MVT_*, to distinguish them from the exposed mv_class
+ enums. Updated all uses.
+ (struct missing_values): Changed type of `type' from `enum
+ mv_type' to `int' because the definition is no longer exposed.
+
+ * missing-values.c (mv_is_value_missing): Add new enum mv_class
+ parameter. Update all callers.
+ (mv_is_num_missing): Ditto.
+ (mv_is_str_missing): Ditto.
+ (mv_is_value_user_missing): Removed. Changed callers to use
+ mv_is_value_missing.
+ (mv_is_num_user_missing): Removed. Changed callers to use
+ mv_is_num_missing.
+ (mv_is_str_user_missing): Removed. Changed callers to use
+ mv_is_str_missing.
+ (mv_is_value_system_missing): Removed. Changed callers to use
+ mv_is_value_missing.
+
+ * variable.c (var_is_value_missing): Add new enum mv_class
+ parameter. Update all callers.
+ (var_is_num_missing): Ditto.
+ (var_is_str_missing): Ditto.
+ (var_is_value_user_missing): Removed. Changed callers to use
+ var_is_value_missing.
+ (var_is_num_user_missing): Removed. Changed callers to use
+ var_is_num_missing.
+ (var_is_str_user_missing): Removed. Changed callers to use
+ var_is_str_missing.
+ (var_is_value_system_missing): Removed. Changed callers to use
+ var_is_value_missing.
+
+ * casefilter.c (struct casefilter): Use enum mv_class in place of
+ bool.
+ (casefilter_variable_missing): Adapt to new member.
+ (casefilter_create): Change signature to take enum mv_class,
+ update callers.
+
Mon Feb 19 10:53:21 2007 John McCabe-Dansted <address@hidden>
Ben Pfaff <address@hidden>
Index: src/data/any-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/any-reader.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -b -r1.7 -r1.7.2.1
--- src/data/any-reader.c 15 Dec 2006 00:16:01 -0000 1.7
+++ src/data/any-reader.c 19 Mar 2007 21:36:24 -0000 1.7.2.1
@@ -36,21 +36,6 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* Type of file backing an any_reader. */
-enum any_reader_type
- {
- SYSTEM_FILE, /* System file. */
- PORTABLE_FILE, /* Portable file. */
- SCRATCH_FILE /* Scratch file. */
- };
-
-/* Reader for any type of case-structured file. */
-struct any_reader
- {
- enum any_reader_type type; /* Type of file. */
- void *private; /* Private data. */
- };
-
/* Result of type detection. */
enum detect_result
{
@@ -83,27 +68,10 @@
return is_type ? YES : NO;
}
-/* If PRIVATE is non-null, creates and returns a new any_reader,
- initializing its fields to TYPE and PRIVATE. If PRIVATE is a
- null pointer, just returns a null pointer. */
-static struct any_reader *
-make_any_reader (enum any_reader_type type, void *private)
-{
- if (private != NULL)
- {
- struct any_reader *reader = xmalloc (sizeof *reader);
- reader->type = type;
- reader->private = private;
- return reader;
- }
- else
- return NULL;
-}
-
-/* Creates an any_reader for HANDLE. On success, returns the new
- any_reader and stores the file's dictionary into *DICT. On
+/* Returns a casereader for HANDLE. On success, returns the new
+ casereader and stores the file's dictionary into *DICT. On
failure, returns a null pointer. */
-struct any_reader *
+struct casereader *
any_reader_open (struct file_handle *handle, struct dictionary **dict)
{
switch (fh_get_referent (handle))
@@ -116,15 +84,13 @@
if (result == IO_ERROR)
return NULL;
else if (result == YES)
- return make_any_reader (SYSTEM_FILE,
- sfm_open_reader (handle, dict, NULL));
+ return sfm_open_reader (handle, dict, NULL);
result = try_detect (handle, pfm_detect);
if (result == IO_ERROR)
return NULL;
else if (result == YES)
- return make_any_reader (PORTABLE_FILE,
- pfm_open_reader (handle, dict, NULL));
+ return pfm_open_reader (handle, dict, NULL);
msg (SE, _("\"%s\" is not a system or portable file."),
fh_get_file_name (handle));
@@ -136,74 +102,7 @@
return NULL;
case FH_REF_SCRATCH:
- return make_any_reader (SCRATCH_FILE,
- scratch_reader_open (handle, dict));
+ return scratch_reader_open (handle, dict);
}
NOT_REACHED ();
}
-
-/* Reads a single case from READER into C.
- Returns true if successful, false at end of file or on error. */
-bool
-any_reader_read (struct any_reader *reader, struct ccase *c)
-{
- switch (reader->type)
- {
- case SYSTEM_FILE:
- return sfm_read_case (reader->private, c);
-
- case PORTABLE_FILE:
- return pfm_read_case (reader->private, c);
-
- case SCRATCH_FILE:
- return scratch_reader_read_case (reader->private, c);
- }
- NOT_REACHED ();
-}
-
-/* Returns true if an I/O error has occurred on READER, false
- otherwise. */
-bool
-any_reader_error (struct any_reader *reader)
-{
- switch (reader->type)
- {
- case SYSTEM_FILE:
- return sfm_read_error (reader->private);
-
- case PORTABLE_FILE:
- return pfm_read_error (reader->private);
-
- case SCRATCH_FILE:
- return scratch_reader_error (reader->private);
- }
- NOT_REACHED ();
-}
-
-/* Closes READER. */
-void
-any_reader_close (struct any_reader *reader)
-{
- if (reader == NULL)
- return;
-
- switch (reader->type)
- {
- case SYSTEM_FILE:
- sfm_close_reader (reader->private);
- break;
-
- case PORTABLE_FILE:
- pfm_close_reader (reader->private);
- break;
-
- case SCRATCH_FILE:
- scratch_reader_close (reader->private);
- break;
-
- default:
- NOT_REACHED ();
- }
-
- free (reader);
-}
Index: src/data/any-reader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/any-reader.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/any-reader.h 15 Dec 2006 00:16:01 -0000 1.2
+++ src/data/any-reader.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -23,11 +23,7 @@
struct file_handle;
struct dictionary;
-struct ccase;
-struct any_reader *any_reader_open (struct file_handle *,
+struct casereader *any_reader_open (struct file_handle *,
struct dictionary **);
-bool any_reader_read (struct any_reader *, struct ccase *);
-bool any_reader_error (struct any_reader *);
-void any_reader_close (struct any_reader *);
#endif /* any-reader.h */
Index: src/data/any-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/any-writer.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -b -r1.7 -r1.7.2.1
--- src/data/any-writer.c 15 Dec 2006 00:16:01 -0000 1.7
+++ src/data/any-writer.c 19 Mar 2007 21:36:24 -0000 1.7.2.1
@@ -36,41 +36,26 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* Type of file backing an any_writer. */
-enum any_writer_type
- {
- SYSTEM_FILE, /* System file. */
- PORTABLE_FILE, /* Portable file. */
- SCRATCH_FILE /* Scratch file. */
- };
-
-/* Writer for any type of case-structured file. */
-struct any_writer
- {
- enum any_writer_type type; /* Type of file. */
- void *private; /* Private data. */
- };
-
/* Creates and returns a writer for HANDLE with the given DICT. */
-struct any_writer *
+struct casewriter *
any_writer_open (struct file_handle *handle, struct dictionary *dict)
{
switch (fh_get_referent (handle))
{
case FH_REF_FILE:
{
- struct any_writer *writer;
+ struct casewriter *writer;
char *extension;
extension = fn_extension (fh_get_file_name (handle));
str_lowercase (extension);
if (!strcmp (extension, ".por"))
- writer = any_writer_from_pfm_writer (
- pfm_open_writer (handle, dict, pfm_writer_default_options ()));
+ writer = pfm_open_writer (handle, dict,
+ pfm_writer_default_options ());
else
- writer = any_writer_from_sfm_writer (
- sfm_open_writer (handle, dict, sfm_writer_default_options ()));
+ writer = sfm_open_writer (handle, dict,
+ sfm_writer_default_options ());
free (extension);
return writer;
@@ -81,137 +66,8 @@
return NULL;
case FH_REF_SCRATCH:
- return any_writer_from_scratch_writer (scratch_writer_open (handle,
- dict));
+ return scratch_writer_open (handle, dict);
}
NOT_REACHED ();
}
-
-/* If PRIVATE is non-null, creates and returns a new any_writer,
- initializing its fields to TYPE and PRIVATE. If PRIVATE is a
- null pointer, just returns a null pointer. */
-static struct any_writer *
-make_any_writer (enum any_writer_type type, void *private)
-{
- if (private != NULL)
- {
- struct any_writer *writer = xmalloc (sizeof *writer);
- writer->type = type;
- writer->private = private;
- return writer;
- }
- else
- return NULL;
-}
-
-/* If SFM_WRITER is non-null, encapsulates SFM_WRITER in an
- any_writer and returns it. If SFM_WRITER is null, just
- returns a null pointer.
-
- Useful when you need to pass options to sfm_open_writer().
- Typical usage:
- any_writer_from_sfm_writer (sfm_open_writer (fh, dict, opts))
- If you don't need to pass options, then any_writer_open() by
- itself is easier and more straightforward. */
-struct any_writer *
-any_writer_from_sfm_writer (struct sfm_writer *sfm_writer)
-{
- return make_any_writer (SYSTEM_FILE, sfm_writer);
-}
-
-/* If PFM_WRITER is non-null, encapsulates PFM_WRITER in an
- any_writer and returns it. If PFM_WRITER is null, just
- returns a null pointer.
-
- Useful when you need to pass options to pfm_open_writer().
- Typical usage:
- any_writer_from_pfm_writer (pfm_open_writer (fh, dict, opts))
- If you don't need to pass options, then any_writer_open() by
- itself is easier and more straightforward. */
-struct any_writer *
-any_writer_from_pfm_writer (struct pfm_writer *pfm_writer)
-{
- return make_any_writer (PORTABLE_FILE, pfm_writer);
-}
-
-/* If SCRATCH_WRITER is non-null, encapsulates SCRATCH_WRITER in
- an any_writer and returns it. If SCRATCH_WRITER is null, just
- returns a null pointer.
-
- Not particularly useful. Included just for consistency. */
-struct any_writer *
-any_writer_from_scratch_writer (struct scratch_writer *scratch_writer)
-{
- return make_any_writer (SCRATCH_FILE, scratch_writer);
-}
-
-/* Writes cases C to WRITER.
- Returns true if successful, false on failure. */
-bool
-any_writer_write (struct any_writer *writer, const struct ccase *c)
-{
- switch (writer->type)
- {
- case SYSTEM_FILE:
- return sfm_write_case (writer->private, c);
-
- case PORTABLE_FILE:
- return pfm_write_case (writer->private, c);
-
- case SCRATCH_FILE:
- return scratch_writer_write_case (writer->private, c);
- }
- NOT_REACHED ();
-}
-
-/* Returns true if an I/O error has occurred on WRITER, false
- otherwise. */
-bool
-any_writer_error (const struct any_writer *writer)
-{
- switch (writer->type)
- {
- case SYSTEM_FILE:
- return sfm_write_error (writer->private);
-
- case PORTABLE_FILE:
- return pfm_write_error (writer->private);
-
- case SCRATCH_FILE:
- return scratch_writer_error (writer->private);
- }
- NOT_REACHED ();
-}
-
-/* Closes WRITER.
- Returns true if successful, false if an I/O error occurred. */
-bool
-any_writer_close (struct any_writer *writer)
-{
- bool ok;
-
- if (writer == NULL)
- return true;
-
- switch (writer->type)
- {
- case SYSTEM_FILE:
- ok = sfm_close_writer (writer->private);
- break;
-
- case PORTABLE_FILE:
- ok = pfm_close_writer (writer->private);
- break;
-
- case SCRATCH_FILE:
- ok = scratch_writer_close (writer->private);
- break;
-
- default:
- NOT_REACHED ();
- }
-
- free (writer);
- return ok;
-}
Index: src/data/any-writer.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/any-writer.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/any-writer.h 15 Dec 2006 00:16:01 -0000 1.2
+++ src/data/any-writer.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -23,18 +23,7 @@
struct file_handle;
struct dictionary;
-struct ccase;
-struct sfm_writer;
-struct pfm_writer;
-struct scratch_writer;
-struct any_writer *any_writer_open (struct file_handle *, struct dictionary *);
-struct any_writer *any_writer_from_sfm_writer (struct sfm_writer *);
-struct any_writer *any_writer_from_pfm_writer (struct pfm_writer *);
-struct any_writer *any_writer_from_scratch_writer (struct scratch_writer *);
-
-bool any_writer_write (struct any_writer *, const struct ccase *);
-bool any_writer_error (const struct any_writer *);
-bool any_writer_close (struct any_writer *);
+struct casewriter *any_writer_open (struct file_handle *, struct dictionary *);
#endif /* any-writer.h */
Index: src/data/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/automake.mk,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -u -b -r1.15 -r1.15.2.1
--- src/data/automake.mk 16 Jan 2007 00:14:41 -0000 1.15
+++ src/data/automake.mk 19 Mar 2007 21:36:24 -0000 1.15.2.1
@@ -6,25 +6,27 @@
src/data/any-reader.h \
src/data/any-writer.c \
src/data/any-writer.h \
+ src/data/buffered-reader.c \
+ src/data/buffered-reader.h \
src/data/calendar.c \
src/data/calendar.h \
- src/data/case-sink.c \
- src/data/case-sink.h \
- src/data/case-source.c \
- src/data/case-source.h \
src/data/case.c \
src/data/casedeque.h \
- src/data/casefilter.c \
- src/data/casefilter.h \
- src/data/casefile.h \
- src/data/casefile.c \
- src/data/casefile-factory.h \
- src/data/casefile-private.h \
- src/data/fastfile.c \
- src/data/fastfile.h \
- src/data/fastfile-factory.h \
- src/data/fastfile-factory.c \
src/data/case.h \
+ src/data/casegrouper.c \
+ src/data/casegrouper.h \
+ src/data/caseinit.c \
+ src/data/caseinit.h \
+ src/data/casereader.c \
+ src/data/casereader.h \
+ src/data/casereader-private.h \
+ src/data/case-tmpfile.c \
+ src/data/case-tmpfile.h \
+ src/data/casewindow.c \
+ src/data/casewindow.h \
+ src/data/casewriter.c \
+ src/data/casewriter.h \
+ src/data/casewriter-private.h \
src/data/category.c \
src/data/category.h \
src/data/cat-routines.h \
@@ -32,6 +34,8 @@
src/data/data-in.h \
src/data/data-out.c \
src/data/data-out.h \
+ src/data/datasheet.c \
+ src/data/datasheet.h \
src/data/dictionary.c \
src/data/dictionary.h \
src/data/file-handle-def.c \
@@ -61,8 +65,6 @@
src/data/scratch-writer.h \
src/data/settings.c \
src/data/settings.h \
- src/data/storage-stream.c \
- src/data/storage-stream.h \
src/data/sys-file-private.c \
src/data/sys-file-private.h \
src/data/sys-file-reader.c \
Index: src/data/case.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/case.c,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -b -r1.10 -r1.10.2.1
--- src/data/case.c 16 Jan 2007 15:30:28 -0000 1.10
+++ src/data/case.c 19 Mar 2007 21:36:24 -0000 1.10.2.1
@@ -95,9 +95,9 @@
if (clone != orig)
*clone = *orig;
orig->case_data->ref_cnt++;
-#ifdef DEBUGGING
+//#ifdef DEBUGGING
case_unshare (clone);
-#endif
+//#endif
}
/* Replaces DST by SRC and nullifies SRC.
Index: src/data/case.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/case.h,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -u -b -r1.9 -r1.9.2.1
--- src/data/case.h 16 Jan 2007 15:30:28 -0000 1.9
+++ src/data/case.h 19 Mar 2007 21:36:24 -0000 1.9.2.1
@@ -26,6 +26,12 @@
struct variable;
+/* A count of cases or the index of a case within a collection of
+ them. */
+#define CASENUMBER_INVALID -1L
+#define CASENUMBER_MAX LONG_MAX
+typedef long int casenumber;
+
/* Opaque structure that represents a case. Use accessor
functions instead of accessing any members directly. Use
case_move() or case_clone() instead of copying. */
@@ -44,7 +50,7 @@
size_t case_get_value_cnt (const struct ccase *);
-void case_resize (struct ccase *, size_t new_value_cnt);
+void case_resize (struct ccase *, size_t new_cnt);
void case_swap (struct ccase *, struct ccase *);
bool case_try_create (struct ccase *, size_t value_cnt);
@@ -55,8 +61,7 @@
size_t cnt);
void case_to_values (const struct ccase *, union value *, size_t);
-void case_from_values (struct ccase *,
- const union value *, size_t);
+void case_from_values (struct ccase *, const union value *, size_t);
const union value *case_data (const struct ccase *, const struct variable *);
double case_num (const struct ccase *, const struct variable *);
Index: src/data/dictionary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/dictionary.c,v
retrieving revision 1.32
retrieving revision 1.32.2.1
diff -u -b -r1.32 -r1.32.2.1
--- src/data/dictionary.c 9 Feb 2007 05:28:21 -0000 1.32
+++ src/data/dictionary.c 19 Mar 2007 21:36:24 -0000 1.32.2.1
@@ -702,7 +702,6 @@
dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
bool *warn_on_invalid)
{
- assert (d != NULL);
assert (c != NULL);
if (d->weight == NULL)
@@ -712,7 +711,7 @@
double w = case_num (c, d->weight);
if (w < 0.0 || var_is_num_missing (d->weight, w, MV_ANY))
w = 0.0;
- if ( w == 0.0 && *warn_on_invalid ) {
+ if ( w == 0.0 && warn_on_invalid != NULL && *warn_on_invalid ) {
*warn_on_invalid = false;
msg (SW, _("At least one case in the data file had a weight value "
"that was user-missing, system-missing, zero, or "
Index: src/data/por-file-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-reader.c,v
retrieving revision 1.17
retrieving revision 1.17.2.1
diff -u -b -r1.17 -r1.17.2.1
--- src/data/por-file-reader.c 18 Feb 2007 19:20:55 -0000 1.17
+++ src/data/por-file-reader.c 19 Mar 2007 21:36:24 -0000 1.17.2.1
@@ -20,29 +20,32 @@
#include <config.h>
#include "por-file-reader.h"
-#include <libpspp/message.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
+
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <setjmp.h>
-#include <libpspp/alloc.h>
+#include <stdarg.h>
#include <stdbool.h>
-#include "case.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <data/casereader-private.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/value-labels.h>
+#include <data/variable.h>
+#include <libpspp/alloc.h>
#include <libpspp/compiler.h>
-#include "dictionary.h"
-#include "file-handle-def.h"
-#include "format.h"
-#include "missing-values.h"
#include <libpspp/hash.h>
#include <libpspp/magic.h>
+#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
-#include "value-labels.h"
-#include "variable.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -71,10 +74,12 @@
int var_cnt; /* Number of variables. */
int weight_index; /* 0-based index of weight variable, or -1. */
int *widths; /* Variable widths, 0 for numeric. */
- int value_cnt; /* Number of `value's per case. */
+ size_t value_cnt; /* Number of `value's per case. */
bool ok; /* Set false on I/O error. */
};
+static struct casereader_class por_file_casereader_class;
+
static void
error (struct pfm_reader *r, const char *msg,...)
PRINTF_FORMAT (2, 3)
@@ -110,11 +115,13 @@
}
/* Closes portable file reader R, after we're done with it. */
-void
-pfm_close_reader (struct pfm_reader *r)
+static bool
+por_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
{
- if (r != NULL)
+ struct pfm_reader *r = r_;
+ bool ok = r->ok;
pool_destroy (r->pool);
+ return ok;
}
/* Read a single character into cur_char. */
@@ -156,7 +163,7 @@
/* Reads the dictionary from file with handle H, and returns it in a
dictionary structure. This dictionary may be modified in order to
rename, reorder, and delete variables, etc. */
-struct pfm_reader *
+struct casereader *
pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
struct pfm_read_info *info)
{
@@ -204,10 +211,12 @@
if (!match (r, 'F'))
error (r, _("Data record expected."));
- return r;
+ r->value_cnt = dict_get_next_value_idx (*dict);
+ return casereader_create (r->value_cnt, CASENUMBER_INVALID,
+ &por_file_casereader_class, r);
error:
- pfm_close_reader (r);
+ pool_destroy (r->pool);
dict_destroy (*dict);
*dict = NULL;
return NULL;
@@ -677,19 +686,27 @@
}
/* Reads one case from portable file R into C. */
-bool
-pfm_read_case (struct pfm_reader *r, struct ccase *c)
+static bool
+por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c)
{
+ struct pfm_reader *r = r_;
size_t i;
size_t idx;
+ case_create (c, casereader_get_value_cnt (reader));
setjmp (r->bail_out);
if (!r->ok)
+ {
+ case_destroy (c);
return false;
+ }
/* Check for end of file. */
if (r->cc == 'Z')
+ {
+ case_destroy (c);
return false;
+ }
idx = 0;
for (i = 0; i < r->var_cnt; i++)
@@ -715,10 +732,11 @@
/* Returns true if an I/O error has occurred on READER, false
otherwise. */
-bool
-pfm_read_error (const struct pfm_reader *reader)
+static bool
+por_file_casereader_error (const struct casereader *reader UNUSED, void *r_)
{
- return !reader->ok;
+ const struct pfm_reader *r = r_;
+ return !r->ok;
}
/* Returns true if FILE is an SPSS portable file,
@@ -755,3 +773,10 @@
return true;
}
+
+static struct casereader_class por_file_casereader_class =
+ {
+ por_file_casereader_read,
+ por_file_casereader_destroy,
+ por_file_casereader_error,
+ };
Index: src/data/por-file-reader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-reader.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/por-file-reader.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/por-file-reader.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -37,12 +37,9 @@
struct dictionary;
struct file_handle;
struct ccase;
-struct pfm_reader *pfm_open_reader (struct file_handle *,
+struct casereader *pfm_open_reader (struct file_handle *,
struct dictionary **,
struct pfm_read_info *);
-bool pfm_read_case (struct pfm_reader *, struct ccase *);
-bool pfm_read_error (const struct pfm_reader *);
-void pfm_close_reader (struct pfm_reader *);
bool pfm_detect (FILE *);
#endif /* por-file-reader.h */
Index: src/data/por-file-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-writer.c,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -u -b -r1.9 -r1.9.2.1
--- src/data/por-file-writer.c 12 Feb 2007 02:10:55 -0000 1.9
+++ src/data/por-file-writer.c 19 Mar 2007 21:36:24 -0000 1.9.2.1
@@ -30,13 +30,15 @@
#include <time.h>
#include <unistd.h>
-#include "case.h"
-#include "dictionary.h"
-#include "file-handle-def.h"
-#include "format.h"
-#include "missing-values.h"
-#include "value-labels.h"
-#include "variable.h"
+#include <data/case.h>
+#include <data/casewriter-private.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/file-handle-def.h>
+#include <data/format.h>
+#include <data/missing-values.h>
+#include <data/value-labels.h>
+#include <data/variable.h>
#include <libpspp/alloc.h>
#include <libpspp/hash.h>
@@ -46,6 +48,8 @@
#include <libpspp/str.h>
#include <libpspp/version.h>
+#include "stat-macros.h"
+
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -70,6 +74,9 @@
int fv; /* Starting case index. */
};
+static struct casewriter_class por_file_casewriter_class;
+
+static bool close_writer (struct pfm_writer *);
static void buf_write (struct pfm_writer *, const void *, size_t);
static void write_header (struct pfm_writer *);
static void write_version_data (struct pfm_writer *);
@@ -94,7 +101,7 @@
/* Writes the dictionary DICT to portable file HANDLE according
to the given OPTS. Returns nonzero only if successful. DICT
will not be modified, except to assign short names. */
-struct pfm_writer *
+struct casewriter *
pfm_open_writer (struct file_handle *fh, struct dictionary *dict,
struct pfm_write_options opts)
{
@@ -153,12 +160,12 @@
write_variables (w, dict);
write_value_labels (w, dict);
buf_write (w, "F", 1);
- if (pfm_write_error (w))
+ if (ferror (w->file))
goto error;
- return w;
+ return casewriter_create (&por_file_casewriter_class, w);
error:
- pfm_close_writer (w);
+ close_writer (w);
return NULL;
open_error:
@@ -356,6 +363,7 @@
write_value (w, &value, v);
}
+ /* Write variable label. */
if (var_get_label (v) != NULL)
{
buf_write (w, "C", 1);
@@ -394,15 +402,16 @@
}
}
-/* Writes case ELEM to the portable file represented by H. */
-int
-pfm_write_case (struct pfm_writer *w, const struct ccase *c)
+/* Writes case C to the portable file represented by H. */
+static void
+por_file_casewriter_write (struct casewriter *writer UNUSED, void *w_,
+ struct ccase *c)
{
+ struct pfm_writer *w = w_;
int i;
- if (ferror (w->file))
- return 0;
-
+ if (!ferror (w->file))
+ {
for (i = 0; i < w->var_cnt; i++)
{
struct pfm_var *v = &w->vars[i];
@@ -415,20 +424,29 @@
buf_write (w, case_str_idx (c, v->fv), v->width);
}
}
+ }
- return !pfm_write_error (w);
+ case_destroy (c);
}
-bool
-pfm_write_error (const struct pfm_writer *w)
+static bool
+por_file_casewriter_destroy (struct casewriter *writer UNUSED, void *w_)
{
+ struct pfm_writer *w = w_;
+ return close_writer (w);
+}
+
+static bool
+por_file_casewriter_error (const struct casewriter *writer UNUSED, void *w_)
+{
+ const struct pfm_writer *w = w_;
return ferror (w->file);
}
/* Closes a portable file after we're done with it.
Returns true if successful, false if an I/O error occurred. */
-bool
-pfm_close_writer (struct pfm_writer *w)
+static bool
+close_writer (struct pfm_writer *w)
{
bool ok;
@@ -442,7 +460,7 @@
memset (buf, 'Z', sizeof buf);
buf_write (w, buf, w->lc >= 80 ? 80 : 80 - w->lc);
- ok = !pfm_write_error (w);
+ ok = !ferror (w->file);
if (fclose (w->file) == EOF)
ok = false;
@@ -844,3 +862,10 @@
strcpy (output, "*.");
return;
}
+
+static struct casewriter_class por_file_casewriter_class =
+ {
+ por_file_casewriter_write,
+ por_file_casewriter_destroy,
+ por_file_casewriter_error,
+ };
Index: src/data/por-file-writer.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/por-file-writer.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/por-file-writer.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/por-file-writer.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -41,12 +41,8 @@
struct file_handle;
struct dictionary;
struct ccase;
-struct pfm_writer *pfm_open_writer (struct file_handle *, struct dictionary *,
+struct casewriter *pfm_open_writer (struct file_handle *, struct dictionary *,
struct pfm_write_options);
struct pfm_write_options pfm_writer_default_options (void);
-int pfm_write_case (struct pfm_writer *, const struct ccase *);
-bool pfm_write_error (const struct pfm_writer *);
-bool pfm_close_writer (struct pfm_writer *);
-
#endif /* por-file-writer.h */
Index: src/data/procedure.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/procedure.c,v
retrieving revision 1.25
retrieving revision 1.25.2.1
diff -u -b -r1.25 -r1.25.2.1
--- src/data/procedure.c 16 Jan 2007 00:14:41 -0000 1.25
+++ src/data/procedure.c 19 Mar 2007 21:36:24 -0000 1.25.2.1
@@ -23,16 +23,15 @@
#include <stdlib.h>
#include <unistd.h>
-#include <data/case-source.h>
-#include <data/case-sink.h>
#include <data/case.h>
#include <data/casedeque.h>
-#include <data/casefile.h>
-#include <data/fastfile.h>
+#include <data/caseinit.h>
+#include <data/casereader.h>
+#include <data/casereader-private.h>
+#include <data/casewriter.h>
#include <data/dictionary.h>
#include <data/file-handle-def.h>
#include <data/procedure.h>
-#include <data/storage-stream.h>
#include <data/transformations.h>
#include <data/variable.h>
#include <libpspp/alloc.h>
@@ -40,31 +39,33 @@
#include <libpspp/str.h>
struct dataset {
-
- /* An abstract factory which creates casefiles */
- struct casefile_factory *cf_factory;
-
- /* Callback which occurs when a procedure provides a new source for
- the dataset */
- replace_source_callback *replace_source ;
-
- /* Callback which occurs whenever the DICT is replaced by a new one */
- replace_dictionary_callback *replace_dict;
-
- /* Cases are read from proc_source,
+ /* 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 proc_sink,
+ 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 case_source *proc_source;
+ struct casereader *source;
+ struct caseinit *caseinit;
struct trns_chain *permanent_trns_chain;
struct dictionary *permanent_dict;
- struct case_sink *proc_sink;
+ struct casewriter *sink;
struct trns_chain *temporary_trns_chain;
struct dictionary *dict;
+ /* Callback which occurs when a procedure provides a new source for
+ the dataset */
+ replace_source_callback *replace_source ;
+
+ /* Callback which occurs whenever the DICT is replaced by a new one */
+ replace_dictionary_callback *replace_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;
@@ -81,25 +82,23 @@
struct casedeque lagged_cases; /* Lagged cases. */
/* Procedure data. */
- bool is_open; /* Procedure open? */
- struct ccase trns_case; /* Case used for transformations. */
- struct ccase sink_case; /* Case written to sink, if
- compacting is necessary. */
+ enum
+ {
+ PROC_COMMITTED,
+ PROC_OPEN,
+ PROC_CLOSED
+ }
+ proc_state;
size_t cases_written; /* Cases output so far. */
- bool ok;
+ bool ok; /* Error status. */
}; /* struct dataset */
static void add_case_limit_trns (struct dataset *ds);
static void add_filter_trns (struct dataset *ds);
-static bool internal_procedure (struct dataset *ds, case_func *,
- end_func *,
- void *aux);
static void update_last_proc_invocation (struct dataset *ds);
-static void create_trns_case (struct ccase *, struct dictionary *);
static void open_active_file (struct dataset *ds);
-static void clear_case (const struct dataset *ds, struct ccase *c);
static bool close_active_file (struct dataset *ds);
/* Public functions. */
@@ -115,146 +114,53 @@
/* Regular procedure. */
-
-
-/* Reads the data from the input program and writes it to a new
- active file. For each case we read from the input program, we
- do the following:
-
- 1. Execute permanent transformations. If these drop the case,
- start the next case from step 1.
-
- 2. Write case to replacement active file.
-
- 3. Execute temporary transformations. If these drop the case,
- start the next case from step 1.
-
- 4. Pass case to PROC_FUNC, passing AUX as auxiliary data.
-
- Returns true if successful, false if an I/O error occurred. */
+/* Executes any pending transformations. */
bool
-procedure (struct dataset *ds, case_func *cf, void *aux)
+proc_execute (struct dataset *ds)
{
- update_last_proc_invocation (ds);
+ bool ok;
- /* Optimize the trivial case where we're not going to do
- anything with the data, by not reading the data at all. */
- if (cf == NULL
- && case_source_is_class (ds->proc_source, &storage_source_class)
- && ds->proc_sink == NULL
- && (ds->temporary_trns_chain == NULL
+ 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;
}
- return internal_procedure (ds, cf, NULL, aux);
-}
-
-/* Multipass procedure. */
-
-struct multipass_aux_data
- {
- struct casefile *casefile;
-
- bool (*proc_func) (const struct casefile *, void *aux);
- void *aux;
- };
-
-/* Case processing function for multipass_procedure(). */
-static bool
-multipass_case_func (const struct ccase *c, void *aux_data_, const struct
dataset *ds UNUSED)
-{
- struct multipass_aux_data *aux_data = aux_data_;
- return casefile_append (aux_data->casefile, c);
-}
-
-/* End-of-file function for multipass_procedure(). */
-static bool
-multipass_end_func (void *aux_data_, const struct dataset *ds UNUSED)
-{
- struct multipass_aux_data *aux_data = aux_data_;
- return (aux_data->proc_func == NULL
- || aux_data->proc_func (aux_data->casefile, aux_data->aux));
-}
-
-/* Procedure that allows multiple passes over the input data.
- The entire active file is passed to PROC_FUNC, with the given
- AUX as auxiliary data, as a unit. */
-bool
-multipass_procedure (struct dataset *ds, casefile_func *proc_func, void *aux)
-{
- struct multipass_aux_data aux_data;
- bool ok;
-
- aux_data.casefile =
- ds->cf_factory->create_casefile (ds->cf_factory,
- dict_get_next_value_idx (ds->dict));
-
- aux_data.proc_func = proc_func;
- aux_data.aux = aux;
-
- ok = internal_procedure (ds, multipass_case_func, multipass_end_func,
&aux_data);
- ok = !casefile_error (aux_data.casefile) && ok;
-
- casefile_destroy (aux_data.casefile);
-
- return ok;
+ ok = casereader_destroy (proc_open (ds));
+ return proc_commit (ds) && ok;
}
-
-/* Procedure implementation. */
-
-/* Executes a procedure.
- Passes each case to CASE_FUNC.
- Calls END_FUNC after the last case.
- Returns true if successful, false if an I/O error occurred (or
- if CASE_FUNC or END_FUNC ever returned false). */
-static bool
-internal_procedure (struct dataset *ds, case_func *proc,
- end_func *end,
- void *aux)
-{
- struct ccase *c;
- bool ok = true;
-
- proc_open (ds);
- while (ok && proc_read (ds, &c))
- if (proc != NULL)
- ok = proc (c, aux, ds) && ok;
- if (end != NULL)
- ok = end (aux, ds) && ok;
-
- if ( proc_close (ds) && ok )
- {
-
- return true;
- }
-
- return false;
-}
+static struct casereader_class proc_casereader_class;
/* Opens dataset DS for reading cases with proc_read.
proc_close must be called when done. */
-void
+struct casereader *
proc_open (struct dataset *ds)
{
- assert (ds->proc_source != NULL);
- assert (!ds->is_open);
+ assert (ds->source != NULL);
+ assert (ds->proc_state == PROC_COMMITTED);
update_last_proc_invocation (ds);
open_active_file (ds);
- ds->is_open = true;
- create_trns_case (&ds->trns_case, ds->dict);
- case_create (&ds->sink_case, dict_get_compacted_value_cnt (ds->dict));
+ ds->proc_state = PROC_OPEN;
ds->cases_written = 0;
ds->ok = true;
+ return casereader_create (dict_get_next_value_idx (ds->dict),
+ CASENUMBER_INVALID,
+ &proc_casereader_class, ds);
+}
+
+bool
+proc_is_open (const struct dataset *ds)
+{
+ return ds->proc_state != PROC_COMMITTED;
}
/* Reads the next case from dataset DS, which must have been
@@ -263,13 +169,14 @@
case is stored in *C.
Return false at end of file or if a read error occurs. In
this case a null pointer is stored in *C. */
-bool
-proc_read (struct dataset *ds, struct ccase **c)
+static bool
+proc_casereader_read (struct casereader *reader UNUSED, void *ds_,
+ struct ccase *c)
{
+ struct dataset *ds = ds_;
enum trns_result retval = TRNS_DROP_CASE;
- assert (ds->is_open);
- *c = NULL;
+ assert (ds->proc_state == PROC_OPEN);
for (;;)
{
size_t case_nr;
@@ -280,51 +187,59 @@
if (!ds->ok)
return false;
- /* Read a case from proc_source. */
- clear_case (ds, &ds->trns_case);
- if (!ds->proc_source->class->read (ds->proc_source, &ds->trns_case))
+ /* Read a case from source. */
+ if (!casereader_read (ds->source, c))
return false;
+ case_resize (c, dict_get_next_value_idx (ds->dict));
+ caseinit_init_reinit_vars (ds->caseinit, c);
+ caseinit_init_left_vars (ds->caseinit, c);
/* Execute permanent transformations. */
case_nr = ds->cases_written + 1;
retval = trns_chain_execute (ds->permanent_trns_chain, TRNS_CONTINUE,
- &ds->trns_case, &case_nr);
+ c, &case_nr);
+ caseinit_update_left_vars (ds->caseinit, c);
if (retval != TRNS_CONTINUE)
+ {
+ case_destroy (c);
continue;
+ }
/* Write case to collection of lagged cases. */
if (ds->n_lag > 0)
{
while (casedeque_count (&ds->lagged_cases) >= ds->n_lag)
case_destroy (casedeque_pop_back (&ds->lagged_cases));
- case_clone (casedeque_push_front (&ds->lagged_cases),
- &ds->trns_case);
+ case_clone (casedeque_push_front (&ds->lagged_cases), c);
}
/* Write case to replacement active file. */
ds->cases_written++;
- if (ds->proc_sink->class->write != NULL)
+ if (ds->sink != NULL)
{
+ struct ccase tmp;
if (ds->compactor != NULL)
{
- dict_compactor_compact (ds->compactor, &ds->sink_case,
- &ds->trns_case);
- ds->proc_sink->class->write (ds->proc_sink, &ds->sink_case);
+ case_create (&tmp, dict_get_compacted_value_cnt (ds->dict));
+ dict_compactor_compact (ds->compactor, &tmp, c);
}
else
- ds->proc_sink->class->write (ds->proc_sink, &ds->trns_case);
+ case_clone (&tmp, c);
+ casewriter_write (ds->sink, &tmp);
}
/* Execute temporary transformations. */
if (ds->temporary_trns_chain != NULL)
{
retval = trns_chain_execute (ds->temporary_trns_chain, TRNS_CONTINUE,
- &ds->trns_case, &ds->cases_written);
+ c, &ds->cases_written);
if (retval != TRNS_CONTINUE)
+ {
+ case_destroy (c);
continue;
}
+ }
- *c = &ds->trns_case;
return true;
}
}
@@ -334,58 +249,45 @@
while reading or closing the data set.
If DS has not been opened, returns true without doing
anything else. */
-bool
-proc_close (struct dataset *ds)
+static bool
+proc_casereader_destroy (struct casereader *reader, void *ds_)
{
- if (!ds->is_open)
- return true;
-
- /* Drain any remaining cases. */
- while (ds->ok)
- {
- struct ccase *c;
- if (!proc_read (ds, &c))
- break;
- }
- ds->ok = free_case_source (ds->proc_source) && ds->ok;
- proc_set_source (ds, NULL);
+ struct dataset *ds = ds_;
+ struct ccase c;
- case_destroy (&ds->sink_case);
- case_destroy (&ds->trns_case);
-
- ds->ok = close_active_file (ds) && ds->ok;
- ds->is_open = false;
+ /* 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 (casereader_read (reader, &c))
+ case_destroy (&c);
+
+ ds->proc_state = PROC_CLOSED;
+ ds->ok = casereader_destroy (ds->source) && ds->ok;
+ ds->source = NULL;
+ proc_set_active_file_data (ds, NULL);
return ds->ok;
}
-/* Updates last_proc_invocation. */
-static void
-update_last_proc_invocation (struct dataset *ds)
+bool
+proc_commit (struct dataset *ds)
{
- ds->last_proc_invocation = time (NULL);
+ assert (ds->proc_state == PROC_CLOSED);
+ ds->proc_state = PROC_COMMITTED;
+ return close_active_file (ds) && ds->ok;
}
-/* Creates and returns a case, initializing it from the vectors
- that say which `value's need to be initialized just once, and
- which ones need to be re-initialized before every case. */
-static void
-create_trns_case (struct ccase *trns_case, struct dictionary *dict)
-{
- size_t var_cnt = dict_get_var_cnt (dict);
- size_t i;
-
- case_create (trns_case, dict_get_next_value_idx (dict));
- for (i = 0; i < var_cnt; i++)
+static struct casereader_class proc_casereader_class =
{
- struct variable *v = dict_get_var (dict, i);
- union value *value = case_data_rw (trns_case, v);
+ proc_casereader_read,
+ proc_casereader_destroy,
+ };
- if (var_is_numeric (v))
- value->f = var_get_leave (v) ? 0.0 : SYSMIS;
- else
- memset (value->s, ' ', var_get_width (v));
- }
+/* Updates last_proc_invocation. */
+static void
+update_last_proc_invocation (struct dataset *ds)
+{
+ ds->last_proc_invocation = time (NULL);
}
/* Makes all preparations for reading from the data source and writing
@@ -393,6 +295,8 @@
static void
open_active_file (struct dataset *ds)
{
+ caseinit_mark_for_init (ds->caseinit, ds->dict);
+
add_case_limit_trns (ds);
add_filter_trns (ds);
@@ -404,46 +308,26 @@
if (ds->permanent_dict == NULL)
ds->permanent_dict = ds->dict;
- /* Figure out whether to compact. */
+ /* Prepare sink. */
+ if (!ds->discard_output)
+ {
ds->compactor =
(dict_compacting_would_shrink (ds->permanent_dict)
? dict_make_compactor (ds->permanent_dict)
: NULL);
-
- /* Prepare sink. */
- if (ds->proc_sink == NULL)
- ds->proc_sink = create_case_sink (&storage_sink_class,
- ds->permanent_dict,
- ds->cf_factory,
- NULL);
- if (ds->proc_sink->class->open != NULL)
- ds->proc_sink->class->open (ds->proc_sink);
+ ds->sink = autopaging_writer_create (dict_get_compacted_value_cnt (
+ ds->permanent_dict));
+ }
+ else
+ {
+ ds->compactor = NULL;
+ ds->sink = NULL;
+ }
/* Allocate memory for lagged cases. */
casedeque_init (&ds->lagged_cases, ds->n_lag);
}
-/* Clears the variables in C that need to be cleared between
- processing cases. */
-static void
-clear_case (const struct dataset *ds, struct ccase *c)
-{
- size_t var_cnt = dict_get_var_cnt (ds->dict);
- size_t i;
-
- for (i = 0; i < var_cnt; i++)
- {
- struct variable *v = dict_get_var (ds->dict, i);
- if (!var_get_leave (v))
- {
- if (var_is_numeric (v))
- case_data_rw (c, v)->f = SYSMIS;
- else
- memset (case_data_rw (c, v)->s, ' ', var_get_width (v));
- }
- }
-}
-
/* Closes the active file. */
static bool
close_active_file (struct dataset *ds)
@@ -456,6 +340,8 @@
/* Dictionary from before TEMPORARY becomes permanent. */
proc_cancel_temporary_transformations (ds);
+ if (!ds->discard_output)
+ {
/* Finish compacting. */
if (ds->compactor != NULL)
{
@@ -465,10 +351,18 @@
}
/* Old data sink becomes new data source. */
- if (ds->proc_sink->class->make_source != NULL)
- proc_set_source (ds, ds->proc_sink->class->make_source (ds->proc_sink) );
- free_case_sink (ds->proc_sink);
- ds->proc_sink = NULL;
+ 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;
@@ -489,218 +383,6 @@
return NULL;
}
-/* Procedure that separates the data into SPLIT FILE groups. */
-
-/* Represents auxiliary data for handling SPLIT FILE. */
-struct split_aux_data
- {
- struct dataset *dataset; /* The dataset */
- struct ccase prev_case; /* Data in previous case. */
-
- /* Callback functions. */
- begin_func *begin;
- case_func *proc;
- end_func *end;
- void *func_aux;
- };
-
-static int equal_splits (const struct ccase *, const struct ccase *, const
struct dataset *ds);
-static bool split_procedure_case_func (const struct ccase *c, void *, const
struct dataset *);
-static bool split_procedure_end_func (void *, const struct dataset *);
-
-/* Like procedure(), but it automatically breaks the case stream
- into SPLIT FILE break groups. Before each group of cases with
- identical SPLIT FILE variable values, BEGIN_FUNC is called
- with the first case in the group.
- Then PROC_FUNC is called for each case in the group (including
- the first).
- END_FUNC is called when the group is finished. FUNC_AUX is
- passed to each of the functions as auxiliary data.
-
- If the active file is empty, none of BEGIN_FUNC, PROC_FUNC,
- and END_FUNC will be called at all.
-
- If SPLIT FILE is not in effect, then there is one break group
- (if the active file is nonempty), and BEGIN_FUNC and END_FUNC
- will be called once.
-
- Returns true if successful, false if an I/O error occurred. */
-bool
-procedure_with_splits (struct dataset *ds,
- begin_func begin,
- case_func *proc,
- end_func *end,
- void *func_aux)
-{
- struct split_aux_data split_aux;
- bool ok;
-
- case_nullify (&split_aux.prev_case);
- split_aux.begin = begin;
- split_aux.proc = proc;
- split_aux.end = end;
- split_aux.func_aux = func_aux;
- split_aux.dataset = ds;
-
- ok = internal_procedure (ds, split_procedure_case_func,
- split_procedure_end_func, &split_aux);
-
- case_destroy (&split_aux.prev_case);
-
- return ok;
-}
-
-/* Case callback used by procedure_with_splits(). */
-static bool
-split_procedure_case_func (const struct ccase *c, void *split_aux_, const
struct dataset *ds)
-{
- struct split_aux_data *split_aux = split_aux_;
-
- /* Start a new series if needed. */
- if (case_is_null (&split_aux->prev_case)
- || !equal_splits (c, &split_aux->prev_case, split_aux->dataset))
- {
- if (!case_is_null (&split_aux->prev_case) && split_aux->end != NULL)
- split_aux->end (split_aux->func_aux, ds);
-
- case_destroy (&split_aux->prev_case);
- case_clone (&split_aux->prev_case, c);
-
- if (split_aux->begin != NULL)
- split_aux->begin (&split_aux->prev_case, split_aux->func_aux, ds);
- }
-
- return (split_aux->proc == NULL
- || split_aux->proc (c, split_aux->func_aux, ds));
-}
-
-/* End-of-file callback used by procedure_with_splits(). */
-static bool
-split_procedure_end_func (void *split_aux_, const struct dataset *ds)
-{
- struct split_aux_data *split_aux = split_aux_;
-
- if (!case_is_null (&split_aux->prev_case) && split_aux->end != NULL)
- split_aux->end (split_aux->func_aux, ds);
- return true;
-}
-
-/* Compares the SPLIT FILE variables in cases A and B and returns
- nonzero only if they differ. */
-static int
-equal_splits (const struct ccase *a, const struct ccase *b,
- const struct dataset *ds)
-{
- return case_compare (a, b,
- dict_get_split_vars (ds->dict),
- dict_get_split_cnt (ds->dict)) == 0;
-}
-
-/* Multipass procedure that separates the data into SPLIT FILE
- groups. */
-
-/* Represents auxiliary data for handling SPLIT FILE in a
- multipass procedure. */
-struct multipass_split_aux_data
- {
- struct dataset *dataset; /* The dataset of the split */
- struct ccase prev_case; /* Data in previous case. */
- struct casefile *casefile; /* Accumulates data for a split. */
- split_func *split; /* Function to call with the accumulated
- data. */
- void *func_aux; /* Auxiliary data. */
- };
-
-static bool multipass_split_case_func (const struct ccase *c, void *aux_,
const struct dataset *);
-static bool multipass_split_end_func (void *aux_, const struct dataset *ds);
-static bool multipass_split_output (struct multipass_split_aux_data *, const
struct dataset *ds);
-
-/* Returns true if successful, false if an I/O error occurred. */
-bool
-multipass_procedure_with_splits (struct dataset *ds,
- split_func *split,
- void *func_aux)
-{
- struct multipass_split_aux_data aux;
- bool ok;
-
- case_nullify (&aux.prev_case);
- aux.casefile = NULL;
- aux.split = split;
- aux.func_aux = func_aux;
- aux.dataset = ds;
-
- ok = internal_procedure (ds, multipass_split_case_func,
- multipass_split_end_func, &aux);
- case_destroy (&aux.prev_case);
-
- return ok;
-}
-
-/* Case callback used by multipass_procedure_with_splits(). */
-static bool
-multipass_split_case_func (const struct ccase *c, void *aux_, const struct
dataset *ds)
-{
- struct multipass_split_aux_data *aux = aux_;
- bool ok = true;
-
- /* Start a new series if needed. */
- if (aux->casefile == NULL || ! equal_splits (c, &aux->prev_case, ds))
- {
- /* Record split values. */
- case_destroy (&aux->prev_case);
- case_clone (&aux->prev_case, c);
-
- /* Pass any cases to split_func. */
- if (aux->casefile != NULL)
- ok = multipass_split_output (aux, ds);
-
- /* Start a new casefile. */
- aux->casefile =
- ds->cf_factory->create_casefile (ds->cf_factory,
- dict_get_next_value_idx (ds->dict));
- }
-
- return casefile_append (aux->casefile, c) && ok;
-}
-
-/* End-of-file callback used by multipass_procedure_with_splits(). */
-static bool
-multipass_split_end_func (void *aux_, const struct dataset *ds)
-{
- struct multipass_split_aux_data *aux = aux_;
- return (aux->casefile == NULL || multipass_split_output (aux, ds));
-}
-
-static bool
-multipass_split_output (struct multipass_split_aux_data *aux, const struct
dataset *ds)
-{
- bool ok;
-
- assert (aux->casefile != NULL);
- ok = aux->split (&aux->prev_case, aux->casefile, aux->func_aux, ds);
- casefile_destroy (aux->casefile);
- aux->casefile = NULL;
-
- return ok;
-}
-
-/* Discards all the current state in preparation for a data-input
- command like DATA LIST or GET. */
-void
-discard_variables (struct dataset *ds)
-{
- dict_clear (ds->dict);
- fh_set_default_handle (NULL);
-
- ds->n_lag = 0;
-
- free_case_source (ds->proc_source);
- proc_set_source (ds, NULL);
-
- proc_cancel_all_transformations (ds);
-}
-
/* Returns the current set of permanent transformations,
and clears the permanent transformations.
For use by INPUT PROGRAM. */
@@ -803,7 +485,8 @@
{
if (proc_in_temporary_transformations (ds))
{
- dataset_set_dict (ds, ds->permanent_dict);
+ dict_destroy (ds->dict);
+ ds->dict = ds->permanent_dict;
ds->permanent_dict = NULL;
trns_chain_destroy (ds->temporary_trns_chain);
@@ -821,6 +504,7 @@
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 ();
@@ -830,14 +514,12 @@
/* Initializes procedure handling. */
struct dataset *
-create_dataset (struct casefile_factory *fact,
- replace_source_callback *rps,
- replace_dictionary_callback *rds
- )
+create_dataset (replace_source_callback *rps,
+ replace_dictionary_callback *rds)
{
struct dataset *ds = xzalloc (sizeof(*ds));
ds->dict = dict_create ();
- ds->cf_factory = fact;
+ ds->caseinit = caseinit_create ();
ds->replace_source = rps;
ds->replace_dict = rds;
proc_cancel_all_transformations (ds);
@@ -848,60 +530,75 @@
void
destroy_dataset (struct dataset *ds)
{
- discard_variables (ds);
+ proc_discard_active_file (ds);
dict_destroy (ds->dict);
+ caseinit_destroy (ds->caseinit);
trns_chain_destroy (ds->permanent_trns_chain);
free (ds);
}
-/* Sets SINK as the destination for procedure output from the
- next procedure. */
+/* Causes output from the next procedure to be discarded, instead
+ of being preserved for use as input for the next procedure. */
void
-proc_set_sink (struct dataset *ds, struct case_sink *sink)
+proc_discard_output (struct dataset *ds)
{
- assert (ds->proc_sink == NULL);
- ds->proc_sink = sink;
+ ds->discard_output = true;
}
-/* Sets SOURCE as the source for procedure input for the next
- procedure. */
+/* Discards the active file dictionary, data, and
+ transformations. */
void
-proc_set_source (struct dataset *ds, struct case_source *source)
+proc_discard_active_file (struct dataset *ds)
{
- ds->proc_source = source;
+ 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;
- if ( ds->replace_source )
- ds->replace_source (ds->proc_source);
+ proc_cancel_all_transformations (ds);
}
-/* Returns true if a source for the next procedure has been
- configured, false otherwise. */
-bool
-proc_has_source (const struct dataset *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)
{
- return ds->proc_source != NULL;
+ assert (ds->proc_state == PROC_COMMITTED);
+ assert (ds->dict != dict);
+
+ proc_discard_active_file (ds);
+
+ dict_destroy (ds->dict);
+ ds->dict = dict;
+
+ proc_set_active_file_data (ds, source);
}
-/* Returns the output from the previous procedure.
- For use only immediately after executing a procedure.
- The returned casefile is owned by the caller; it will not be
- automatically used for the next procedure's input. */
-struct casefile *
-proc_capture_output (struct dataset *ds)
+/* Replaces the active file's data by READER without replacing
+ the associated dictionary. */
+void
+proc_set_active_file_data (struct dataset *ds, struct casereader *reader)
{
- struct casefile *casefile;
-
- /* Try to make sure that this function is called immediately
- after procedure() or a similar function. */
- assert (ds->proc_source != NULL);
- assert (case_source_is_class (ds->proc_source, &storage_source_class));
- assert (trns_chain_is_empty (ds->permanent_trns_chain));
- assert (!proc_in_temporary_transformations (ds));
+ casereader_destroy (ds->source);
+ ds->source = reader;
- casefile = storage_source_decapsulate (ds->proc_source);
- proc_set_source (ds, NULL);
+ caseinit_clear (ds->caseinit);
+ caseinit_mark_as_preinited (ds->caseinit, ds->dict);
+}
- return casefile;
+/* 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;
}
static trns_proc_func case_limit_trns_proc;
@@ -982,32 +679,8 @@
return ds->dict;
}
-
-/* Set or replace dataset DS's dictionary with DICT.
- The old dictionary is destroyed */
-void
-dataset_set_dict (struct dataset *ds, struct dictionary *dict)
-{
- struct dictionary *old_dict = ds->dict;
-
- dict_copy_callbacks (dict, ds->dict);
- ds->dict = dict;
-
- if ( ds->replace_dict )
- ds->replace_dict (dict);
-
- dict_destroy (old_dict);
-}
-
void
dataset_need_lag (struct dataset *ds, int n_before)
{
ds->n_lag = MAX (ds->n_lag, n_before);
}
-
-struct casefile_factory *
-dataset_get_casefile_factory (const struct dataset *ds)
-{
- return ds->cf_factory;
-}
-
Index: src/data/procedure.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/procedure.h,v
retrieving revision 1.12
retrieving revision 1.12.2.1
diff -u -b -r1.12 -r1.12.2.1
--- src/data/procedure.h 16 Jan 2007 00:14:41 -0000 1.12
+++ src/data/procedure.h 19 Mar 2007 21:36:24 -0000 1.12.2.1
@@ -23,16 +23,11 @@
#include <stdbool.h>
#include <data/transformations.h>
-#include <data/casefile-factory.h>
#include <libpspp/compiler.h>
-struct ccase;
-struct casefile;
-struct case_sink;
-struct case_source;
-
+struct casereader;
struct dataset;
-
+struct dictionary;
/* Transformations. */
@@ -44,10 +39,6 @@
trns_free_func *, void *);
size_t next_transformation (const struct dataset *ds);
-void discard_variables (struct dataset *ds);
-
-
-
bool proc_cancel_all_transformations (struct dataset *ds);
struct trns_chain *proc_capture_transformations (struct dataset *ds);
@@ -59,63 +50,33 @@
/* Procedures. */
struct dictionary ;
-typedef void replace_source_callback (struct case_source *);
+typedef void replace_source_callback (struct casereader *);
typedef void replace_dictionary_callback (struct dictionary *);
-struct dataset * create_dataset (struct casefile_factory *fact,
- replace_source_callback *,
- replace_dictionary_callback *
- );
+struct dataset * create_dataset (replace_source_callback *,
+ replace_dictionary_callback *);
void destroy_dataset (struct dataset *);
-struct casefile_factory *dataset_get_casefile_factory (const struct dataset *);
-
-void proc_set_source (struct dataset *ds, struct case_source *);
-bool proc_has_source (const struct dataset *ds);
-
-void proc_set_sink (struct dataset *ds, struct case_sink *);
-struct casefile *proc_capture_output (struct dataset *ds);
-
-typedef bool casefile_func (const struct casefile *, void *);
-typedef bool case_func (const struct ccase *, void *, const struct dataset *);
-typedef void begin_func (const struct ccase *, void *, const struct dataset*);
+void proc_discard_active_file (struct dataset *);
+void proc_set_active_file (struct dataset *,
+ struct casereader *, struct dictionary *);
+void proc_set_active_file_data (struct dataset *, struct casereader *);
+bool proc_has_active_file (const struct dataset *ds);
-typedef bool end_func (void *, const struct dataset *);
-
-typedef bool split_func (const struct ccase *, const struct casefile *,
- void *, const struct dataset *);
-
-
-
-bool procedure (struct dataset *ds, case_func *, void *aux)
WARN_UNUSED_RESULT;
-
-bool procedure_with_splits (struct dataset *ds,
- begin_func *,
- case_func *,
- end_func *,
- void *aux)
- WARN_UNUSED_RESULT;
-bool multipass_procedure (struct dataset *ds, casefile_func *, void *aux)
- WARN_UNUSED_RESULT;
-bool multipass_procedure_with_splits (struct dataset *ds,
- split_func *,
- void *aux)
- WARN_UNUSED_RESULT;
+void proc_discard_output (struct dataset *ds);
+bool proc_execute (struct dataset *ds);
time_t time_of_last_procedure (struct dataset *ds);
-void proc_open (struct dataset *);
-bool proc_read (struct dataset *, struct ccase **);
-bool proc_close (struct dataset *);
+struct casereader *proc_open (struct dataset *);
+bool proc_is_open (const struct dataset *);
+bool proc_commit (struct dataset *);
+struct dictionary *dataset_dict (const struct dataset *ds);
struct ccase *lagged_case (const struct dataset *ds, int n_before);
-
-inline struct dictionary *dataset_dict (const struct dataset *ds);
-inline void dataset_set_dict ( struct dataset *ds, struct dictionary *dict);
-
void dataset_need_lag (struct dataset *ds, int n_before);
#endif /* procedure.h */
Index: src/data/scratch-handle.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-handle.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/scratch-handle.c 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/scratch-handle.c 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -18,9 +18,9 @@
#include <config.h>
#include <stdlib.h>
-#include "scratch-handle.h"
-#include "casefile.h"
-#include "dictionary.h"
+#include <data/casereader.h>
+#include <data/scratch-handle.h>
+#include <data/dictionary.h>
/* Destroys HANDLE. */
void
@@ -29,7 +29,7 @@
if (handle != NULL)
{
dict_destroy (handle->dictionary);
- casefile_destroy (handle->casefile);
+ casereader_destroy (handle->casereader);
free (handle);
}
}
Index: src/data/scratch-handle.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-handle.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/scratch-handle.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/scratch-handle.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -25,7 +25,7 @@
struct scratch_handle
{
struct dictionary *dictionary; /* Dictionary. */
- struct casefile *casefile; /* Cases. */
+ struct casereader *casereader; /* Cases. */
};
void scratch_handle_destroy (struct scratch_handle *);
Index: src/data/scratch-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-reader.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- src/data/scratch-reader.c 15 Dec 2006 00:16:02 -0000 1.5
+++ src/data/scratch-reader.c 19 Mar 2007 21:36:24 -0000 1.5.2.1
@@ -22,11 +22,11 @@
#include <stdlib.h>
-#include "casefile.h"
#include "dictionary.h"
#include "file-handle-def.h"
#include "scratch-handle.h"
#include <data/case.h>
+#include <data/casereader.h>
#include <libpspp/message.h>
#include "xalloc.h"
@@ -34,31 +34,20 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* A reader for a scratch file. */
-struct scratch_reader
- {
- struct file_handle *fh; /* Underlying file handle. */
- struct casereader *casereader; /* Case reader. */
- };
-
/* 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.
-
- If you use an any_reader instead, then your code can be more
- flexible without being any harder to write. */
-struct scratch_reader *
+ *DICT. */
+struct casereader *
scratch_reader_open (struct file_handle *fh, struct dictionary **dict)
{
struct scratch_handle *sh;
- struct scratch_reader *reader;
if (!fh_open (fh, FH_REF_SCRATCH, "scratch file", "rs"))
return NULL;
sh = fh_get_scratch_handle (fh);
- if (sh == NULL)
+ 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 "
@@ -68,42 +57,5 @@
}
*dict = dict_clone (sh->dictionary);
- reader = xmalloc (sizeof *reader);
- reader->fh = fh;
- reader->casereader = casefile_get_reader (sh->casefile, NULL);
- return reader;
-}
-
-/* Reads a case from READER and copies it into C.
- Returns true if successful, false on error or at end of file. */
-bool
-scratch_reader_read_case (struct scratch_reader *reader, struct ccase *c)
-{
- struct ccase tmp;
- if (casereader_read (reader->casereader, &tmp))
- {
- case_copy (c, 0, &tmp, 0,
- casefile_get_value_cnt (
- casereader_get_casefile (reader->casereader)));
- case_destroy (&tmp);
- return true;
- }
- else
- return false;
-}
-
-/* Returns true if an I/O error occurred on READER, false otherwise. */
-bool
-scratch_reader_error (const struct scratch_reader *reader)
-{
- return casefile_error (casereader_get_casefile (reader->casereader));
-}
-
-/* Closes READER. */
-void
-scratch_reader_close (struct scratch_reader *reader)
-{
- fh_close (reader->fh, "scratch file", "rs");
- casereader_destroy (reader->casereader);
- free (reader);
+ return casereader_clone (sh->casereader);
}
Index: src/data/scratch-reader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-reader.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/scratch-reader.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/scratch-reader.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -24,10 +24,7 @@
struct dictionary;
struct file_handle;
struct ccase;
-struct scratch_reader *scratch_reader_open (struct file_handle *,
+struct casereader *scratch_reader_open (struct file_handle *,
struct dictionary **);
-bool scratch_reader_read_case (struct scratch_reader *, struct ccase *);
-bool scratch_reader_error (const struct scratch_reader *);
-void scratch_reader_close (struct scratch_reader *);
#endif /* scratch-reader.h */
Index: src/data/scratch-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-writer.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/data/scratch-writer.c 15 Dec 2006 00:16:02 -0000 1.4
+++ src/data/scratch-writer.c 19 Mar 2007 21:36:24 -0000 1.4.2.1
@@ -17,14 +17,20 @@
02110-1301, USA. */
#include <config.h>
+
#include "scratch-writer.h"
+
#include <stdlib.h>
-#include "case.h"
-#include "casefile.h"
-#include "fastfile.h"
-#include "dictionary.h"
-#include "file-handle-def.h"
-#include "scratch-handle.h"
+
+#include <data/case.h>
+#include <data/casereader.h>
+#include <data/casewriter-private.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/file-handle-def.h>
+#include <data/scratch-handle.h>
+#include <libpspp/compiler.h>
+
#include "xalloc.h"
/* A scratch file writer. */
@@ -33,16 +39,16 @@
struct scratch_handle *handle; /* Underlying scratch handle. */
struct file_handle *fh; /* Underlying file handle. */
struct dict_compactor *compactor; /* Compacts into handle->dictionary. */
+ struct casewriter *writer; /* Data output. */
};
+static 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.
-
- If you use an any_writer instead, then your code can be more
- flexible without being any harder to write. */
-struct scratch_writer *
+ to be drawn from DICTIONARY. */
+struct casewriter *
scratch_writer_open (struct file_handle *fh,
const struct dictionary *dictionary)
{
@@ -72,50 +78,66 @@
/* Create new contents. */
sh = xmalloc (sizeof *sh);
sh->dictionary = scratch_dict;
- sh->casefile = fastfile_create (dict_get_next_value_idx (sh->dictionary));
+ sh->casereader = NULL;
/* Create writer. */
writer = xmalloc (sizeof *writer);
writer->handle = sh;
writer->fh = fh;
writer->compactor = compactor;
+ writer->writer = autopaging_writer_create (dict_get_next_value_idx (
+ scratch_dict));
fh_set_scratch_handle (fh, sh);
- return writer;
+ return casewriter_create (&scratch_writer_casewriter_class, writer);
}
/* Writes case C to WRITER. */
-bool
-scratch_writer_write_case (struct scratch_writer *writer,
- const struct ccase *c)
+static void
+scratch_writer_casewriter_write (struct casewriter *w UNUSED, void *writer_,
+ struct ccase *c)
{
+ struct scratch_writer *writer = writer_;
struct scratch_handle *handle = writer->handle;
+ struct ccase tmp;
if (writer->compactor)
{
- struct ccase tmp_case;
- case_create (&tmp_case, dict_get_next_value_idx (handle->dictionary));
- dict_compactor_compact (writer->compactor, &tmp_case, c);
- return casefile_append_xfer (handle->casefile, &tmp_case);
+ case_create (&tmp, dict_get_next_value_idx (handle->dictionary));
+ dict_compactor_compact (writer->compactor, &tmp, c);
+ case_destroy (c);
}
else
- return casefile_append (handle->casefile, c);
+ case_move (&tmp, c);
+ casewriter_write (writer->writer, &tmp);
}
/* Returns true if an I/O error occurred on WRITER, false otherwise. */
-bool
-scratch_writer_error (const struct scratch_writer *writer)
+static bool
+scratch_writer_casewriter_error (const struct casewriter *w UNUSED,
+ void *writer_)
{
- return casefile_error (writer->handle->casefile);
+ const struct scratch_writer *writer = writer_;
+ return casewriter_error (writer->writer);
}
/* Closes WRITER.
Returns true if successful, false if an I/O error occurred on WRITER. */
-bool
-scratch_writer_close (struct scratch_writer *writer)
+static bool
+scratch_writer_casewriter_destroy (struct casewriter *w UNUSED, void *writer_)
{
- struct casefile *cf = writer->handle->casefile;
- bool ok = casefile_error (cf);
+ struct scratch_writer *writer = writer_;
+ struct casereader *reader = casewriter_make_reader (writer->writer);
+ bool ok = !casereader_error (reader);
+ if (ok)
+ writer->handle->casereader = reader;
fh_close (writer->fh, "scratch file", "we");
free (writer);
return ok;
}
+
+static struct casewriter_class scratch_writer_casewriter_class =
+ {
+ scratch_writer_casewriter_write,
+ scratch_writer_casewriter_destroy,
+ scratch_writer_casewriter_error,
+ };
Index: src/data/scratch-writer.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/scratch-writer.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/scratch-writer.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/scratch-writer.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -24,10 +24,7 @@
struct dictionary;
struct file_handle;
struct ccase;
-struct scratch_writer *scratch_writer_open (struct file_handle *,
+struct casewriter *scratch_writer_open (struct file_handle *,
const struct dictionary *);
-bool scratch_writer_write_case (struct scratch_writer *, const struct ccase *);
-bool scratch_writer_error (const struct scratch_writer *);
-bool scratch_writer_close (struct scratch_writer *);
#endif /* scratch-writer.h */
Index: src/data/settings.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/settings.c,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -b -r1.6 -r1.6.2.1
--- src/data/settings.c 15 Dec 2006 00:16:02 -0000 1.6
+++ src/data/settings.c 19 Mar 2007 21:36:24 -0000 1.6.2.1
@@ -425,6 +425,16 @@
return workspace;
}
+/* Approximate maximum number of cases to allocate in-core, given
+ that each case contains VALUE_CNT values. */
+size_t
+get_workspace_cases (size_t value_cnt)
+{
+ size_t case_size = sizeof (union value) * value_cnt + 4 * sizeof (void *);
+ size_t case_cnt = MAX (get_workspace () / case_size, 4);
+ return case_cnt;
+}
+
/* Set approximate maximum amount of memory to use for cases, in
bytes. */
Index: src/data/settings.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/settings.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/data/settings.h 15 Dec 2006 00:16:02 -0000 1.4
+++ src/data/settings.h 19 Mar 2007 21:36:24 -0000 1.4.2.1
@@ -79,6 +79,7 @@
void set_endcmd (char);
size_t get_workspace (void);
+size_t get_workspace_cases (size_t value_cnt);
void set_workspace (size_t);
const struct fmt_spec *get_format (void);
Index: src/data/sys-file-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-reader.c,v
retrieving revision 1.32
retrieving revision 1.32.2.1
diff -u -b -r1.32 -r1.32.2.1
--- src/data/sys-file-reader.c 9 Feb 2007 05:19:08 -0000 1.32
+++ src/data/sys-file-reader.c 19 Mar 2007 21:36:24 -0000 1.32.2.1
@@ -18,8 +18,8 @@
#include <config.h>
-#include "sys-file-reader.h"
-#include "sys-file-private.h"
+#include <data/sys-file-reader.h>
+#include <data/sys-file-private.h>
#include <errno.h>
#include <float.h>
@@ -38,15 +38,17 @@
#include <libpspp/hash.h>
#include <libpspp/array.h>
-#include "case.h"
-#include "dictionary.h"
-#include "file-handle-def.h"
-#include "file-name.h"
-#include "format.h"
-#include "missing-values.h"
-#include "value-labels.h"
-#include "variable.h"
-#include "value.h"
+#include <data/case.h>
+#include <data/casereader-private.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/value-labels.h>
+#include <data/variable.h>
+#include <data/value.h>
#include "c-ctype.h"
#include "inttostr.h"
@@ -69,11 +71,12 @@
struct file_handle *fh; /* File handle. */
FILE *file; /* File stream. */
bool error; /* I/O or corruption error? */
+ size_t value_cnt; /* Number of "union value"s in struct case. */
/* File format. */
enum integer_format integer_format; /* On-disk integer format. */
enum float_format float_format; /* On-disk floating point format. */
- int value_cnt; /* Number of 8-byte units per case. */
+ int flt64_cnt; /* Number of 8-byte units per case. */
struct sfm_var *vars; /* Variables. */
size_t var_cnt; /* Number of variables. */
bool has_vls; /* File has one or more very long strings? */
@@ -92,6 +95,10 @@
int case_index; /* Index into case. */
};
+static 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 *,
@@ -125,6 +132,8 @@
struct variable **var, char **value,
int *warning_cnt);
+static bool close_reader (struct sfm_reader *r);
+
/* Dictionary reader. */
enum which_format
@@ -134,7 +143,7 @@
};
static void read_header (struct sfm_reader *, struct dictionary *,
- int *weight_idx, int *claimed_value_cnt,
+ int *weight_idx, int *claimed_flt64_cnt,
struct sfm_read_info *);
static void read_variable_record (struct sfm_reader *, struct dictionary *,
int *format_warning_cnt);
@@ -168,7 +177,7 @@
reading. Reads the system file's dictionary into *DICT.
If INFO is non-null, then it receives additional info about the
system file. */
-struct sfm_reader *
+struct casereader *
sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
struct sfm_read_info *info)
{
@@ -176,7 +185,7 @@
struct variable **var_by_value_idx;
int format_warning_cnt = 0;
int weight_idx;
- int claimed_value_cnt;
+ int claimed_flt64_cnt;
int rec_type;
size_t i;
@@ -190,13 +199,13 @@
r->fh = fh;
r->file = fn_open (fh_get_file_name (fh), "rb");
r->error = false;
- r->value_cnt = 0;
+ r->flt64_cnt = 0;
r->has_vls = false;
r->opcode_idx = sizeof r->opcodes;
if (setjmp (r->bail_out))
{
- sfm_close_reader (r);
+ close_reader (r);
dict_destroy (*dict);
*dict = NULL;
return NULL;
@@ -210,7 +219,7 @@
}
/* Read header. */
- read_header (r, *dict, &weight_idx, &claimed_value_cnt, info);
+ read_header (r, *dict, &weight_idx, &claimed_flt64_cnt, info);
/* Read all the variable definition records. */
rec_type = read_int32 (r);
@@ -253,10 +262,10 @@
/* Read record 999 data, which is just filler. */
read_int32 (r);
- if (claimed_value_cnt != -1 && claimed_value_cnt != r->value_cnt)
+ if (claimed_flt64_cnt != -1 && claimed_flt64_cnt != r->flt64_cnt)
sys_warn (r, _("File header claims %d variable positions but "
"%d were read from file."),
- claimed_value_cnt, r->value_cnt);
+ claimed_flt64_cnt, r->flt64_cnt);
/* Create an index of dictionary variable widths for
sfm_read_case to use. We cannot use the `struct variable's
@@ -273,36 +282,58 @@
}
pool_free (r->pool, var_by_value_idx);
- return r;
+ r->value_cnt = dict_get_next_value_idx (*dict);
+ return casereader_create (r->value_cnt, CASENUMBER_INVALID,
+ &sys_file_casereader_class, r);
}
-/* Closes a system file after we're done with it. */
-void
-sfm_close_reader (struct sfm_reader *r)
+/* Closes a system file after we're done with it.
+ Returns true if an I/O error has occurred on READER, false
+ otherwise. */
+static bool
+close_reader (struct sfm_reader *r)
{
+ bool error;
+
if (r == NULL)
- return;
+ return true;
if (r->file)
{
if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
+ {
msg (ME, _("Error closing system file \"%s\": %s."),
fh_get_file_name (r->fh), strerror (errno));
+ r->error = true;
+ }
r->file = NULL;
}
if (r->fh != NULL)
fh_close (r->fh, "system file", "rs");
+ error = r->error;
pool_destroy (r->pool);
+
+ return !error;
}
/* Returns true if an I/O error has occurred on READER, false
otherwise. */
-bool
-sfm_read_error (const struct sfm_reader *reader)
+static bool
+sys_file_casereader_error (const struct casereader *reader UNUSED, void *r_)
{
- return reader->error;
+ struct sfm_reader *r = r_;
+ return r->error;
+}
+
+/* Destroys READER. Returns true if successful, false if an I/O
+ error occurred, whether during destruction or earlier. */
+static bool
+sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
+{
+ struct sfm_reader *r = r_;
+ return close_reader (r);
}
/* Returns true if FILE is an SPSS system file,
@@ -323,13 +354,13 @@
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_VALUE_CNT to the number of values that the file
+ Sets *CLAIMED_FLT64_CNT to the number of values that the file
claims to have (although it is not always correct).
If INFO is non-null, initializes *INFO with header
information. */
static void
read_header (struct sfm_reader *r, struct dictionary *dict,
- int *weight_idx, int *claimed_value_cnt,
+ int *weight_idx, int *claimed_flt64_cnt,
struct sfm_read_info *info)
{
char rec_type[5];
@@ -358,9 +389,9 @@
&& r->integer_format != INTEGER_LSB_FIRST))
sys_error (r, _("This is not an SPSS system file."));
- *claimed_value_cnt = read_int32 (r);
- if (*claimed_value_cnt < 0 || *claimed_value_cnt > INT_MAX / 16)
- *claimed_value_cnt = -1;
+ *claimed_flt64_cnt = read_int32 (r);
+ if (*claimed_flt64_cnt < 0 || *claimed_flt64_cnt > INT_MAX / 16)
+ *claimed_flt64_cnt = -1;
r->compressed = read_int32 (r) != 0;
@@ -537,7 +568,7 @@
/* Account for values.
Skip long string continuation records, if any. */
nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
- r->value_cnt += nv;
+ r->flt64_cnt += nv;
if (width > 8)
{
int i;
@@ -1076,23 +1107,32 @@
static bool read_compressed_string (struct sfm_reader *, char *);
static bool read_whole_strings (struct sfm_reader *, char *, size_t);
-/* Reads one case from READER's file into C. Returns nonzero
- only if successful. */
-int
-sfm_read_case (struct sfm_reader *r, struct ccase *c)
+/* Reads one case from READER's file into C. Returns true only
+ if successful. */
+static bool
+sys_file_casereader_read (struct casereader *reader UNUSED, void *r_,
+ struct ccase *c)
{
+ struct sfm_reader *r = r_;
if (r->error)
- return 0;
+ return false;
+ case_create (c, r->value_cnt);
if (setjmp (r->bail_out))
- return 0;
+ {
+ case_destroy (c);
+ return false;
+ }
if (!r->compressed && sizeof (double) == 8 && !r->has_vls)
{
/* Fast path. Read the whole case directly. */
if (!try_read_bytes (r, case_data_all_rw (c),
- sizeof (union value) * r->value_cnt))
- return 0;
+ sizeof (union value) * r->flt64_cnt))
+ {
+ case_destroy (c);
+ return false;
+ }
/* Convert floating point numbers to native format if needed. */
if (r->float_format != FLOAT_NATIVE_DOUBLE)
@@ -1106,7 +1146,7 @@
float_convert (r->float_format, d, FLOAT_NATIVE_DOUBLE, d);
}
}
- return 1;
+ return true;
}
else
{
@@ -1160,12 +1200,13 @@
}
}
}
- return 1;
+ return true;
eof:
+ case_destroy (c);
if (i != 0)
partial_record (r);
- return 0;
+ return false;
}
}
@@ -1352,7 +1393,7 @@
int i;
var_by_value_idx = pool_nmalloc (r->pool,
- r->value_cnt, sizeof *var_by_value_idx);
+ r->flt64_cnt, sizeof *var_by_value_idx);
for (i = 0; i < dict_get_var_cnt (dict); i++)
{
struct variable *v = dict_get_var (dict, i);
@@ -1363,7 +1404,7 @@
for (j = 1; j < nv; j++)
var_by_value_idx[value_idx++] = NULL;
}
- assert (value_idx == r->value_cnt);
+ assert (value_idx == r->flt64_cnt);
return var_by_value_idx;
}
@@ -1377,9 +1418,9 @@
{
struct variable *var;
- if (value_idx < 1 || value_idx > r->value_cnt)
+ if (value_idx < 1 || value_idx > r->flt64_cnt)
sys_error (r, _("Variable index %d not in valid range 1...%d."),
- value_idx, r->value_cnt);
+ value_idx, r->flt64_cnt);
var = var_by_value_idx[value_idx - 1];
if (var == NULL)
@@ -1653,3 +1694,9 @@
return x;
}
+static struct casereader_class sys_file_casereader_class =
+ {
+ sys_file_casereader_read,
+ sys_file_casereader_destroy,
+ sys_file_casereader_error,
+ };
Index: src/data/sys-file-reader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-reader.h,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -b -r1.3 -r1.3.2.1
--- src/data/sys-file-reader.h 15 Dec 2006 00:16:02 -0000 1.3
+++ src/data/sys-file-reader.h 19 Mar 2007 21:36:24 -0000 1.3.2.1
@@ -42,12 +42,9 @@
struct dictionary;
struct file_handle;
struct ccase;
-struct sfm_reader *sfm_open_reader (struct file_handle *,
+struct casereader *sfm_open_reader (struct file_handle *,
struct dictionary **,
struct sfm_read_info *);
-int sfm_read_case (struct sfm_reader *, struct ccase *);
-bool sfm_read_error (const struct sfm_reader *);
-void sfm_close_reader (struct sfm_reader *);
bool sfm_detect (FILE *);
#endif /* sys-file-reader.h */
Index: src/data/sys-file-writer.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-writer.c,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -b -r1.22 -r1.22.2.1
--- src/data/sys-file-writer.c 12 Feb 2007 02:10:55 -0000 1.22
+++ src/data/sys-file-writer.c 19 Mar 2007 21:36:24 -0000 1.22.2.1
@@ -37,14 +37,16 @@
#include <libpspp/str.h>
#include <libpspp/version.h>
-#include "case.h"
-#include "dictionary.h"
-#include "file-handle-def.h"
-#include "format.h"
-#include "missing-values.h"
-#include "settings.h"
-#include "value-labels.h"
-#include "variable.h"
+#include <data/case.h>
+#include <data/casewriter-private.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/file-handle-def.h>
+#include <data/format.h>
+#include <data/missing-values.h>
+#include <data/settings.h>
+#include <data/value-labels.h>
+#include <data/variable.h>
#include "minmax.h"
@@ -144,6 +146,8 @@
size_t flt64_cnt; /* Number of flt64 elements. */
};
+static struct casewriter_class sys_file_casewriter_class;
+
static char *append_string_max (char *, const char *, const char *);
static void write_header (struct sfm_writer *, const struct dictionary *);
static void buf_write (struct sfm_writer *, const void *, size_t);
@@ -164,6 +168,9 @@
static void write_documents (struct sfm_writer *, const struct dictionary *);
+bool write_error (const struct sfm_writer *);
+bool close_writer (struct sfm_writer *);
+
static inline int
var_flt64_cnt (const struct variable *v)
{
@@ -219,7 +226,7 @@
No reference to D is retained, so it may be modified or
destroyed at will after this function returns. D is not
modified by this function, except to assign short names. */
-struct sfm_writer *
+struct casewriter *
sfm_open_writer (struct file_handle *fh, struct dictionary *d,
struct sfm_write_options opts)
{
@@ -374,13 +381,13 @@
w->y = (unsigned char *) w->ptr;
}
- if (sfm_write_error (w))
+ if (write_error (w))
goto error;
- return w;
+ return casewriter_create (&sys_file_casewriter_class, w);
error:
- sfm_close_writer (w);
+ close_writer (w);
return NULL;
open_error:
@@ -926,13 +933,17 @@
static void write_compressed_data (struct sfm_writer *w, const flt64 *elem);
-/* Writes case C to system file W.
- Returns 1 if successful, 0 if an I/O error occurred. */
-int
-sfm_write_case (struct sfm_writer *w, const struct ccase *c)
+/* Writes case C to system file W. */
+static void
+sys_file_casewriter_write (struct casewriter *writer UNUSED, void *w_,
+ struct ccase *c)
{
+ struct sfm_writer *w = w_;
if (ferror (w->file))
- return 0;
+ {
+ case_destroy (c);
+ return;
+ }
w->case_cnt++;
@@ -992,7 +1003,21 @@
local_free (bounce);
}
- return !sfm_write_error (w);
+ case_destroy (c);
+}
+
+static bool
+sys_file_casewriter_destroy (struct casewriter *writer UNUSED, void *w_)
+{
+ struct sfm_writer *w = w_;
+ return close_writer (w);
+}
+
+static bool
+sys_file_casewriter_error (const struct casewriter *writer UNUSED, void *w_)
+{
+ const struct sfm_writer *w = w_;
+ return write_error (w);
}
static void
@@ -1058,7 +1083,7 @@
/* Returns true if an I/O error has occurred on WRITER, false otherwise. */
bool
-sfm_write_error (const struct sfm_writer *writer)
+write_error (const struct sfm_writer *writer)
{
return ferror (writer->file);
}
@@ -1066,7 +1091,7 @@
/* Closes a system file after we're done with it.
Returns true if successful, false if an I/O error occurred. */
bool
-sfm_close_writer (struct sfm_writer *w)
+close_writer (struct sfm_writer *w)
{
bool ok;
@@ -1084,7 +1109,7 @@
}
fflush (w->file);
- ok = !sfm_write_error (w);
+ ok = !write_error (w);
/* Seek back to the beginning and update the number of cases.
This is just a courtesy to later readers, so there's no need
@@ -1113,3 +1138,10 @@
return ok;
}
+
+static struct casewriter_class sys_file_casewriter_class =
+ {
+ sys_file_casewriter_write,
+ sys_file_casewriter_destroy,
+ sys_file_casewriter_error,
+ };
Index: src/data/sys-file-writer.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/sys-file-writer.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/data/sys-file-writer.h 15 Dec 2006 00:16:02 -0000 1.2
+++ src/data/sys-file-writer.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -34,12 +34,8 @@
struct file_handle;
struct dictionary;
struct ccase;
-struct sfm_writer *sfm_open_writer (struct file_handle *, struct dictionary *,
+struct casewriter *sfm_open_writer (struct file_handle *, struct dictionary *,
struct sfm_write_options);
struct sfm_write_options sfm_writer_default_options (void);
-int sfm_write_case (struct sfm_writer *, const struct ccase *);
-bool sfm_write_error (const struct sfm_writer *);
-bool sfm_close_writer (struct sfm_writer *);
-
#endif /* sys-file-writer.h */
Index: src/data/transformations.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/transformations.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- src/data/transformations.h 19 Dec 2006 14:21:53 -0000 1.5
+++ src/data/transformations.h 19 Mar 2007 21:36:24 -0000 1.5.2.1
@@ -19,10 +19,10 @@
#ifndef TRANSFORMATIONS_H
#define TRANSFORMATIONS_H 1
+#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
-
-typedef unsigned long casenumber ;
+#include <data/case.h>
/* trns_proc_func return values. */
enum trns_result
Index: src/data/value.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/value.h,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -b -r1.7 -r1.7.2.1
--- src/data/value.h 23 Dec 2006 09:03:45 -0000 1.7
+++ src/data/value.h 19 Mar 2007 21:36:24 -0000 1.7.2.1
@@ -38,6 +38,14 @@
#define LOWEST second_lowest_value
#define HIGHEST DBL_MAX
+/* Number of "union value"s required for a variable of the given
+ WIDTH. */
+static inline size_t
+value_cnt_from_width (int width)
+{
+ return width == 0 ? 1 : DIV_RND_UP (width, MAX_SHORT_STRING);
+}
+
/* A numeric or short string value.
Multiple consecutive values represent a long string. */
union value
Index: src/data/variable.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/variable.c,v
retrieving revision 1.21
retrieving revision 1.21.2.1
diff -u -b -r1.21 -r1.21.2.1
--- src/data/variable.c 23 Dec 2006 06:11:33 -0000 1.21
+++ src/data/variable.c 19 Mar 2007 21:36:24 -0000 1.21.2.1
@@ -422,7 +422,7 @@
size_t
var_get_value_cnt (const struct variable *v)
{
- return v->width == 0 ? 1 : DIV_RND_UP (v->width, MAX_SHORT_STRING);
+ return value_cnt_from_width (v->width);
}
/* Returns variable V's missing values. */
Index: src/language/command.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/command.c,v
retrieving revision 1.23
retrieving revision 1.23.2.1
diff -u -b -r1.23 -r1.23.2.1
--- src/language/command.c 12 Feb 2007 02:10:54 -0000 1.23
+++ src/language/command.c 19 Mar 2007 21:36:24 -0000 1.23.2.1
@@ -26,6 +26,7 @@
#include <errno.h>
#include <unistd.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/settings.h>
@@ -147,6 +148,7 @@
if (cmd_result_is_failure (result))
lex_discard_rest_of_command (lexer);
+ assert (!proc_is_open (ds));
unset_cmd_algorithm ();
dict_clear_aux (dataset_dict (ds));
@@ -158,7 +160,7 @@
{
const struct dictionary *dict = dataset_dict (ds);
return cmd_parse_in_state (lexer, ds,
- proc_has_source (ds) &&
+ proc_has_active_file (ds) &&
dict_get_var_cnt (dict) > 0 ?
CMD_STATE_DATA : CMD_STATE_INITIAL);
}
@@ -687,7 +689,8 @@
int
cmd_execute (struct lexer *lexer, struct dataset *ds)
{
- if (!procedure (ds, NULL, NULL))
+ bool ok = casereader_destroy (proc_open (ds));
+ if (!proc_commit (ds) || !ok)
return CMD_CASCADING_FAILURE;
return lex_end_of_command (lexer);
}
@@ -840,7 +843,7 @@
int
cmd_new_file (struct lexer *lexer, struct dataset *ds)
{
- discard_variables (ds);
+ proc_discard_active_file (ds);
return lex_end_of_command (lexer);
}
Index: src/language/command.def
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/command.def,v
retrieving revision 1.14
retrieving revision 1.14.2.1
diff -u -b -r1.14 -r1.14.2.1
--- src/language/command.def 22 Dec 2006 04:38:22 -0000 1.14
+++ src/language/command.def 19 Mar 2007 21:36:24 -0000 1.14.2.1
@@ -127,7 +127,6 @@
DEF_CMD (S_INPUT_PROGRAM, 0, "REREAD", cmd_reread)
/* Commands for testing PSPP. */
-DEF_CMD (S_ANY, F_TESTING, "DEBUG CASEFILE", cmd_debug_casefile)
DEF_CMD (S_ANY, F_TESTING, "DEBUG EVALUATE", cmd_debug_evaluate)
DEF_CMD (S_ANY, F_TESTING, "DEBUG MOMENTS", cmd_debug_moments)
DEF_CMD (S_ANY, F_TESTING, "DEBUG POOL", cmd_debug_pool)
Index: src/language/control/do-if.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/control/do-if.c,v
retrieving revision 1.12
retrieving revision 1.12.2.1
diff -u -b -r1.12 -r1.12.2.1
--- src/language/control/do-if.c 15 Dec 2006 00:16:02 -0000 1.12
+++ src/language/control/do-if.c 19 Mar 2007 21:36:24 -0000 1.12.2.1
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include "control-stack.h"
+#include <data/case.h>
#include <data/procedure.h>
#include <data/transformations.h>
#include <data/value.h>
Index: src/language/data-io/data-list.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/data-list.c,v
retrieving revision 1.30
retrieving revision 1.30.2.1
diff -u -b -r1.30 -r1.30.2.1
--- src/language/data-io/data-list.c 19 Dec 2006 14:21:53 -0000 1.30
+++ src/language/data-io/data-list.c 19 Mar 2007 21:36:24 -0000 1.30.2.1
@@ -23,10 +23,10 @@
#include <stdio.h>
#include <stdlib.h>
-#include <data/case-source.h>
#include <data/case.h>
-#include <data/case-source.h>
#include <data/data-in.h>
+#include <data/casereader.h>
+#include <data/casereader-private.h>
#include <data/dictionary.h>
#include <data/format.h>
#include <data/procedure.h>
@@ -99,9 +99,10 @@
int record_cnt; /* Number of records. */
struct string delims; /* Field delimiters. */
int skip_records; /* Records to skip before first case. */
+ size_t value_cnt; /* Number of `union value's in case. */
};
-static const struct case_source_class data_list_source_class;
+static const struct casereader_class data_list_casereader_class;
static bool parse_fixed (struct lexer *, struct dictionary *dict,
struct pool *tmp_pool, struct data_list_pgm *);
@@ -118,15 +119,14 @@
int
cmd_data_list (struct lexer *lexer, struct dataset *ds)
{
- struct dictionary *dict = dataset_dict (ds);
+ struct dictionary *dict;
struct data_list_pgm *dls;
int table = -1; /* Print table if nonzero, -1=undecided. */
struct file_handle *fh = fh_inline_file ();
struct pool *tmp_pool;
bool ok;
- if (!in_input_program ())
- discard_variables (ds);
+ dict = in_input_program () ? dataset_dict (ds) : dict_create ();
dls = pool_create_container (struct data_list_pgm, pool);
ll_init (&dls->specs);
@@ -178,9 +178,9 @@
lex_match (lexer, '=');
if (!lex_force_id (lexer))
goto error;
- dls->end = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer));
+ dls->end = dict_lookup_var (dict, lex_tokid (lexer));
if (!dls->end)
- dls->end = dict_create_var_assert (dataset_dict (ds), lex_tokid
(lexer), 0);
+ dls->end = dict_create_var_assert (dict, lex_tokid (lexer), 0);
lex_get (lexer);
}
else if (lex_token (lexer) == T_ID)
@@ -273,10 +273,16 @@
if (dls->reader == NULL)
goto error;
+ dls->value_cnt = dict_get_next_value_idx (dict);
+
if (in_input_program ())
add_transformation (ds, data_list_trns_proc, data_list_trns_free, dls);
else
- proc_set_source (ds, create_case_source (&data_list_source_class, dls));
+ proc_set_active_file (ds,
+ casereader_create (dict_get_next_value_idx (dict),
+ -1, &data_list_casereader_class,
+ dls),
+ dict);
pool_destroy (tmp_pool);
@@ -810,9 +816,11 @@
Returns true if successful, false at end of file or if an
I/O error occurred. */
static bool
-data_list_source_read (struct case_source *source, struct ccase *c)
+data_list_casereader_read (struct casereader *reader UNUSED, void *dls_,
+ struct ccase *c)
{
- struct data_list_pgm *dls = source->aux;
+ struct data_list_pgm *dls = dls_;
+ bool ok;
/* Skip the requested number of records before reading the
first case. */
@@ -824,25 +832,27 @@
dls->skip_records--;
}
- return read_from_data_list (dls, c);
+ case_create (c, dls->value_cnt);
+ ok = read_from_data_list (dls, c);
+ if (!ok)
+ case_destroy (c);
+ return ok;
}
-/* Destroys the source.
+/* Destroys the casereader.
Returns true if successful read, false if an I/O occurred
during destruction or previously. */
static bool
-data_list_source_destroy (struct case_source *source)
+data_list_casereader_destroy (struct casereader *reader UNUSED, void *dls_)
{
- struct data_list_pgm *dls = source->aux;
+ struct data_list_pgm *dls = dls_;
bool ok = !dfm_reader_error (dls->reader);
data_list_trns_free (dls);
return ok;
}
-static const struct case_source_class data_list_source_class =
+static const struct casereader_class data_list_casereader_class =
{
- "DATA LIST",
- NULL,
- data_list_source_read,
- data_list_source_destroy,
+ data_list_casereader_read,
+ data_list_casereader_destroy,
};
Index: src/language/data-io/data-reader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/data-reader.c,v
retrieving revision 1.20
retrieving revision 1.20.2.1
diff -u -b -r1.20 -r1.20.2.1
--- src/language/data-io/data-reader.c 15 Dec 2006 00:16:02 -0000 1.20
+++ src/language/data-io/data-reader.c 19 Mar 2007 21:36:24 -0000 1.20.2.1
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <data/casereader.h>
#include <data/file-handle-def.h>
#include <data/file-name.h>
#include <data/procedure.h>
@@ -444,8 +445,8 @@
/* Input procedure reads from inline file. */
prompt_set_style (PROMPT_DATA);
- ok = procedure (ds, NULL, NULL);
-
+ ok = casereader_destroy (proc_open (ds));
+ ok = proc_commit (ds) && ok;
dfm_close_reader (r);
return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
Index: src/language/data-io/get.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/get.c,v
retrieving revision 1.29
retrieving revision 1.29.2.1
diff -u -b -r1.29 -r1.29.2.1
--- src/language/data-io/get.c 7 Jan 2007 04:04:00 -0000 1.29
+++ src/language/data-io/get.c 19 Mar 2007 21:36:24 -0000 1.29.2.1
@@ -22,17 +22,14 @@
#include <data/any-reader.h>
#include <data/any-writer.h>
-#include <data/case-sink.h>
-#include <data/case-source.h>
#include <data/case.h>
-#include <data/casefile.h>
-#include <data/fastfile.h>
+#include <data/casereader.h>
+#include <data/casewriter.h>
#include <data/format.h>
#include <data/dictionary.h>
#include <data/por-file-writer.h>
#include <data/procedure.h>
#include <data/settings.h>
-#include <data/storage-stream.h>
#include <data/sys-file-writer.h>
#include <data/transformations.h>
#include <data/value-labels.h>
@@ -71,25 +68,18 @@
IMPORT_CMD
};
-/* Case reader input program. */
-struct case_reader_pgm
- {
- struct any_reader *reader; /* File reader. */
- struct case_map *map; /* Map from file dict to active file dict. */
- struct ccase bounce; /* Bounce buffer. */
- };
-
-static const struct case_source_class case_reader_source_class;
-
-static void case_reader_pgm_free (struct case_reader_pgm *);
+static void get_translate_case (const struct ccase *, struct ccase *,
+ void *map_);
+static bool get_destroy_case_map (void *map_);
/* Parses a GET or IMPORT command. */
static int
parse_read_command (struct lexer *lexer, struct dataset *ds, enum
reader_command type)
{
- struct case_reader_pgm *pgm = NULL;
+ struct casereader *reader = NULL;
struct file_handle *fh = NULL;
struct dictionary *dict = NULL;
+ struct case_map *map = NULL;
for (;;)
{
@@ -127,17 +117,10 @@
goto error;
}
- discard_variables (ds);
-
- pgm = xmalloc (sizeof *pgm);
- pgm->reader = any_reader_open (fh, &dict);
- pgm->map = NULL;
- case_nullify (&pgm->bounce);
- if (pgm->reader == NULL)
+ reader = any_reader_open (fh, &dict);
+ if (reader == NULL)
goto error;
- case_create (&pgm->bounce, dict_get_next_value_idx (dict));
-
start_case_map (dict);
while (lex_token (lexer) != '.')
@@ -147,72 +130,41 @@
goto error;
}
- pgm->map = finish_case_map (dict);
-
- dataset_set_dict (ds, dict);
+ map = finish_case_map (dict);
+ if (map != NULL)
+ reader = casereader_create_translator (reader,
+ dict_get_next_value_idx (dict),
+ get_translate_case,
+ get_destroy_case_map,
+ map);
- proc_set_source (ds,
- create_case_source (&case_reader_source_class, pgm));
+ proc_set_active_file (ds, reader, dict);
return CMD_SUCCESS;
error:
- case_reader_pgm_free (pgm);
+ casereader_destroy (reader);
if (dict != NULL)
dict_destroy (dict);
return CMD_CASCADING_FAILURE;
}
-/* Frees a struct case_reader_pgm. */
static void
-case_reader_pgm_free (struct case_reader_pgm *pgm)
+get_translate_case (const struct ccase *input, struct ccase *output,
+ void *map_)
{
- if (pgm != NULL)
- {
- any_reader_close (pgm->reader);
- destroy_case_map (pgm->map);
- case_destroy (&pgm->bounce);
- free (pgm);
- }
+ struct case_map *map = map_;
+ map_case (map, input, output);
}
-/* Reads one case into C.
- Returns true if successful, false at end of file or if an
- I/O error occurred. */
static bool
-case_reader_source_read (struct case_source *source, struct ccase *c)
+get_destroy_case_map (void *map_)
{
- struct case_reader_pgm *pgm = source->aux;
- if (any_reader_read (pgm->reader, pgm->map == NULL ? c : &pgm->bounce))
- {
- if (pgm->map != NULL)
- map_case (pgm->map, &pgm->bounce, c);
+ struct case_map *map = map_;
+ destroy_case_map (map);
return true;
- }
- else
- return false;
-}
-
-/* Destroys the source.
- Returns true if successful read, false if an I/O occurred
- during destruction or previously. */
-static bool
-case_reader_source_destroy (struct case_source *source)
-{
- struct case_reader_pgm *pgm = source->aux;
- bool ok = !any_reader_error (pgm->reader);
- case_reader_pgm_free (pgm);
- return ok;
}
-static const struct case_source_class case_reader_source_class =
- {
- "case reader",
- NULL,
- case_reader_source_read,
- case_reader_source_destroy,
- };
-
/* GET. */
int
cmd_get (struct lexer *lexer, struct dataset *ds)
@@ -243,30 +195,6 @@
PROC_CMD /* Procedure. */
};
-/* File writer plus a case map. */
-struct case_writer
- {
- struct any_writer *writer; /* File writer. */
- struct case_map *map; /* Map to output file dictionary
- (null pointer for identity mapping). */
- struct ccase bounce; /* Bounce buffer for mapping (if needed). */
- };
-
-/* Destroys AW. */
-static bool
-case_writer_destroy (struct case_writer *aw)
-{
- bool ok = true;
- if (aw != NULL)
- {
- ok = any_writer_close (aw->writer);
- destroy_case_map (aw->map);
- case_destroy (&aw->bounce);
- free (aw);
- }
- return ok;
-}
-
/* Parses SAVE or XSAVE or EXPORT or XEXPORT command.
WRITER_TYPE identifies the type of file to write,
and COMMAND_TYPE identifies the type of command.
@@ -277,7 +205,7 @@
included.
On failure, returns a null pointer. */
-static struct case_writer *
+static struct casewriter *
parse_write_command (struct lexer *lexer, struct dataset *ds,
enum writer_type writer_type,
enum command_type command_type,
@@ -286,7 +214,8 @@
/* Common data. */
struct file_handle *handle; /* Output file. */
struct dictionary *dict; /* Dictionary for output file. */
- struct case_writer *aw; /* Writer. */
+ struct casewriter *writer; /* Writer. */
+ struct case_map *map; /* Map from input data to data for writer. */
/* Common options. */
bool print_map; /* Print map? TODO. */
@@ -303,10 +232,8 @@
handle = NULL;
dict = dict_clone (dataset_dict (ds));
- aw = xmalloc (sizeof *aw);
- aw->writer = NULL;
- aw->map = NULL;
- case_nullify (&aw->bounce);
+ writer = NULL;
+ map = NULL;
print_map = false;
print_short_names = false;
sysfile_opts = sfm_writer_default_options ();
@@ -412,50 +339,41 @@
}
dict_compact_values (dict);
- aw->map = finish_case_map (dict);
- if (aw->map != NULL)
- case_create (&aw->bounce, dict_get_next_value_idx (dict));
if (fh_get_referent (handle) == FH_REF_FILE)
{
switch (writer_type)
{
case SYSFILE_WRITER:
- aw->writer = any_writer_from_sfm_writer (
- sfm_open_writer (handle, dict, sysfile_opts));
+ writer = sfm_open_writer (handle, dict, sysfile_opts);
break;
case PORFILE_WRITER:
- aw->writer = any_writer_from_pfm_writer (
- pfm_open_writer (handle, dict, porfile_opts));
+ writer = pfm_open_writer (handle, dict, porfile_opts);
break;
}
}
else
- aw->writer = any_writer_open (handle, dict);
- if (aw->writer == NULL)
+ writer = any_writer_open (handle, dict);
+ if (writer == NULL)
goto error;
+
+ map = finish_case_map (dict);
+ if (map != NULL)
+ writer = casewriter_create_translator (writer,
+ get_translate_case,
+ get_destroy_case_map,
+ map);
dict_destroy (dict);
- return aw;
+ return writer;
error:
- case_writer_destroy (aw);
+ casewriter_destroy (writer);
dict_destroy (dict);
+ destroy_case_map (map);
return NULL;
}
-/* Writes case C to writer AW. */
-static bool
-case_writer_write_case (struct case_writer *aw, const struct ccase *c)
-{
- if (aw->map != NULL)
- {
- map_case (aw->map, c, &aw->bounce);
- c = &aw->bounce;
- }
- return any_writer_write (aw->writer, c);
-}
-
/* SAVE and EXPORT. */
/* Parses and performs the SAVE or EXPORT procedure. */
@@ -464,26 +382,28 @@
{
bool retain_unselected;
struct variable *saved_filter_variable;
- struct case_writer *aw;
- struct ccase *c;
+ struct casereader *input;
+ struct casewriter *output;
+ struct ccase c;
bool ok = true;
- aw = parse_write_command (lexer, ds, writer_type, PROC_CMD,
&retain_unselected);
- if (aw == NULL)
+ output = parse_write_command (lexer, ds, writer_type, PROC_CMD,
&retain_unselected);
+ if (output == NULL)
return CMD_CASCADING_FAILURE;
saved_filter_variable = dict_get_filter (dataset_dict (ds));
if (retain_unselected)
dict_set_filter (dataset_dict (ds), NULL);
- proc_open (ds);
- while (ok && proc_read (ds, &c))
- ok = case_writer_write_case (aw, c);
- ok = proc_close (ds) && ok;
+ input = proc_open (ds);
+ while (casereader_read (input, &c))
+ casewriter_write (output, &c);
+ ok = casereader_destroy (input) && ok;
+ ok = casewriter_destroy (output) && ok;
+ ok = proc_commit (ds) && ok;
dict_set_filter (dataset_dict (ds), saved_filter_variable);
- case_writer_destroy (aw);
return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
@@ -504,7 +424,7 @@
/* Transformation. */
struct output_trns
{
- struct case_writer *aw; /* Writer. */
+ struct casewriter *writer; /* Writer. */
};
static trns_proc_func output_trns_proc;
@@ -515,8 +435,8 @@
parse_output_trns (struct lexer *lexer, struct dataset *ds, enum writer_type
writer_type)
{
struct output_trns *t = xmalloc (sizeof *t);
- t->aw = parse_write_command (lexer, ds, writer_type, XFORM_CMD, NULL);
- if (t->aw == NULL)
+ t->writer = parse_write_command (lexer, ds, writer_type, XFORM_CMD, NULL);
+ if (t->writer == NULL)
{
free (t);
return CMD_CASCADING_FAILURE;
@@ -531,7 +451,9 @@
output_trns_proc (void *trns_, struct ccase *c, casenumber case_num UNUSED)
{
struct output_trns *t = trns_;
- case_writer_write_case (t->aw, c);
+ struct ccase tmp;
+ case_clone (&tmp, c);
+ casewriter_write (t->writer, &tmp);
return TRNS_CONTINUE;
}
@@ -541,13 +463,8 @@
output_trns_free (void *trns_)
{
struct output_trns *t = trns_;
- bool ok = true;
-
- if (t != NULL)
- {
- ok = case_writer_destroy (t->aw);
+ bool ok = casewriter_destroy (t->writer);
free (t);
- }
return ok;
}
@@ -748,15 +665,15 @@
int type; /* One of MTF_*. */
struct variable **by; /* List of BY variables for this file. */
struct file_handle *handle; /* File handle. */
- struct any_reader *reader; /* File reader. */
+ struct casereader *reader; /* File reader. */
struct dictionary *dict; /* Dictionary from system file. */
+ bool active_file; /* Active file? */
/* IN subcommand. */
char *in_name; /* Variable name. */
struct variable *in_var; /* Variable (in master dictionary). */
- struct ccase input_storage; /* Input record storage. */
- struct ccase *input; /* Input record. */
+ struct ccase input; /* Input record. */
};
/* MATCH FILES procedure. */
@@ -773,7 +690,7 @@
char first[LONG_NAME_LEN + 1], last[LONG_NAME_LEN + 1];
struct dictionary *dict; /* Dictionary of output file. */
- struct casefile *output; /* MATCH FILES output. */
+ struct casewriter *output; /* MATCH FILES output. */
struct ccase mtf_case; /* Case used for output. */
unsigned seq_num; /* Have we initialized this variable? */
@@ -782,11 +699,12 @@
static bool mtf_free (struct mtf_proc *);
static bool mtf_close_file (struct mtf_file *);
+static bool mtf_close_all_files (struct mtf_proc *);
static int mtf_merge_dictionary (struct dictionary *const, struct mtf_file *);
-static bool mtf_read_records (struct mtf_proc *, struct dataset *);
+static bool mtf_read_records (struct mtf_proc *);
static bool mtf_delete_file_in_place (struct mtf_proc *, struct mtf_file **);
-static bool mtf_processing (struct mtf_proc *, struct dataset *);
+static bool mtf_processing (struct mtf_proc *);
static char *var_type_description (struct variable *);
@@ -804,6 +722,7 @@
bool used_active_file = false;
bool saw_table = false;
bool saw_in = false;
+ bool open_active_file = false;
mtf.head = mtf.tail = NULL;
mtf.by_cnt = 0;
@@ -840,8 +759,8 @@
file->dict = NULL;
file->in_name = NULL;
file->in_var = NULL;
- case_nullify (&file->input_storage);
- file->input = &file->input_storage;
+ file->active_file = false;
+ case_nullify (&file->input);
/* FILEs go first, then TABLEs. */
if (file->type == MTF_TABLE || first_table == NULL)
@@ -881,7 +800,7 @@
}
used_active_file = true;
- if (!proc_has_source (ds))
+ if (!proc_has_active_file (ds))
{
msg (SE, _("Cannot specify the active file since no active "
"file has been defined."));
@@ -895,6 +814,7 @@
"Temporary transformations will be made permanent."));
file->dict = dataset_dict (ds);
+ file->active_file = true;
}
else
{
@@ -905,9 +825,6 @@
file->reader = any_reader_open (file->handle, &file->dict);
if (file->reader == NULL)
goto error;
-
- case_create (&file->input_storage,
- dict_get_next_value_idx (file->dict));
}
while (lex_match (lexer, '/'))
@@ -1109,42 +1026,37 @@
if (used_active_file)
{
- proc_set_sink (ds, create_case_sink (&null_sink_class,
- dataset_dict (ds),
- dataset_get_casefile_factory (ds),
- NULL));
- proc_open (ds);
+ proc_discard_output (ds);
+ for (iter = mtf.head; iter != NULL; iter = iter->next)
+ if (iter->reader == NULL)
+ iter->reader = proc_open (ds);
+ open_active_file = true;
}
- else
- discard_variables (ds);
dict_compact_values (mtf.dict);
- mtf.output = dataset_get_casefile_factory (ds)->create_casefile
- (dataset_get_casefile_factory (ds),
- dict_get_next_value_idx (mtf.dict));
-
+ mtf.output = autopaging_writer_create (dict_get_next_value_idx (mtf.dict));
mtf.seq_nums = xcalloc (dict_get_var_cnt (mtf.dict), sizeof *mtf.seq_nums);
case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));
- if (!mtf_read_records (&mtf, ds))
+ if (!mtf_read_records (&mtf))
goto error;
while (mtf.head && mtf.head->type == MTF_FILE)
- if (!mtf_processing (&mtf, ds))
+ if (!mtf_processing (&mtf))
goto error;
- if (!proc_close (ds))
+ if (!mtf_close_all_files (&mtf))
goto error;
+ if (open_active_file)
+ proc_commit (ds);
- discard_variables (ds);
-
- dataset_set_dict (ds, mtf.dict);
+ proc_set_active_file (ds, casewriter_make_reader (mtf.output), mtf.dict);
mtf.dict = NULL;
- proc_set_source (ds, storage_source_create (mtf.output));
mtf.output = NULL;
return mtf_free (&mtf) ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
error:
- proc_close (ds);
+ if (open_active_file)
+ proc_commit (ds);
mtf_free (&mtf);
return CMD_CASCADING_FAILURE;
}
@@ -1174,22 +1086,18 @@
static bool
mtf_close_file (struct mtf_file *file)
{
- bool ok = file->reader == NULL || !any_reader_error (file->reader);
+ bool ok = casereader_destroy (file->reader);
free (file->by);
- any_reader_close (file->reader);
- if (file->handle != NULL)
+ if (!file->active_file)
dict_destroy (file->dict);
- case_destroy (&file->input_storage);
free (file->in_name);
+ case_destroy (&file->input);
free (file);
return ok;
}
-/* Free all the data for the MATCH FILES procedure.
- Returns true if successful, false if an I/O error
- occurred. */
static bool
-mtf_free (struct mtf_proc *mtf)
+mtf_close_all_files (struct mtf_proc *mtf)
{
struct mtf_file *iter, *next;
bool ok = true;
@@ -1201,8 +1109,21 @@
if (!mtf_close_file (iter))
ok = false;
}
+ mtf->head = NULL;
+ return ok;
+}
+
+/* Free all the data for the MATCH FILES procedure.
+ Returns true if successful, false if an I/O error
+ occurred. */
+static bool
+mtf_free (struct mtf_proc *mtf)
+{
+ bool ok;
- if (mtf->dict)
+ ok = mtf_close_all_files (mtf);
+
+ casewriter_destroy (mtf->output);
dict_destroy (mtf->dict);
case_destroy (&mtf->mtf_case);
free (mtf->seq_nums);
@@ -1252,7 +1173,7 @@
/* Read a record from every input file.
Returns true if successful, false if an I/O error occurred. */
static bool
-mtf_read_records (struct mtf_proc *mtf, struct dataset *ds)
+mtf_read_records (struct mtf_proc *mtf)
{
struct mtf_file *iter, *next;
bool ok = true;
@@ -1260,9 +1181,7 @@
for (iter = mtf->head; ok && iter != NULL; iter = next)
{
next = iter->next;
- if (iter->handle
- ? !any_reader_read (iter->reader, iter->input)
- : !proc_read (ds, &iter->input))
+ if (!casereader_read (iter->reader, &iter->input))
{
if (!mtf_delete_file_in_place (mtf, &iter))
ok = false;
@@ -1277,17 +1196,18 @@
mtf_compare_BY_values (struct mtf_proc *mtf,
struct mtf_file *a, struct mtf_file *b)
{
- return case_compare_2dict (a->input, b->input, a->by, b->by, mtf->by_cnt);
+ return case_compare_2dict (&a->input, &b->input, a->by, b->by, mtf->by_cnt);
}
/* Perform one iteration of steps 3...7 above.
Returns true if successful, false if an I/O error occurred. */
static bool
-mtf_processing (struct mtf_proc *mtf, struct dataset *ds)
+mtf_processing (struct mtf_proc *mtf)
{
struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
struct mtf_file *max_head, *max_tail; /* Files with non-minimum BYs. */
struct mtf_file *iter, *next;
+ struct ccase out_case;
/* 3. Find the FILE input record(s) that have minimum BY
values. Store all the values from these input records into
@@ -1346,9 +1266,8 @@
min_tail = min_tail->next_min = iter;
else /* cmp > 0 */
{
- if (iter->handle
- ? any_reader_read (iter->reader, iter->input)
- : proc_read (ds, &iter->input))
+ case_destroy (&iter->input);
+ if (casereader_read (iter->reader, &iter->input))
continue;
if (!mtf_delete_file_in_place (mtf, &iter))
return false;
@@ -1375,14 +1294,13 @@
if (mv != NULL && mtf->seq_nums[mv_index] != mtf->seq_num)
{
- const struct ccase *record = iter->input;
union value *out = case_data_rw (&mtf->mtf_case, mv);
mtf->seq_nums[mv_index] = mtf->seq_num;
if (var_is_numeric (v))
- out->f = case_num (record, v);
+ out->f = case_num (&iter->input, v);
else
- memcpy (out->s, case_str (record, v), var_get_width (v));
+ memcpy (out->s, case_str (&iter->input, v), var_get_width (v));
}
}
if (iter->in_var != NULL)
@@ -1418,7 +1336,8 @@
}
/* 5. Write the output record. */
- casefile_append (mtf->output, &mtf->mtf_case);
+ case_clone (&out_case, &mtf->mtf_case);
+ casewriter_write (mtf->output, &out_case);
/* 6. Read another record from each input file FILE and TABLE
that we stored values from above. If we come to the end of
@@ -1427,9 +1346,8 @@
for (iter = min_head; iter && iter->type == MTF_FILE; iter = next)
{
next = iter->next_min;
- if (iter->reader != NULL
- ? !any_reader_read (iter->reader, iter->input)
- : !proc_read (ds, &iter->input))
+ case_destroy (&iter->input);
+ if (!casereader_read (iter->reader, &iter->input))
if (!mtf_delete_file_in_place (mtf, &iter))
return false;
}
@@ -1620,11 +1538,6 @@
{
size_t dst_idx;
- assert (map != NULL);
- assert (src != NULL);
- assert (dst != NULL);
- assert (src != dst);
-
for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++)
{
int src_idx = map->map[dst_idx];
Index: src/language/data-io/inpt-pgm.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/inpt-pgm.c,v
retrieving revision 1.23
retrieving revision 1.23.2.1
diff -u -b -r1.23 -r1.23.2.1
--- src/language/data-io/inpt-pgm.c 24 Jan 2007 08:30:22 -0000 1.23
+++ src/language/data-io/inpt-pgm.c 19 Mar 2007 21:36:24 -0000 1.23.2.1
@@ -23,9 +23,9 @@
#include <float.h>
#include <stdlib.h>
-#include <data/case-source.h>
#include <data/case.h>
-#include <data/case-source.h>
+#include <data/caseinit.h>
+#include <data/casereader-private.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/transformations.h>
@@ -68,12 +68,10 @@
struct trns_chain *trns_chain;
enum trns_result restart;
- bool inited_case; /* Did one-time case initialization? */
size_t case_nr; /* Incremented by END CASE transformation. */
- enum value_init_type *init; /* How to initialize each `union value'. */
- size_t init_cnt; /* Number of elements in inp_init. */
- size_t case_size; /* Size of case in bytes. */
+ struct caseinit *init;
+ size_t value_cnt;
};
static void destroy_input_program (struct input_program_pgm *);
@@ -82,7 +80,7 @@
static trns_proc_func end_file_trns_proc;
static trns_free_func reread_trns_free;
-static const struct case_source_class input_program_source_class;
+static const struct casereader_class input_program_casereader_class;
static bool inside_input_program;
@@ -105,10 +103,9 @@
cmd_input_program (struct lexer *lexer, struct dataset *ds)
{
struct input_program_pgm *inp;
- size_t i;
bool saw_END_CASE = false;
- discard_variables (ds);
+ proc_discard_active_file (ds);
if (lex_token (lexer) != '.')
return lex_end_of_command (lexer);
@@ -132,7 +129,7 @@
if (result == CMD_EOF)
msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
inside_input_program = false;
- discard_variables (ds);
+ proc_discard_active_file (ds);
destroy_input_program (inp);
return result;
}
@@ -144,7 +141,7 @@
if (dict_get_next_value_idx (dataset_dict (ds)) == 0)
{
msg (SE, _("Input program did not create any variables."));
- discard_variables (ds);
+ proc_discard_active_file (ds);
destroy_input_program (inp);
return CMD_FAILURE;
}
@@ -153,33 +150,15 @@
trns_chain_finalize (inp->trns_chain);
inp->restart = TRNS_CONTINUE;
- inp->inited_case = false;
- inp->case_nr = 1;
/* Figure out how to initialize each input case. */
- inp->init_cnt = dict_get_next_value_idx (dataset_dict (ds));
- inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init);
- for (i = 0; i < inp->init_cnt; i++)
- inp->init[i] = -1;
- for (i = 0; i < dict_get_var_cnt (dataset_dict (ds)); i++)
- {
- struct variable *var = dict_get_var (dataset_dict (ds), i);
- size_t value_cnt = var_get_value_cnt (var);
- enum value_init_type value_init;
- size_t j;
-
- value_init = var_is_numeric (var) ? INP_NUMERIC : INP_STRING;
- value_init |= var_get_leave (var) ? INP_INIT_ONCE : INP_REINIT;
-
- for (j = 0; j < value_cnt; j++)
- inp->init[j + var_get_case_index (var)] = value_init;
- }
- for (i = 0; i < inp->init_cnt; i++)
- assert (inp->init[i] != -1);
- inp->case_size = dict_get_case_size (dataset_dict (ds));
-
- proc_set_source (ds,
- create_case_source (&input_program_source_class, inp));
+ inp->init = caseinit_create ();
+ caseinit_mark_for_init (inp->init, dataset_dict (ds));
+ inp->value_cnt = dict_get_next_value_idx (dataset_dict (ds));
+
+ proc_set_active_file_data
+ (ds, casereader_create (inp->value_cnt, CASENUMBER_INVALID,
+ &input_program_casereader_class, inp));
return CMD_SUCCESS;
}
@@ -191,56 +170,6 @@
return CMD_END_INPUT_PROGRAM;
}
-/* Initializes case C. Called before the first case is read. */
-static void
-init_case (const struct input_program_pgm *inp, struct ccase *c)
-{
- size_t i;
-
- for (i = 0; i < inp->init_cnt; i++)
- switch (inp->init[i])
- {
- case INP_NUMERIC | INP_INIT_ONCE:
- case_data_rw_idx (c, i)->f = 0.0;
- break;
- case INP_NUMERIC | INP_REINIT:
- case_data_rw_idx (c, i)->f = SYSMIS;
- break;
- case INP_STRING | INP_INIT_ONCE:
- case INP_STRING | INP_REINIT:
- memset (case_data_rw_idx (c, i)->s, ' ',
- sizeof case_data_rw_idx (c, i)->s);
- break;
- default:
- NOT_REACHED ();
- }
-}
-
-/* Clears case C. Called between reading successive records. */
-static void
-clear_case (const struct input_program_pgm *inp, struct ccase *c)
-{
- size_t i;
-
- for (i = 0; i < inp->init_cnt; i++)
- switch (inp->init[i])
- {
- case INP_NUMERIC | INP_INIT_ONCE:
- break;
- case INP_NUMERIC | INP_REINIT:
- case_data_rw_idx (c, i)->f = SYSMIS;
- break;
- case INP_STRING | INP_INIT_ONCE:
- break;
- case INP_STRING | INP_REINIT:
- memset (case_data_rw_idx (c, i)->s, ' ',
- sizeof case_data_rw_idx (c, i)->s);
- break;
- default:
- NOT_REACHED ();
- }
-}
-
/* Returns true if STATE is valid given the transformations that
are allowed within INPUT PROGRAM. */
static bool
@@ -256,26 +185,28 @@
Returns true if successful, false at end of file or if an
I/O error occurred. */
static bool
-input_program_source_read (struct case_source *source, struct ccase *c)
+input_program_casereader_read (struct casereader *reader UNUSED, void *inp_,
+ struct ccase *c)
{
- struct input_program_pgm *inp = source->aux;
+ struct input_program_pgm *inp = inp_;
- if (!inp->inited_case)
- {
- init_case (inp, c);
- inp->inited_case = true;
- }
+ case_create (c, inp->value_cnt);
do
{
assert (is_valid_state (inp->restart));
if (inp->restart == TRNS_ERROR || inp->restart == TRNS_END_FILE)
+ {
+ case_destroy (c);
return false;
+ }
- clear_case (inp, c);
+ caseinit_init_reinit_vars (inp->init, c);
+ caseinit_init_left_vars (inp->init, c);
inp->restart = trns_chain_execute (inp->trns_chain, inp->restart,
c, &inp->case_nr);
assert (is_valid_state (inp->restart));
+ caseinit_update_left_vars (inp->init, c);
}
while (inp->restart < 0);
@@ -288,29 +219,29 @@
if (pgm != NULL)
{
trns_chain_destroy (pgm->trns_chain);
- free (pgm->init);
+ caseinit_destroy (pgm->init);
free (pgm);
}
}
-/* Destroys the source.
+/* Destroys the casereader.
Returns true if successful read, false if an I/O occurred
during destruction or previously. */
static bool
-input_program_source_destroy (struct case_source *source)
+input_program_casereader_destroy (struct casereader *reader UNUSED, void *inp_)
{
- struct input_program_pgm *inp = source->aux;
+ struct input_program_pgm *inp = inp_;
bool ok = inp->restart != TRNS_ERROR;
destroy_input_program (inp);
return ok;
}
-static const struct case_source_class input_program_source_class =
+static const struct casereader_class input_program_casereader_class =
{
- "INPUT PROGRAM",
+ input_program_casereader_read,
+ input_program_casereader_destroy,
+ NULL,
NULL,
- input_program_source_read,
- input_program_source_destroy,
};
int
@@ -322,7 +253,7 @@
return lex_end_of_command (lexer);
}
-/* Sends the current case as the source's output. */
+/* Outputs the current case */
int
end_case_trns_proc (void *inp_, struct ccase *c UNUSED,
casenumber case_nr UNUSED)
Index: src/language/data-io/list.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/data-io/list.q,v
retrieving revision 1.24
retrieving revision 1.24.2.1
diff -u -b -r1.24 -r1.24.2.1
--- src/language/data-io/list.q 15 Dec 2006 00:16:02 -0000 1.24
+++ src/language/data-io/list.q 19 Mar 2007 21:36:24 -0000 1.24.2.1
@@ -23,7 +23,8 @@
#include "intprops.h"
#include "size_max.h"
-#include <data/case.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/data-out.h>
#include <data/format.h>
@@ -73,9 +74,6 @@
/* Parsed command. */
static struct cmd_list cmd;
-/* Current case number. */
-static int case_idx;
-
/* Line buffer. */
static struct string line_buffer;
@@ -85,11 +83,12 @@
static void write_line (struct outp_driver *d, const char *s);
/* Other functions. */
-static bool list_cases (const struct ccase *, void *, const struct dataset *);
+static void list_case (struct ccase *, casenumber case_idx,
+ const struct dataset *);
static void determine_layout (void);
static void clean_up (void);
static void write_header (struct outp_driver *);
-static void write_all_headers (const struct ccase *, void *, const struct
dataset*);
+static void write_all_headers (struct casereader *, const struct dataset*);
/* Returns the number of text lines that can fit on the remainder of
the page. */
@@ -133,7 +132,11 @@
int
cmd_list (struct lexer *lexer, struct dataset *ds)
{
+ struct dictionary *dict = dataset_dict (ds);
struct variable *casenum_var = NULL;
+ struct casegrouper *grouper;
+ struct casereader *group;
+ casenumber case_idx;
bool ok;
if (!parse_list (lexer, ds, &cmd, NULL))
@@ -147,7 +150,7 @@
if (cmd.last == NOT_LONG)
cmd.last = LONG_MAX;
if (!cmd.sbc_variables)
- dict_get_vars (dataset_dict (ds), &cmd.v_variables, &cmd.n_variables,
+ dict_get_vars (dict, &cmd.v_variables, &cmd.n_variables,
(1u << DC_SYSTEM) | (1u << DC_SCRATCH));
if (cmd.n_variables == 0)
{
@@ -187,12 +190,12 @@
/* Weighting variable. */
if (cmd.weight == LST_WEIGHT)
{
- if (dict_get_weight (dataset_dict (ds)) != NULL)
+ if (dict_get_weight (dict) != NULL)
{
size_t i;
for (i = 0; i < cmd.n_variables; i++)
- if (cmd.v_variables[i] == dict_get_weight (dataset_dict (ds)))
+ if (cmd.v_variables[i] == dict_get_weight (dict))
break;
if (i >= cmd.n_variables)
{
@@ -201,7 +204,7 @@
cmd.v_variables = xnrealloc (cmd.v_variables, cmd.n_variables,
sizeof *cmd.v_variables);
cmd.v_variables[cmd.n_variables - 1]
- = dict_get_weight (dataset_dict (ds));
+ = dict_get_weight (dict);
}
}
else
@@ -229,7 +232,24 @@
determine_layout ();
case_idx = 0;
- ok = procedure_with_splits (ds, write_all_headers, list_cases, NULL, NULL);
+ for (grouper = casegrouper_create_splits (proc_open (ds), dict);
+ casegrouper_get_next_group (grouper, &group);
+ casereader_destroy (group))
+ {
+ struct ccase c;
+
+ write_all_headers (group, ds);
+ for (; casereader_read (group, &c); case_destroy (&c))
+ {
+ case_idx++;
+ if (case_idx >= cmd.first && case_idx <= cmd.last
+ && (case_idx - cmd.first) % cmd.step == 0)
+ list_case (&c, case_idx, ds);
+ }
+ }
+ ok = casegrouper_destroy (grouper);
+ proc_commit (ds);
+
ds_destroy(&line_buffer);
clean_up ();
@@ -242,11 +262,15 @@
/* Writes headers to all devices. This is done at the beginning of
each SPLIT FILE group. */
static void
-write_all_headers (const struct ccase *c, void *aux UNUSED, const struct
dataset *ds)
+write_all_headers (struct casereader *input, const struct dataset *ds)
{
struct outp_driver *d;
+ struct ccase c;
+
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
- output_split_file_values (ds, c);
for (d = outp_drivers (NULL); d; d = outp_drivers (d))
{
if (!d->class->special)
@@ -623,16 +647,12 @@
}
/* Writes case C to output. */
-static bool
-list_cases (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
+static void
+list_case (struct ccase *c, casenumber case_idx, const struct dataset *ds)
{
+ struct dictionary *dict = dataset_dict (ds);
struct outp_driver *d;
- case_idx++;
- if (case_idx < cmd.first || case_idx > cmd.last
- || (cmd.step != 1 && (case_idx - cmd.first) % cmd.step))
- return true;
-
for (d = outp_drivers (NULL); d; d = outp_drivers (d))
if (d->class->special == 0)
{
@@ -681,7 +701,7 @@
ds_put_char_multiple(&line_buffer, ' ', width - print->w);
if (fmt_is_string (print->type)
- || dict_contains_var (dataset_dict (ds), v))
+ || dict_contains_var (dict, v))
{
data_out (case_data (c, v), print,
ds_put_uninit (&line_buffer, print->w));
@@ -720,7 +740,7 @@
char buf[256];
if (fmt_is_string (print->type)
- || dict_contains_var (dataset_dict (ds), v))
+ || dict_contains_var (dict, v))
data_out (case_data (c, v), print, buf);
else
{
@@ -738,8 +758,6 @@
}
else
NOT_REACHED ();
-
- return true;
}
/*
Index: src/language/dictionary/apply-dictionary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/apply-dictionary.c,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -b -r1.13 -r1.13.2.1
--- src/language/dictionary/apply-dictionary.c 15 Dec 2006 00:16:02 -0000
1.13
+++ src/language/dictionary/apply-dictionary.c 19 Mar 2007 21:36:24 -0000
1.13.2.1
@@ -21,6 +21,7 @@
#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>
@@ -42,7 +43,7 @@
cmd_apply_dictionary (struct lexer *lexer, struct dataset *ds)
{
struct file_handle *handle;
- struct any_reader *reader;
+ struct casereader *reader;
struct dictionary *dict;
int n_matched = 0;
@@ -58,7 +59,7 @@
reader = any_reader_open (handle, &dict);
if (dict == NULL)
return CMD_FAILURE;
- any_reader_close (reader);
+ casereader_destroy (reader);
for (i = 0; i < dict_get_var_cnt (dict); i++)
{
@@ -136,7 +137,7 @@
dict_set_weight (dataset_dict (ds), new_weight);
}
- any_reader_close (reader);
+ casereader_destroy (reader);
return lex_end_of_command (lexer);
}
Index: src/language/dictionary/delete-variables.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/delete-variables.c,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -u -b -r1.1 -r1.1.2.1
--- src/language/dictionary/delete-variables.c 22 Dec 2006 04:38:22 -0000
1.1
+++ src/language/dictionary/delete-variables.c 19 Mar 2007 21:36:24 -0000
1.1.2.1
@@ -1,5 +1,5 @@
/* PSPP - computes sample statistics.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
Written by Ben Pfaff <address@hidden>.
This program is free software; you can redistribute it and/or
@@ -21,6 +21,7 @@
#include <stdlib.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <language/command.h>
@@ -36,6 +37,7 @@
{
struct variable **vars;
size_t var_cnt;
+ bool ok;
if (proc_make_temporary_transformations_permanent (ds))
msg (SE, _("DELETE VARIABLES may not be used after TEMPORARY. "
@@ -50,10 +52,12 @@
goto error;
}
- if (!procedure (ds, NULL, NULL))
+ ok = casereader_destroy (proc_open (ds));
+ dict_delete_vars (dataset_dict (ds), vars, var_cnt);
+ ok = proc_commit (ds) && ok;
+ if (!ok)
goto error;
- dict_delete_vars (dataset_dict (ds), vars, var_cnt);
free (vars);
return CMD_SUCCESS;
Index: src/language/dictionary/modify-variables.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/modify-variables.c,v
retrieving revision 1.16
retrieving revision 1.16.2.1
diff -u -b -r1.16 -r1.16.2.1
--- src/language/dictionary/modify-variables.c 9 Feb 2007 05:19:08 -0000
1.16
+++ src/language/dictionary/modify-variables.c 19 Mar 2007 21:36:24 -0000
1.16.2.1
@@ -40,7 +40,6 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* FIXME: should change weighting variable, etc. */
/* These control the ordering produced by
compare_variables_given_ordering(). */
struct ordering
@@ -322,7 +321,7 @@
if (already_encountered & (1 | 4))
{
/* Read the data. */
- if (!procedure (ds,NULL, NULL))
+ if (!proc_execute (ds))
goto done;
}
Index: src/language/dictionary/sys-file-info.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/dictionary/sys-file-info.c,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -b -r1.22 -r1.22.2.1
--- src/language/dictionary/sys-file-info.c 9 Feb 2007 05:28:21 -0000
1.22
+++ src/language/dictionary/sys-file-info.c 19 Mar 2007 21:36:24 -0000
1.22.2.1
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <stdlib.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/file-handle-def.h>
#include <data/format.h>
@@ -87,7 +88,7 @@
struct file_handle *h;
struct dictionary *d;
struct tab_table *t;
- struct sfm_reader *reader;
+ struct casereader *reader;
struct sfm_read_info info;
int r, nr;
int i;
@@ -102,7 +103,7 @@
reader = sfm_open_reader (h, &d, &info);
if (!reader)
return CMD_FAILURE;
- sfm_close_reader (reader);
+ casereader_destroy (reader);
t = tab_create (2, 10, 0);
tab_vline (t, TAL_GAP, 1, 0, 8);
Index: src/language/expressions/evaluate.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/expressions/evaluate.c,v
retrieving revision 1.18
retrieving revision 1.18.2.1
diff -u -b -r1.18 -r1.18.2.1
--- src/language/expressions/evaluate.c 16 Jan 2007 15:30:28 -0000 1.18
+++ src/language/expressions/evaluate.c 19 Mar 2007 21:36:24 -0000 1.18.2.1
@@ -158,7 +158,7 @@
if ( ds == NULL )
{
- ds = create_dataset (NULL, NULL, NULL);
+ ds = create_dataset (NULL, NULL);
d = dataset_dict (ds);
}
Index: src/language/lexer/variable-parser.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/lexer/variable-parser.c,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -u -b -r1.15 -r1.15.2.1
--- src/language/lexer/variable-parser.c 22 Dec 2006 04:38:23 -0000
1.15
+++ src/language/lexer/variable-parser.c 19 Mar 2007 21:36:24 -0000
1.15.2.1
@@ -106,12 +106,6 @@
vs = var_set_create_from_dict (d);
success = parse_var_set_vars (lexer, vs, var, cnt, opts);
- if ( success == 0 )
- {
- free ( *var ) ;
- *var = NULL;
- *cnt = 0;
- }
var_set_destroy (vs);
return success;
}
Index: src/language/stats/ChangeLog
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/ChangeLog,v
retrieving revision 1.45
retrieving revision 1.45.2.1
diff -u -b -r1.45 -r1.45.2.1
--- src/language/stats/ChangeLog 17 Feb 2007 16:16:23 -0000 1.45
+++ src/language/stats/ChangeLog 19 Mar 2007 21:36:24 -0000 1.45.2.1
@@ -1,3 +1,20 @@
+Fri Dec 22 14:04:09 2006 Ben Pfaff <address@hidden>
+
+ Simplify missing value handling.
+
+ * aggregate.c (struct agr_var): Remove `bool include_missing', add
+ `enum mv_class exclude'. Remove `int missing', add `bool
+ saw_missing'. Update users.
+
+ * descriptives.c (struct dsc_trns): Removed `int
+ include_user_missing', add `enum mv_class exclude'. Update users.
+ (struct dsc_proc): Ditto.
+
+ * examine.q: (static var value_is_missing): Rename
+ `exclude_values', change type to `enum mv_class'. Update users.
+
+ * rank.q: Ditto.
+
Sat Feb 17 08:16:00 2007 Ben Pfaff <address@hidden>
* flip.c (flip_sink_create): Improve error message when temporary
Index: src/language/stats/aggregate.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/aggregate.c,v
retrieving revision 1.30
retrieving revision 1.30.2.1
diff -u -b -r1.30 -r1.30.2.1
--- src/language/stats/aggregate.c 9 Feb 2007 05:19:08 -0000 1.30
+++ src/language/stats/aggregate.c 19 Mar 2007 21:36:24 -0000 1.30.2.1
@@ -21,15 +21,15 @@
#include <stdlib.h>
#include <data/any-writer.h>
-#include <data/case-sink.h>
#include <data/case.h>
-#include <data/casefile.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/storage-stream.h>
#include <data/sys-file-writer.h>
#include <data/variable.h>
#include <language/command.h>
@@ -44,6 +44,7 @@
#include <libpspp/pool.h>
#include <libpspp/str.h>
#include <math/moments.h>
+#include <math/ordering.h>
#include <math/sort.h>
#include "minmax.h"
@@ -135,12 +136,8 @@
/* An entire AGGREGATE procedure. */
struct agr_proc
{
- /* We have either an output file or a sink. */
- struct any_writer *writer; /* Output file, or null if none. */
- struct case_sink *sink; /* Sink, or null if none. */
-
/* Break variables. */
- struct sort_criteria *sort; /* Sort criteria. */
+ struct case_ordering *sort; /* Sort criteria. */
struct variable **break_vars; /* Break variables. */
size_t break_var_cnt; /* Number of break variables. */
struct ccase break_case; /* Last values of break variables. */
@@ -150,20 +147,18 @@
struct dictionary *dict; /* Aggregate dictionary. */
const struct dictionary *src_dict; /* Dict of the source */
int case_cnt; /* Counts aggregated cases. */
- struct ccase agr_case; /* Aggregate case for output. */
};
static void initialize_aggregate_info (struct agr_proc *,
const struct ccase *);
-
+static void accumulate_aggregate_info (struct agr_proc *,
+ const struct ccase *);
/* Prototypes. */
static bool parse_aggregate_functions (struct lexer *, const struct dictionary
*,
struct agr_proc *);
static void agr_destroy (struct agr_proc *);
-static bool aggregate_single_case (struct agr_proc *agr,
- const struct ccase *input,
- struct ccase *output);
-static void dump_aggregate_info (struct agr_proc *agr, struct ccase *output);
+static void dump_aggregate_info (struct agr_proc *agr,
+ struct casewriter *output);
/* Parsing. */
@@ -174,10 +169,14 @@
struct dictionary *dict = dataset_dict (ds);
struct agr_proc agr;
struct file_handle *out_file = NULL;
+ struct casereader *input = NULL, *group;
+ struct casegrouper *grouper;
+ struct casewriter *output = NULL;
bool copy_documents = false;
bool presorted = false;
bool saw_direction;
+ bool ok;
memset(&agr, 0 , sizeof (agr));
agr.missing = ITEMWISE;
@@ -223,11 +222,13 @@
int i;
lex_match (lexer, '=');
- agr.sort = sort_parse_criteria (lexer, dict,
- &agr.break_vars, &agr.break_var_cnt,
- &saw_direction, NULL);
+ agr.sort = parse_case_ordering (lexer, dict,
+
+ &saw_direction);
if (agr.sort == NULL)
goto error;
+ case_ordering_get_vars (agr.sort,
+ &agr.break_vars, &agr.break_var_cnt);
for (i = 0; i < agr.break_var_cnt; i++)
dict_clone_var_assert (agr.dict, agr.break_vars[i],
@@ -261,109 +262,63 @@
/* Initialize. */
agr.case_cnt = 0;
- case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict));
- /* Output to active file or external file? */
if (out_file == NULL)
{
- struct ccase *c;
-
/* The active file will be replaced by the aggregated data,
so TEMPORARY is moot. */
proc_cancel_temporary_transformations (ds);
-
- if (agr.sort != NULL && !presorted)
- {
- if (!sort_active_file_in_place (ds, agr.sort))
- goto error;
+ proc_discard_output (ds);
+ output = autopaging_writer_create (dict_get_next_value_idx (agr.dict));
}
-
- agr.sink = create_case_sink (&storage_sink_class, agr.dict,
- dataset_get_casefile_factory (ds),
- NULL);
- if (agr.sink->class->open != NULL)
- agr.sink->class->open (agr.sink);
- proc_set_sink (ds,
- create_case_sink (&null_sink_class, dict,
- dataset_get_casefile_factory (ds),
- NULL));
- proc_open (ds);
- while (proc_read (ds, &c))
- if (aggregate_single_case (&agr, c, &agr.agr_case))
- if (!agr.sink->class->write (agr.sink, &agr.agr_case))
+ else
{
- proc_close (ds);
+ output = any_writer_open (out_file, agr.dict);
+ if (output == NULL)
goto error;
}
- if (!proc_close (ds))
- goto error;
- if (agr.case_cnt > 0)
+ input = proc_open (ds);
+ if (agr.sort != NULL && !presorted)
{
- dump_aggregate_info (&agr, &agr.agr_case);
- if (!agr.sink->class->write (agr.sink, &agr.agr_case))
- goto error;
- }
- discard_variables (ds);
- dataset_set_dict (ds, agr.dict);
- agr.dict = NULL;
- proc_set_source (ds, agr.sink->class->make_source (agr.sink));
- free_case_sink (agr.sink);
+ input = sort_execute (input, agr.sort);
+ agr.sort = NULL;
}
- else
- {
- agr.writer = any_writer_open (out_file, agr.dict);
- if (agr.writer == NULL)
- goto error;
- if (agr.sort != NULL && !presorted)
+ for (grouper = casegrouper_create_vars (input, agr.break_vars,
+ agr.break_var_cnt);
+ casegrouper_get_next_group (grouper, &group);
+ casereader_destroy (group))
{
- /* Sorting is needed. */
- struct casefile *dst;
- struct casereader *reader;
struct ccase c;
- bool ok = true;
- dst = sort_active_file_to_casefile (ds, agr.sort);
- if (dst == NULL)
- goto error;
- reader = casefile_get_destructive_reader (dst);
- while (ok && casereader_read_xfer (reader, &c))
- {
- if (aggregate_single_case (&agr, &c, &agr.agr_case))
- ok = any_writer_write (agr.writer, &agr.agr_case);
+ casereader_peek (group, 0, &c);
+ initialize_aggregate_info (&agr, &c);
case_destroy (&c);
+
+ for (; casereader_read (group, &c); case_destroy (&c))
+ accumulate_aggregate_info (&agr, &c);
+ dump_aggregate_info (&agr, output);
}
- casereader_destroy (reader);
- if (ok)
- ok = !casefile_error (dst);
- casefile_destroy (dst);
- if (!ok)
+ if (!casegrouper_destroy (grouper))
goto error;
- }
- else
- {
- /* Active file is already sorted. */
- struct ccase *c;
- proc_open (ds);
- while (proc_read (ds, &c))
- if (aggregate_single_case (&agr, c, &agr.agr_case))
- if (!any_writer_write (agr.writer, &agr.agr_case))
+ proc_commit (ds);
+
+ if (out_file == NULL)
{
- proc_close (ds);
- goto error;
- }
- if (!proc_close (ds))
+ struct casereader *next_input = casewriter_make_reader (output);
+ if (next_input == NULL)
goto error;
- }
- if (agr.case_cnt > 0)
- {
- dump_aggregate_info (&agr, &agr.agr_case);
- any_writer_write (agr.writer, &agr.agr_case);
+ proc_set_active_file (ds, next_input, agr.dict);
+ agr.dict = NULL;
}
- if (any_writer_error (agr.writer))
+ else
+ {
+ ok = casewriter_destroy (output);
+ output = NULL;
+ if (!ok)
goto error;
}
@@ -371,6 +326,9 @@
return CMD_SUCCESS;
error:
+ if (input != NULL)
+ proc_commit (ds);
+ casewriter_destroy (output);
agr_destroy (&agr);
return CMD_CASCADING_FAILURE;
}
@@ -717,9 +675,7 @@
{
struct agr_var *iter, *next;
- any_writer_close (agr->writer);
- if (agr->sort != NULL)
- sort_destroy_criteria (agr->sort);
+ case_ordering_destroy (agr->sort);
free (agr->break_vars);
case_destroy (&agr->break_case);
for (iter = agr->agr_vars; iter; iter = next)
@@ -742,44 +698,13 @@
}
if (agr->dict != NULL)
dict_destroy (agr->dict);
-
- case_destroy (&agr->agr_case);
}
/* Execution. */
-static void accumulate_aggregate_info (struct agr_proc *,
- const struct ccase *);
-static void dump_aggregate_info (struct agr_proc *, struct ccase *);
-
-/* Processes a single case INPUT for aggregation. If output is
- warranted, writes it to OUTPUT and returns true.
- Otherwise, returns false and OUTPUT is unmodified. */
-static bool
-aggregate_single_case (struct agr_proc *agr,
- const struct ccase *input, struct ccase *output)
-{
- bool finished_group = false;
-
- if (agr->case_cnt++ == 0)
- initialize_aggregate_info (agr, input);
- else if (case_compare (&agr->break_case, input,
- agr->break_vars, agr->break_var_cnt))
- {
- dump_aggregate_info (agr, output);
- finished_group = true;
-
- initialize_aggregate_info (agr, input);
- }
-
- accumulate_aggregate_info (agr, input);
- return finished_group;
-}
-
/* Accumulates aggregation data from the case INPUT. */
static void
-accumulate_aggregate_info (struct agr_proc *agr,
- const struct ccase *input)
+accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
{
struct agr_var *iter;
double weight;
@@ -947,12 +872,14 @@
}
}
-/* We've come to a record that differs from the previous in one or
- more of the break variables. Make an output record from the
- accumulated statistics in the OUTPUT case. */
+/* Writes an aggregated record to OUTPUT. */
static void
-dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
+dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
{
+ struct ccase c;
+
+ case_create (&c, dict_get_next_value_idx (agr->dict));
+
{
int value_idx = 0;
int i;
@@ -961,7 +888,7 @@
{
struct variable *v = agr->break_vars[i];
size_t value_cnt = var_get_value_cnt (v);
- memcpy (case_data_rw_idx (output, value_idx),
+ memcpy (case_data_rw_idx (&c, value_idx),
case_data (&agr->break_case, v),
sizeof (union value) * value_cnt);
value_idx += value_cnt;
@@ -973,7 +900,7 @@
for (i = agr->agr_vars; i; i = i->next)
{
- union value *v = case_data_rw (output, i->dest);
+ union value *v = case_data_rw (&c, i->dest);
if (agr->missing == COLUMNWISE && i->saw_missing
&& (i->function & FUNC) != N && (i->function & FUNC) != NU
@@ -1076,6 +1003,8 @@
}
}
}
+
+ casewriter_write (output, &c);
}
/* Resets the state for all the aggregate functions. */
Index: src/language/stats/autorecode.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/autorecode.c,v
retrieving revision 1.18
retrieving revision 1.18.2.1
diff -u -b -r1.18 -r1.18.2.1
--- src/language/stats/autorecode.c 19 Dec 2006 14:21:53 -0000 1.18
+++ src/language/stats/autorecode.c 19 Mar 2007 21:36:24 -0000 1.18.2.1
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <data/case.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/transformations.h>
@@ -103,7 +104,8 @@
cmd_autorecode (struct lexer *lexer, struct dataset *ds)
{
struct autorecode_pgm arc;
- struct ccase *c;
+ struct casereader *input;
+ struct ccase c;
size_t dst_cnt;
size_t i;
bool ok;
@@ -184,16 +186,16 @@
arc.src_values[i] = hsh_create (10, compare_numeric_value,
hash_numeric_value, NULL, NULL);
- proc_open (ds);
- while (proc_read (ds, &c))
+ input = proc_open (ds);
+ for (; casereader_read (input, &c); case_destroy (&c))
for (i = 0; i < arc.var_cnt; i++)
{
union arc_value v, *vp, **vpp;
if (var_is_numeric (arc.src_vars[i]))
- v.f = case_num (c, arc.src_vars[i]);
+ v.f = case_num (&c, arc.src_vars[i]);
else
- v.c = (char *) case_str (c, arc.src_vars[i]);
+ v.c = (char *) case_str (&c, arc.src_vars[i]);
vpp = (union arc_value **) hsh_probe (arc.src_values[i], &v);
if (*vpp == NULL)
@@ -207,7 +209,8 @@
*vpp = vp;
}
}
- ok = proc_close (ds);
+ ok = casereader_destroy (input);
+ proc_commit (ds);
for (i = 0; i < arc.var_cnt; i++)
arc.dst_vars[i] = dict_create_var_assert (dataset_dict (ds),
Index: src/language/stats/binomial.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/binomial.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/binomial.c 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/binomial.c 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -22,13 +22,12 @@
#include <libpspp/alloc.h>
#include <data/case.h>
-#include <data/casefile.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 <data/casefilter.h>
#include <libpspp/message.h>
#include <libpspp/assertion.h>
@@ -91,20 +90,19 @@
static void
do_binomial (const struct dictionary *dict,
- const struct casefile *cf,
+ struct casereader *input,
const struct binomial_test *bst,
- struct freq *cat1,
- struct freq *cat2,
- const struct casefilter *filter
+ struct freq_mutable *cat1,
+ struct freq_mutable *cat2,
+ enum mv_class exclude
)
{
bool warn = true;
const struct one_sample_test *ost = (const struct one_sample_test *) bst;
struct ccase c;
- struct casereader *r = casefile_get_reader (cf, NULL);
- while (casereader_read(r, &c))
+ while (casereader_read(input, &c))
{
int v;
double w =
@@ -115,7 +113,7 @@
const struct variable *var = ost->vars[v];
const union value *value = case_data (&c, var);
- if ( casefilter_variable_missing (filter, &c, var))
+ if (var_is_value_missing (var, value, exclude))
break;
if ( NULL == cat1[v].value )
@@ -140,23 +138,23 @@
case_destroy (&c);
}
- casereader_destroy (r);
+ casereader_destroy (input);
}
void
binomial_execute (const struct dataset *ds,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
+ enum mv_class exclude,
const struct npar_test *test)
{
int v;
const struct binomial_test *bst = (const struct binomial_test *) test;
const struct one_sample_test *ost = (const struct one_sample_test*) test;
- struct freq *cat1 = xzalloc (sizeof (*cat1) * ost->n_vars);
- struct freq *cat2 = xzalloc (sizeof (*cat1) * ost->n_vars);
+ struct freq_mutable *cat1 = xzalloc (sizeof (*cat1) * ost->n_vars);
+ struct freq_mutable *cat2 = xzalloc (sizeof (*cat1) * ost->n_vars);
struct tab_table *table ;
assert ((bst->category1 == SYSMIS) == (bst->category2 == SYSMIS) );
@@ -175,7 +173,7 @@
cat2->value = value_dup (&v, 0);
}
- do_binomial (dataset_dict(ds), cf, bst, cat1, cat2, filter);
+ do_binomial (dataset_dict(ds), input, bst, cat1, cat2, exclude);
table = tab_create (7, ost->n_vars * 3 + 1, 0);
@@ -261,6 +259,11 @@
tab_vline (table, TAL_2, 2, 0, tab_nr (table) -1);
+ for (v = 0; v < ost->n_vars; v++)
+ {
+ free (cat1[v].value);
+ free (cat2[v].value);
+ }
free (cat1);
free (cat2);
Index: src/language/stats/binomial.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/binomial.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/binomial.h 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/binomial.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -36,13 +36,13 @@
};
-struct casefile;
+struct casereader;
struct dataset;
void binomial_execute (const struct dataset *,
- const struct casefile *,
- struct casefilter *,
+ struct casereader *,
+ enum mv_class,
const struct npar_test *);
#endif
Index: src/language/stats/chisquare.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/chisquare.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -b -r1.3 -r1.3.2.1
--- src/language/stats/chisquare.c 16 Jan 2007 15:30:28 -0000 1.3
+++ src/language/stats/chisquare.c 19 Mar 2007 21:36:24 -0000 1.3.2.1
@@ -23,8 +23,7 @@
#include <stdlib.h>
#include <data/case.h>
-#include <data/casefile.h>
-#include <data/casefilter.h>
+#include <data/casereader.h>
#include <data/variable.h>
#include <data/dictionary.h>
#include <data/procedure.h>
@@ -57,8 +56,7 @@
*/
static struct hsh_table *
create_freq_hash_with_range (const struct dictionary *dict,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
const struct variable *var,
double lo,
double hi)
@@ -66,7 +64,6 @@
bool warn = true;
float i_d;
struct ccase c;
- struct casereader *r = casefile_get_reader (cf, filter);
struct hsh_table *freq_hash =
hsh_create (4, compare_freq, hash_freq,
@@ -87,19 +84,13 @@
hsh_insert (freq_hash, fr);
}
- while (casereader_read(r, &c))
+ while (casereader_read (input, &c))
{
union value obs_value;
struct freq **existing_fr;
struct freq *fr = xmalloc(sizeof (*fr));
fr->value = case_data (&c, var);
- if ( casefilter_variable_missing (filter, &c, var))
- {
- free (fr);
- continue;
- }
-
fr->count = dict_get_case_weight (dict, &c, &warn);
obs_value.f = trunc (fr->value->f);
@@ -124,43 +115,35 @@
case_destroy (&c);
}
- casereader_destroy (r);
+ casereader_destroy (input);
return freq_hash;
}
/* Return a hash table containing the frequency counts of each
- value of VAR in CF .
+ value of VAR in INPUT .
It is the caller's responsibility to free the hash table when
no longer required.
*/
static struct hsh_table *
create_freq_hash (const struct dictionary *dict,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
const struct variable *var)
{
bool warn = true;
struct ccase c;
- struct casereader *r = casefile_get_reader (cf, filter);
struct hsh_table *freq_hash =
hsh_create (4, compare_freq, hash_freq,
free_freq_mutable_hash,
(void *) var);
- while (casereader_read(r, &c))
+ for (; casereader_read (input, &c); case_destroy (&c))
{
struct freq **existing_fr;
struct freq *fr = xmalloc(sizeof (*fr));
- fr->value = case_data (&c, var );
-
- if ( casefilter_variable_missing (filter, &c, var))
- {
- free (fr);
- continue;
- }
+ fr->value = case_data (&c, var);
fr->count = dict_get_case_weight (dict, &c, &warn);
@@ -175,10 +158,8 @@
*existing_fr = fr;
fr->value = value_dup (fr->value, var_get_width (var));
}
-
- case_destroy (&c);
}
- casereader_destroy (r);
+ casereader_destroy (input);
return freq_hash;
}
@@ -187,8 +168,7 @@
static struct tab_table *
create_variable_frequency_table (const struct dictionary *dict,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
const struct chisquare_test *test,
int v,
struct hsh_table **freq_hash)
@@ -200,7 +180,7 @@
struct tab_table *table ;
const struct variable *var = ost->vars[v];
- *freq_hash = create_freq_hash (dict, cf, filter, var);
+ *freq_hash = create_freq_hash (dict, input, var);
n_cells = hsh_count (*freq_hash);
@@ -305,7 +285,8 @@
{
const struct one_sample_test *ost = (const struct one_sample_test*) test;
- struct tab_table *table = tab_create (1 + ost->n_vars, 4, 0);
+ struct tab_table *table;
+ table = tab_create (1 + ost->n_vars, 4, 0);
tab_dim (table, tab_natural_dimensions);
tab_title (table, _("Test Statistics"));
tab_headers (table, 1, 0, 1, 0);
@@ -331,8 +312,8 @@
void
chisquare_execute (const struct dataset *ds,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
+ enum mv_class exclude,
const struct npar_test *test)
{
const struct dictionary *dict = dataset_dict (ds);
@@ -355,9 +336,11 @@
{
double total_obs = 0.0;
struct hsh_table *freq_hash = NULL;
+ struct casereader *reader =
+ casereader_create_filter_missing (casereader_clone (input),
+ &ost->vars[v], 1, exclude, NULL);
struct tab_table *freq_table =
- create_variable_frequency_table(dict, cf, filter, cst,
- v, &freq_hash);
+ create_variable_frequency_table(dict, reader, cst, v, &freq_hash);
struct freq **ff = (struct freq **) hsh_sort (freq_hash);
@@ -420,9 +403,12 @@
for ( v = 0 ; v < ost->n_vars ; ++v )
{
double total_obs = 0.0;
+ struct casereader *reader =
+ casereader_create_filter_missing (casereader_clone (input),
+ &ost->vars[v], 1, exclude, NULL);
struct hsh_table *freq_hash =
- create_freq_hash_with_range (dict, cf, filter, ost->vars[v],
- cst->lo, cst->hi);
+ create_freq_hash_with_range (dict, reader,
+ ost->vars[v], cst->lo, cst->hi);
struct freq **ff = (struct freq **) hsh_sort (freq_hash);
@@ -473,7 +459,7 @@
tab_submit (freq_table);
}
-
+ casereader_destroy (input);
/* Populate the summary statistics table */
for ( v = 0 ; v < ost->n_vars ; ++v )
Index: src/language/stats/chisquare.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/chisquare.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/chisquare.h 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/chisquare.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -37,8 +37,8 @@
int n_expected;
};
-struct casefile;
-struct dictionary ;
+struct casereader;
+struct dictionary;
struct hsh_table;
void chisquare_insert_variables (const struct npar_test *test,
@@ -46,8 +46,8 @@
void chisquare_execute (const struct dataset *ds,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
+ enum mv_class exclude,
const struct npar_test *test);
Index: src/language/stats/crosstabs.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/crosstabs.q,v
retrieving revision 1.27
retrieving revision 1.27.2.1
diff -u -b -r1.27 -r1.27.2.1
--- src/language/stats/crosstabs.q 23 Dec 2006 06:11:33 -0000 1.27
+++ src/language/stats/crosstabs.q 19 Mar 2007 21:36:24 -0000 1.27.2.1
@@ -36,6 +36,8 @@
#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>
@@ -177,10 +179,10 @@
static struct pool *pl_col; /* For column data. */
static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds);
-static void precalc (const struct ccase *, void *, const struct dataset *);
-static bool calc_general (const struct ccase *, void *, const struct dataset
*);
-static bool calc_integer (const struct ccase *, void *, const struct dataset
*);
-static bool postcalc (void *, const struct dataset *);
+static void precalc (struct casereader *, const struct dataset *);
+static void calc_general (struct ccase *, const struct dataset *);
+static void calc_integer (struct ccase *, const struct dataset *);
+static void postcalc (void);
static void submit (struct tab_table *);
static void format_short (char *s, const struct fmt_spec *fp,
@@ -203,8 +205,9 @@
static int
internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *input, *group;
int i;
- bool ok;
variables = NULL;
variables_cnt = 0;
@@ -294,11 +297,30 @@
else
write = CRS_WR_NONE;
- ok = procedure_with_splits (ds, precalc,
- mode == GENERAL ? calc_general : calc_integer,
- postcalc, NULL);
+ input = casereader_create_filter_weight (proc_open (ds), dataset_dict (ds),
+ NULL, NULL);
+ grouper = casegrouper_create_splits (input, dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ {
+ struct ccase c;
+
+ precalc (group, ds);
- return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
+ for (; casereader_read (group, &c); case_destroy (&c))
+ {
+ if (mode == GENERAL)
+ calc_general (&c, ds);
+ else
+ calc_integer (&c, ds);
+ }
+ casereader_destroy (group);
+
+ postcalc ();
+ }
+ casegrouper_destroy (grouper);
+ proc_commit (ds);
+
+ return true ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
/* Parses the TABLES subcommand. */
@@ -490,9 +512,14 @@
/* Set up the crosstabulation tables for processing. */
static void
-precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
+precalc (struct casereader *input, const struct dataset *ds)
{
- output_split_file_values (ds, first);
+ struct ccase c;
+
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
+
if (mode == GENERAL)
{
gen_tab = hsh_create (512, compare_table_entry, hash_table_entry,
@@ -564,18 +591,16 @@
}
/* Form crosstabulations for general mode. */
-static bool
-calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset
*ds)
+static void
+calc_general (struct ccase *c, const struct dataset *ds)
{
- bool bad_warn = true;
-
/* Missing values to exclude. */
enum mv_class exclude = (cmd.miss == CRS_TABLE ? MV_ANY
: cmd.miss == CRS_INCLUDE ? MV_SYSTEM
: MV_NEVER);
/* Case weight. */
- double weight = dict_get_case_weight (dataset_dict (ds), c, &bad_warn);
+ double weight = dict_get_case_weight (dataset_dict (ds), c, NULL);
/* Flattened current table index. */
int t;
@@ -636,12 +661,10 @@
next_crosstab:
local_free (te);
}
-
- return true;
}
-static bool
-calc_integer (const struct ccase *c, void *aux UNUSED, const struct dataset
*ds)
+static void
+calc_integer (struct ccase *c, const struct dataset *ds)
{
bool bad_warn = true;
@@ -694,8 +717,6 @@
next_crosstab: ;
}
-
- return true;
}
/* Compare the table_entry's at A and B and return a strcmp()-type
@@ -763,8 +784,8 @@
int *, int *, int *);
static void make_summary_table (void);
-static bool
-postcalc (void *aux UNUSED, const struct dataset *ds UNUSED)
+static void
+postcalc (void)
{
if (mode == GENERAL)
{
@@ -800,8 +821,6 @@
}
hsh_destroy (gen_tab);
-
- return true;
}
static void insert_summary (struct tab_table *, int tab_index, double valid);
Index: src/language/stats/descriptives.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/descriptives.c,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -b -r1.22 -r1.22.2.1
--- src/language/stats/descriptives.c 9 Feb 2007 05:19:08 -0000 1.22
+++ src/language/stats/descriptives.c 19 Mar 2007 21:36:24 -0000 1.22.2.1
@@ -16,16 +16,14 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
-/* FIXME: Many possible optimizations. */
-
#include <config.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
-#include <data/case.h>
-#include <data/casefile.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/transformations.h>
@@ -180,9 +178,8 @@
static void setup_z_trns (struct dsc_proc *, struct dataset *);
/* Procedure execution functions. */
-static bool calc_descriptives (const struct ccase *first,
- const struct casefile *, void *dsc_,
- const struct dataset *);
+static void calc_descriptives (struct dsc_proc *, struct casereader *,
+ struct dataset *);
static void display (struct dsc_proc *dsc);
/* Parser and outline. */
@@ -200,6 +197,9 @@
size_t i;
bool ok;
+ struct casegrouper *grouper;
+ struct casereader *group;
+
/* Create and initialize dsc. */
dsc = xmalloc (sizeof *dsc);
dsc->vars = NULL;
@@ -316,7 +316,7 @@
{
int i;
- if (!parse_variables (lexer, dataset_dict (ds), &vars, &var_cnt,
+ if (!parse_variables (lexer, dict, &vars, &var_cnt,
PV_APPEND | PV_NO_DUPLICATE | PV_NUMERIC))
goto error;
@@ -412,8 +412,12 @@
for (i = 0; i < dsc->var_cnt; i++)
dsc->vars[i].moments = moments_create (dsc->max_moment);
- /* Data pass. */
- ok = multipass_procedure_with_splits (ds, calc_descriptives, dsc);
+ /* Data pass. FIXME: error handling. */
+ grouper = casegrouper_create_splits (proc_open (ds), dict);
+ while (casegrouper_get_next_group (grouper, &group))
+ calc_descriptives (dsc, group, ds);
+ ok = casegrouper_destroy (grouper);
+ ok = proc_commit (ds) && ok;
/* Z-scoring! */
if (ok && z_cnt)
@@ -688,17 +692,24 @@
/* Calculates and displays descriptive statistics for the cases
in CF. */
-static bool
-calc_descriptives (const struct ccase *first,
- const struct casefile *cf, void *dsc_,
- const struct dataset *ds)
+static void
+calc_descriptives (struct dsc_proc *dsc, struct casereader *group,
+ struct dataset *ds)
{
- struct dsc_proc *dsc = dsc_;
- struct casereader *reader;
+ struct casereader *pass1, *pass2;
struct ccase c;
size_t i;
- output_split_file_values (ds, first);
+ casereader_peek (group, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
+
+ group = casereader_create_filter_weight (group, dataset_dict (ds),
+ NULL, NULL);
+
+ casereader_split (group, &pass1, &pass2);
+ if (dsc->max_moment <= MOMENT_MEAN)
+ casereader_destroy (pass2);
for (i = 0; i < dsc->var_cnt; i++)
{
@@ -714,13 +725,9 @@
dsc->valid = 0.;
/* First pass to handle most of the work. */
- for (reader = casefile_get_reader (cf, NULL);
- casereader_read (reader, &c);
- case_destroy (&c))
+ for (; casereader_read (pass1, &c); case_destroy (&c))
{
- double weight = dict_get_case_weight (dataset_dict (ds), &c,
&dsc->bad_warn);
- if (weight <= 0.0)
- continue;
+ double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL);
/* Check for missing values. */
if (listwise_missing (dsc, &c))
@@ -736,8 +743,7 @@
struct dsc_var *dv = &dsc->vars[i];
double x = case_num (&c, dv->v);
- if (dsc->missing_type != DSC_LISTWISE
- && var_is_num_missing (dv->v, x, dsc->exclude))
+ if (var_is_num_missing (dv->v, x, dsc->exclude))
{
dv->missing += weight;
continue;
@@ -752,19 +758,14 @@
dv->max = x;
}
}
- casereader_destroy (reader);
+ casereader_destroy (pass1);
/* Second pass for higher-order moments. */
if (dsc->max_moment > MOMENT_MEAN)
{
- for (reader = casefile_get_reader (cf, NULL);
- casereader_read (reader, &c);
- case_destroy (&c))
- {
- double weight = dict_get_case_weight (dataset_dict (ds), &c,
- &dsc->bad_warn);
- if (weight <= 0.0)
- continue;
+ for (; casereader_read (pass2, &c); case_destroy (&c))
+ {
+ double weight = dict_get_case_weight (dataset_dict (ds), &c, NULL);
/* Check for missing values. */
if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, &c))
@@ -775,15 +776,14 @@
struct dsc_var *dv = &dsc->vars[i];
double x = case_num (&c, dv->v);
- if (dsc->missing_type != DSC_LISTWISE
- && var_is_num_missing (dv->v, x, dsc->exclude))
+ if (var_is_num_missing (dv->v, x, dsc->exclude))
continue;
if (dv->moments != NULL)
moments_pass_two (dv->moments, x, weight);
}
}
- casereader_destroy (reader);
+ casereader_destroy (pass2);
}
/* Calculate results. */
@@ -824,8 +824,6 @@
/* Output results. */
display (dsc);
-
- return true;
}
/* Returns true if any of the descriptives variables in DSC's
Index: src/language/stats/examine.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/examine.q,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -b -r1.22 -r1.22.2.1
--- src/language/stats/examine.q 23 Dec 2006 06:11:33 -0000 1.22
+++ src/language/stats/examine.q 19 Mar 2007 21:36:24 -0000 1.22.2.1
@@ -26,7 +26,8 @@
#include <stdlib.h>
#include <data/case.h>
-#include <data/casefile.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/value-labels.h>
@@ -152,8 +153,8 @@
/* Per Split function */
-static bool run_examine (const struct ccase *,
- const struct casefile *cf, void *cmd_, const struct
dataset *);
+static void run_examine (struct cmd_examine *, struct casereader *,
+ struct dataset *);
static void output_examine (void);
@@ -193,6 +194,8 @@
int
cmd_examine (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *group;
bool ok;
subc_list_double_create (&percentile_list);
@@ -222,7 +225,11 @@
subc_list_double_push (&percentile_list, 75);
}
- ok = multipass_procedure_with_splits (ds, run_examine, &cmd);
+ grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ run_examine (&cmd, group, ds);
+ ok = casegrouper_destroy (grouper);
+ ok = proc_commit (ds) && ok;
if ( totals )
{
@@ -627,9 +634,6 @@
-static bool bad_weight_warn = true;
-
-
/* Perform calculations for the sub factors */
void
factor_calc (const struct ccase *c, int case_no, double weight,
@@ -706,23 +710,26 @@
}
}
-static bool
-run_examine (const struct ccase *first, const struct casefile *cf,
- void *cmd_, const struct dataset *ds)
+static void
+run_examine (struct cmd_examine *cmd, struct casereader *input,
+ struct dataset *ds)
{
struct dictionary *dict = dataset_dict (ds);
- struct casereader *r;
+ casenumber case_no;
struct ccase c;
int v;
- const struct cmd_examine *cmd = (struct cmd_examine *) cmd_;
-
struct factor *fctr;
- output_split_file_values (ds, first);
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
+
+ input = casereader_create_filter_weight (input, dict, NULL, NULL);
+ input = casereader_create_counter (input, &case_no, 0);
/* Make sure we haven't got rubbish left over from a
- previous split */
+ previous split. */
fctr = factors;
while (fctr)
{
@@ -738,15 +745,10 @@
for ( v = 0 ; v < n_dependent_vars ; ++v )
metrics_precalc (&totals[v]);
- for (r = casefile_get_reader (cf, NULL);
- casereader_read (r, &c) ;
- case_destroy (&c) )
+ for (; casereader_read (input, &c); case_destroy (&c))
{
- int case_missing=0;
- const int case_no = casereader_cnum (r);
-
- const double weight =
- dict_get_case_weight (dict, &c, &bad_weight_warn);
+ int case_missing = 0;
+ const double weight = dict_get_case_weight (dict, &c, NULL);
if ( cmd->miss == XMN_LISTWISE )
{
@@ -787,6 +789,7 @@
factor_calc (&c, case_no, weight, case_missing);
}
+ casereader_destroy (input);
for ( v = 0 ; v < n_dependent_vars ; ++v)
{
@@ -893,8 +896,6 @@
metrics_destroy (&totals[i]);
}
}
-
- return true;
}
Index: src/language/stats/flip.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/flip.c,v
retrieving revision 1.22
retrieving revision 1.22.2.1
diff -u -b -r1.22 -r1.22.2.1
--- src/language/stats/flip.c 17 Feb 2007 16:16:23 -0000 1.22
+++ src/language/stats/flip.c 19 Mar 2007 21:36:24 -0000 1.22.2.1
@@ -27,9 +27,9 @@
#include <sys/types.h>
#endif
-#include <data/case-sink.h>
-#include <data/case-source.h>
#include <data/case.h>
+#include <data/casereader.h>
+#include <data/casereader-private.h>
#include <data/dictionary.h>
#include <data/procedure.h>
#include <data/settings.h>
@@ -42,7 +42,6 @@
#include <libpspp/array.h>
#include <libpspp/assertion.h>
#include <libpspp/message.h>
-#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
@@ -70,8 +69,6 @@
int case_cnt; /* Pre-flip case count. */
size_t case_size; /* Post-flip bytes per case. */
- union value *output_buf; /* Case output buffer. */
-
struct variable *new_names; /* Variable containing new variable names. */
struct varname *new_names_head; /* First new variable. */
struct varname *new_names_tail; /* Last new variable. */
@@ -82,23 +79,23 @@
bool error; /* Error reading temporary file? */
};
+static const struct casereader_class flip_casereader_class;
+
static void destroy_flip_pgm (struct flip_pgm *);
-static struct case_sink *flip_sink_create (struct dataset *ds, struct flip_pgm
*);
-static struct case_source *flip_source_create (struct flip_pgm *);
static bool flip_file (struct flip_pgm *);
-static int build_dictionary (struct dictionary *, struct flip_pgm *);
-
-static const struct case_source_class flip_source_class;
-static const struct case_sink_class flip_sink_class;
+static bool build_dictionary (struct dictionary *, struct flip_pgm *);
+static bool write_flip_case (struct flip_pgm *, const struct ccase *);
/* Parses and executes FLIP. */
int
cmd_flip (struct lexer *lexer, struct dataset *ds)
{
- struct flip_pgm *flip;
- struct case_sink *sink;
struct dictionary *dict = dataset_dict (ds);
- bool ok;
+ struct flip_pgm *flip;
+ struct casereader *input;
+ union value *output_buf;
+ struct ccase c;
+ size_t i;
if (proc_make_temporary_transformations_permanent (ds))
msg (SW, _("FLIP ignores TEMPORARY. "
@@ -144,8 +141,6 @@
if (flip->new_names)
{
- size_t i;
-
for (i = 0; i < flip->var_cnt; i++)
if (flip->var[i] == flip->new_names)
{
@@ -155,20 +150,46 @@
}
}
+ output_buf = pool_nalloc (flip->pool,
+ flip->var_cnt, sizeof *output_buf);
+
+ flip->file = pool_tmpfile (flip->pool);
+ if (flip->file == NULL)
+ {
+ msg (SE, _("Could not create temporary file for FLIP."));
+ goto error;
+ }
+
+ /* Write variable names as first case. */
+ for (i = 0; i < flip->var_cnt; i++)
+ buf_copy_str_rpad (output_buf[i].s, MAX_SHORT_STRING,
+ var_get_name (flip->var[i]));
+ if (fwrite (output_buf, sizeof *output_buf,
+ flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
+ {
+ msg (SE, _("Error writing FLIP file: %s."), strerror (errno));
+ goto error;
+ }
+
+ flip->case_cnt = 1;
+
/* Read the active file into a flip_sink. */
- flip->case_cnt = 0;
proc_make_temporary_transformations_permanent (ds);
- sink = flip_sink_create (ds, flip);
- if (sink == NULL)
- goto error;
- proc_set_sink (ds, sink);
- flip->new_names_tail = NULL;
- ok = procedure (ds,NULL, NULL);
+ proc_discard_output (ds);
+
+ input = proc_open (ds);
+ while (casereader_read (input, &c))
+ {
+ write_flip_case (flip, &c);
+ case_destroy (&c);
+ }
+ casereader_destroy (input);
+ proc_commit (ds);
/* Flip the data we read. */
if (!flip_file (flip))
{
- discard_variables (ds);
+ proc_discard_active_file (ds);
goto error;
}
@@ -176,15 +197,17 @@
dict_clear (dict);
if (!build_dictionary (dict, flip))
{
- discard_variables (ds);
+ proc_discard_active_file (ds);
goto error;
}
flip->case_size = dict_get_case_size (dict);
/* Set up flipped data for reading. */
- proc_set_source (ds, flip_source_create (flip));
-
- return ok ? lex_end_of_command (lexer) : CMD_CASCADING_FAILURE;
+ proc_set_active_file_data (ds,
+ casereader_create (dict_get_next_value_idx (dict),
+ flip->case_cnt,
+ &flip_casereader_class, flip));
+ return lex_end_of_command (lexer);
error:
destroy_flip_pgm (flip);
@@ -251,7 +274,7 @@
}
/* Make a new dictionary for all the new variable names. */
-static int
+static bool
build_dictionary (struct dictionary *dict, struct flip_pgm *flip)
{
dict_create_var_assert (dict, "CASE_LBL", 8);
@@ -263,7 +286,7 @@
if (flip->case_cnt > 99999)
{
msg (SE, _("Cannot create more than 99999 variable names."));
- return 0;
+ return false;
}
for (i = 0; i < flip->case_cnt; i++)
@@ -281,54 +304,17 @@
for (v = flip->new_names_head; v; v = v->next)
if (!make_new_var (dict, v->name))
- return 0;
- }
-
- return 1;
-}
-
-/* Creates a flip sink based on FLIP. */
-static struct case_sink *
-flip_sink_create (struct dataset *ds, struct flip_pgm *flip)
-{
- size_t i;
-
- flip->output_buf = pool_nalloc (flip->pool,
- flip->var_cnt, sizeof *flip->output_buf);
-
- flip->file = pool_tmpfile (flip->pool);
- if (flip->file == NULL)
- {
- msg (SE, _("Could not create temporary file for FLIP: %s."),
- strerror (errno));
- return NULL;
- }
-
- /* Write variable names as first case. */
- for (i = 0; i < flip->var_cnt; i++)
- buf_copy_str_rpad (flip->output_buf[i].s, MAX_SHORT_STRING,
- var_get_name (flip->var[i]));
- if (fwrite (flip->output_buf, sizeof *flip->output_buf,
- flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
- {
- msg (SE, _("Error writing FLIP file: %s."), strerror (errno));
- return NULL;
+ return false;
}
- flip->case_cnt = 1;
-
- return create_case_sink (&flip_sink_class,
- dataset_dict (ds),
- dataset_get_casefile_factory (ds),
- flip);
+ return true;
}
/* Writes case C to the FLIP sink.
Returns true if successful, false if an I/O error occurred. */
static bool
-flip_sink_write (struct case_sink *sink, const struct ccase *c)
+write_flip_case (struct flip_pgm *flip, const struct ccase *c)
{
- struct flip_pgm *flip = sink->aux;
size_t i;
flip->case_cnt++;
@@ -377,14 +363,7 @@
}
else
out = SYSMIS;
- flip->output_buf[i].f = out;
- }
-
- if (fwrite (flip->output_buf, sizeof *flip->output_buf,
- flip->var_cnt, flip->file) != (size_t) flip->var_cnt)
- {
- msg (SE, _("Error writing FLIP file: %s."), strerror (errno));
- return false;
+ fwrite (&out, sizeof out, 1, flip->file);
}
return true;
}
@@ -511,43 +490,26 @@
return true;
}
-/* FLIP sink class. */
-static const struct case_sink_class flip_sink_class =
- {
- "FLIP",
- NULL,
- flip_sink_write,
- NULL,
- NULL,
- };
-
-/* Creates and returns a FLIP source based on PGM,
- which should have already been used as a sink. */
-static struct case_source *
-flip_source_create (struct flip_pgm *pgm)
-{
- return create_case_source (&flip_source_class, pgm);
-}
-
/* Reads one case into C.
Returns true if successful, false at end of file or if an
I/O error occurred. */
static bool
-flip_source_read (struct case_source *source, struct ccase *c)
+flip_casereader_read (struct casereader *reader UNUSED, void *flip_,
+ struct ccase *c)
{
- struct flip_pgm *flip = source->aux;
+ struct flip_pgm *flip = flip_;
size_t i;
if (flip->error || flip->cases_read >= flip->var_cnt)
return false;
- if (flip->input_buf == NULL)
- flip->input_buf = pool_nmalloc (flip->pool,
- flip->case_cnt, sizeof *flip->input_buf);
-
- if (fread (flip->input_buf, sizeof *flip->input_buf, flip->case_cnt,
- flip->file) != flip->case_cnt)
+ case_create (c, flip->case_cnt);
+ for (i = 0; i < flip->case_cnt; i++)
+ {
+ double in;
+ if (fread (&in, sizeof in, 1, flip->file) != 1)
{
+ case_destroy (c);
if (ferror (flip->file))
msg (SE, _("Error reading FLIP temporary file: %s."),
strerror (errno));
@@ -558,9 +520,8 @@
flip->error = true;
return false;
}
-
- for (i = 0; i < flip->case_cnt; i++)
- case_data_rw_idx (c, i)->f = flip->input_buf[i].f;
+ case_data_rw_idx (c, i)->f = in;
+ }
flip->cases_read++;
@@ -571,18 +532,16 @@
Returns true if successful read, false if an I/O occurred
during destruction or previously. */
static bool
-flip_source_destroy (struct case_source *source)
+flip_casereader_destroy (struct casereader *reader UNUSED, void *flip_)
{
- struct flip_pgm *flip = source->aux;
+ struct flip_pgm *flip = flip_;
bool ok = !flip->error;
destroy_flip_pgm (flip);
return ok;
}
-static const struct case_source_class flip_source_class =
+static const struct casereader_class flip_casereader_class =
{
- "FLIP",
- NULL,
- flip_source_read,
- flip_source_destroy
+ flip_casereader_read,
+ flip_casereader_destroy,
};
Index: src/language/stats/frequencies.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/frequencies.q,v
retrieving revision 1.29
retrieving revision 1.29.2.1
diff -u -b -r1.29 -r1.29.2.1
--- src/language/stats/frequencies.q 23 Dec 2006 06:11:33 -0000 1.29
+++ src/language/stats/frequencies.q 19 Mar 2007 21:36:24 -0000 1.29.2.1
@@ -29,6 +29,8 @@
#include <gsl/gsl_histogram.h>
#include <data/case.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include <data/format.h>
#include <data/procedure.h>
@@ -45,7 +47,6 @@
#include <libpspp/hash.h>
#include <libpspp/magic.h>
#include <libpspp/message.h>
-#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
@@ -271,9 +272,9 @@
static void calc_stats (struct variable *v, double d[frq_n_stats]);
-static void precalc (const struct ccase *, void *, const struct dataset *);
-static bool calc (const struct ccase *, void *, const struct dataset *);
-static bool postcalc (void *, const struct dataset *);
+static void precalc (struct casereader *, struct dataset *);
+static void calc (const struct ccase *, const struct dataset *);
+static void postcalc (void);
static void postprocess_freq_tab (struct variable *);
static void dump_full (struct variable *);
@@ -318,8 +319,9 @@
static int
internal_cmd_frequencies (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *input, *group;
int i;
- bool ok;
n_percentiles = 0;
percentiles = NULL;
@@ -383,11 +385,26 @@
/* Do it! */
- ok = procedure_with_splits (ds, precalc, calc, postcalc, NULL);
+ input = casereader_create_filter_weight (proc_open (ds), dataset_dict (ds),
+ NULL, NULL);
+ grouper = casegrouper_create_splits (input, dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ {
+ struct ccase c;
+
+ precalc (group, ds);
+ for (; casereader_read (group, &c); case_destroy (&c))
+ calc (&c, ds);
+ postcalc ();
+
+ casereader_destroy (group);
+ }
+ casegrouper_destroy (grouper);
+ proc_commit (ds);
free_frequencies(&cmd);
- return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
+ return true ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
}
/* Figure out which charts the user requested. */
@@ -496,14 +513,11 @@
}
/* Add data from case C to the frequency table. */
-static bool
-calc (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
+static void
+calc (const struct ccase *c, const struct dataset *ds)
{
- double weight;
+ double weight = dict_get_case_weight (dataset_dict (ds), c, NULL);
size_t i;
- bool bad_warn = true;
-
- weight = dict_get_case_weight (dataset_dict (ds), c, &bad_warn);
for (i = 0; i < n_variables; i++)
{
@@ -530,7 +544,8 @@
struct freq *fp = pool_alloc (gen_pool, sizeof *fp);
fp->count = weight;
fp->value = pool_clone (gen_pool,
- val, MAX (MAX_SHORT_STRING, vf->width));
+ val,
+ MAX (MAX_SHORT_STRING, vf->width));
*fpp = fp;
}
}
@@ -552,17 +567,19 @@
NOT_REACHED ();
}
}
- return true;
}
/* Prepares each variable that is the target of FREQUENCIES by setting
up its hash table. */
static void
-precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
+precalc (struct casereader *input, struct dataset *ds)
{
+ struct ccase c;
size_t i;
- output_split_file_values (ds, first);
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
pool_destroy (gen_pool);
gen_pool = pool_create ();
@@ -590,8 +607,8 @@
/* Finishes up with the variables after frequencies have been
calculated. Displays statistics, percentiles, ... */
-static bool
-postcalc (void *aux UNUSED, const struct dataset *ds UNUSED)
+static void
+postcalc (void)
{
size_t i;
@@ -666,8 +683,6 @@
cleanup_freq_tab (v);
}
-
- return true;
}
/* Returns the comparison function that should be used for
Index: src/language/stats/npar-summary.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/npar-summary.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/npar-summary.c 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/npar-summary.c 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -18,12 +18,11 @@
#include <config.h>
#include <output/table.h>
+#include <data/casereader.h>
#include <libpspp/hash.h>
#include <data/variable.h>
#include "npar-summary.h"
#include <math/moments.h>
-#include <data/casefile.h>
-#include <data/casefilter.h>
#include <data/case.h>
#include <data/dictionary.h>
#include <math.h>
@@ -35,38 +34,38 @@
void
npar_summary_calc_descriptives (struct descriptives *desc,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
const struct dictionary *dict,
const struct variable *const *vv,
- int n_vars UNUSED)
+ int n_vars UNUSED,
+ enum mv_class filter)
{
int i = 0;
while (*vv)
{
- bool warn = true;
double minimum = DBL_MAX;
double maximum = -DBL_MAX;
double var;
struct moments1 *moments = moments1_create (MOMENT_VARIANCE);
- struct casereader *r = casefile_get_reader (cf, filter);
struct ccase c;
const struct variable *v = *vv++;
+ struct casereader *pass;
- while (casereader_read(r, &c))
- {
- const union value *val = case_data (&c, v);
- double w = dict_get_case_weight (dict, &c, &warn);
-
- if ( ! casefilter_variable_missing (filter, &c, v ))
- {
- minimum = MIN (minimum, val->f);
- maximum = MAX (maximum, val->f);
- moments1_add (moments, val->f, w);
- }
+ pass = casereader_clone (input);
+ pass = casereader_create_filter_missing (pass,
+ (struct variable **) &v, 1,
+ filter, NULL);
+ pass = casereader_create_filter_weight (pass, dict, NULL, NULL);
+ while (casereader_read(pass, &c))
+ {
+ double val = case_num (&c, v);
+ double w = dict_get_case_weight (dict, &c, NULL);
+ minimum = MIN (minimum, val);
+ maximum = MAX (maximum, val);
+ moments1_add (moments, val, w);
case_destroy (&c);
}
- casereader_destroy (r);
+ casereader_destroy (pass);
moments1_calculate (moments,
&desc[i].n,
@@ -83,6 +82,7 @@
i++;
}
+ casereader_destroy (input);
}
Index: src/language/stats/npar-summary.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/npar-summary.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/npar-summary.h 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/npar-summary.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -22,9 +22,8 @@
#include <config.h>
struct variable ;
-struct casefile ;
+struct casereader ;
struct dictionary;
-struct casefilter;
struct descriptives
{
@@ -36,11 +35,11 @@
};
void npar_summary_calc_descriptives (struct descriptives *desc,
- const struct casefile *cf,
- struct casefilter *filter,
+ struct casereader *input,
const struct dictionary *dict,
const struct variable *const *vv,
- int n_vars);
+ int n_vars,
+ enum mv_class filter);
void do_summary_box (const struct descriptives *desc,
Index: src/language/stats/npar.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/npar.h,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/language/stats/npar.h 20 Dec 2006 22:19:48 -0000 1.2
+++ src/language/stats/npar.h 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -28,8 +28,8 @@
struct npar_test
{
void (*execute) (const struct dataset *,
- const struct casefile *,
- struct casefilter *,
+ struct casereader *,
+ enum mv_class exclude,
const struct npar_test *
);
Index: src/language/stats/npar.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/npar.q,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -b -r1.3 -r1.3.2.1
--- src/language/stats/npar.q 9 Feb 2007 05:19:08 -0000 1.3
+++ src/language/stats/npar.q 19 Mar 2007 21:36:24 -0000 1.3.2.1
@@ -27,9 +27,9 @@
#include <libpspp/pool.h>
#include <libpspp/hash.h>
-#include <data/casefilter.h>
#include <data/case.h>
-#include <data/casefile.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <math/moments.h>
#include <data/dictionary.h>
#include <language/stats/chisquare.h>
@@ -75,7 +75,7 @@
(those mentioned on ANY subcommand */
int n_vars; /* Number of variables in vv */
- struct casefilter *filter; /* The missing value filter */
+ enum mv_class filter; /* Missing values to filter. */
bool descriptives; /* Descriptive statistics should be calculated */
bool quartiles; /* Quartiles should be calculated */
@@ -84,13 +84,12 @@
void one_sample_insert_variables (const struct npar_test *test,
struct hsh_table *variables);
-static bool
-npar_execute(const struct ccase *first UNUSED,
- const struct casefile *cf, void *aux,
+static void
+npar_execute(struct casereader *input,
+ const struct npar_specs *specs,
const struct dataset *ds)
{
int t;
- const struct npar_specs *specs = aux;
struct descriptives *summary_descriptives = NULL;
for ( t = 0 ; t < specs->n_tests; ++t )
@@ -101,7 +100,7 @@
msg (SW, _("NPAR subcommand not currently implemented."));
continue;
}
- test->execute (ds, cf, specs->filter, test);
+ test->execute (ds, casereader_clone (input), specs->filter, test);
}
if ( specs->descriptives )
@@ -109,21 +108,20 @@
summary_descriptives = xnmalloc (sizeof (*summary_descriptives),
specs->n_vars);
- npar_summary_calc_descriptives (summary_descriptives, cf,
- specs->filter,
+ npar_summary_calc_descriptives (summary_descriptives,
+ casereader_clone (input),
dataset_dict (ds),
- specs->vv, specs->n_vars);
+ specs->vv, specs->n_vars,
+ specs->filter);
}
if ( specs->descriptives || specs->quartiles )
do_summary_box (summary_descriptives, specs->vv, specs->n_vars );
free (summary_descriptives);
-
- return true;
+ casereader_destroy (input);
}
-
int
cmd_npar_tests (struct lexer *lexer, struct dataset *ds)
{
@@ -131,6 +129,9 @@
int i;
struct npar_specs npar_specs = {0, 0, 0, 0, 0, 0, 0, 0};
struct hsh_table *var_hash;
+ struct casegrouper *grouper;
+ struct casereader *input, *group;
+
npar_specs.pool = pool_create ();
var_hash = hsh_create_pool (npar_specs.pool, 0,
@@ -179,17 +180,20 @@
}
}
- npar_specs.filter =
- casefilter_create (cmd.incl == NPAR_EXCLUDE ? MV_ANY : MV_SYSTEM, 0, 0);
+ npar_specs.filter = cmd.incl == NPAR_EXCLUDE ? MV_ANY : MV_SYSTEM;
+ input = proc_open (ds);
if ( cmd.miss == NPAR_LISTWISE )
- casefilter_add_variables (npar_specs.filter,
- npar_specs.vv,
- npar_specs.n_vars);
-
- ok = multipass_procedure_with_splits (ds, npar_execute, &npar_specs);
-
- casefilter_destroy (npar_specs.filter);
+ input = casereader_create_filter_missing (input,
+ (struct variable **)
npar_specs.vv,
+ npar_specs.n_vars,
+ npar_specs.filter, NULL);
+
+ grouper = casegrouper_create_splits (input, dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ npar_execute (group, &npar_specs, ds);
+ ok = casegrouper_destroy (grouper);
+ proc_commit (ds);
hsh_destroy (var_hash);
Index: src/language/stats/oneway.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/oneway.q,v
retrieving revision 1.21
retrieving revision 1.21.2.1
diff -u -b -r1.21 -r1.21.2.1
--- src/language/stats/oneway.q 9 Feb 2007 05:19:08 -0000 1.21
+++ src/language/stats/oneway.q 19 Mar 2007 21:36:24 -0000 1.21.2.1
@@ -25,12 +25,12 @@
#include <stdlib.h>
#include <data/case.h>
-#include <data/casefile.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 <data/casefilter.h>
#include <language/command.h>
#include <language/dictionary/split-file.h>
#include <language/lexer/lexer.h>
@@ -65,9 +65,6 @@
/* (declarations) */
/* (functions) */
-static bool bad_weight_warn = true;
-
-
static struct cmd_oneway cmd;
/* The independent variable */
@@ -89,9 +86,8 @@
static int ostensible_number_of_groups = -1;
-static bool run_oneway(const struct ccase *first,
- const struct casefile *cf,
- void *_mode, const struct dataset *);
+static void run_oneway (struct cmd_oneway *, struct casereader *,
+ const struct dataset *);
/* Routines to show the output tables */
@@ -113,6 +109,8 @@
int
cmd_oneway (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *group;
int i;
bool ok;
@@ -138,7 +136,12 @@
}
}
- ok = multipass_procedure_with_splits (ds, run_oneway, &cmd);
+ /* Data pass. FIXME: error handling. */
+ grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ run_oneway (&cmd, group, ds);
+ ok = casegrouper_destroy (grouper);
+ proc_commit (ds);
free (vars);
free_oneway (&cmd);
@@ -887,17 +890,19 @@
free (value);
}
-static bool
-run_oneway(const struct ccase *first, const struct casefile *cf,
- void *cmd_, const struct dataset *ds)
+static void
+run_oneway (struct cmd_oneway *cmd,
+ struct casereader *input,
+ const struct dataset *ds)
{
- struct casereader *r;
+ struct dictionary *dict = dataset_dict (ds);
+ enum mv_class exclude;
+ struct casereader *reader;
struct ccase c;
- struct casefilter *filter = NULL;
-
- struct cmd_oneway *cmd = (struct cmd_oneway *) cmd_;
- output_split_file_values (ds, first);
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
global_group_hash = hsh_create(4,
(hsh_compare_func *) compare_values,
@@ -907,32 +912,26 @@
precalc(cmd);
- filter = casefilter_create ( (cmd->incl != ONEWAY_INCLUDE
- ? MV_ANY : MV_SYSTEM),
- vars, n_vars );
-
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
- case_destroy (&c))
+ exclude = cmd->incl != ONEWAY_INCLUDE ? MV_ANY : MV_SYSTEM;
+ input = casereader_create_filter_missing (input, &indep_var, 1,
+ exclude, NULL);
+ if (cmd->miss == ONEWAY_LISTWISE)
+ input = casereader_create_filter_missing (input, vars, n_vars,
+ exclude, NULL);
+ input = casereader_create_filter_weight (input, dict, NULL, NULL);
+
+ reader = casereader_clone (input);
+ for (; casereader_read (reader, &c); case_destroy (&c))
{
size_t i;
- const double weight =
- dict_get_case_weight (dataset_dict (ds), &c, &bad_weight_warn);
+ const double weight = dict_get_case_weight (dict, &c, NULL);
- const union value *indep_val;
- void **p;
-
- if ( casefilter_variable_missing (filter, &c, indep_var))
- continue;
-
- indep_val = case_data (&c, indep_var);
- p = hsh_probe (global_group_hash, indep_val);
+ const union value *indep_val = case_data (&c, indep_var);
+ void **p = hsh_probe (global_group_hash, indep_val);
if (*p == NULL)
*p = value_dup (indep_val, var_get_width (indep_var));
- hsh_insert ( global_group_hash, (void *) indep_val );
-
for ( i = 0 ; i < n_vars ; ++i )
{
const struct variable *v = vars[i];
@@ -960,7 +959,7 @@
hsh_insert ( group_hash, (void *) gs );
}
- if (! casefilter_variable_missing (filter, &c, v))
+ if (!var_is_value_missing (v, val, exclude))
{
struct group_statistics *totals = &gp->ugs;
@@ -989,24 +988,20 @@
}
}
-
- casereader_destroy (r);
+ casereader_destroy (reader);
postcalc(cmd);
if ( stat_tables & STAT_HOMO )
- levene (dataset_dict (ds), cf, indep_var, n_vars, vars,
- filter);
+ levene (dict, casereader_clone (input), indep_var, n_vars, vars, exclude);
- casefilter_destroy (filter);
+ casereader_destroy (input);
ostensible_number_of_groups = hsh_count (global_group_hash);
output_oneway();
-
- return true;
}
Index: src/language/stats/rank.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/rank.q,v
retrieving revision 1.27
retrieving revision 1.27.2.1
diff -u -b -r1.27 -r1.27.2.1
--- src/language/stats/rank.q 16 Jan 2007 15:30:28 -0000 1.27
+++ src/language/stats/rank.q 19 Mar 2007 21:36:24 -0000 1.27.2.1
@@ -18,27 +18,27 @@
#include <config.h>
-#include "sort-criteria.h"
+#include <limits.h>
+#include <math.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/variable.h>
#include <data/case.h>
-#include <data/casefile.h>
-#include <data/fastfile.h>
-#include <data/storage-stream.h>
#include <language/command.h>
#include <language/stats/sort-criteria.h>
-#include <limits.h>
#include <libpspp/compiler.h>
+#include <math/ordering.h>
#include <math/sort.h>
#include <output/table.h>
#include <output/manager.h>
#include <gsl/gsl_cdf.h>
-#include <math.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -152,7 +152,7 @@
static struct rank_spec *rank_specs;
static size_t n_rank_specs;
-static struct sort_criteria *sc;
+static struct case_ordering *sc;
static struct variable **group_vars;
static size_t n_group_vars;
@@ -165,14 +165,14 @@
static struct cmd_rank cmd;
-static struct casefile *rank_sorted_casefile (struct casefile *cf,
- const struct sort_criteria *,
+static void rank_sorted_file (struct casereader *,
+ struct casewriter *,
const struct dictionary *,
const struct rank_spec *rs,
int n_rank_specs,
int idx,
- const struct missing_values *miss
- );
+ struct variable *rank_var);
+
static const char *
fraction_name(void)
{
@@ -233,68 +233,58 @@
static bool
-rank_cmd (struct dataset *ds, const struct sort_criteria *sc,
+rank_cmd (struct dataset *ds, const struct case_ordering *sc,
const struct rank_spec *rank_specs, int n_rank_specs)
{
- struct sort_criteria criteria;
+ struct case_ordering *base_ordering;
bool result = true;
int i;
const int n_splits = dict_get_split_cnt (dataset_dict (ds));
- criteria.crit_cnt = n_splits + n_group_vars + 1;
- criteria.crits = xnmalloc (criteria.crit_cnt, sizeof *criteria.crits);
+ base_ordering = case_ordering_create (dataset_dict (ds));
for (i = 0; i < n_splits ; i++)
- {
- struct variable *v = dict_get_split_vars (dataset_dict (ds))[i];
- criteria.crits[i].fv = var_get_case_index (v);
- criteria.crits[i].width = var_get_width (v);
- criteria.crits[i].dir = SRT_ASCEND;
- }
+ case_ordering_add_var (base_ordering,
+ dict_get_split_vars (dataset_dict (ds))[i],
+ SRT_ASCEND);
for (i = 0; i < n_group_vars; i++)
+ case_ordering_add_var (base_ordering, group_vars[i], SRT_ASCEND);
+ for (i = 0 ; i < case_ordering_get_var_cnt (sc) ; ++i )
{
- criteria.crits[i + n_splits].fv = var_get_case_index (group_vars[i]);
- criteria.crits[i + n_splits].width = var_get_width (group_vars[i]);
- criteria.crits[i + n_splits].dir = SRT_ASCEND;
- }
- for (i = 0 ; i < sc->crit_cnt ; ++i )
- {
- struct casefile *out ;
- struct casefile *cf ;
- struct casereader *reader ;
- struct casefile *sorted_cf ;
-
- /* Obtain active file in CF. */
- if (!procedure (ds, NULL, NULL))
- goto error;
-
- cf = proc_capture_output (ds);
-
- /* Sort CF into SORTED_CF. */
- reader = casefile_get_destructive_reader (cf) ;
- criteria.crits[criteria.crit_cnt - 1] = sc->crits[i];
- assert ( sc->crits[i].fv == var_get_case_index (src_vars[i]) );
- sorted_cf = sort_execute (reader, &criteria, NULL);
- casefile_destroy (cf);
-
- out = rank_sorted_casefile (sorted_cf, &criteria,
- dataset_dict (ds),
+ struct case_ordering *ordering;
+ struct casegrouper *grouper;
+ struct casereader *group;
+ struct casewriter *output;
+ struct casereader *ranked_file;
+
+ ordering = case_ordering_clone (base_ordering);
+ case_ordering_add_var (ordering,
+ case_ordering_get_var (sc, i),
+ case_ordering_get_direction (sc, i));
+
+ proc_discard_output (ds);
+ grouper = casegrouper_create_case_ordering (sort_execute (proc_open (ds),
+ ordering),
+ base_ordering);
+ output = autopaging_writer_create (dict_get_next_value_idx (
+ dataset_dict (ds)));
+ while (casegrouper_get_next_group (grouper, &group))
+ rank_sorted_file (group, output, dataset_dict (ds),
rank_specs, n_rank_specs,
- i, var_get_missing_values (src_vars[i]));
- if ( NULL == out )
+ i, src_vars[i]);
+ casegrouper_destroy (grouper);
+ proc_commit (ds);
+
+ ranked_file = casewriter_make_reader (output);
+ if (ranked_file == NULL)
{
- result = false ;
- continue ;
+ result = false;
+ break;
}
-
- proc_set_source (ds, storage_source_create (out));
+ proc_set_active_file_data (ds, ranked_file);
}
+ case_ordering_destroy (base_ordering);
- free (criteria.crits);
- return result ;
-
-error:
- free (criteria.crits);
- return false ;
+ return result;
}
/* Hardly a rank function !! */
@@ -311,6 +301,7 @@
int i, double w UNUSED)
{
double rank;
+
if ( c >= 1.0 )
{
switch (cmd.ties)
@@ -471,192 +462,69 @@
NOT_REACHED();
}
-
-/* Rank the casefile belonging to CR, starting from the current
- postition of CR continuing up to and including the ENDth case.
-
- RS points to an array containing the rank specifications to
- use. N_RANK_SPECS is the number of elements of RS.
-
-
- DEST_VAR_INDEX is the index into the rank_spec destvar element
- to be used for this ranking.
-
- Prerequisites: 1. The casefile must be sorted according to CRITERION.
- 2. W is the sum of the non-missing caseweights for this
- range of the casefile.
-*/
static void
-rank_cases (struct casereader *cr,
- unsigned long end,
+rank_sorted_file (struct casereader *input,
+ struct casewriter *output,
const struct dictionary *dict,
- const struct sort_criterion *criterion,
- const struct missing_values *mv,
- double w,
const struct rank_spec *rs,
int n_rank_specs,
- int dest_var_index,
- struct casefile *dest)
+ int dest_idx,
+ struct variable *rank_var)
{
- bool warn = true;
+ struct casereader *pass1, *pass2, *pass2_1;
+ struct casegrouper *tie_grouper;
+ struct ccase c;
+ double w = 0.0;
double cc = 0.0;
- double cc_1;
- int iter = 1;
+ int tie_group = 1;
- const int fv = criterion->fv;
- const int width = criterion->width;
- while (casereader_cnum (cr) < end)
- {
- struct casereader *lookahead;
- const union value *this_value;
- bool this_value_is_missing;
- struct ccase this_case, lookahead_case;
- double c;
- int i;
- size_t n = 0;
+ input = casereader_create_filter_missing (input, &rank_var, 1,
+ exclude_values, output);
+ input = casereader_create_filter_weight (input, dict, NULL, output);
- if (!casereader_read_xfer (cr, &this_case))
- break;
-
- this_value = case_data_idx (&this_case, fv);
- this_value_is_missing = mv_is_value_missing (mv, this_value,
- exclude_values);
- c = dict_get_case_weight (dict, &this_case, &warn);
+ casereader_split (input, &pass1, &pass2);
- lookahead = casereader_clone (cr);
- n = 0;
- while (casereader_cnum (lookahead) < end
- && casereader_read_xfer (lookahead, &lookahead_case))
- {
- const union value *lookahead_value = case_data_idx (&lookahead_case,
fv);
- int diff = compare_values (this_value, lookahead_value, width);
+ /* Pass 1: Get total group weight. */
+ for (; casereader_read (pass1, &c); case_destroy (&c))
+ w += dict_get_case_weight (dict, &c, NULL);
+ casereader_destroy (pass1);
- if (diff != 0)
+ /* Pass 2: Do ranking. */
+ tie_grouper = casegrouper_create_vars (pass2, &rank_var, 1);
+ while (casegrouper_get_next_group (tie_grouper, &pass2_1))
{
- /* Make sure the casefile was sorted */
- assert ( diff == ((criterion->dir == SRT_ASCEND) ? -1 :1));
-
- case_destroy (&lookahead_case);
- break;
- }
-
- c += dict_get_case_weight (dict, &lookahead_case, &warn);
- case_destroy (&lookahead_case);
- n++;
- }
- casereader_destroy (lookahead);
+ struct casereader *pass2_2 = casereader_clone (pass2_1);
+ double cc_1 = cc;
+ double tw = 0.0;
+ int i;
- cc_1 = cc;
- if ( !this_value_is_missing )
- cc += c;
+ /* Pass 2.1: Sum up weight for tied cases. */
+ for (; casereader_read (pass2_1, &c); case_destroy (&c))
+ tw += dict_get_case_weight (dict, &c, NULL);
+ cc += tw;
+ casereader_destroy (pass2_1);
- do
+ /* Pass 2.2: Rank tied cases. */
+ while (casereader_read (pass2_2, &c))
{
for (i = 0; i < n_rank_specs; ++i)
{
- const struct variable *dst_var = rs[i].destvars[dest_var_index];
-
- if (this_value_is_missing)
- case_data_rw (&this_case, dst_var)->f = SYSMIS;
- else
- case_data_rw (&this_case, dst_var)->f =
- rank_func[rs[i].rfunc](c, cc, cc_1, iter, w);
- }
- casefile_append_xfer (dest, &this_case);
- }
- while (n-- > 0 && casereader_read_xfer (cr, &this_case));
-
- if ( !this_value_is_missing )
- iter++;
- }
-
- /* If this isn't true, then all the results will be wrong */
- assert ( w == cc );
-}
-
-static bool
-same_group (const struct ccase *a, const struct ccase *b,
- const struct sort_criteria *crit)
-{
- size_t i;
-
- for (i = 0; i < crit->crit_cnt - 1; i++)
- {
- struct sort_criterion *c = &crit->crits[i];
- if (compare_values (case_data_idx (a, c->fv),
- case_data_idx (b, c->fv), c->width) != 0)
- return false;
+ const struct variable *dst_var = rs[i].destvars[dest_idx];
+ double *dst_value = &case_data_rw (&c, dst_var)->f;
+ *dst_value = rank_func[rs[i].rfunc] (tw, cc, cc_1, tie_group, w);
}
-
- return true;
-}
-
-static struct casefile *
-rank_sorted_casefile (struct casefile *cf,
- const struct sort_criteria *crit,
- const struct dictionary *dict,
- const struct rank_spec *rs,
- int n_rank_specs,
- int dest_idx,
- const struct missing_values *mv)
-{
- struct casefile *dest = fastfile_create (casefile_get_value_cnt (cf));
- struct casereader *lookahead = casefile_get_reader (cf, NULL);
- struct casereader *pos = casereader_clone (lookahead);
- struct ccase group_case;
- bool warn = true;
-
- struct sort_criterion *ultimate_crit = &crit->crits[crit->crit_cnt - 1];
-
- if (casereader_read (lookahead, &group_case))
- {
- struct ccase this_case;
- const union value *this_value ;
- double w = 0.0;
- this_value = case_data_idx( &group_case, ultimate_crit->fv);
-
- if ( !mv_is_value_missing (mv, this_value, exclude_values) )
- w = dict_get_case_weight (dict, &group_case, &warn);
-
- while (casereader_read (lookahead, &this_case))
- {
- const union value *this_value =
- case_data_idx(&this_case, ultimate_crit->fv);
- double c = dict_get_case_weight (dict, &this_case, &warn);
- if (!same_group (&group_case, &this_case, crit))
- {
- rank_cases (pos, casereader_cnum (lookahead) - 1,
- dict,
- ultimate_crit,
- mv, w,
- rs, n_rank_specs,
- dest_idx, dest);
-
- w = 0.0;
- case_destroy (&group_case);
- case_move (&group_case, &this_case);
- }
- if ( !mv_is_value_missing (mv, this_value, exclude_values) )
- w += c;
- case_destroy (&this_case);
- }
- case_destroy (&group_case);
- rank_cases (pos, ULONG_MAX, dict, ultimate_crit, mv, w,
- rs, n_rank_specs, dest_idx, dest);
+ casewriter_write (output, &c);
}
+ casereader_destroy (pass2_2);
- if (casefile_error (dest))
- {
- casefile_destroy (dest);
- dest = NULL;
+ tie_group++;
}
+ casegrouper_destroy (tie_grouper);
- casefile_destroy (cf);
- return dest;
+ /* FIXME: needs to detect errors. */
}
-
/* Transformation function to enumerate all the cases */
static int
create_resort_key (void *key_var_, struct ccase *cc, casenumber case_num)
@@ -749,7 +617,7 @@
rank_specs = NULL;
n_rank_specs = 0;
- sort_destroy_criteria (sc);
+ case_ordering_destroy (sc);
sc = NULL;
free (src_vars);
@@ -784,12 +652,12 @@
rank_specs = xmalloc (sizeof (*rank_specs));
rank_specs[0].rfunc = RANK;
rank_specs[0].destvars =
- xcalloc (sc->crit_cnt, sizeof (struct variable *));
+ xcalloc (case_ordering_get_var_cnt (sc), sizeof (struct variable *));
n_rank_specs = 1;
}
- assert ( sc->crit_cnt == n_src_vars);
+ assert ( case_ordering_get_var_cnt (sc) == n_src_vars);
/* Create variables for all rank destinations which haven't
already been created with INTO.
@@ -899,22 +767,20 @@
/* Do the ranking */
result = rank_cmd (ds, sc, rank_specs, n_rank_specs);
- /* Put the active file back in its original order */
+ /* Put the active file back in its original order. Delete
+ our sort key, which we don't need anymore. */
{
- struct sort_criteria criteria;
- struct sort_criterion restore_criterion ;
- restore_criterion.fv = var_get_case_index (order);
- restore_criterion.width = 0;
- restore_criterion.dir = SRT_ASCEND;
+ struct case_ordering *ordering = case_ordering_create (dataset_dict (ds));
+ struct casereader *sorted;
+ case_ordering_add_var (ordering, order, SRT_ASCEND);
+ /* FIXME: loses error conditions. */
+ proc_discard_output (ds);
+ sorted = sort_execute (proc_open (ds), ordering);
+ proc_commit (ds);
- criteria.crits = &restore_criterion;
- criteria.crit_cnt = 1;
-
- sort_active_file_in_place (ds, &criteria);
- }
-
- /* ... and we don't need our sort key anymore. So delete it */
dict_delete_var (dataset_dict (ds), order);
+ proc_set_active_file_data (ds, sorted);
+ }
rank_cleanup();
@@ -928,16 +794,16 @@
static int
rank_custom_variables (struct lexer *lexer, struct dataset *ds, struct
cmd_rank *cmd UNUSED, void *aux UNUSED)
{
- static const int terminators[2] = {T_BY, 0};
-
lex_match (lexer, '=');
if ((lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds),
lex_tokid (lexer)) == NULL)
&& lex_token (lexer) != T_ALL)
return 2;
- sc = sort_parse_criteria (lexer, dataset_dict (ds),
- &src_vars, &n_src_vars, 0, terminators);
+ sc = parse_case_ordering (lexer, dataset_dict (ds), NULL);
+ if (sc == NULL)
+ return 0;
+ case_ordering_get_vars (sc, &src_vars, &n_src_vars);
if ( lex_match (lexer, T_BY) )
{
@@ -971,7 +837,8 @@
rank_specs[n_rank_specs - 1].destvars = NULL;
rank_specs[n_rank_specs - 1].destvars =
- xcalloc (sc->crit_cnt, sizeof (struct variable *));
+ xcalloc (case_ordering_get_var_cnt (sc),
+ sizeof (struct variable *));
if (lex_match_id (lexer, "INTO"))
{
@@ -985,7 +852,7 @@
msg(SE, _("Variable %s already exists."), lex_tokid (lexer));
return 0;
}
- if ( var_count >= sc->crit_cnt )
+ if ( var_count >= case_ordering_get_var_cnt (sc) )
{
msg(SE, _("Too many variables in INTO clause."));
return 0;
Index: src/language/stats/regression.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/regression.q,v
retrieving revision 1.45
retrieving revision 1.45.2.1
diff -u -b -r1.45 -r1.45.2.1
--- src/language/stats/regression.q 9 Feb 2007 05:19:08 -0000 1.45
+++ src/language/stats/regression.q 19 Mar 2007 21:36:24 -0000 1.45.2.1
@@ -26,7 +26,8 @@
#include "regression-export.h"
#include <data/case.h>
-#include <data/casefile.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
#include <data/cat-routines.h>
#include <data/category.h>
#include <data/dictionary.h>
@@ -116,9 +117,8 @@
*/
static int pspp_reg_rc = CMD_SUCCESS;
-static bool run_regression (const struct ccase *,
- const struct casefile *, void *,
- const struct dataset *);
+static void run_regression (struct casereader *, struct cmd_regression *,
+ struct dataset *);
/*
STATISTICS subcommand output functions.
@@ -938,12 +938,21 @@
int
cmd_regression (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *group;
+
if (!parse_regression (lexer, ds, &cmd, NULL))
return CMD_FAILURE;
models = xnmalloc (cmd.n_dependent, sizeof *models);
- if (!multipass_procedure_with_splits (ds, run_regression, &cmd))
- return CMD_CASCADING_FAILURE;
+
+ /* Data pass. FIXME: error handling. */
+ grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ run_regression (group, &cmd, ds);
+ casegrouper_destroy (grouper);
+ proc_commit (ds);
+
subcommand_save (ds, cmd.sbc_save, models);
free (v_variables);
free (models);
@@ -959,40 +968,6 @@
return v == v_variables[k];
}
-/*
- Mark missing cases. Return the number of non-missing cases.
- */
-static size_t
-mark_missing_cases (const struct casefile *cf, struct variable *v,
- int *is_missing_case, double n_data)
-{
- struct casereader *r;
- struct ccase c;
- size_t row;
- const union value *val;
-
- for (r = casefile_get_reader (cf, NULL);
- casereader_read (r, &c); case_destroy (&c))
- {
- row = casereader_cnum (r) - 1;
-
- val = case_data (&c, v);
- cat_value_update (v, val);
- if (var_is_value_missing (v, val, MV_ANY))
- {
- if (!is_missing_case[row])
- {
- /* Now it is missing. */
- n_data--;
- is_missing_case[row] = 1;
- }
- }
- }
- casereader_destroy (r);
-
- return n_data;
-}
-
/* Parser for the variables sub command */
static int
regression_custom_variables (struct lexer *lexer, struct dataset *ds,
@@ -1018,67 +993,51 @@
return 1;
}
-/*
- Count the explanatory variables. The user may or may
- not have specified a response variable in the syntax.
- */
+/* Identify the explanatory variables in v_variables. Returns
+ the number of independent variables. */
static int
-get_n_indep (const struct variable *v)
+identify_indep_vars (struct variable **indep_vars, struct variable *depvar)
{
- int result;
- int i = 0;
+ int n_indep_vars = 0;
+ int i;
- result = n_variables;
- while (i < n_variables)
- {
- if (is_depvar (i, v))
- {
- result--;
- i = n_variables;
- }
- i++;
- }
- return result;
+ for (i = 0; i < n_variables; i++)
+ if (!is_depvar (i, depvar))
+ indep_vars[n_indep_vars++] = v_variables[i];
+
+ return n_indep_vars;
}
-/*
- Read from the active file. Identify the explanatory variables in
- v_variables. Encode categorical variables. Drop cases with missing
- values.
-*/
+/* Encode categorical variables.
+ Returns number of valid cases. */
static int
-prepare_data (int n_data, int is_missing_case[],
- struct variable **indep_vars,
- struct variable *depvar, const struct casefile *cf)
+prepare_categories (struct casereader *input,
+ struct variable **vars, size_t n_vars)
{
- int i;
- int j;
+ int n_data;
+ struct ccase c;
+ size_t i;
- assert (indep_vars != NULL);
- j = 0;
- for (i = 0; i < n_variables; i++)
+ for (i = 0; i < n_vars; i++)
+ if (var_is_alpha (vars[i]))
+ cat_stored_values_create (vars[i]);
+
+ n_data = 0;
+ for (; casereader_read (input, &c); case_destroy (&c))
{
- if (!is_depvar (i, depvar))
+ for (i = 0; i < n_vars; i++)
+ if (var_is_alpha (vars[i]))
{
- indep_vars[j] = v_variables[i];
- j++;
- if (var_is_alpha (v_variables[i]))
- {
- /* Make a place to hold the binary vectors
- corresponding to this variable's values. */
- cat_stored_values_create (v_variables[i]);
- }
- n_data =
- mark_missing_cases (cf, v_variables[i], is_missing_case, n_data);
+ const union value *val = case_data (&c, vars[i]);
+ cat_value_update (vars[i], val);
}
+ n_data++;
}
- /*
- Mark missing cases for the dependent variable.
- */
- n_data = mark_missing_cases (cf, depvar, is_missing_case, n_data);
+ casereader_destroy (input);
return n_data;
}
+
static void
coeff_init (pspp_linreg_cache * c, struct design_matrix *dm)
{
@@ -1088,23 +1047,13 @@
pspp_coeff_init (c->coeff + 1, dm);
}
-static bool
-run_regression (const struct ccase *first,
- const struct casefile *cf, void *cmd_ UNUSED, const struct
dataset *ds)
+static void
+run_regression (struct casereader *input, struct cmd_regression *cmd,
+ struct dataset *ds)
{
size_t i;
- size_t n_data = 0; /* Number of valide cases. */
- size_t n_cases; /* Number of cases. */
- size_t row;
- size_t case_num;
int n_indep = 0;
int k;
- /*
- Keep track of the missing cases.
- */
- int *is_missing_case;
- const union value *val;
- struct casereader *r;
struct ccase c;
struct variable **indep_vars;
struct design_matrix *X;
@@ -1114,7 +1063,9 @@
assert (models != NULL);
- output_split_file_values (ds, first);
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
if (!v_variables)
{
@@ -1122,40 +1073,39 @@
1u << DC_SYSTEM);
}
- n_cases = casefile_get_case_cnt (cf);
-
- for (i = 0; i < cmd.n_dependent; i++)
+ for (i = 0; i < cmd->n_dependent; i++)
{
- if (!var_is_numeric (cmd.v_dependent[i]))
+ if (!var_is_numeric (cmd->v_dependent[i]))
{
msg (SE, gettext ("Dependent variable must be numeric."));
pspp_reg_rc = CMD_FAILURE;
- return true;
+ return;
}
}
- is_missing_case = xnmalloc (n_cases, sizeof (*is_missing_case));
-
lopts.get_depvar_mean_std = 1;
- for (k = 0; k < cmd.n_dependent; k++)
- {
- n_indep = get_n_indep ((const struct variable *) cmd.v_dependent[k]);
- lopts.get_indep_mean_std = xnmalloc (n_indep, sizeof (int));
- indep_vars = xnmalloc (n_indep, sizeof *indep_vars);
- assert (indep_vars != NULL);
+ lopts.get_indep_mean_std = xnmalloc (n_variables, sizeof (int));
+ indep_vars = xnmalloc (n_variables, sizeof *indep_vars);
- for (i = 0; i < n_cases; i++)
+ for (k = 0; k < cmd->n_dependent; k++)
{
- is_missing_case[i] = 0;
- }
- n_data = prepare_data (n_cases, is_missing_case, indep_vars,
- cmd.v_dependent[k],
- (const struct casefile *) cf);
+ struct casereader *reader = casereader_clone (input);
+ struct variable *dep_var = cmd->v_dependent[k];
+ casenumber row;
+ struct ccase c;
+ size_t n_data; /* Number of valid cases. */
+
+ n_indep = identify_indep_vars (indep_vars, dep_var);
+ reader = casereader_create_filter_missing (reader, indep_vars, n_indep,
+ MV_ANY, NULL);
+ reader = casereader_create_filter_missing (reader, &dep_var, 1,
+ MV_ANY, NULL);
+ n_data = prepare_categories (casereader_clone (reader), indep_vars,
n_indep);
+
Y = gsl_vector_alloc (n_data);
- X =
- design_matrix_create (n_indep, (const struct variable **) indep_vars,
+ X = design_matrix_create (n_indep, (const struct variable **) indep_vars,
n_data);
for (i = 0; i < X->m->size2; i++)
{
@@ -1164,7 +1114,7 @@
models[k] = pspp_linreg_cache_alloc (X->m->size1, X->m->size2);
models[k]->indep_means = gsl_vector_alloc (X->m->size2);
models[k]->indep_std = gsl_vector_alloc (X->m->size2);
- models[k]->depvar = (const struct variable *) cmd.v_dependent[k];
+ models[k]->depvar = dep_var;
/*
For large data sets, use QR decomposition.
*/
@@ -1176,47 +1126,23 @@
/*
The second pass fills the design matrix.
*/
- row = 0;
- for (r = casefile_get_reader (cf, NULL); casereader_read (r, &c);
- case_destroy (&c))
- /* Iterate over the cases. */
- {
- case_num = casereader_cnum (r) - 1;
- if (!is_missing_case[case_num])
- {
- for (i = 0; i < n_variables; ++i) /* Iterate over the
- variables for the
- current case.
- */
- {
- val = case_data (&c, v_variables[i]);
- /*
- Independent/dependent variable separation. The
- 'variables' subcommand specifies a varlist which contains
- both dependent and independent variables. The dependent
- variables are specified with the 'dependent'
- subcommand, and maybe also in the 'variables' subcommand.
- We need to separate the two.
- */
- if (!is_depvar (i, cmd.v_dependent[k]))
+ reader = casereader_create_counter (reader, &row, -1);
+ for (; casereader_read (reader, &c); case_destroy (&c))
{
- if (var_is_alpha (v_variables[i]))
+ const union value *val;
+ for (i = 0; i < n_indep; ++i)
{
- design_matrix_set_categorical (X, row,
- v_variables[i], val);
- }
+ struct variable *v = indep_vars[i];
+ val = case_data (&c, v);
+ if (var_is_alpha (v))
+ design_matrix_set_categorical (X, row, v, val);
else
- {
- design_matrix_set_numeric (X, row, v_variables[i],
- val);
- }
+ design_matrix_set_numeric (X, row, v, val);
}
- }
- val = case_data (&c, cmd.v_dependent[k]);
+ val = case_data (&c, dep_var);
gsl_vector_set (Y, row, val->f);
- row++;
- }
}
+ casereader_destroy (reader);
/*
Now that we know the number of coefficients, allocate space
and store pointers to the variables that correspond to the
@@ -1228,19 +1154,15 @@
Find the least-squares estimates and other statistics.
*/
pspp_linreg ((const gsl_vector *) Y, X->m, &lopts, models[k]);
- subcommand_statistics (cmd.a_statistics, models[k]);
- subcommand_export (cmd.sbc_export, models[k]);
+ subcommand_statistics (cmd->a_statistics, models[k]);
+ subcommand_export (cmd->sbc_export, models[k]);
gsl_vector_free (Y);
design_matrix_destroy (X);
+ }
free (indep_vars);
free (lopts.get_indep_mean_std);
- casereader_destroy (r);
- }
-
- free (is_missing_case);
-
- return true;
+ casereader_destroy (input);
}
/*
Index: src/language/stats/sort-cases.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/sort-cases.c,v
retrieving revision 1.8
retrieving revision 1.8.2.1
diff -u -b -r1.8 -r1.8.2.1
--- src/language/stats/sort-cases.c 15 Dec 2006 00:16:03 -0000 1.8
+++ src/language/stats/sort-cases.c 19 Mar 2007 21:36:24 -0000 1.8.2.1
@@ -30,6 +30,7 @@
#include <language/lexer/lexer.h>
#include <libpspp/alloc.h>
#include <libpspp/message.h>
+#include <math/ordering.h>
#include <math/sort.h>
#include <sys/types.h>
@@ -41,13 +42,15 @@
int
cmd_sort_cases (struct lexer *lexer, struct dataset *ds)
{
- struct sort_criteria *criteria;
+ struct case_ordering *ordering;
+ struct casereader *input;
+ struct casereader *output;
bool success = false;
lex_match (lexer, T_BY);
- criteria = sort_parse_criteria (lexer, dataset_dict (ds), NULL, NULL, NULL,
NULL);
- if (criteria == NULL)
+ ordering = parse_case_ordering (lexer, dataset_dict (ds), NULL);
+ if (ordering == NULL)
return CMD_CASCADING_FAILURE;
if (get_testing_mode () && lex_match (lexer, '/'))
@@ -57,7 +60,6 @@
goto done;
min_buffers = max_buffers = lex_integer (lexer);
- allow_internal_sort = false;
if (max_buffers < 2)
{
msg (SE, _("Buffer limit must be at least 2."));
@@ -67,14 +69,25 @@
lex_get (lexer);
}
- success = sort_active_file_in_place (ds, criteria);
+ /* FIXME: the case_ordering was created for dataset_dict(ds),
+ but proc_cancel_temporary_transformations(ds) causes the
+ size of cases to shrink... */
+ proc_cancel_temporary_transformations (ds);
+ proc_discard_output (ds);
+ input = proc_open (ds);
+ output = sort_execute (input, ordering);
+ proc_commit (ds);
+ ordering = NULL;
+ if (output == NULL)
+ goto done;
+ proc_set_active_file_data (ds, output);
+ success = true;
done:
min_buffers = 64;
max_buffers = INT_MAX;
- allow_internal_sort = true;
- sort_destroy_criteria (criteria);
+ case_ordering_destroy (ordering);
return success ? lex_end_of_command (lexer) : CMD_CASCADING_FAILURE;
}
Index: src/language/stats/sort-criteria.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/sort-criteria.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -u -b -r1.7 -r1.7.2.1
--- src/language/stats/sort-criteria.c 15 Dec 2006 00:16:03 -0000 1.7
+++ src/language/stats/sort-criteria.c 19 Mar 2007 21:36:24 -0000 1.7.2.1
@@ -1,5 +1,5 @@
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ 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
@@ -17,72 +17,46 @@
02110-1301, USA. */
#include <config.h>
-#include <sys/types.h>
-#include <assert.h>
+
+#include <language/stats/sort-criteria.h>
+
#include <stdlib.h>
-#include <limits.h>
-#include <libpspp/alloc.h>
-#include <language/command.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 <data/settings.h>
-#include <data/variable.h>
-#include "sort-criteria.h"
-#include <math/sort.h>
+#include <libpspp/message.h>
+#include <math/ordering.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
-static bool is_terminator(int tok, const int *terminators);
-
-
/* Parses a list of sort keys and returns a struct sort_criteria
based on it. Returns a null pointer on error.
If SAW_DIRECTION is nonnull, sets *SAW_DIRECTION to true if at
least one parenthesized sort direction was specified, false
- otherwise.
- If TERMINATORS is non-null, then it must be a pointer to a
- null terminated list of tokens, in addition to the defaults,
- which are to be considered terminators of the clause being parsed.
- The default terminators are '/' and '.'
-
-*/
-struct sort_criteria *
-sort_parse_criteria (struct lexer *lexer, const struct dictionary *dict,
- struct variable ***vars, size_t *var_cnt,
- bool *saw_direction,
- const int *terminators
- )
+ otherwise. */
+struct case_ordering *
+parse_case_ordering (struct lexer *lexer, const struct dictionary *dict,
+ bool *saw_direction)
{
- struct sort_criteria *criteria;
- struct variable **local_vars = NULL;
- size_t local_var_cnt;
-
- assert ((vars == NULL) == (var_cnt == NULL));
- if (vars == NULL)
- {
- vars = &local_vars;
- var_cnt = &local_var_cnt;
- }
+ struct case_ordering *ordering = case_ordering_create (dict);
+ struct variable **vars = NULL;
+ size_t var_cnt = 0;
- criteria = xmalloc (sizeof *criteria);
- criteria->crits = NULL;
- criteria->crit_cnt = 0;
-
- *vars = NULL;
- *var_cnt = 0;
if (saw_direction != NULL)
*saw_direction = false;
do
{
- size_t prev_var_cnt = *var_cnt;
enum sort_direction direction;
+ size_t i;
/* Variables. */
- if (!parse_variables (lexer, dict, vars, var_cnt,
- PV_NO_DUPLICATE | PV_APPEND | PV_NO_SCRATCH))
+ free (vars);
+ vars = NULL;
+ if (!parse_variables (lexer, dict, &vars, &var_cnt, PV_NO_SCRATCH))
goto error;
/* Sort direction. */
@@ -108,57 +82,19 @@
else
direction = SRT_ASCEND;
- criteria->crits = xnrealloc (criteria->crits,
- *var_cnt, sizeof *criteria->crits);
- criteria->crit_cnt = *var_cnt;
- for (; prev_var_cnt < criteria->crit_cnt; prev_var_cnt++)
- {
- struct sort_criterion *c = &criteria->crits[prev_var_cnt];
- c->fv = var_get_case_index ((*vars)[prev_var_cnt]);
- c->width = var_get_width ((*vars)[prev_var_cnt]);
- c->dir = direction;
+ for (i = 0; i < var_cnt; i++)
+ if (!case_ordering_add_var (ordering, vars[i], direction))
+ msg (SW, _("Variable %s specified twice in sort criteria."),
+ var_get_name (vars[i]));
}
- }
- while (lex_token (lexer) != '.' && lex_token (lexer) != '/' &&
!is_terminator(lex_token (lexer), terminators));
+ while (lex_token (lexer) == T_ID
+ && dict_lookup_var (dict, lex_tokid (lexer)) != NULL);
- free (local_vars);
- return criteria;
+ free (vars);
+ return ordering;
error:
- free (local_vars);
- sort_destroy_criteria (criteria);
+ free (vars);
+ case_ordering_destroy (ordering);
return NULL;
}
-
-/* Return TRUE if TOK is a member of the list of TERMINATORS.
- FALSE otherwise */
-static bool
-is_terminator(int tok, const int *terminators)
-{
- if (terminators == NULL )
- return false;
-
- while ( *terminators)
- {
- if (tok == *terminators++)
- return true;
- }
-
- return false;
-}
-
-
-
-/* Destroys a SORT CASES program. */
-void
-sort_destroy_criteria (struct sort_criteria *criteria)
-{
- if (criteria != NULL)
- {
- free (criteria->crits);
- free (criteria);
- }
-}
-
-
-
Index: src/language/stats/sort-criteria.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/sort-criteria.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/language/stats/sort-criteria.h 15 Dec 2006 00:16:03 -0000 1.4
+++ src/language/stats/sort-criteria.h 19 Mar 2007 21:36:24 -0000 1.4.2.1
@@ -23,17 +23,12 @@
#include <stdbool.h>
#include <stddef.h>
-struct variable;
struct dictionary;
-struct lexer ;
+struct lexer;
-struct sort_criteria *sort_parse_criteria (struct lexer *, const struct
dictionary *,
- struct variable ***, size_t *,
- bool *saw_direction,
- const int *terminators
- );
-
-void sort_destroy_criteria (struct sort_criteria *criteria) ;
+struct case_ordering *parse_case_ordering (struct lexer *,
+ const struct dictionary *,
+ bool *saw_direction);
#endif /* SORT_PRS_H */
Index: src/language/stats/t-test.q
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/stats/t-test.q,v
retrieving revision 1.20
retrieving revision 1.20.2.1
diff -u -b -r1.20 -r1.20.2.1
--- src/language/stats/t-test.q 9 Feb 2007 05:19:08 -0000 1.20
+++ src/language/stats/t-test.q 19 Mar 2007 21:36:24 -0000 1.20.2.1
@@ -25,12 +25,12 @@
#include <stdlib.h>
#include <data/case.h>
-#include <data/casefile.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 <data/casefilter.h>
#include <language/command.h>
#include <language/dictionary/split-file.h>
@@ -215,28 +215,28 @@
static int common_calc (const struct dictionary *dict,
const struct ccase *, void *,
- const struct casefilter *filter);
+ enum mv_class);
static void common_precalc (struct cmd_t_test *);
static void common_postcalc (struct cmd_t_test *);
-static int one_sample_calc (const struct dictionary *dict, const struct ccase
*, void *, const struct casefilter *);
+static int one_sample_calc (const struct dictionary *dict, const struct ccase
*, void *, enum mv_class);
static void one_sample_precalc (struct cmd_t_test *);
static void one_sample_postcalc (struct cmd_t_test *);
static int paired_calc (const struct dictionary *dict, const struct ccase *,
- struct cmd_t_test*, const struct casefilter *);
+ struct cmd_t_test*, enum mv_class);
static void paired_precalc (struct cmd_t_test *);
static void paired_postcalc (struct cmd_t_test *);
static void group_precalc (struct cmd_t_test *);
static int group_calc (const struct dictionary *dict, const struct ccase *,
- struct cmd_t_test *, const struct casefilter *);
+ struct cmd_t_test *, enum mv_class);
static void group_postcalc (struct cmd_t_test *);
-static bool calculate(const struct ccase *first,
- const struct casefile *cf, void *_mode,
- const struct dataset *ds);
+static bool calculate(struct cmd_t_test *,
+ struct casereader *,
+ const struct dataset *);
static int mode;
@@ -258,6 +258,8 @@
int
cmd_t_test (struct lexer *lexer, struct dataset *ds)
{
+ struct casegrouper *grouper;
+ struct casereader *group;
bool ok;
if ( !parse_t_test (lexer, ds, &cmd, NULL) )
@@ -339,7 +341,12 @@
bad_weight_warn = true;
- ok = multipass_procedure_with_splits (ds, calculate, &cmd);
+ /* Data pass. FIXME: error handling. */
+ grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
+ while (casegrouper_get_next_group (grouper, &group))
+ calculate (&cmd, group, ds);
+ ok = casegrouper_destroy (grouper);
+ proc_commit (ds);
n_pairs=0;
free(pairs);
@@ -1412,29 +1419,29 @@
common_calc (const struct dictionary *dict,
const struct ccase *c,
void *_cmd,
- const struct casefilter *filter)
+ enum mv_class exclude)
{
int i;
struct cmd_t_test *cmd = (struct cmd_t_test *)_cmd;
- double weight = dict_get_case_weight (dict, c, &bad_weight_warn);
+ double weight = dict_get_case_weight (dict, c, NULL);
/* Listwise has to be implicit if the independent variable is missing ?? */
if ( cmd->sbc_groups )
{
- if ( casefilter_variable_missing (filter, c, indep_var) )
+ if (var_is_value_missing (indep_var, case_data (c, indep_var), exclude))
return 0;
}
for(i = 0; i < cmd->n_variables ; ++i)
{
struct variable *v = cmd->v_variables[i];
+ const union value *val = case_data (c, v);
- if (! casefilter_variable_missing (filter, c, v) )
+ if (!var_is_value_missing (v, val, exclude))
{
struct group_statistics *gs;
- const union value *val = case_data (c, v);
gs = &group_proc_get (cmd->v_variables[i])->ugs;
gs->n += weight;
@@ -1493,13 +1500,13 @@
static int
one_sample_calc (const struct dictionary *dict,
const struct ccase *c, void *cmd_,
- const struct casefilter *filter)
+ enum mv_class exclude)
{
int i;
struct cmd_t_test *cmd = (struct cmd_t_test *)cmd_;
- double weight = dict_get_case_weight (dict, c, &bad_weight_warn);
+ double weight = dict_get_case_weight (dict, c, NULL);
for(i=0; i< cmd->n_variables ; ++i)
@@ -1510,7 +1517,7 @@
gs= &group_proc_get (cmd->v_variables[i])->ugs;
- if ( ! casefilter_variable_missing (filter, c, v))
+ if (!var_is_value_missing (v, val, exclude))
gs->sum_diff += weight * (val->f - cmd->n_testval[0]);
}
@@ -1570,11 +1577,11 @@
static int
paired_calc (const struct dictionary *dict, const struct ccase *c,
- struct cmd_t_test *cmd UNUSED, const struct casefilter *filter)
+ struct cmd_t_test *cmd UNUSED, enum mv_class exclude)
{
int i;
- double weight = dict_get_case_weight (dict, c, &bad_weight_warn);
+ double weight = dict_get_case_weight (dict, c, NULL);
for(i=0; i < n_pairs ; ++i )
{
@@ -1584,8 +1591,8 @@
const union value *val0 = case_data (c, v0);
const union value *val1 = case_data (c, v1);
- if ( ! casefilter_variable_missing (filter, c, v0) &&
- ! casefilter_variable_missing (filter, c, v1) )
+ if (!var_is_value_missing (v0, val0, exclude) &&
+ !var_is_value_missing (v1, val1, exclude))
{
pairs[i].n += weight;
pairs[i].sum[0] += weight * val0->f;
@@ -1695,16 +1702,15 @@
static int
group_calc (const struct dictionary *dict,
const struct ccase *c, struct cmd_t_test *cmd,
- const struct casefilter *filter)
+ enum mv_class exclude)
{
int i;
- const double weight =
- dict_get_case_weight (dict, c, &bad_weight_warn);
+ const double weight = dict_get_case_weight (dict, c, NULL);
const union value *gv;
- if ( casefilter_variable_missing (filter, c, indep_var))
+ if (var_is_value_missing (indep_var, case_data (c, indep_var), exclude))
return 0;
gv = case_data (c, indep_var);
@@ -1723,7 +1729,7 @@
if ( ! gs )
return 0;
- if ( ! casefilter_variable_missing (filter, c, var) )
+ if (!var_is_value_missing (var, val, exclude))
{
gs->n += weight;
gs->sum += weight * val->f;
@@ -1773,81 +1779,66 @@
static bool
-calculate(const struct ccase *first, const struct casefile *cf,
- void *cmd_, const struct dataset *ds)
+calculate(struct cmd_t_test *cmd,
+ struct casereader *input, const struct dataset *ds)
{
const struct dictionary *dict = dataset_dict (ds);
struct ssbox stat_summary_box;
struct trbox test_results_box;
- struct casereader *r;
+ struct casereader *pass1, *pass2, *pass3;
struct ccase c;
- struct cmd_t_test *cmd = (struct cmd_t_test *) cmd_;
+ enum mv_class exclude = cmd->miss != TTS_INCLUDE ? MV_ANY : MV_SYSTEM;
- struct casefilter *filter = casefilter_create ((cmd->miss != TTS_INCLUDE
- ? MV_ANY : MV_SYSTEM),
- NULL, 0);
+ casereader_peek (input, 0, &c);
+ output_split_file_values (ds, &c);
+ case_destroy (&c);
if ( cmd->miss == TTS_LISTWISE )
- casefilter_add_variables (filter,
- cmd->v_variables, cmd->n_variables);
+ input = casereader_create_filter_missing (input,
+ cmd->v_variables,
+ cmd->n_variables,
+ exclude, NULL);
- output_split_file_values (ds, first);
- common_precalc (cmd);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
- case_destroy (&c))
- {
- common_calc (dict, &c, cmd, filter);
- }
+ input = casereader_create_filter_weight (input, dict, NULL, NULL);
+
+ casereader_split (input, &pass1, &pass2);
- casereader_destroy (r);
+ common_precalc (cmd);
+ for (; casereader_read (pass1, &c); case_destroy (&c))
+ common_calc (dict, &c, cmd, exclude);
+ casereader_destroy (pass1);
common_postcalc (cmd);
switch(mode)
{
case T_1_SAMPLE:
one_sample_precalc (cmd);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
- case_destroy (&c))
- {
- one_sample_calc (dict, &c, cmd, filter);
- }
- casereader_destroy (r);
+ for (; casereader_read (pass2, &c); case_destroy (&c))
+ one_sample_calc (dict, &c, cmd, exclude);
one_sample_postcalc (cmd);
break;
case T_PAIRED:
paired_precalc(cmd);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
- case_destroy (&c))
- {
- paired_calc (dict, &c, cmd, filter);
- }
- casereader_destroy (r);
+ for (; casereader_read (pass2, &c); case_destroy (&c))
+ paired_calc (dict, &c, cmd, exclude);
paired_postcalc (cmd);
-
break;
case T_IND_SAMPLES:
+ pass3 = casereader_clone (pass2);
group_precalc(cmd);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
- case_destroy (&c))
- {
- group_calc (dict, &c, cmd, filter);
- }
- casereader_destroy (r);
+ for(; casereader_read (pass2, &c); case_destroy (&c))
+ group_calc (dict, &c, cmd, exclude);
group_postcalc(cmd);
- levene (dict, cf, indep_var, cmd->n_variables, cmd->v_variables,
- filter);
+ levene (dict, pass3, indep_var, cmd->n_variables, cmd->v_variables,
+ exclude);
break;
}
+ casereader_destroy (pass2);
- casefilter_destroy (filter);
ssbox_create(&stat_summary_box,cmd,mode);
ssbox_populate(&stat_summary_box,cmd);
Index: src/language/tests/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/language/tests/automake.mk,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/language/tests/automake.mk 14 Dec 2006 10:45:20 -0000 1.4
+++ src/language/tests/automake.mk 19 Mar 2007 21:36:24 -0000 1.4.2.1
@@ -1,7 +1,6 @@
## Process this file with automake to produce Makefile.in -*- makefile -*-
language_tests_sources = \
- src/language/tests/casefile-test.c \
src/language/tests/moments-test.c \
src/language/tests/pool-test.c \
src/language/tests/float-format.c
Index: src/libpspp/alloc.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/alloc.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/libpspp/alloc.c 15 Dec 2006 00:16:03 -0000 1.2
+++ src/libpspp/alloc.c 19 Mar 2007 21:36:24 -0000 1.2.2.1
@@ -1,5 +1,5 @@
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-92007 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -29,3 +29,4 @@
{
return !xalloc_oversized (n, s) ? malloc (n * s) : NULL;
}
+
Index: src/libpspp/array.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/array.c,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -u -b -r1.10 -r1.10.2.1
--- src/libpspp/array.c 15 Dec 2006 00:16:03 -0000 1.10
+++ src/libpspp/array.c 19 Mar 2007 21:36:24 -0000 1.10.2.1
@@ -476,7 +476,7 @@
void *value,
algo_compare_func *compare, const void *aux)
{
- assert (array != NULL);
+ assert (array != NULL || count == 0);
assert (count <= INT_MAX);
assert (compare != NULL);
Index: src/libpspp/deque.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/libpspp/deque.h,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -u -b -r1.1 -r1.1.2.1
--- src/libpspp/deque.h 16 Jan 2007 00:14:41 -0000 1.1
+++ src/libpspp/deque.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -22,6 +22,7 @@
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdlib.h>
#include <libpspp/compiler.h>
Index: src/math/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/automake.mk,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/math/automake.mk 4 Jul 2006 04:39:04 -0000 1.4
+++ src/math/automake.mk 19 Mar 2007 21:36:24 -0000 1.4.2.1
@@ -17,6 +17,10 @@
src/math/group-proc.h \
src/math/levene.c \
src/math/levene.h \
+ src/math/merge.c \
+ src/math/merge.h \
+ src/math/ordering.c \
+ src/math/ordering.h \
src/math/moments.c src/math/moments.h \
src/math/percentiles.c src/math/percentiles.h \
src/math/design-matrix.c src/math/design-matrix.h \
Index: src/math/levene.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/levene.c,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -u -b -r1.9 -r1.9.2.1
--- src/math/levene.c 16 Dec 2006 04:26:43 -0000 1.9
+++ src/math/levene.c 19 Mar 2007 21:36:24 -0000 1.9.2.1
@@ -22,14 +22,13 @@
#include "levene.h"
#include <libpspp/message.h>
#include <data/case.h>
-#include <data/casefile.h>
+#include <data/casereader.h>
#include <data/dictionary.h>
#include "group-proc.h"
#include <libpspp/hash.h>
#include <libpspp/str.h>
#include <data/variable.h>
#include <data/procedure.h>
-#include <data/casefilter.h>
#include <libpspp/alloc.h>
#include <libpspp/misc.h>
#include "group.h"
@@ -74,7 +73,7 @@
struct variable **v_dep;
/* Filter for missing values */
- struct casefilter *filter;
+ enum mv_class exclude;
};
/* First pass */
@@ -93,38 +92,39 @@
void
levene(const struct dictionary *dict,
- const struct casefile *cf,
+ struct casereader *reader,
struct variable *v_indep, size_t n_dep, struct variable **v_dep,
- struct casefilter *filter)
+ enum mv_class exclude)
{
- struct casereader *r;
+ struct casereader *pass1, *pass2;
struct ccase c;
struct levene_info l;
l.n_dep = n_dep;
l.v_indep = v_indep;
l.v_dep = v_dep;
- l.filter = filter;
+ l.exclude = exclude;
+ casereader_split (reader, &pass1, &pass2);
levene_precalc (&l);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
+ for(;
+ casereader_read (pass1, &c) ;
case_destroy (&c))
{
levene_calc (dict, &c, &l);
}
- casereader_destroy (r);
+ casereader_destroy (pass1);
levene_postcalc (&l);
levene2_precalc(&l);
- for(r = casefile_get_reader (cf, filter);
- casereader_read (r, &c) ;
+ for(;
+ casereader_read (pass2, &c) ;
case_destroy (&c))
{
levene2_calc (dict, &c,&l);
}
- casereader_destroy (r);
+ casereader_destroy (pass2);
levene2_postcalc (&l);
}
@@ -205,7 +205,7 @@
if ( 0 == gs )
continue ;
- if ( ! casefilter_variable_missing (l->filter, c, var))
+ if ( !var_is_value_missing (var, v, l->exclude))
{
levene_z= fabs(v->f - gs->mean);
lz[i].grand_total += levene_z * weight;
@@ -294,8 +294,7 @@
if ( 0 == gs )
continue;
- if ( ! casefilter_variable_missing (l->filter, c, var))
-
+ if ( !var_is_value_missing (var, v, l->exclude))
{
levene_z = fabs(v->f - gs->mean);
lz_denominator[i] += weight * pow2 (levene_z - gs->lz_mean);
Index: src/math/levene.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/levene.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- src/math/levene.h 16 Dec 2006 04:26:43 -0000 1.5
+++ src/math/levene.h 19 Mar 2007 21:36:24 -0000 1.5.2.1
@@ -21,9 +21,9 @@
#if !levene_h
#define levene_h 1
-
+#include <data/casereader.h>
+#include <data/missing-values.h>
#include <data/variable.h>
-#include <data/casefile.h>
/* Calculate the Levene statistic
@@ -39,9 +39,9 @@
struct dictionary ;
struct casefilter ;
-void levene(const struct dictionary *dict, const struct casefile *cf,
+void levene(const struct dictionary *dict, struct casereader *,
struct variable *v_indep, size_t n_dep, struct variable **v_dep,
- struct casefilter *filter);
+ enum mv_class exclude);
Index: src/math/sort.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/sort.c,v
retrieving revision 1.23
retrieving revision 1.23.2.1
diff -u -b -r1.23 -r1.23.2.1
--- src/math/sort.c 9 Feb 2007 05:19:09 -0000 1.23
+++ src/math/sort.c 19 Mar 2007 21:36:24 -0000 1.23.2.1
@@ -20,31 +20,17 @@
#include "sort.h"
-#include <errno.h>
-#include <limits.h>
-#include <stdbool.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <data/case-source.h>
#include <data/case.h>
-#include <data/casefile.h>
-#include <data/fastfile.h>
-#include <data/casefile-factory.h>
-#include <data/fastfile-factory.h>
-#include <data/procedure.h>
+#include <data/casereader.h>
+#include <data/casewriter-private.h>
#include <data/settings.h>
-#include <data/variable.h>
-#include <data/storage-stream.h>
#include <libpspp/alloc.h>
#include <libpspp/array.h>
#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/str.h>
-
-#include "minmax.h"
+#include <math/merge.h>
+#include <math/ordering.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
@@ -52,701 +38,270 @@
/* These should only be changed for testing purposes. */
int min_buffers = 64;
int max_buffers = INT_MAX;
-bool allow_internal_sort = true;
-
-static int compare_record (const struct ccase *, const struct ccase *,
- const struct sort_criteria *);
-static struct casefile *do_internal_sort (struct casereader *,
- const struct sort_criteria *,
- struct casefile_factory *
- );
-static struct casefile *do_external_sort (struct casereader *,
- const struct sort_criteria *,
- struct casefile_factory *
- );
-
-
-/* Sorts the active file in-place according to CRITERIA.
- Returns true if successful. */
-bool
-sort_active_file_in_place (struct dataset *ds,
- const struct sort_criteria *criteria)
-{
- struct casefile *in, *out;
-
- proc_cancel_temporary_transformations (ds);
- if (!procedure (ds, NULL, NULL))
- return false;
-
- in = proc_capture_output (ds);
- out = sort_execute (casefile_get_destructive_reader (in), criteria,
- dataset_get_casefile_factory (ds));
- if (out == NULL)
- return false;
- proc_set_source (ds, storage_source_create (out));
- return true;
-}
-
-/* Data passed to sort_to_casefile_callback(). */
-struct sort_to_casefile_cb_data
+struct sort_writer
{
- const struct sort_criteria *criteria;
- struct casefile *output;
- struct casefile_factory *factory ;
+ struct case_ordering *ordering;
+ struct merge *merge;
+ struct pqueue *pqueue;
+
+ struct casewriter *run;
+ casenumber run_id;
+ struct ccase run_end;
};
-/* Sorts casefile CF according to the criteria in CB_DATA. */
-static bool
-sort_to_casefile_callback (const struct casefile *cf, void *cb_data_)
-{
- struct sort_to_casefile_cb_data *cb_data = cb_data_;
- cb_data->output = sort_execute (casefile_get_reader (cf, NULL),
- cb_data->criteria,
- cb_data->factory
- );
- return cb_data->output != NULL;
-}
-
-/* Sorts the active file to a separate casefile. If successful,
- returns the sorted casefile. Returns a null pointer on
- failure. */
-struct casefile *
-sort_active_file_to_casefile (struct dataset *ds,
- const struct sort_criteria *criteria)
-{
- struct sort_to_casefile_cb_data cb_data;
-
- proc_cancel_temporary_transformations (ds);
-
- cb_data.criteria = criteria;
- cb_data.output = NULL;
- cb_data.factory = dataset_get_casefile_factory (ds);
- if (!multipass_procedure (ds, sort_to_casefile_callback, &cb_data))
- {
- casefile_destroy (cb_data.output);
- return NULL;
- }
- return cb_data.output;
-}
+static struct casewriter_class sort_casewriter_class;
+static struct pqueue *pqueue_create (const struct case_ordering *);
+static void pqueue_destroy (struct pqueue *);
+static bool pqueue_is_full (const struct pqueue *);
+static bool pqueue_is_empty (const struct pqueue *);
+static void pqueue_push (struct pqueue *, struct ccase *, casenumber);
+static void pqueue_pop (struct pqueue *, struct ccase *, casenumber *);
-/* Reads all the cases from READER, which is destroyed. Sorts
- the cases according to CRITERIA. Returns the sorted cases in
- a newly created casefile, which will be created by FACTORY.
- If FACTORY is NULL, then a local fastfile_factory will be used.
-*/
-struct casefile *
-sort_execute (struct casereader *reader,
- const struct sort_criteria *criteria,
- struct casefile_factory *factory
- )
-{
- struct casefile_factory *local_factory = NULL;
- struct casefile *output ;
- if ( factory == NULL )
- factory = local_factory = fastfile_factory_create ();
-
- output = do_internal_sort (reader, criteria, factory);
- if (output == NULL)
- output = do_external_sort (reader, criteria, factory);
- casereader_destroy (reader);
+static void output_record (struct sort_writer *);
- fastfile_factory_destroy (local_factory);
+struct casewriter *
+sort_create_writer (struct case_ordering *ordering)
+{
+ struct sort_writer *sort;
- return output;
-}
+ sort = xmalloc (sizeof *sort);
+ sort->ordering = case_ordering_clone (ordering);
+ sort->merge = merge_create (ordering);
+ sort->pqueue = pqueue_create (ordering);
+ sort->run = NULL;
+ sort->run_id = 0;
+ case_nullify (&sort->run_end);
-/* A case and its index. */
-struct indexed_case
- {
- struct ccase c; /* Case. */
- unsigned long idx; /* Index to allow for stable sorting. */
- };
+ case_ordering_destroy (ordering);
-static int compare_indexed_cases (const void *, const void *, const void *);
+ return casewriter_create (&sort_casewriter_class, sort);
+}
-/* If the data is in memory, do an internal sort and return a new
- casefile for the data. Otherwise, return a null pointer. */
-static struct casefile *
-do_internal_sort (struct casereader *reader,
- const struct sort_criteria *criteria,
- struct casefile_factory *factory)
-{
- const struct casefile *src;
- struct casefile *dst;
- unsigned long case_cnt;
-
- if (!allow_internal_sort)
- return NULL;
-
- src = casereader_get_casefile (reader);
- if (casefile_get_case_cnt (src) > 1 && !casefile_in_core (src))
- return NULL;
-
- case_cnt = casefile_get_case_cnt (src);
- dst = factory->create_casefile (factory, casefile_get_value_cnt (src));
- if (case_cnt != 0)
- {
- struct indexed_case *cases = nmalloc (sizeof *cases, case_cnt);
- if (cases != NULL)
- {
- unsigned long i;
+static void
+sort_casewriter_write (struct casewriter *writer UNUSED, void *sort_,
+ struct ccase *c)
+{
+ struct sort_writer *sort = sort_;
+ bool next_run;
- for (i = 0; i < case_cnt; i++)
- {
- bool ok = casereader_read_xfer (reader, &cases[i].c);
- if (!ok)
- NOT_REACHED ();
- cases[i].idx = i;
- }
+ if (pqueue_is_full (sort->pqueue))
+ output_record (sort);
- sort (cases, case_cnt, sizeof *cases, compare_indexed_cases,
- (void *) criteria);
+ next_run = (case_is_null (&sort->run_end)
+ || case_ordering_compare_cases (c, &sort->run_end,
+ sort->ordering) < 0);
+ pqueue_push (sort->pqueue, c, sort->run_id + (next_run ? 1 : 0));
+}
- for (i = 0; i < case_cnt; i++)
- casefile_append_xfer (dst, &cases[i].c);
- if (casefile_error (dst))
- NOT_REACHED ();
+static bool
+sort_casewriter_destroy (struct casewriter *writer UNUSED, void *sort_)
+{
+ struct sort_writer *sort = sort_;
+ bool ok;
- free (cases);
- }
- else
- {
- /* Failure. */
- casefile_destroy (dst);
- dst = NULL;
- }
- }
+ case_ordering_destroy (sort->ordering);
+ ok = merge_destroy (sort->merge);
+ pqueue_destroy (sort->pqueue);
+ ok = casewriter_destroy (sort->run) && ok;
+ case_destroy (&sort->run_end);
+ free (sort);
- return dst;
+ return ok;
}
-/* Compares the variables specified by CRITERIA between the cases
- at A and B, with a "last resort" comparison for stability, and
- returns a strcmp()-type result. */
-static int
-compare_indexed_cases (const void *a_, const void *b_, const void *criteria_)
+static struct casereader *
+sort_casewriter_convert_to_reader (struct casewriter *writer, void *sort_)
{
- const struct sort_criteria *criteria = criteria_;
- const struct indexed_case *a = a_;
- const struct indexed_case *b = b_;
- int result = compare_record (&a->c, &b->c, criteria);
- if (result == 0)
- result = a->idx < b->idx ? -1 : a->idx > b->idx;
- return result;
-}
+ struct sort_writer *sort = sort_;
+ struct casereader *output;
-/* External sort. */
-
-/* Maximum order of merge (external sort only). The maximum
- reasonable value is about 7. Above that, it would be a good
- idea to use a heap in merge_once() to select the minimum. */
-#define MAX_MERGE_ORDER 7
-
-/* Results of an external sort. */
-struct external_sort
+ if (sort->run == NULL && sort->run_id == 0)
{
- const struct sort_criteria *criteria; /* Sort criteria. */
- size_t value_cnt; /* Size of data in `union value's. */
- struct casefile **runs; /* Array of initial runs. */
- size_t run_cnt, run_cap; /* Number of runs, allocated capacity. */
- struct casefile_factory *factory; /* Factory used to create the result */
- };
+ /* In-core sort. */
+ sort->run = mem_writer_create (case_ordering_get_value_cnt (
+ sort->ordering));
+ sort->run_id = 1;
+ }
+ while (!pqueue_is_empty (sort->pqueue))
+ output_record (sort);
-/* Prototypes for helper functions. */
-static int write_runs (struct external_sort *, struct casereader *);
-static struct casefile *merge (struct external_sort *);
-static void destroy_external_sort (struct external_sort *);
-
-/* Performs a stable external sort of the active file according
- to the specification in SCP. Forms initial runs using a heap
- as a reservoir. Merges the initial runs according to a
- pattern that assures stability. */
-static struct casefile *
-do_external_sort (struct casereader *reader,
- const struct sort_criteria *criteria,
- struct casefile_factory *factory
- )
-{
- struct external_sort *xsrt;
-
- if (!casefile_to_disk (casereader_get_casefile (reader)))
- return NULL;
-
- xsrt = xmalloc (sizeof *xsrt);
- xsrt->criteria = criteria;
- xsrt->value_cnt = casefile_get_value_cnt (casereader_get_casefile (reader));
- xsrt->run_cap = 512;
- xsrt->run_cnt = 0;
- xsrt->runs = xnmalloc (xsrt->run_cap, sizeof *xsrt->runs);
- xsrt->factory = factory;
- if (write_runs (xsrt, reader))
- {
- struct casefile *output = merge (xsrt);
- destroy_external_sort (xsrt);
+ merge_append (sort->merge, casewriter_make_reader (sort->run));
+ sort->run = NULL;
+
+ output = merge_make_reader (sort->merge);
+ sort_casewriter_destroy (writer, sort);
return output;
- }
- else
- {
- destroy_external_sort (xsrt);
- return NULL;
- }
}
-/* Destroys XSRT. */
static void
-destroy_external_sort (struct external_sort *xsrt)
+output_record (struct sort_writer *sort)
{
- if (xsrt != NULL)
- {
- int i;
-
- for (i = 0; i < xsrt->run_cnt; i++)
- casefile_destroy (xsrt->runs[i]);
- free (xsrt->runs);
- free (xsrt);
- }
-}
+ struct ccase min_case;
+ casenumber min_run_id;
-/* Replacement selection. */
+ pqueue_pop (sort->pqueue, &min_case, &min_run_id);
+#if 0
+ printf ("\toutput: %f to run %d\n", case_num_idx (&min_case, 0), min_run_id);
+#endif
-/* Pairs a record with a run number. */
-struct record_run
+ if (sort->run_id != min_run_id && sort->run != NULL)
{
- int run; /* Run number of case. */
- struct ccase record; /* Case data. */
- size_t idx; /* Case number (for stability). */
- };
-
-/* Represents a set of initial runs during an external sort. */
-struct initial_run_state
+ merge_append (sort->merge, casewriter_make_reader (sort->run));
+ sort->run = NULL;
+ }
+ if (sort->run == NULL)
{
- struct external_sort *xsrt;
+ sort->run = tmpfile_writer_create (case_ordering_get_value_cnt (
+ sort->ordering));
+ sort->run_id = min_run_id;
+ }
- /* Reservoir. */
- struct record_run *records; /* Records arranged as a heap. */
- size_t record_cnt; /* Current number of records. */
- size_t record_cap; /* Capacity for records. */
-
- /* Run currently being output. */
- int run; /* Run number. */
- size_t case_cnt; /* Number of cases so far. */
- struct casefile *casefile; /* Output file. */
- struct ccase last_output; /* Record last output. */
+ case_destroy (&sort->run_end);
+ case_clone (&sort->run_end, &min_case);
- int okay; /* Zero if an error has been encountered. */
- };
+ casewriter_write (sort->run, &min_case);
+}
-static bool destroy_initial_run_state (struct initial_run_state *);
-static void process_case (struct initial_run_state *,
- const struct ccase *, size_t);
-static int allocate_cases (struct initial_run_state *);
-static void output_record (struct initial_run_state *);
-static void start_run (struct initial_run_state *);
-static void end_run (struct initial_run_state *);
-static int compare_record_run (const struct record_run *,
- const struct record_run *,
- const struct initial_run_state *);
-static int compare_record_run_minheap (const void *, const void *,
- const void *);
+static struct casewriter_class sort_casewriter_class =
+ {
+ sort_casewriter_write,
+ sort_casewriter_destroy,
+ NULL,
+ sort_casewriter_convert_to_reader,
+ };
-/* Reads cases from READER and composes initial runs in XSRT. */
-static int
-write_runs (struct external_sort *xsrt, struct casereader *reader)
+/* Reads all the cases from INPUT. Sorts the cases according to
+ ORDERING. Returns the sorted cases in a new casereader, or a
+ null pointer if an I/O error occurs. Both INPUT and ORDERING
+ are destroyed upon return, regardless of success. */
+struct casereader *
+sort_execute (struct casereader *input, struct case_ordering *ordering)
{
- struct initial_run_state *irs;
+ struct casewriter *output;
struct ccase c;
- size_t idx = 0;
- int success = 0;
- /* Allocate memory for cases. */
- irs = xmalloc (sizeof *irs);
- irs->xsrt = xsrt;
- irs->records = NULL;
- irs->record_cnt = irs->record_cap = 0;
- irs->run = 0;
- irs->case_cnt = 0;
- irs->casefile = NULL;
- case_nullify (&irs->last_output);
- irs->okay = 1;
- if (!allocate_cases (irs))
- goto done;
-
- /* Create initial runs. */
- start_run (irs);
- for (; irs->okay && casereader_read (reader, &c); case_destroy (&c))
- process_case (irs, &c, idx++);
- while (irs->okay && irs->record_cnt > 0)
- output_record (irs);
- end_run (irs);
-
- success = irs->okay;
-
- done:
- if (!destroy_initial_run_state (irs))
- success = false;
-
- return success;
+ output = sort_create_writer (ordering);
+ while (casereader_read (input, &c))
+ casewriter_write (output, &c);
+ casereader_destroy (input);
+ return casewriter_make_reader (output);
}
-/* Add a single case to an initial run. */
-static void
-process_case (struct initial_run_state *irs, const struct ccase *c,
- size_t idx)
-{
- struct record_run *rr;
-
- /* Compose record_run for this run and add to heap. */
- assert (irs->record_cnt < irs->record_cap - 1);
- rr = irs->records + irs->record_cnt++;
- case_copy (&rr->record, 0, c, 0, irs->xsrt->value_cnt);
- rr->run = irs->run;
- rr->idx = idx;
- if (!case_is_null (&irs->last_output)
- && compare_record (c, &irs->last_output, irs->xsrt->criteria) < 0)
- rr->run = irs->run + 1;
- push_heap (irs->records, irs->record_cnt, sizeof *irs->records,
- compare_record_run_minheap, irs);
-
- /* Output a record if the reservoir is full. */
- if (irs->record_cnt == irs->record_cap - 1 && irs->okay)
- output_record (irs);
-}
-
-/* Destroys the initial run state represented by IRS.
- Returns true if successful, false if an I/O error occurred. */
-static bool
-destroy_initial_run_state (struct initial_run_state *irs)
-{
- int i;
- bool ok = true;
-
- if (irs == NULL)
- return true;
+struct pqueue
+ {
+ struct case_ordering *ordering;
+ struct pqueue_record *records;
+ size_t record_cnt;
+ size_t record_cap;
+ casenumber idx;
+ };
- for (i = 0; i < irs->record_cap; i++)
- case_destroy (&irs->records[i].record);
- free (irs->records);
+struct pqueue_record
+ {
+ casenumber id;
+ struct ccase c;
+ casenumber idx;
+ };
- if (irs->casefile != NULL)
- ok = casefile_sleep (irs->casefile);
+static int compare_pqueue_records_minheap (const void *a, const void *b,
+ const void *pq_);
- free (irs);
- return ok;
-}
-
-/* Allocates room for lots of cases as a buffer. */
-static int
-allocate_cases (struct initial_run_state *irs)
+static struct pqueue *
+pqueue_create (const struct case_ordering *ordering)
{
- int approx_case_cost; /* Approximate memory cost of one case in bytes. */
- int max_cases; /* Maximum number of cases to allocate. */
- int i;
-
- /* Allocate as many cases as we can within the workspace
- limit. */
- approx_case_cost = (sizeof *irs->records
- + irs->xsrt->value_cnt * sizeof (union value)
- + 4 * sizeof (void *));
- max_cases = get_workspace() / approx_case_cost;
- if (max_cases > max_buffers)
- max_cases = max_buffers;
- irs->records = nmalloc (sizeof *irs->records, max_cases);
- if (irs->records != NULL)
- for (i = 0; i < max_cases; i++)
- if (!case_try_create (&irs->records[i].record, irs->xsrt->value_cnt))
- {
- max_cases = i;
- break;
- }
- irs->record_cap = max_cases;
+ struct pqueue *pq;
- /* Fail if we didn't allocate an acceptable number of cases. */
- if (irs->records == NULL || max_cases < min_buffers)
- {
- msg (SE, _("Out of memory. Could not allocate room for minimum of %d "
- "cases of %d bytes each. (PSPP workspace is currently "
- "restricted to a maximum of %lu KB.)"),
- min_buffers, approx_case_cost,
- (unsigned long int) (get_workspace() / 1024));
- return 0;
- }
- return 1;
+ pq = xmalloc (sizeof *pq);
+ pq->ordering = case_ordering_clone (ordering);
+ pq->record_cap
+ = get_workspace_cases (case_ordering_get_value_cnt (ordering));
+ if (pq->record_cap > max_buffers)
+ pq->record_cap = max_buffers;
+ else if (pq->record_cap < min_buffers)
+ pq->record_cap = min_buffers;
+ pq->record_cnt = 0;
+ pq->records = xnmalloc (pq->record_cap, sizeof *pq->records);
+ pq->idx = 0;
+
+ return pq;
}
-/* Compares the VAR_CNT variables in VARS[] between the `value's at
- A and B, and returns a strcmp()-type result. */
-static int
-compare_record (const struct ccase *a, const struct ccase *b,
- const struct sort_criteria *criteria)
+static void
+pqueue_destroy (struct pqueue *pq)
{
- int i;
-
- assert (a != NULL);
- assert (b != NULL);
-
- for (i = 0; i < criteria->crit_cnt; i++)
+ if (pq != NULL)
{
- const struct sort_criterion *c = &criteria->crits[i];
- int result;
-
- if (c->width == 0)
+ while (!pqueue_is_empty (pq))
{
- double af = case_num_idx (a, c->fv);
- double bf = case_num_idx (b, c->fv);
-
- result = af < bf ? -1 : af > bf;
- }
- else
- result = memcmp (case_str_idx (a, c->fv),
- case_str_idx (b, c->fv), c->width);
-
- if (result != 0)
- return c->dir == SRT_ASCEND ? result : -result;
+ struct ccase c;
+ casenumber id;
+ pqueue_pop (pq, &c, &id);
+ case_destroy (&c);
+ }
+ case_ordering_destroy (pq->ordering);
+ free (pq->records);
+ free (pq);
}
-
- return 0;
}
-/* Compares record-run tuples A and B on run number first, then
- on record, then on case index. */
-static int
-compare_record_run (const struct record_run *a,
- const struct record_run *b,
- const struct initial_run_state *irs)
+static bool
+pqueue_is_full (const struct pqueue *pq)
{
- int result = a->run < b->run ? -1 : a->run > b->run;
- if (result == 0)
- result = compare_record (&a->record, &b->record, irs->xsrt->criteria);
- if (result == 0)
- result = a->idx < b->idx ? -1 : a->idx > b->idx;
- return result;
+ return pq->record_cnt >= pq->record_cap;
}
-/* Compares record-run tuples A and B on run number first, then
- on the current record according to SCP, but in descending
- order. */
-static int
-compare_record_run_minheap (const void *a, const void *b, const void *irs)
+static bool
+pqueue_is_empty (const struct pqueue *pq)
{
- return -compare_record_run (a, b, irs);
+ return pq->record_cnt == 0;
}
-/* Begins a new initial run, specifically its output file. */
static void
-start_run (struct initial_run_state *irs)
+pqueue_push (struct pqueue *pq, struct ccase *c, casenumber id)
{
- irs->run++;
- irs->case_cnt = 0;
+ struct pqueue_record *r;
- /* This casefile is internal to the sort, so don't use the factory
- to create it. */
- irs->casefile = fastfile_create (irs->xsrt->value_cnt);
- casefile_to_disk (irs->casefile);
- case_nullify (&irs->last_output);
-}
+ assert (!pqueue_is_full (pq));
-/* Ends the current initial run. */
-static void
-end_run (struct initial_run_state *irs)
-{
- struct external_sort *xsrt = irs->xsrt;
+ r = &pq->records[pq->record_cnt++];
+ r->id = id;
+ case_move (&r->c, c);
+ r->idx = pq->idx++;
- /* Record initial run. */
- if (irs->casefile != NULL)
- {
- casefile_sleep (irs->casefile);
- if (xsrt->run_cnt >= xsrt->run_cap)
- {
- xsrt->run_cap *= 2;
- xsrt->runs = xnrealloc (xsrt->runs,
- xsrt->run_cap, sizeof *xsrt->runs);
- }
- xsrt->runs[xsrt->run_cnt++] = irs->casefile;
- if (casefile_error (irs->casefile))
- irs->okay = false;
- irs->casefile = NULL;
- }
+ push_heap (pq->records, pq->record_cnt, sizeof *pq->records,
+ compare_pqueue_records_minheap, pq);
}
-/* Writes a record to the current initial run. */
static void
-output_record (struct initial_run_state *irs)
+pqueue_pop (struct pqueue *pq, struct ccase *c, casenumber *id)
{
- struct record_run *record_run;
- struct ccase case_tmp;
+ struct pqueue_record *r;
- /* Extract minimum case from heap. */
- assert (irs->record_cnt > 0);
- pop_heap (irs->records, irs->record_cnt--, sizeof *irs->records,
- compare_record_run_minheap, irs);
- record_run = irs->records + irs->record_cnt;
-
- /* Bail if an error has occurred. */
- if (!irs->okay)
- return;
-
- /* Start new run if necessary. */
- assert (record_run->run == irs->run
- || record_run->run == irs->run + 1);
- if (record_run->run != irs->run)
- {
- end_run (irs);
- start_run (irs);
- }
- assert (record_run->run == irs->run);
- irs->case_cnt++;
+ assert (!pqueue_is_empty (pq));
- /* Write to disk. */
- if (irs->casefile != NULL)
- casefile_append (irs->casefile, &record_run->record);
-
- /* This record becomes last_output. */
- irs->last_output = case_tmp = record_run->record;
- record_run->record = irs->records[irs->record_cap - 1].record;
- irs->records[irs->record_cap - 1].record = case_tmp;
-}
-
-/* Merging. */
-
-static int choose_merge (struct casefile *runs[], int run_cnt, int order);
-static struct casefile *merge_once (struct external_sort *,
- struct casefile *[], size_t);
-
-/* Repeatedly merges run until only one is left,
- and returns the final casefile.
- Returns a null pointer if an I/O error occurs. */
-static struct casefile *
-merge (struct external_sort *xsrt)
-{
- while (xsrt->run_cnt > 1)
- {
- int order = MIN (MAX_MERGE_ORDER, xsrt->run_cnt);
- int idx = choose_merge (xsrt->runs, xsrt->run_cnt, order);
- xsrt->runs[idx] = merge_once (xsrt, xsrt->runs + idx, order);
- remove_range (xsrt->runs, xsrt->run_cnt, sizeof *xsrt->runs,
- idx + 1, order - 1);
- xsrt->run_cnt -= order - 1;
+ pop_heap (pq->records, pq->record_cnt--, sizeof *pq->records,
+ compare_pqueue_records_minheap, pq);
- if (xsrt->runs[idx] == NULL)
- return NULL;
- }
- assert (xsrt->run_cnt == 1);
- xsrt->run_cnt = 0;
- return xsrt->runs[0];
+ r = &pq->records[pq->record_cnt];
+ *id = r->id;
+ case_move (c, &r->c);
}
-/* Chooses ORDER runs out of the RUN_CNT runs in RUNS to merge,
- and returns the index of the first one.
-
- For stability, we must merge only consecutive runs. For
- efficiency, we choose the shortest consecutive sequence of
- runs. */
+/* Compares record-run tuples A and B on id, then on case data,
+ then on insertion order, in descending order. */
static int
-choose_merge (struct casefile *runs[], int run_cnt, int order)
-{
- int min_idx, min_sum;
- int cur_idx, cur_sum;
- int i;
-
- /* Sum up the length of the first ORDER runs. */
- cur_sum = 0;
- for (i = 0; i < order; i++)
- cur_sum += casefile_get_case_cnt (runs[i]);
-
- /* Find the shortest group of ORDER runs,
- using a running total for efficiency. */
- min_idx = 0;
- min_sum = cur_sum;
- for (cur_idx = 1; cur_idx + order <= run_cnt; cur_idx++)
- {
- cur_sum -= casefile_get_case_cnt (runs[cur_idx - 1]);
- cur_sum += casefile_get_case_cnt (runs[cur_idx + order - 1]);
- if (cur_sum < min_sum)
- {
- min_sum = cur_sum;
- min_idx = cur_idx;
- }
- }
-
- return min_idx;
-}
-
-/* Merges the RUN_CNT initial runs specified in INPUT_FILES into a
- new run, and returns the new run.
- Returns a null pointer if an I/O error occurs. */
-static struct casefile *
-merge_once (struct external_sort *xsrt,
- struct casefile **const input_files,
- size_t run_cnt)
+compare_pqueue_records_minheap (const void *a_, const void *b_,
+ const void *pq_)
{
- struct run
- {
- struct casefile *file;
- struct casereader *reader;
- struct ccase ccase;
- }
- *runs;
-
- struct casefile *output = NULL;
- int i;
-
- /* Open input files. */
- runs = xnmalloc (run_cnt, sizeof *runs);
- for (i = 0; i < run_cnt; i++)
- {
- struct run *r = &runs[i];
- r->file = input_files[i];
- r->reader = casefile_get_destructive_reader (r->file);
- if (!casereader_read_xfer (r->reader, &r->ccase))
- {
- run_cnt--;
- i--;
- }
- }
-
- /* Create output file. */
- output = xsrt->factory->create_casefile (xsrt->factory, xsrt->value_cnt);
- casefile_to_disk (output);
-
- /* Merge. */
- while (run_cnt > 0)
- {
- struct run *min_run, *run;
-
- /* Find minimum. */
- min_run = runs;
- for (run = runs + 1; run < runs + run_cnt; run++)
- if (compare_record (&run->ccase, &min_run->ccase, xsrt->criteria) < 0)
- min_run = run;
-
- /* Write minimum to output file. */
- casefile_append_xfer (output, &min_run->ccase);
-
- /* Read another case from minimum run. */
- if (!casereader_read_xfer (min_run->reader, &min_run->ccase))
- {
- if (casefile_error (min_run->file) || casefile_error (output))
- goto error;
- casereader_destroy (min_run->reader);
- casefile_destroy (min_run->file);
-
- remove_element (runs, run_cnt, sizeof *runs, min_run - runs);
- run_cnt--;
- }
- }
-
- if (!casefile_sleep (output))
- goto error;
- free (runs);
-
- return output;
-
- error:
- for (i = 0; i < run_cnt; i++)
- casefile_destroy (runs[i].file);
- casefile_destroy (output);
- free (runs);
- return NULL;
+ const struct pqueue_record *a = a_;
+ const struct pqueue_record *b = b_;
+ const struct pqueue *pq = pq_;
+ int result = a->id < b->id ? -1 : a->id > b->id;
+ if (result == 0)
+ result = case_ordering_compare_cases (&a->c, &b->c, pq->ordering);
+ if (result == 0)
+ result = a->idx < b->idx ? -1 : a->idx > b->idx;
+ return -result;
}
Index: src/math/sort.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/sort.h,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- src/math/sort.h 22 Dec 2006 11:12:15 -0000 1.5
+++ src/math/sort.h 19 Mar 2007 21:36:24 -0000 1.5.2.1
@@ -1,5 +1,5 @@
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ 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
@@ -16,57 +16,18 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
-#if !sort_h
-#define sort_h 1
+#ifndef MATH_SORT_H
+#define MATH_SORT_H 1
#include <stddef.h>
#include <stdbool.h>
-struct casereader;
-struct dictionary;
-struct variable;
-struct casefile_factory;
+struct case_ordering;
extern int min_buffers ;
extern int max_buffers ;
-extern bool allow_internal_sort ;
+struct casewriter *sort_create_writer (struct case_ordering *);
+struct casereader *sort_execute (struct casereader *, struct case_ordering *);
-/* Sort direction. */
-enum sort_direction
- {
- SRT_ASCEND, /* A, B, C, ..., X, Y, Z. */
- SRT_DESCEND /* Z, Y, X, ..., C, B, A. */
- };
-
-/* A sort criterion. */
-struct sort_criterion
- {
- int fv; /* Variable data index. */
- int width; /* 0=numeric, otherwise string width. */
- enum sort_direction dir; /* Sort direction. */
- };
-
-/* A set of sort criteria. */
-struct sort_criteria
- {
- struct sort_criterion *crits;
- size_t crit_cnt;
- };
-
-
-void sort_destroy_criteria (struct sort_criteria *);
-
-struct casefile *sort_execute (struct casereader *,
- const struct sort_criteria *,
- struct casefile_factory *
- );
-
-struct dataset ;
-bool sort_active_file_in_place (struct dataset *ds,
- const struct sort_criteria *);
-
-struct casefile *sort_active_file_to_casefile (struct dataset *ds,
- const struct sort_criteria *);
-
-#endif /* !sort_h */
+#endif /* math/sort.h */
Index: src/ui/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/automake.mk,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- src/ui/automake.mk 16 Nov 2006 12:47:22 -0000 1.2
+++ src/ui/automake.mk 19 Mar 2007 21:36:25 -0000 1.2.2.1
@@ -10,6 +10,4 @@
src_ui_libuicommon_a_SOURCES = \
src/ui/debugger.c \
- src/ui/debugger.h \
- src/ui/flexifile.c \
- src/ui/flexifile.h
+ src/ui/debugger.h
Index: src/ui/gui/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/automake.mk,v
retrieving revision 1.21
retrieving revision 1.21.2.1
diff -u -b -r1.21 -r1.21.2.1
--- src/ui/gui/automake.mk 26 Jan 2007 07:35:04 -0000 1.21
+++ src/ui/gui/automake.mk 19 Mar 2007 21:36:25 -0000 1.21.2.1
@@ -1,10 +1,7 @@
## Process this file with automake to produce Makefile.in -*- makefile -*-
-
-
bin_PROGRAMS += src/ui/gui/psppire
-
src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) $(GLADE_CFLAGS) -Wall
src_ui_gui_psppire_LDFLAGS = \
@@ -33,7 +30,7 @@
src/libpspp/libpspp.a \
$(GTK_LIBS) \
$(GLADE_LIBS) \
- gl/libgl.la \
+ gl/libgl.a \
@LIBINTL@ @LIBREADLINE@
src_ui_gui_psppiredir = $(pkgdatadir)
@@ -64,8 +61,6 @@
src/ui/gui/data-editor.h \
src/ui/gui/dict-display.c \
src/ui/gui/dict-display.h \
- src/ui/gui/flexifile-factory.h \
- src/ui/gui/flexifile-factory.c \
src/ui/gui/message-dialog.c \
src/ui/gui/message-dialog.h \
src/ui/gui/psppire.c \
Index: src/ui/gui/helper.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/helper.c,v
retrieving revision 1.16
retrieving revision 1.16.2.1
diff -u -b -r1.16 -r1.16.2.1
--- src/ui/gui/helper.c 26 Jan 2007 07:35:04 -0000 1.16
+++ src/ui/gui/helper.c 19 Mar 2007 21:36:25 -0000 1.16.2.1
@@ -9,7 +9,6 @@
#include <data/data-in.h>
#include <data/data-out.h>
#include <data/dictionary.h>
-#include <data/storage-stream.h>
#include <libpspp/message.h>
#include <libpspp/i18n.h>
@@ -151,7 +150,7 @@
{
struct lexer *lexer;
- g_return_val_if_fail (proc_has_source (the_dataset), FALSE);
+ g_return_val_if_fail (proc_has_active_file (the_dataset), FALSE);
lexer = lex_create (the_source_stream);
@@ -169,18 +168,10 @@
lex_destroy (lexer);
- /* The GUI must *always* have a data source, even if it's an empty one.
- Therefore, we find that there is none, (for example NEW FILE was the last
- item in the syntax) then we create a new one. */
- if ( ! proc_has_source (the_dataset))
- proc_set_source (the_dataset,
- storage_source_create
(the_data_store->case_file->flexifile)
- );
-
/* GUI syntax needs this implicit EXECUTE command at the end of
every script. Otherwise commands like GET could leave the GUI without
a casefile. */
- return procedure (the_dataset, NULL, NULL);
+ return proc_execute (the_dataset);
}
Index: src/ui/gui/missing-val-dialog.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/missing-val-dialog.c,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -b -r1.13 -r1.13.2.1
--- src/ui/gui/missing-val-dialog.c 7 Feb 2007 02:12:57 -0000 1.13
+++ src/ui/gui/missing-val-dialog.c 19 Mar 2007 21:36:25 -0000 1.13.2.1
@@ -90,8 +90,8 @@
gint nvals = 0;
gint badvals = 0;
gint i;
- mv_clear (&dialog->mvl);
- for (i = 0 ; i < 3 ; ++i )
+ mv_clear(&dialog->mvl);
+ for(i = 0 ; i < 3 ; ++i )
{
gchar *text =
g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
Index: src/ui/gui/psppire-case-file.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-case-file.c,v
retrieving revision 1.17
retrieving revision 1.17.2.1
diff -u -b -r1.17 -r1.17.2.1
--- src/ui/gui/psppire-case-file.c 26 Jan 2007 07:35:04 -0000 1.17
+++ src/ui/gui/psppire-case-file.c 19 Mar 2007 21:36:25 -0000 1.17.2.1
@@ -26,13 +26,14 @@
#include <gtksheet/gtkextra-marshal.h>
#include <data/case.h>
-#include <ui/flexifile.h>
-#include "flexifile-factory.h"
-#include <data/casefile.h>
#include <data/data-in.h>
+#include <data/datasheet.h>
#include <math/sort.h>
#include <libpspp/misc.h>
+#include "xalloc.h"
+#include "xallocsa.h"
+
/* --- prototypes --- */
static void psppire_case_file_class_init (PsppireCaseFileClass *class);
static void psppire_case_file_init (PsppireCaseFile *case_file);
@@ -132,8 +133,7 @@
{
PsppireCaseFile *cf = PSPPIRE_CASE_FILE (object);
- if ( cf->flexifile)
- casefile_destroy (cf->flexifile);
+ datasheet_destroy (cf->datasheet);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -141,7 +141,7 @@
static void
psppire_case_file_init (PsppireCaseFile *cf)
{
- cf->flexifile = 0;
+ cf->datasheet = NULL;
}
@@ -156,16 +156,16 @@
{
PsppireCaseFile *cf = g_object_new (G_TYPE_PSPPIRE_CASE_FILE, NULL);
- cf->flexifile = flexifile_create (0);
+ cf->datasheet = datasheet_create (NULL);
return cf;
}
void
-psppire_case_file_replace_flexifile (PsppireCaseFile *cf, struct flexifile *ff)
+psppire_case_file_replace_datasheet (PsppireCaseFile *cf, struct datasheet *ds)
{
- cf->flexifile = (struct casefile *) ff;
+ cf->datasheet = ds;
}
@@ -173,16 +173,14 @@
gboolean
psppire_case_file_delete_cases (PsppireCaseFile *cf, gint n_cases, gint first)
{
- int result;
-
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- result = flexifile_delete_cases (FLEXIFILE (cf->flexifile), n_cases,
first);
+ datasheet_delete_cases (cf->datasheet, first, n_cases);
g_signal_emit (cf, signals [CASES_DELETED], 0, n_cases, first);
- return result;
+ return TRUE;
}
/* Insert case CC into the case file before POSN */
@@ -191,12 +189,14 @@
struct ccase *cc,
gint posn)
{
+ struct ccase tmp;
bool result ;
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- result = flexifile_insert_case (FLEXIFILE (cf->flexifile), cc, posn);
+ case_clone (&tmp, cc);
+ result = datasheet_insert_cases (cf->datasheet, posn, &tmp, 1);
if ( result )
g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
@@ -212,15 +212,17 @@
psppire_case_file_append_case (PsppireCaseFile *cf,
struct ccase *c)
{
+ struct ccase tmp;
bool result ;
gint posn ;
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- posn = casefile_get_case_cnt (cf->flexifile);
+ posn = datasheet_get_case_cnt (cf->datasheet);
- result = casefile_append (cf->flexifile, c);
+ case_clone (&tmp, c);
+ result = datasheet_insert_cases (cf->datasheet, posn, &tmp, 1);
g_signal_emit (cf, signals [CASE_INSERTED], 0, posn);
@@ -233,69 +235,68 @@
{
g_return_val_if_fail (cf, FALSE);
- if ( ! cf->flexifile)
+ if ( ! cf->datasheet)
return 0;
- return casefile_get_case_cnt (cf->flexifile);
+ return datasheet_get_case_cnt (cf->datasheet);
}
-/* Return the IDXth value from case CASENUM.
- The return value must not be freed or written to
- */
-const union value *
-psppire_case_file_get_value (const PsppireCaseFile *cf, gint casenum, gint idx)
+/* Copies the IDXth value from case CASENUM into VALUE.
+ If VALUE is null, then memory is allocated is allocated with
+ malloc. Returns the value if successful, NULL on failure. */
+union value *
+psppire_case_file_get_value (const PsppireCaseFile *cf,
+ casenumber casenum, size_t idx,
+ union value *value, int width)
{
- const union value *v;
- struct ccase c;
-
- g_return_val_if_fail (cf, NULL);
- g_return_val_if_fail (cf->flexifile, NULL);
+ bool allocated;
- g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), NULL);
+ g_return_val_if_fail (cf, false);
+ g_return_val_if_fail (cf->datasheet, false);
- flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &c);
+ g_return_val_if_fail (idx < datasheet_get_value_cnt (cf->datasheet), false);
- v = case_data_idx (&c, idx);
- case_destroy (&c);
-
- return v;
+ if (value == NULL)
+ {
+ value = xnmalloc (value_cnt_from_width (width), sizeof *value);
+ allocated = true;
+ }
+ else
+ allocated = false;
+ if (!datasheet_get_value (cf->datasheet, casenum, idx, value, width))
+ {
+ if (allocated)
+ free (value);
+ value = NULL;
+ }
+ return value;
}
void
psppire_case_file_clear (PsppireCaseFile *cf)
{
- casefile_destroy (cf->flexifile);
- cf->flexifile = 0;
+ datasheet_destroy (cf->datasheet);
+ cf->datasheet = NULL;
g_signal_emit (cf, signals [CASES_DELETED], 0, 0, -1);
}
-/* Set the IDXth value of case C to SYSMIS/EMPTY */
+/* Set the IDXth value of case C to V.
+ Returns true if successful, false on I/O error. */
gboolean
psppire_case_file_set_value (PsppireCaseFile *cf, gint casenum, gint idx,
union value *v, gint width)
{
- struct ccase cc ;
- int bytes;
+ bool ok;
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), FALSE);
-
- if ( ! flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &cc) )
- return FALSE;
-
- if ( width == 0 )
- bytes = MAX_SHORT_STRING;
- else
- bytes = DIV_RND_UP (width, MAX_SHORT_STRING) * MAX_SHORT_STRING ;
-
- /* Cast away const in flagrant abuse of the casefile */
- memcpy ((union value *)case_data_idx (&cc, idx), v, bytes);
+ g_return_val_if_fail (idx < datasheet_get_value_cnt (cf->datasheet), FALSE);
+ ok = datasheet_put_value (cf->datasheet, casenum, idx, v, width);
+ if (ok)
g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
-
- return TRUE;
+ return ok;
}
@@ -305,49 +306,43 @@
psppire_case_file_data_in (PsppireCaseFile *cf, gint casenum, gint idx,
struct substring input, const struct fmt_spec *fmt)
{
- struct ccase cc ;
+ union value *value;
+ int width;
+ bool ok;
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
-
- g_return_val_if_fail (idx < casefile_get_value_cnt (cf->flexifile), FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- if ( ! flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, &cc) )
- return FALSE;
+ g_return_val_if_fail (idx < datasheet_get_value_cnt (cf->datasheet), FALSE);
- /* Cast away const in flagrant abuse of the casefile */
- if (!data_in (input, fmt->type, 0, 0,
- (union value *) case_data_idx (&cc, idx), fmt_var_width (fmt)))
- g_warning ("Cant set value\n");
+ width = fmt_var_width (fmt);
+ value = xallocsa (value_cnt_from_width (width) * sizeof *value);
+ ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
+ && data_in (input, fmt->type, 0, 0, value, width)
+ && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
+ if (ok)
g_signal_emit (cf, signals [CASE_CHANGED], 0, casenum);
+ freesa (value);
+
return TRUE;
}
void
-psppire_case_file_sort (PsppireCaseFile *cf, const struct sort_criteria *sc)
+psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
{
+ struct casereader *sorted_data;
gint c;
- struct casereader *reader = casefile_get_reader (cf->flexifile, NULL);
- struct casefile *cfile;
-
- struct casefile_factory *factory = flexifile_factory_create ();
-
- cfile = sort_execute (reader, sc, factory);
-
- casefile_destroy (cf->flexifile);
-
- cf->flexifile = cfile;
+ sorted_data = sort_execute (datasheet_make_reader (cf->datasheet), ordering);
+ cf->datasheet = datasheet_create (sorted_data);
/* FIXME: Need to have a signal to change a range of cases, instead of
calling a signal many times */
- for ( c = 0 ; c < casefile_get_case_cnt (cf->flexifile) ; ++c )
+ for ( c = 0 ; c < datasheet_get_case_cnt (cf->datasheet) ; ++c )
g_signal_emit (cf, signals [CASE_CHANGED], 0, c);
-
- flexifile_factory_destroy (factory);
}
@@ -357,16 +352,17 @@
psppire_case_file_insert_values (PsppireCaseFile *cf,
gint n_values, gint before)
{
+ union value *values;
g_return_val_if_fail (cf, FALSE);
- if ( ! cf->flexifile )
- {
- cf->flexifile = flexifile_create (n_values);
+ if ( ! cf->datasheet )
+ cf->datasheet = datasheet_create_empty ();
- return TRUE;
- }
+ values = xcalloc (n_values, sizeof *values);
+ datasheet_insert_values (cf->datasheet, values, n_values, before);
+ free (values);
- return flexifile_resize (FLEXIFILE (cf->flexifile), n_values, before);
+ return TRUE;
}
/* Fills C with the CASENUMth case.
@@ -377,7 +373,7 @@
struct ccase *c)
{
g_return_val_if_fail (cf, FALSE);
- g_return_val_if_fail (cf->flexifile, FALSE);
+ g_return_val_if_fail (cf->datasheet, FALSE);
- return flexifile_get_case (FLEXIFILE (cf->flexifile), casenum, c);
+ return datasheet_get_case (cf->datasheet, casenum, c);
}
Index: src/ui/gui/psppire-case-file.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-case-file.h,v
retrieving revision 1.11
retrieving revision 1.11.2.1
diff -u -b -r1.11 -r1.11.2.1
--- src/ui/gui/psppire-case-file.h 1 Jan 2007 01:44:33 -0000 1.11
+++ src/ui/gui/psppire-case-file.h 19 Mar 2007 21:36:25 -0000 1.11.2.1
@@ -26,6 +26,7 @@
#include <glib.h>
#include <libpspp/str.h>
+#include <data/case.h>
@@ -55,7 +56,7 @@
{
GObject parent;
- struct casefile *flexifile;
+ struct datasheet *datasheet;
};
@@ -75,8 +76,9 @@
gint psppire_case_file_get_case_count (const PsppireCaseFile *cf);
-const union value * psppire_case_file_get_value (const PsppireCaseFile *cf,
- gint c, gint idx);
+union value * psppire_case_file_get_value (const PsppireCaseFile *cf,
+ casenumber, size_t idx,
+ union value *, int width);
struct fmt_spec;
@@ -95,14 +97,14 @@
gboolean psppire_case_file_insert_values (PsppireCaseFile *cf, gint n_values,
gint before);
-struct sort_criteria;
-void psppire_case_file_sort (PsppireCaseFile *cf, const struct sort_criteria
*);
+struct case_ordering;
+void psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *);
gboolean psppire_case_file_get_case (const PsppireCaseFile *cf, gint casenum,
struct ccase *c);
-void psppire_case_file_replace_flexifile (PsppireCaseFile *,
- struct flexifile *);
+void psppire_case_file_replace_datasheet (PsppireCaseFile *,
+ struct datasheet *);
Index: src/ui/gui/psppire-data-store.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire-data-store.c,v
retrieving revision 1.33
retrieving revision 1.33.2.1
diff -u -b -r1.33 -r1.33.2.1
--- src/ui/gui/psppire-data-store.c 12 Jan 2007 22:50:14 -0000 1.33
+++ src/ui/gui/psppire-data-store.c 19 Mar 2007 21:36:25 -0000 1.33.2.1
@@ -25,8 +25,8 @@
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
-#include <data/casefile.h>
-#include <data/case.h>
+#include <data/casewriter.h>
+#include <data/datasheet.h>
#include <data/data-out.h>
#include <data/variable.h>
@@ -454,7 +454,7 @@
/* Opportunity for optimisation exists here when creating a blank case */
- val_cnt = casefile_get_value_cnt (ds->case_file->flexifile) ;
+ val_cnt = datasheet_get_value_cnt (ds->case_file->datasheet) ;
case_create (&cc, val_cnt);
@@ -484,7 +484,7 @@
char *text;
const struct fmt_spec *fp ;
const struct variable *pv ;
- const union value *v ;
+ union value *v ;
GString *s;
PsppireDataStore *store = PSPPIRE_DATA_STORE (model);
@@ -505,17 +505,17 @@
g_assert (idx >= 0);
- v = psppire_case_file_get_value (store->case_file, row, idx);
+ v = psppire_case_file_get_value (store->case_file, row, idx, NULL,
+ var_get_width (pv));
g_return_val_if_fail (v, NULL);
if ( store->show_labels)
{
- const struct val_labs * vl = var_get_value_labels (pv);
-
- const gchar *label;
- if ( (label = val_labs_find (vl, *v)) )
+ const gchar *label = var_lookup_value_label (pv, v);
+ if (label)
{
+ free (v);
return pspp_locale_to_utf8 (label, -1, 0);
}
}
@@ -539,6 +539,7 @@
g_strchomp (text);
+ free (v);
return text;
}
@@ -649,7 +650,7 @@
3 /* version */
};
- struct sfm_writer *writer ;
+ struct casewriter *writer;
g_assert (handle);
@@ -664,15 +665,10 @@
for (i = 0 ; i < psppire_case_file_get_case_count (store->case_file); ++i )
{
struct ccase c;
-
- case_create (&c, var_cnt);
psppire_case_file_get_case (store->case_file, i, &c);
- sfm_write_case (writer, &c);
-
- case_destroy (&c);
+ casewriter_write (writer, &c);
}
-
- sfm_close_writer (writer);
+ casewriter_destroy (writer);
}
Index: src/ui/gui/psppire.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/psppire.c,v
retrieving revision 1.35
retrieving revision 1.35.2.1
diff -u -b -r1.35 -r1.35.2.1
--- src/ui/gui/psppire.c 20 Jan 2007 00:02:13 -0000 1.35
+++ src/ui/gui/psppire.c 19 Mar 2007 21:36:25 -0000 1.35.2.1
@@ -26,16 +26,14 @@
#include "data-editor.h"
#include <libpspp/version.h>
#include <libpspp/copyleft.h>
+#include <data/datasheet.h>
#include <data/file-handle-def.h>
#include <data/format.h>
-#include <data/storage-stream.h>
-#include <data/case-source.h>
#include <data/settings.h>
#include <data/file-name.h>
#include <data/procedure.h>
#include <libpspp/getl.h>
#include <language/lexer/lexer.h>
-#include <ui/flexifile.h>
#include <getopt.h>
#include <gtk/gtk.h>
@@ -48,7 +46,6 @@
#include "data-sheet.h"
#include "var-sheet.h"
#include "message-dialog.h"
-#include "flexifile-factory.h"
PsppireDataStore *the_data_store = 0;
@@ -73,27 +70,17 @@
static void
-replace_flexifile (struct case_source *s)
+replace_flexifile (struct casereader *s)
{
if ( NULL == s )
- psppire_case_file_replace_flexifile (the_data_store->case_file,
- (struct flexifile *) flexifile_create
(0));
- else
- {
- if ( ! case_source_is_class (s, &storage_source_class))
- return ;
-
- psppire_case_file_replace_flexifile (the_data_store->case_file,
- (struct flexifile *)
- storage_source_get_casefile (s));
- }
+ psppire_case_file_replace_datasheet (the_data_store->case_file,
+ datasheet_create_empty ());
}
int
main (int argc, char *argv[])
{
- struct casefile_factory *factory;
PsppireDict *dictionary = 0;
@@ -129,13 +116,11 @@
fmt_init ();
settings_init ();
fh_init ();
- factory = flexifile_factory_create ();
the_source_stream = create_source_stream (
fn_getenv_default ("STAT_INCLUDE_PATH", include_path)
);
- the_dataset = create_dataset (factory,
- replace_flexifile,
+ the_dataset = create_dataset (replace_flexifile,
replace_dictionary);
message_dialog_init (the_source_stream);
@@ -152,10 +137,6 @@
the_data_store = psppire_data_store_new (dictionary);
- proc_set_source (the_dataset,
- storage_source_create (the_data_store->case_file->flexifile)
- );
-
create_icon_factory ();
new_data_window (NULL, NULL);
Index: src/ui/gui/sort-cases-dialog.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/sort-cases-dialog.c,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -b -r1.6 -r1.6.2.1
--- src/ui/gui/sort-cases-dialog.c 24 Dec 2006 23:08:25 -0000 1.6
+++ src/ui/gui/sort-cases-dialog.c 19 Mar 2007 21:36:25 -0000 1.6.2.1
@@ -51,7 +51,7 @@
#include "helper.h"
#include "sort-cases-dialog.h"
#include "psppire-dict.h"
-#include <math/sort.h>
+#include <math/ordering.h>
#include <gettext.h>
#define _(msgid) gettext (msgid)
@@ -396,10 +396,9 @@
}
-static void
-convert_list_store_to_criteria (GtkListStore *list,
- PsppireDict *dict,
- struct sort_criteria *criteria);
+static struct case_ordering *
+convert_list_store_to_ordering (GtkListStore *list,
+ PsppireDict *dict);
/* Run the dialog.
@@ -409,7 +408,7 @@
gint
sort_cases_dialog_run (struct sort_cases_dialog *dialog,
PsppireDict *dict,
- struct sort_criteria *criteria
+ struct case_ordering **ordering
)
{
g_assert (! g_main_loop_is_running (dialog->loop));
@@ -432,50 +431,43 @@
g_main_loop_run (dialog->loop);
if ( GTK_RESPONSE_OK == dialog->response)
- convert_list_store_to_criteria (dialog->criteria_list,
- dict, criteria);
+ *ordering = convert_list_store_to_ordering (dialog->criteria_list, dict);
return dialog->response;
}
-/* Convert the GtkListStore to a struct sort_criteria*/
-static void
-convert_list_store_to_criteria (GtkListStore *list,
- PsppireDict *dict,
- struct sort_criteria *criteria)
+/* Convert the GtkListStore to a struct case_ordering. */
+static struct case_ordering *
+convert_list_store_to_ordering (GtkListStore *list,
+ PsppireDict *dict)
{
+ struct case_ordering *ordering;
GtkTreeIter iter;
gboolean valid;
- gint n = 0;
GtkTreeModel *model = GTK_TREE_MODEL (list);
- criteria->crit_cnt = gtk_tree_model_iter_n_children (model, NULL);
-
- criteria->crits = g_malloc (sizeof (struct sort_criterion) *
- criteria->crit_cnt);
+ ordering = case_ordering_create (dict->dict);
for (valid = gtk_tree_model_get_iter_first (model, &iter);
valid;
valid = gtk_tree_model_iter_next (model, &iter))
{
- struct variable *variable;
+ enum sort_direction dir;
gint index;
- struct sort_criterion *scn = &criteria->crits[n];
- g_assert ( n < criteria->crit_cnt);
- n++;
gtk_tree_model_get (model, &iter,
CRIT_TVM_IDX, &index,
- CRIT_TVM_DIR, &scn->dir,
+ CRIT_TVM_DIR, &dir,
-1);
- variable = psppire_dict_get_variable (dict, index);
-
- scn->fv = var_get_case_index (variable);
- scn->width = var_get_width (variable);
+ case_ordering_add_var (ordering,
+ psppire_dict_get_variable (dict, index),
+ dir);
}
+
+ return ordering;
}
Index: src/ui/gui/sort-cases-dialog.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/sort-cases-dialog.h,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- src/ui/gui/sort-cases-dialog.h 24 Dec 2006 22:49:18 -0000 1.4
+++ src/ui/gui/sort-cases-dialog.h 19 Mar 2007 21:36:25 -0000 1.4.2.1
@@ -25,7 +25,7 @@
#include <glade/glade.h>
#include "psppire-dict.h"
-struct sort_criteria;
+struct case_ordering;
struct sort_cases_dialog
{
@@ -59,7 +59,7 @@
gint sort_cases_dialog_run (struct sort_cases_dialog *dialog,
PsppireDict *dict,
- struct sort_criteria *criteria
+ struct case_ordering **ordering
);
#endif
Index: src/ui/gui/var-sheet.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/var-sheet.c,v
retrieving revision 1.20
retrieving revision 1.20.2.1
diff -u -b -r1.20 -r1.20.2.1
--- src/ui/gui/var-sheet.c 21 Feb 2007 08:27:16 -0000 1.20
+++ src/ui/gui/var-sheet.c 19 Mar 2007 21:36:25 -0000 1.20.2.1
@@ -418,7 +418,9 @@
gchar *string2,
gint int1, gint int2)
{
+#if HAVE_LANGINFO_H
gchar *codeset;
+#endif
gint i;
GtkWidget *sheet;
Index: src/ui/terminal/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/terminal/automake.mk,v
retrieving revision 1.14
retrieving revision 1.14.2.1
diff -u -b -r1.14 -r1.14.2.1
--- src/ui/terminal/automake.mk 4 Jan 2007 08:15:27 -0000 1.14
+++ src/ui/terminal/automake.mk 19 Mar 2007 21:36:25 -0000 1.14.2.1
@@ -30,6 +30,6 @@
src/data/libdata.a \
src/libpspp/libpspp.a \
$(LIBICONV) \
- gl/libgl.la \
+ gl/libgl.a \
@LIBINTL@ @LIBREADLINE@
Index: src/ui/terminal/main.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/terminal/main.c,v
retrieving revision 1.30
retrieving revision 1.30.2.1
diff -u -b -r1.30 -r1.30.2.1
--- src/ui/terminal/main.c 24 Jan 2007 08:30:22 -0000 1.30
+++ src/ui/terminal/main.c 19 Mar 2007 21:36:25 -0000 1.30.2.1
@@ -27,7 +27,6 @@
#include "progname.h"
#include "read-line.h"
-#include <data/fastfile-factory.h>
#include <data/dictionary.h>
#include <data/file-handle-def.h>
#include <libpspp/getl.h>
@@ -82,7 +81,6 @@
int
main (int argc, char **argv)
{
- struct casefile_factory *factory;
signal (SIGABRT, bug_handler);
signal (SIGSEGV, bug_handler);
signal (SIGFPE, bug_handler);
@@ -106,9 +104,7 @@
settings_init ();
random_init ();
- factory = fastfile_factory_create ();
-
- the_dataset = create_dataset (factory, NULL, NULL);
+ the_dataset = create_dataset (NULL, NULL);
if (parse_command_line (argc, argv, the_source_stream))
{
@@ -166,7 +162,7 @@
bug_handler(int sig)
{
#if DEBUGGING
- connect_debugger ();
+ //connect_debugger ();
#endif
switch (sig)
{
Index: tests/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/automake.mk,v
retrieving revision 1.27
retrieving revision 1.27.2.1
diff -u -b -r1.27 -r1.27.2.1
--- tests/automake.mk 9 Feb 2007 05:28:22 -0000 1.27
+++ tests/automake.mk 19 Mar 2007 21:36:25 -0000 1.27.2.1
@@ -117,7 +117,6 @@
tests/bugs/temp-freq.sh \
tests/bugs/print-crash.sh \
tests/bugs/keep-all.sh \
- tests/xforms/casefile.sh \
tests/stats/descript-basic.sh \
tests/stats/descript-missing.sh \
tests/stats/descript-mean-bug.sh \
@@ -161,14 +160,14 @@
src/libpspp/pool.c \
src/libpspp/pool.h \
tests/libpspp/heap-test.c
-tests_libpspp_heap_test_LDADD = gl/libgl.la @LIBINTL@
+tests_libpspp_heap_test_LDADD = gl/libgl.a @LIBINTL@
tests_libpspp_heap_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
tests_libpspp_abt_test_SOURCES = \
src/libpspp/abt.c \
src/libpspp/abt.h \
tests/libpspp/abt-test.c
-tests_libpspp_abt_test_LDADD = gl/libgl.la
+tests_libpspp_abt_test_LDADD = gl/libgl.a
tests_libpspp_abt_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
tests_formats_inexactify_SOURCES = tests/formats/inexactify.c
Index: tests/command/rank.sh
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/command/rank.sh,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -u -b -r1.4 -r1.4.2.1
--- tests/command/rank.sh 22 Dec 2006 04:38:23 -0000 1.4
+++ tests/command/rank.sh 19 Mar 2007 21:36:25 -0000 1.4.2.1
@@ -58,91 +58,6 @@
cd $TEMPDIR
-# Some tests for proper behaviour in the face of invalid input.
-activity="create file 1"
-cat > $TESTFILE <<EOF
-DATA LIST LIST NOTABLE /x * a (a2).
-BEGIN DATA.
--1 s
-0 s
-1 s
-2 s
-2 s
-4 s
-5 s
-END DATA.
-
-DEBUG XFORM FAIL.
-
-RANK x.
-
-EOF
-if [ $? -ne 0 ] ; then no_result ; fi
-
-# Check that it properly handles failed transformations.
-activity="run program 1"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii -e $TEMPDIR/err $TESTFILE
-if [ $? -ne 1 ] ; then fail ; fi
-
-activity="diff 1"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/err
-diff -b $TEMPDIR/err - <<EOF
-$TEMPDIR/rank.sh.sps:14: error: Stopping syntax file processing here to avoid
a cascade of dependent command failures.
-EOF
-if [ $? -ne 0 ] ; then fail ; fi
-
-
-#Now for some general error conditions.
-activity="create file 2"
-cat > $TESTFILE <<EOF
-DATA LIST LIST NOTABLE /x * a (a2).
-BEGIN DATA.
--1 s
-0 s
-1 s
-2 s
-2 s
-4 s
-5 s
-END DATA.
-
-* invalid NTILES (no parameter)
-RANK x
- /NTILES
-.
-
-* invalid NTILES (not an integer)
-RANK x
- /NTILES(d)
-.
-
-
-* destination variable already exists
-RANK x
- /RANK INTO x.
-
-
-* Too many variables in INTO
-RANK x
- /RANK INTO foo bar wiz.
-EOF
-if [ $? -ne 0 ] ; then no_result ; fi
-
-
-activity="run program (syntax errors)"
-$SUPERVISOR $PSPP --testing-mode -o raw-ascii -e $TEMPDIR/errs $TESTFILE
-if [ $? -ne 1 ] ; then fail ; fi
-
-activity="compare errors"
-perl -pi -e 's/^\s*$//g' $TEMPDIR/errs
-diff -b $TEMPDIR/errs - << EOF
-$TEMPDIR/rank.sh.sps:15: error: RANK: Syntax error expecting \`(' at end of
command.
-$TEMPDIR/rank.sh.sps:19: error: RANK: Syntax error expecting integer at \`d'.
-$TEMPDIR/rank.sh.sps:25: error: RANK: Variable x already exists.
-$TEMPDIR/rank.sh.sps:30: error: RANK: Too many variables in INTO clause.
-EOF
-if [ $? -ne 0 ] ; then fail ; fi
-
# Now some real tests.
activity="create file 3"
@@ -319,11 +234,11 @@
WEIGHT BY w.
+
RANK x
/TIES=low
/RANK into xl.
-
RANK x
/TIES=high
/RANK into xh.
@@ -334,10 +249,9 @@
* Test VW fraction
-
RANK x
/FRACTION=VW
- /NORMAL.
+ /NORMAL into Nx.
LIST.
EOF
Index: tests/libpspp/heap-test.c
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/libpspp/heap-test.c,v
retrieving revision 1.2
retrieving revision 1.2.2.1
diff -u -b -r1.2 -r1.2.2.1
--- tests/libpspp/heap-test.c 26 Jan 2007 03:34:01 -0000 1.2
+++ tests/libpspp/heap-test.c 19 Mar 2007 21:36:25 -0000 1.2.2.1
@@ -79,7 +79,7 @@
int x; /* Primary value. */
};
-int aux_data;
+static int aux_data;
/* Returns the `struct element' that NODE is embedded within. */
static struct element *
Index: tests/libpspp/ll-test.c
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/libpspp/ll-test.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- tests/libpspp/ll-test.c 12 Feb 2007 14:30:23 -0000 1.5
+++ tests/libpspp/ll-test.c 19 Mar 2007 21:36:25 -0000 1.5.2.1
@@ -118,7 +118,7 @@
int y; /* Secondary value. */
};
-int aux_data;
+static int aux_data;
/* Returns the `struct element' that LL is embedded within. */
static struct element *
Index: tests/libpspp/llx-test.c
===================================================================
RCS file: /cvsroot/pspp/pspp/tests/libpspp/llx-test.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -u -b -r1.5 -r1.5.2.1
--- tests/libpspp/llx-test.c 12 Feb 2007 14:30:23 -0000 1.5
+++ tests/libpspp/llx-test.c 19 Mar 2007 21:36:25 -0000 1.5.2.1
@@ -138,7 +138,7 @@
int y; /* Secondary value. */
};
-int aux_data;
+static int aux_data;
/* Prints the elements in LIST. */
static void UNUSED
Index: src/data/buffered-reader.c
===================================================================
RCS file: src/data/buffered-reader.c
diff -N src/data/buffered-reader.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/buffered-reader.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,179 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/buffered-reader.h>
+
+#include <stdlib.h>
+
+#include <data/casereader-private.h>
+#include <libpspp/compiler.h>
+#include <libpspp/heap.h>
+
+#include "xalloc.h"
+
+struct buffered_reader
+ {
+ struct buffered_reader_shared *shared;
+ struct heap_node heap_node;
+ casenumber offset;
+ };
+
+static struct buffered_reader *
+buffered_reader_from_heap_node (const struct heap_node *node)
+{
+ return heap_data (node, struct buffered_reader, heap_node);
+}
+
+struct buffered_reader_shared
+ {
+ struct heap *readers;
+ casenumber min_offset;
+ const struct buffered_reader_class *class;
+ void *aux;
+ };
+
+static struct casereader_class buffered_reader_casereader_class;
+
+static struct buffered_reader *
+make_buffered_reader (struct buffered_reader_shared *shared, casenumber offset)
+{
+ struct buffered_reader *br = xmalloc (sizeof *br);
+ br->offset = offset;
+ br->shared = shared;
+ heap_insert (shared->readers, &br->heap_node);
+ return br;
+}
+
+static int
+compare_buffered_readers_by_offset (const struct heap_node *a_,
+ const struct heap_node *b_,
+ const void *aux UNUSED)
+{
+ const struct buffered_reader *a = buffered_reader_from_heap_node (a_);
+ const struct buffered_reader *b = buffered_reader_from_heap_node (b_);
+ return a->offset < b->offset ? -1 : a->offset > b->offset;
+}
+
+struct casereader *
+buffered_reader_create (size_t value_cnt, casenumber case_cnt,
+ const struct buffered_reader_class *class, void *aux)
+{
+ struct buffered_reader_shared *shared = xmalloc (sizeof *shared);
+ shared->readers = heap_create (compare_buffered_readers_by_offset, NULL);
+ shared->class = class;
+ shared->aux = aux;
+ shared->min_offset = 0;
+ return casereader_create (value_cnt, case_cnt,
+ &buffered_reader_casereader_class,
+ make_buffered_reader (shared, 0));
+}
+
+static void
+advance_buffered_reader (struct buffered_reader_shared *shared)
+{
+ casenumber old_min = shared->min_offset;
+ casenumber new_min
+ = buffered_reader_from_heap_node (heap_minimum (shared->readers))->offset;
+ if (new_min > old_min)
+ {
+ shared->min_offset = new_min;
+ shared->class->advance (shared->aux, new_min - old_min);
+ }
+}
+
+static bool
+buffered_reader_read (struct casereader *reader UNUSED,
+ void *br_, struct ccase *c)
+{
+ struct buffered_reader *br = br_;
+ struct buffered_reader_shared *shared = br->shared;
+
+ if (shared->class->read (shared->aux, br->offset - shared->min_offset, c))
+ {
+ br->offset++;
+ heap_changed (shared->readers, &br->heap_node);
+ advance_buffered_reader (shared);
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool
+buffered_reader_destroy (struct casereader *reader UNUSED, void *br_)
+{
+ struct buffered_reader *br = br_;
+ struct buffered_reader_shared *shared = br->shared;
+ bool ok = !shared->class->error (shared->aux);
+
+ heap_delete (shared->readers, &br->heap_node);
+ if (heap_is_empty (shared->readers))
+ {
+ heap_destroy (shared->readers);
+ if (!shared->class->destroy (shared->aux))
+ ok = false;
+ free (shared);
+ }
+ else
+ advance_buffered_reader (shared);
+
+ free (br);
+ return ok;
+}
+
+static bool
+buffered_reader_error (const struct casereader *reader UNUSED, void *br_)
+{
+ struct buffered_reader *br = br_;
+ struct buffered_reader_shared *shared = br->shared;
+ return shared->class->error (shared->aux);
+}
+
+static struct casereader *
+buffered_reader_clone (struct casereader *reader, void *br_)
+{
+ struct buffered_reader *br = br_;
+ struct buffered_reader_shared *shared = br->shared;
+ return casereader_create (casereader_get_value_cnt (reader),
+ casereader_get_case_cnt (reader),
+ &buffered_reader_casereader_class,
+ make_buffered_reader (shared, br->offset));
+}
+
+static bool
+buffered_reader_peek (struct casereader *reader UNUSED, void *br_,
+ casenumber idx, struct ccase *c)
+{
+ struct buffered_reader *br = br_;
+ struct buffered_reader_shared *shared = br->shared;
+
+ return shared->class->read (shared->aux,
+ br->offset - shared->min_offset + idx, c);
+}
+
+static struct casereader_class buffered_reader_casereader_class =
+ {
+ buffered_reader_read,
+ buffered_reader_destroy,
+ buffered_reader_error,
+ buffered_reader_clone,
+ buffered_reader_peek,
+ };
+
Index: src/data/buffered-reader.h
===================================================================
RCS file: src/data/buffered-reader.h
diff -N src/data/buffered-reader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/buffered-reader.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,36 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_BUFFERED_READER_H
+#define DATA_BUFFERED_READER_H 1
+
+#include <data/casereader.h>
+
+struct buffered_reader_class
+ {
+ bool (*read) (void *aux, casenumber, struct ccase *);
+ bool (*error) (void *aux);
+ bool (*destroy) (void *aux);
+ void (*advance) (void *aux, casenumber);
+ };
+
+struct casereader *
+buffered_reader_create (size_t value_cnt, casenumber case_cnt,
+ const struct buffered_reader_class *, void *aux);
+
+#endif /* data/buffered-reader.h */
Index: src/data/case-tmpfile.c
===================================================================
RCS file: src/data/case-tmpfile.c
diff -N src/data/case-tmpfile.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/case-tmpfile.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,152 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/case-tmpfile.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libpspp/assertion.h>
+
+#include "error.h"
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct case_tmpfile
+ {
+ FILE *file;
+ size_t value_cnt;
+ };
+
+struct case_tmpfile *
+case_tmpfile_create (size_t value_cnt)
+{
+ struct case_tmpfile *ctf = xmalloc (sizeof *ctf);
+ ctf->file = tmpfile ();
+ if (ctf->file == NULL)
+ error (0, errno, _("failed to create temporary file"));
+ ctf->value_cnt = value_cnt;
+ return ctf;
+}
+
+bool
+case_tmpfile_destroy (struct case_tmpfile *ctf)
+{
+ if (ctf != NULL)
+ {
+ bool ok = !case_tmpfile_error (ctf);
+ if (ctf->file != NULL)
+ fclose (ctf->file);
+ free (ctf);
+ return ok;
+ }
+ else
+ return true;
+}
+
+bool
+case_tmpfile_error (const struct case_tmpfile *ctf)
+{
+ return ctf->file == NULL;
+}
+
+#ifndef HAVE_FSEEKO
+#define fseeko fseek
+#endif
+
+#ifndef HAVE_OFF_T
+#define off_t long int
+#endif
+
+static void
+mark_error (struct case_tmpfile *ctf)
+{
+ if (ctf->file != NULL)
+ {
+ fclose (ctf->file);
+ ctf->file = NULL;
+ }
+}
+
+static bool
+seek_to_case (struct case_tmpfile *ctf, casenumber case_idx)
+{
+ if (ctf->file != NULL
+ && fseeko (ctf->file,
+ (off_t) sizeof (union value) * ctf->value_cnt * case_idx,
+ SEEK_SET) == 0)
+ return true;
+
+ if (!case_tmpfile_error (ctf))
+ {
+ error (0, errno, _("seeking in temporary file"));
+ mark_error (ctf);
+ }
+ return false;
+}
+
+bool
+case_tmpfile_get (const struct case_tmpfile *ctf_, casenumber index,
+ struct ccase *c)
+{
+ struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
+ if (seek_to_case (ctf, index))
+ {
+ case_create (c, ctf->value_cnt);
+ if (fread (case_data_all_rw (c), sizeof (union value) * ctf->value_cnt,
+ 1, ctf->file) != 1)
+ {
+ case_destroy (c);
+ mark_error (ctf);
+ if (ferror (ctf->file))
+ error (0, errno, _("reading temporary file"));
+ else if (feof (ctf->file))
+ error (0, 0, _("unexpected end of file reading temporary file"));
+ else
+ NOT_REACHED ();
+ }
+ }
+
+ if (!case_tmpfile_error (ctf))
+ return true;
+ else
+ {
+ case_nullify (c);
+ return false;
+ }
+}
+
+bool
+case_tmpfile_put (struct case_tmpfile *ctf, casenumber index,
+ struct ccase *c)
+{
+ if (seek_to_case (ctf, index)
+ && fwrite (case_data_all (c), sizeof (union value) * ctf->value_cnt,
+ 1, ctf->file) != 1)
+ {
+ mark_error (ctf);
+ error (0, errno, _("writing to temporary file"));
+ }
+ case_destroy (c);
+ return !case_tmpfile_error (ctf);
+}
Index: src/data/case-tmpfile.h
===================================================================
RCS file: src/data/case-tmpfile.h
diff -N src/data/case-tmpfile.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/case-tmpfile.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,33 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASE_TMPFILE_H
+#define DATA_CASE_TMPFILE_H 1
+
+#include <data/case.h>
+
+struct case_tmpfile *case_tmpfile_create (size_t value_cnt);
+bool case_tmpfile_destroy (struct case_tmpfile *);
+bool case_tmpfile_error (const struct case_tmpfile *);
+
+bool case_tmpfile_get (const struct case_tmpfile *, casenumber index,
+ struct ccase *);
+bool case_tmpfile_put (struct case_tmpfile *, casenumber index,
+ struct ccase *);
+
+#endif /* data/case-tmpfile.h */
Index: src/data/casegrouper.c
===================================================================
RCS file: src/data/casegrouper.c
diff -N src/data/casegrouper.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casegrouper.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,183 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casegrouper.h>
+
+#include <stdlib.h>
+
+#include <data/casereader.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <math/ordering.h>
+
+#include "xalloc.h"
+
+struct casegrouper
+ {
+ struct casereader *reader;
+
+ bool (*same_group) (const struct ccase *, const struct ccase *, void *aux);
+ void (*destroy) (void *aux);
+ void *aux;
+ };
+
+struct casegrouper *
+casegrouper_create_func (struct casereader *reader,
+ bool (*same_group) (const struct ccase *,
+ const struct ccase *,
+ void *aux),
+ void (*destroy) (void *aux),
+ void *aux)
+{
+ struct casegrouper *grouper = xmalloc (sizeof *grouper);
+ grouper->reader = casereader_rename (reader);
+ grouper->same_group = same_group;
+ grouper->destroy = destroy;
+ grouper->aux = aux;
+ return grouper;
+}
+
+/* FIXME: we really shouldn't need a temporary casewriter for the
+ common case where we read an entire group's data before going
+ on to the next. */
+bool
+casegrouper_get_next_group (struct casegrouper *grouper,
+ struct casereader **reader)
+{
+ if (grouper->same_group != NULL)
+ {
+ struct casewriter *writer;
+ struct ccase group_case, tmp;
+
+ if (!casereader_read (grouper->reader, &group_case))
+ {
+ *reader = NULL;
+ return false;
+ }
+
+ writer = autopaging_writer_create (casereader_get_value_cnt
(grouper->reader));
+ case_clone (&tmp, &group_case);
+ casewriter_write (writer, &tmp);
+
+ while (casereader_peek (grouper->reader, 0, &tmp)
+ && grouper->same_group (&group_case, &tmp, grouper->aux))
+ {
+ struct ccase discard;
+ casereader_read (grouper->reader, &discard);
+ case_destroy (&discard);
+ casewriter_write (writer, &tmp);
+ }
+ case_destroy (&tmp);
+ case_destroy (&group_case);
+
+ *reader = casewriter_make_reader (writer);
+ return true;
+ }
+ else
+ {
+ if (grouper->reader != NULL)
+ {
+ *reader = grouper->reader;
+ grouper->reader = NULL;
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool
+casegrouper_destroy (struct casegrouper *grouper)
+{
+ bool ok = true;
+ if (grouper != NULL)
+ {
+ ok = casereader_destroy (grouper->reader);
+ if (grouper->destroy != NULL)
+ grouper->destroy (grouper->aux);
+ free (grouper);
+ }
+ return ok;
+}
+
+struct casegrouper_vars
+ {
+ struct variable **vars;
+ size_t var_cnt;
+ };
+
+static bool
+casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b,
+ void *cv_)
+{
+ struct casegrouper_vars *cv = cv_;
+ return case_compare (a, b, cv->vars, cv->var_cnt) == 0;
+}
+
+static void
+casegrouper_vars_destroy (void *cv_)
+{
+ struct casegrouper_vars *cv = cv_;
+ free (cv->vars);
+ free (cv);
+}
+
+struct casegrouper *
+casegrouper_create_vars (struct casereader *reader,
+ struct variable *const *vars,
+ size_t var_cnt)
+{
+ if (var_cnt > 0)
+ {
+ struct casegrouper_vars *cv = xmalloc (sizeof *cv);
+ cv->vars = xmemdup (vars, sizeof *vars * var_cnt);
+ cv->var_cnt = var_cnt;
+ return casegrouper_create_func (reader,
+ casegrouper_vars_same_group,
+ casegrouper_vars_destroy,
+ cv);
+ }
+ else
+ return casegrouper_create_func (reader, NULL, NULL, NULL);
+}
+
+struct casegrouper *
+casegrouper_create_splits (struct casereader *reader,
+ const struct dictionary *dict)
+{
+ return casegrouper_create_vars (reader,
+ dict_get_split_vars (dict),
+ dict_get_split_cnt (dict));
+}
+
+struct casegrouper *
+casegrouper_create_case_ordering (struct casereader *reader,
+ const struct case_ordering *co)
+{
+ struct variable **vars;
+ size_t var_cnt;
+ struct casegrouper *grouper;
+
+ case_ordering_get_vars (co, &vars, &var_cnt);
+ grouper = casegrouper_create_vars (reader, vars, var_cnt);
+ free (vars);
+
+ return grouper;
+}
Index: src/data/casegrouper.h
===================================================================
RCS file: src/data/casegrouper.h
diff -N src/data/casegrouper.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casegrouper.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,48 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEGROUPER_H
+#define DATA_CASEGROUPER_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct case_ordering;
+struct casereader;
+struct ccase;
+struct dictionary;
+struct variable;
+
+struct casegrouper *
+casegrouper_create_func (struct casereader *,
+ bool (*same_group) (const struct ccase *,
+ const struct ccase *,
+ void *aux),
+ void (*destroy) (void *aux),
+ void *aux);
+struct casegrouper *casegrouper_create_vars (struct casereader *,
+ struct variable *const *vars,
+ size_t var_cnt);
+struct casegrouper *casegrouper_create_splits (struct casereader *,
+ const struct dictionary *);
+struct casegrouper *casegrouper_create_case_ordering (struct casereader *,
+ const struct
case_ordering *);
+bool casegrouper_get_next_group (struct casegrouper *, struct casereader **);
+bool casegrouper_destroy (struct casegrouper *);
+
+#endif /* data/casegrouper.h */
Index: src/data/caseinit.c
===================================================================
RCS file: src/data/caseinit.c
diff -N src/data/caseinit.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/caseinit.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,229 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/caseinit.h>
+
+#include <assert.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/compiler.h>
+
+#include "xalloc.h"
+
+struct init_value
+ {
+ union value value;
+ size_t case_index;
+ };
+
+struct init_list
+ {
+ struct init_value *values;
+ size_t cnt;
+ };
+
+enum leave_class
+ {
+ LEAVE_REINIT = 0x001,
+ LEAVE_LEFT = 0x002
+ };
+
+static void
+init_list_create (struct init_list *list)
+{
+ list->values = NULL;
+ list->cnt = 0;
+}
+
+static void
+init_list_clear (struct init_list *list)
+{
+ free (list->values);
+ init_list_create (list);
+}
+
+static void
+init_list_destroy (struct init_list *list)
+{
+ init_list_clear (list);
+}
+
+static int
+compare_init_values (const void *a_, const void *b_, const void *aux UNUSED)
+{
+ const struct init_value *a = a_;
+ const struct init_value *b = b_;
+
+ return a->case_index < b->case_index ? -1 : a->case_index > b->case_index;
+}
+
+static bool
+init_list_includes (const struct init_list *list, size_t case_index)
+{
+ struct init_value value;
+ value.case_index = case_index;
+ return binary_search (list->values, list->cnt, sizeof *list->values,
+ &value, compare_init_values, NULL) != NULL;
+}
+
+static void
+init_list_mark (struct init_list *list, const struct init_list *exclude,
+ enum leave_class include, const struct dictionary *d)
+{
+ size_t var_cnt = dict_get_var_cnt (d);
+ size_t i;
+
+ assert (list != exclude);
+ list->values = xnrealloc (list->values,
+ list->cnt + dict_get_next_value_idx (d),
+ sizeof *list->values);
+ for (i = 0; i < var_cnt; i++)
+ {
+ struct variable *v = dict_get_var (d, i);
+ size_t case_index = var_get_case_index (v);
+ int offset;
+
+ /* Only include the correct class. */
+ if (!(include & (var_get_leave (v) ? LEAVE_LEFT : LEAVE_REINIT)))
+ continue;
+
+ /* Don't include those to be excluded. */
+ if (exclude != NULL && init_list_includes (exclude, case_index))
+ continue;
+
+ offset = 0;
+ do
+ {
+ struct init_value *iv = &list->values[list->cnt++];
+ iv->case_index = case_index++;
+ if (var_is_numeric (v))
+ iv->value.f = var_get_leave (v) ? 0 : SYSMIS;
+ else
+ memset (iv->value.s, ' ', sizeof iv->value.s);
+
+ offset += sizeof iv->value.s;
+ }
+ while (offset < var_get_width (v));
+ }
+
+ /* Drop duplicates. */
+ list->cnt = sort_unique (list->values, list->cnt, sizeof *list->values,
+ compare_init_values, NULL);
+
+}
+
+static void
+init_list_init (const struct init_list *list, struct ccase *c)
+{
+ size_t i;
+
+ for (i = 0; i < list->cnt; i++)
+ {
+ const struct init_value *value = &list->values[i];
+ *case_data_rw_idx (c, value->case_index) = value->value;
+ }
+}
+
+static void
+init_list_update (const struct init_list *list, const struct ccase *c)
+{
+ size_t i;
+
+ for (i = 0; i < list->cnt; i++)
+ {
+ struct init_value *value = &list->values[i];
+ value->value = *case_data_idx (c, value->case_index);
+ }
+}
+
+struct caseinit
+ {
+ struct init_list preinited_values;
+ struct init_list reinit_values;
+ struct init_list left_values;
+ };
+
+struct caseinit *
+caseinit_create (void)
+{
+ struct caseinit *ci = xmalloc (sizeof *ci);
+ init_list_create (&ci->preinited_values);
+ init_list_create (&ci->reinit_values);
+ init_list_create (&ci->left_values);
+ return ci;
+}
+
+void
+caseinit_clear (struct caseinit *ci)
+{
+ init_list_clear (&ci->preinited_values);
+ init_list_clear (&ci->reinit_values);
+ init_list_clear (&ci->left_values);
+}
+
+void
+caseinit_destroy (struct caseinit *ci)
+{
+ if (ci != NULL)
+ {
+ init_list_destroy (&ci->preinited_values);
+ init_list_destroy (&ci->reinit_values);
+ init_list_destroy (&ci->left_values);
+ free (ci);
+ }
+}
+
+void
+caseinit_mark_as_preinited (struct caseinit *ci, const struct dictionary *d)
+{
+ init_list_mark (&ci->preinited_values, NULL, LEAVE_REINIT | LEAVE_LEFT, d);
+}
+
+void
+caseinit_mark_for_init (struct caseinit *ci, const struct dictionary *d)
+{
+ init_list_mark (&ci->reinit_values, &ci->preinited_values, LEAVE_REINIT, d);
+ init_list_mark (&ci->left_values, &ci->preinited_values, LEAVE_LEFT, d);
+}
+
+void
+caseinit_init_reinit_vars (const struct caseinit *ci, struct ccase *c)
+{
+ init_list_init (&ci->reinit_values, c);
+}
+
+void caseinit_init_left_vars (const struct caseinit *ci, struct ccase *c)
+{
+ init_list_init (&ci->left_values, c);
+}
+
+void
+caseinit_update_left_vars (struct caseinit *ci, const struct ccase *c)
+{
+ init_list_update (&ci->left_values, c);
+}
+
Index: src/data/caseinit.h
===================================================================
RCS file: src/data/caseinit.h
diff -N src/data/caseinit.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/caseinit.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,36 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEINIT_H
+#define DATA_CASEINIT_H 1
+
+struct dictionary;
+struct ccase;
+
+struct caseinit *caseinit_create (void);
+void caseinit_clear (struct caseinit *);
+void caseinit_destroy (struct caseinit *);
+
+void caseinit_mark_as_preinited (struct caseinit *, const struct dictionary *);
+void caseinit_mark_for_init (struct caseinit *, const struct dictionary *);
+
+void caseinit_init_reinit_vars (const struct caseinit *, struct ccase *);
+void caseinit_init_left_vars (const struct caseinit *, struct ccase *);
+void caseinit_update_left_vars (struct caseinit *, const struct ccase *);
+
+#endif /* data/case-initializer.h */
Index: src/data/casereader-private.h
===================================================================
RCS file: src/data/casereader-private.h
diff -N src/data/casereader-private.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casereader-private.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,49 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEREADER_PRIVATE_H
+#define DATA_CASEREADER_PRIVATE_H 1
+
+#include <data/casereader.h>
+
+/* This header file should really be renamed: it's not really
+ private. */
+
+struct casereader_class
+ {
+ /* Mandatory. */
+ bool (*read) (struct casereader *, void *aux, struct ccase *);
+ bool (*destroy) (struct casereader *, void *aux);
+
+ /* Need only be supplied if reads can fail. */
+ bool (*error) (const struct casereader *, void *aux);
+
+ /* Optional. If convenient and efficiently implementable,
+ supply as an optimization for use by casereader_clone. */
+ struct casereader *(*clone) (struct casereader *, void *aux);
+
+ /* Optional. If convenient and efficiently implementable,
+ supply as an optimization for use by casereader_peek. */
+ bool (*peek) (struct casereader *, void *aux, casenumber idx,
+ struct ccase *);
+ };
+
+struct casereader *casereader_create (size_t value_cnt, casenumber case_cnt,
+ const struct casereader_class *, void *);
+
+#endif /* data/casereader-private.h */
Index: src/data/casereader.c
===================================================================
RCS file: src/data/casereader.c
diff -N src/data/casereader.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casereader.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,532 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casereader.h>
+#include <data/casereader-private.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <data/buffered-reader.h>
+#include <data/casewindow.h>
+#include <data/casewriter.h>
+#include <data/dictionary.h>
+#include <data/settings.h>
+#include <data/variable.h>
+#include <libpspp/message.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct casereader
+ {
+ bool eof;
+ size_t value_cnt;
+ casenumber case_cnt;
+ //casenumber next_case_idx;
+ const struct casereader_class *class;
+ void *aux;
+ };
+
+static void insert_casereader_buffer (struct casereader *);
+
+struct casereader *
+casereader_rename (struct casereader *old)
+{
+ struct casereader *new = xmalloc (sizeof *old);
+ *new = *old;
+ free (old);
+ return new;
+}
+
+struct casereader *
+casereader_create (size_t value_cnt, casenumber case_cnt,
+ const struct casereader_class *class, void *aux)
+{
+ struct casereader *reader = xmalloc (sizeof *reader);
+ assert (class->destroy != NULL);
+ reader->eof = false;
+ reader->value_cnt = value_cnt;
+ reader->case_cnt = case_cnt;
+ reader->class = class;
+ reader->aux = aux;
+ return reader;
+}
+
+struct casereader *
+casereader_clone (const struct casereader *reader_)
+{
+ struct casereader *reader = (struct casereader *) reader_;
+ struct casereader *clone;
+
+ if (reader->class->clone == NULL)
+ insert_casereader_buffer (reader);
+ clone = reader->class->clone (reader, reader->aux);
+ assert (clone != NULL);
+ assert (clone != reader);
+ return clone;
+}
+
+static void
+casereader_swap (struct casereader *a, struct casereader *b)
+{
+ if (a != b)
+ {
+ struct casereader tmp = *a;
+ *a = *b;
+ *b = tmp;
+ }
+}
+
+void
+casereader_split (struct casereader *original,
+ struct casereader **new1, struct casereader **new2)
+{
+ if (new1 != NULL && new2 != NULL)
+ {
+ *new1 = casereader_rename (original);
+ *new2 = casereader_clone (*new1);
+ }
+ else if (new1 != NULL)
+ *new1 = casereader_rename (original);
+ else if (new2 != NULL)
+ *new2 = casereader_rename (original);
+ else
+ casereader_destroy (original);
+}
+
+bool
+casereader_destroy (struct casereader *reader)
+{
+ bool ok = true;
+ if (reader != NULL)
+ {
+ ok = reader->class->destroy (reader, reader->aux);
+ free (reader);
+ }
+ return ok;
+}
+
+bool
+casereader_read (struct casereader *reader, struct ccase *c)
+{
+ // FIXME: adjust case_cnt
+ if (!reader->eof && reader->class->read (reader, reader->aux, c))
+ {
+ //assert (case_get_value_cnt (c) == reader->value_cnt);
+ return true;
+ }
+ else
+ {
+ reader->eof = true;
+ case_nullify (c);
+ return false;
+ }
+}
+
+bool
+casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c)
+{
+ if (reader->class->peek == NULL)
+ insert_casereader_buffer (reader);
+ return reader->class->peek (reader, reader->aux, idx, c);
+}
+
+bool
+casereader_error (const struct casereader *reader)
+{
+ if (reader->class->error != NULL)
+ return reader->class->error (reader, reader->aux);
+ else
+ return false;
+}
+
+casenumber
+casereader_get_case_cnt (struct casereader *reader)
+{
+ return reader->case_cnt;
+}
+
+size_t
+casereader_get_value_cnt (struct casereader *reader)
+{
+ return reader->value_cnt;
+}
+
+struct casereader_filter
+ {
+ struct casereader *subreader;
+ bool (*include) (const struct ccase *, void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ struct casewriter *exclude;
+ };
+
+static struct casereader_class casereader_filter_class;
+
+struct casereader *
+casereader_create_filter_func (struct casereader *subreader,
+ bool (*include) (const struct ccase *,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux,
+ struct casewriter *exclude)
+{
+ struct casereader_filter *filter = xmalloc (sizeof *filter);
+ filter->subreader = casereader_rename (subreader);
+ filter->include = include;
+ filter->destroy = destroy;
+ filter->aux = aux;
+ filter->exclude = exclude;
+ return casereader_create (casereader_get_value_cnt (filter->subreader),
+ CASENUMBER_INVALID,
+ &casereader_filter_class, filter);
+}
+
+static bool
+casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
+ struct ccase *c)
+
+{
+ struct casereader_filter *filter = filter_;
+ for (;;)
+ {
+ if (!casereader_read (filter->subreader, c))
+ return false;
+ else if (filter->include (c, filter->aux))
+ return true;
+ else if (filter->exclude != NULL)
+ casewriter_write (filter->exclude, c);
+ else
+ case_destroy (c);
+ }
+}
+
+static bool
+casereader_filter_destroy (struct casereader *reader UNUSED, void *filter_)
+{
+ struct casereader_filter *filter = filter_;
+ bool ok = casereader_destroy (filter->subreader);
+ if (filter->destroy != NULL)
+ ok = filter->destroy (filter->aux) && ok;
+ free (filter);
+ return ok;
+}
+
+static bool
+casereader_filter_error (const struct casereader *reader UNUSED,
+ void *filter_)
+{
+ struct casereader_filter *filter = filter_;
+ return casereader_error (filter->subreader);
+}
+
+static struct casereader_class casereader_filter_class =
+ {
+ casereader_filter_read,
+ casereader_filter_destroy,
+ casereader_filter_error,
+
+ /* We could in fact delegate clone to the subreader, if the
+ filter function is required to have no memory and if we
+ added reference counting. But it might be useful to have
+ filter functions with memory and in any case this would
+ require a little extra work. */
+ NULL,
+ };
+
+struct casereader_filter_weight
+ {
+ const struct variable *weight_var;
+ bool *warn_on_invalid;
+ bool local_warn_on_invalid;
+ };
+
+static bool
+casereader_filter_weight_include (const struct ccase *c, void *cfw_)
+{
+ struct casereader_filter_weight *cfw = cfw_;
+ double value = case_num (c, cfw->weight_var);
+ if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
+ return true;
+ else
+ {
+ if (*cfw->warn_on_invalid)
+ {
+ msg (SW, _("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."));
+ *cfw->warn_on_invalid = false;
+ }
+ return false;
+ }
+}
+
+static bool
+casereader_filter_weight_destroy (void *cfw_)
+{
+ struct casereader_filter_weight *cfw = cfw_;
+ free (cfw);
+ return true;
+}
+
+struct casereader *
+casereader_create_filter_weight (struct casereader *reader,
+ const struct dictionary *dict,
+ bool *warn_on_invalid,
+ struct casewriter *exclude)
+{
+ struct variable *weight_var = dict_get_weight (dict);
+ if (weight_var != NULL)
+ {
+ struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
+ cfw->weight_var = weight_var;
+ cfw->warn_on_invalid = (warn_on_invalid
+ ? warn_on_invalid
+ : &cfw->local_warn_on_invalid);
+ cfw->local_warn_on_invalid = true;
+ reader = casereader_create_filter_func (reader,
+ casereader_filter_weight_include,
+ casereader_filter_weight_destroy,
+ cfw, exclude);
+ }
+ else
+ reader = casereader_rename (reader);
+ return reader;
+}
+
+struct casereader_filter_missing
+ {
+ struct variable **vars;
+ size_t var_cnt;
+ enum mv_class class;
+ };
+
+static bool
+casereader_filter_missing_include (const struct ccase *c, void *cfm_)
+{
+ const struct casereader_filter_missing *cfm = cfm_;
+ size_t i;
+
+ for (i = 0; i < cfm->var_cnt; i++)
+ {
+ struct variable *var = cfm->vars[i];
+ const union value *value = case_data (c, var);
+ if (var_is_value_missing (var, value, cfm->class))
+ return false;
+ }
+ return true;
+}
+
+static bool
+casereader_filter_missing_destroy (void *cfm_)
+{
+ struct casereader_filter_missing *cfm = cfm_;
+ free (cfm->vars);
+ free (cfm);
+ return true;
+}
+
+struct casereader *
+casereader_create_filter_missing (struct casereader *reader,
+ struct variable **vars, size_t var_cnt,
+ enum mv_class class,
+ struct casewriter *exclude)
+{
+ if (var_cnt > 0 && class != MV_NEVER)
+ {
+ struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
+ cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
+ cfm->var_cnt = var_cnt;
+ cfm->class = class;
+ return casereader_create_filter_func (reader,
+ casereader_filter_missing_include,
+ casereader_filter_missing_destroy,
+ cfm,
+ exclude);
+ }
+ else
+ return casereader_rename (reader);
+}
+
+struct casereader_buffer
+ {
+ struct casewindow *window;
+ struct casereader *subreader;
+ };
+
+static struct buffered_reader_class casereader_buffer_class;
+
+static void
+insert_casereader_buffer (struct casereader *reader)
+{
+ size_t value_cnt = casereader_get_value_cnt (reader);
+ casenumber case_cnt = casereader_get_case_cnt (reader);
+ struct casereader_buffer *b = xmalloc (sizeof *b);
+ b->window = casewindow_create (value_cnt, get_workspace_cases (value_cnt));
+ b->subreader = buffered_reader_create (value_cnt, case_cnt,
+ &casereader_buffer_class, b);
+ casereader_swap (reader, b->subreader);
+}
+
+static bool
+prime_casereader_buffer (struct casereader_buffer *b, casenumber case_cnt)
+{
+ while (casewindow_get_case_cnt (b->window) < case_cnt)
+ {
+ struct ccase tmp;
+ if (!casereader_read (b->subreader, &tmp))
+ return false;
+ casewindow_push_head (b->window, &tmp);
+ }
+ return true;
+}
+
+static bool
+casereader_buffer_read (void *b_, casenumber offset, struct ccase *c)
+{
+ struct casereader_buffer *b = b_;
+ return (prime_casereader_buffer (b, offset + 1)
+ && casewindow_get_case (b->window, offset, c));
+}
+
+static bool
+casereader_buffer_error (void *b_)
+{
+ struct casereader_buffer *b = b_;
+ return casewindow_error (b->window) || casereader_error (b->subreader);
+}
+
+static bool
+casereader_buffer_destroy (void *b_)
+{
+ struct casereader_buffer *b = b_;
+ bool ok = !casereader_error (b->subreader);
+ ok = casewindow_destroy (b->window) && ok;
+ ok = casereader_destroy (b->subreader) && ok;
+ free (b);
+ return ok;
+}
+
+static void
+casereader_buffer_advance (void *b_, casenumber cnt)
+{
+ struct casereader_buffer *b = b_;
+ casewindow_pop_tail (b->window, cnt);
+}
+
+static struct buffered_reader_class casereader_buffer_class =
+ {
+ casereader_buffer_read,
+ casereader_buffer_error,
+ casereader_buffer_destroy,
+ casereader_buffer_advance,
+ };
+
+static bool
+casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
+{
+ casenumber *counter = counter_;
+ ++*counter;
+ return true;
+}
+
+struct casereader *
+casereader_create_counter (struct casereader *reader, casenumber *counter,
+ casenumber initial_value)
+{
+ *counter = initial_value;
+ return casereader_create_filter_func (reader, casereader_counter_include,
+ NULL, counter, NULL);
+}
+
+struct casereader_translator
+ {
+ struct casereader *subreader;
+
+ void (*translate) (const struct ccase *input, struct ccase *output,
+ void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ };
+
+static struct casereader_class casereader_translator_class;
+
+struct casereader *
+casereader_create_translator (struct casereader *reader,
+ size_t output_value_cnt,
+ void (*translate) (const struct ccase *input,
+ struct ccase *output,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux)
+{
+ struct casereader_translator *ct = xmalloc (sizeof *ct);
+ ct->subreader = casereader_rename (reader);
+ ct->translate = translate;
+ ct->destroy = destroy;
+ ct->aux = aux;
+ return casereader_create (output_value_cnt,
+ casereader_get_case_cnt (ct->subreader),
+ &casereader_translator_class, ct);
+}
+
+static bool
+casereader_translator_read (struct casereader *reader UNUSED,
+ void *ct_, struct ccase *c)
+{
+ struct casereader_translator *ct = ct_;
+ struct ccase tmp;
+
+ if (casereader_read (ct->subreader, &tmp))
+ {
+ ct->translate (&tmp, c, ct->aux);
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool
+casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
+{
+ struct casereader_translator *ct = ct_;
+ bool ok = casereader_destroy (ct->subreader);
+ ct->destroy (ct->aux);
+ free (ct);
+ return ok;
+}
+
+static bool
+casereader_translator_error (const struct casereader *reader UNUSED, void *ct_)
+{
+ struct casereader_translator *ct = ct_;
+
+ return casereader_error (ct->subreader);
+}
+
+static struct casereader_class casereader_translator_class =
+ {
+ casereader_translator_read,
+ casereader_translator_destroy,
+ casereader_translator_error,
+ };
Index: src/data/casereader.h
===================================================================
RCS file: src/data/casereader.h
diff -N src/data/casereader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casereader.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,73 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEREADER_H
+#define DATA_CASEREADER_H 1
+
+#include <data/case.h>
+#include <data/missing-values.h>
+
+struct dictionary;
+struct casereader;
+struct casewriter;
+
+bool casereader_read (struct casereader *, struct ccase *);
+bool casereader_destroy (struct casereader *);
+
+struct casereader *casereader_clone (const struct casereader *);
+void casereader_split (struct casereader *,
+ struct casereader **, struct casereader **);
+struct casereader *casereader_rename (struct casereader *);
+
+bool casereader_peek (struct casereader *, casenumber, struct ccase *);
+bool casereader_error (const struct casereader *);
+
+casenumber casereader_get_case_cnt (struct casereader *);
+size_t casereader_get_value_cnt (struct casereader *);
+
+struct casereader *
+casereader_create_filter_func (struct casereader *,
+ bool (*include) (const struct ccase *,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux,
+ struct casewriter *exclude);
+struct casereader *
+casereader_create_filter_weight (struct casereader *,
+ const struct dictionary *dict,
+ bool *warn_on_invalid,
+ struct casewriter *exclude);
+struct casereader *
+casereader_create_filter_missing (struct casereader *,
+ struct variable **vars, size_t var_cnt,
+ enum mv_class,
+ struct casewriter *exclude);
+
+struct casereader *
+casereader_create_counter (struct casereader *, casenumber *counter,
+ casenumber initial_value);
+
+struct casereader *
+casereader_create_translator (struct casereader *, size_t output_value_cnt,
+ void (*translate) (const struct ccase *input,
+ struct ccase *output,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux);
+
+#endif /* data/casereader.h */
Index: src/data/casewindow.c
===================================================================
RCS file: src/data/casewindow.c
diff -N src/data/casewindow.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casewindow.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,297 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casedeque.h>
+#include <data/casewindow.h>
+#include <data/case-tmpfile.h>
+
+#include "xalloc.h"
+
+struct casewindow
+ {
+ const struct casewindow_class *class;
+ void *aux;
+
+ size_t value_cnt;
+ casenumber max_in_core_cases;
+ bool ok;
+ };
+
+struct casewindow_class
+ {
+ void *(*create) (size_t value_cnt);
+ bool (*destroy) (void *aux);
+ bool (*push_head) (void *aux, struct ccase *);
+ bool (*pop_tail) (void *aux, casenumber cnt);
+ bool (*get_case) (void *aux, casenumber ofs, struct ccase *);
+ casenumber (*get_case_cnt) (const void *aux);
+ };
+
+static const struct casewindow_class casewindow_memory_class;
+static const struct casewindow_class casewindow_file_class;
+
+struct casewindow *
+casewindow_create (size_t value_cnt, casenumber max_in_core_cases)
+{
+ struct casewindow *cw = xmalloc (sizeof *cw);
+ cw->class = (max_in_core_cases
+ ? &casewindow_memory_class
+ : &casewindow_file_class);
+ cw->aux = cw->class->create (value_cnt);
+ cw->value_cnt = value_cnt;
+ cw->max_in_core_cases = max_in_core_cases;
+ cw->ok = true;
+ return cw;
+}
+
+bool
+casewindow_destroy (struct casewindow *cw)
+{
+ bool ok = true;
+ if (cw != NULL)
+ {
+ ok = cw->class->destroy (cw->aux);
+ free (cw);
+ }
+ return ok;
+}
+
+static void
+casewindow_swap (struct casewindow *a, struct casewindow *b)
+{
+ struct casewindow tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static void
+casewindow_to_disk (struct casewindow *old)
+{
+ struct casewindow *new = casewindow_create (old->value_cnt, 0);
+ while (casewindow_get_case_cnt (old) > 0 && !casewindow_error (old))
+ {
+ struct ccase c;
+ if (!casewindow_get_case (old, 0, &c))
+ break;
+ casewindow_pop_tail (old, 1);
+ casewindow_push_head (new, &c);
+ }
+ if (casewindow_error (old))
+ new->ok = false;
+ casewindow_swap (old, new);
+ casewindow_destroy (new);
+}
+
+void
+casewindow_push_head (struct casewindow *cw, struct ccase *c)
+{
+ if (cw->ok)
+ {
+ if (cw->class->push_head (cw->aux, c))
+ {
+ casenumber case_cnt = cw->class->get_case_cnt (cw->aux);
+ if (case_cnt > cw->max_in_core_cases
+ && cw->class == &casewindow_memory_class)
+ casewindow_to_disk (cw);
+ }
+ else
+ cw->ok = false;
+ }
+ else
+ case_destroy (c);
+}
+
+void
+casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt)
+{
+ if (cw->ok)
+ cw->ok = cw->class->pop_tail (cw->aux, case_cnt);
+}
+
+bool
+casewindow_get_case (const struct casewindow *cw_, casenumber case_idx,
+ struct ccase *c)
+{
+ struct casewindow *cw = (struct casewindow *) cw_;
+
+ assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
+ if (cw->ok && cw->class->get_case (cw->aux, case_idx, c))
+ return true;
+ else
+ {
+ cw->ok = false;
+ case_nullify (c);
+ return false;
+ }
+}
+
+casenumber
+casewindow_get_case_cnt (const struct casewindow *cw)
+{
+ return cw->class->get_case_cnt (cw->aux);
+}
+
+size_t
+casewindow_get_value_cnt (const struct casewindow *cw)
+{
+ return cw->value_cnt;
+}
+
+bool
+casewindow_error (const struct casewindow *cw)
+{
+ return !cw->ok;
+}
+
+static void *
+casewindow_memory_create (size_t value_cnt UNUSED)
+{
+ struct casedeque *deque = xmalloc (sizeof *deque);
+ casedeque_init (deque, 4);
+ return deque;
+}
+
+static bool
+casewindow_memory_destroy (void *deque_)
+{
+ struct casedeque *deque = deque_;
+ while (!casedeque_is_empty (deque))
+ case_destroy (casedeque_pop_front (deque));
+ casedeque_destroy (deque);
+ free (deque);
+ return true;
+}
+
+static bool
+casewindow_memory_push_head (void *deque_, struct ccase *c)
+{
+ struct casedeque *deque = deque_;
+ if (casedeque_is_full (deque))
+ casedeque_expand (deque);
+ case_move (casedeque_push_back (deque), c);
+ return true;
+}
+
+static bool
+casewindow_memory_pop_tail (void *deque_, casenumber case_cnt)
+{
+ struct casedeque *deque = deque_;
+ assert (casedeque_count (deque) >= case_cnt);
+ while (case_cnt-- > 0)
+ case_destroy (casedeque_pop_front (deque));
+ return true;
+}
+
+static bool
+casewindow_memory_get_case (void *deque_, casenumber ofs, struct ccase *c)
+{
+ struct casedeque *deque = deque_;
+ case_clone (c, casedeque_front (deque, ofs));
+ return true;
+}
+
+static casenumber
+casewindow_memory_get_case_cnt (const void *deque_)
+{
+ const struct casedeque *deque = deque_;
+ return casedeque_count (deque);
+}
+
+static const struct casewindow_class casewindow_memory_class =
+ {
+ casewindow_memory_create,
+ casewindow_memory_destroy,
+ casewindow_memory_push_head,
+ casewindow_memory_pop_tail,
+ casewindow_memory_get_case,
+ casewindow_memory_get_case_cnt,
+ };
+
+struct casewindow_file
+ {
+ struct case_tmpfile *file;
+ casenumber head, tail;
+ };
+
+static void *
+casewindow_file_create (size_t value_cnt)
+{
+ struct casewindow_file *cwf = xmalloc (sizeof *cwf);
+ cwf->file = case_tmpfile_create (value_cnt);
+ cwf->head = cwf->tail = 0;
+ return cwf;
+}
+
+static bool
+casewindow_file_destroy (void *cwf_)
+{
+ struct casewindow_file *cwf = cwf_;
+ bool ok = case_tmpfile_destroy (cwf->file);
+ free (cwf);
+ return ok;
+}
+
+static bool
+casewindow_file_push_head (void *cwf_, struct ccase *c)
+{
+ struct casewindow_file *cwf = cwf_;
+ if (case_tmpfile_put (cwf->file, cwf->head, c))
+ {
+ cwf->head++;
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool
+casewindow_file_pop_tail (void *cwf_, casenumber cnt)
+{
+ struct casewindow_file *cwf = cwf_;
+ assert (cnt <= cwf->head - cwf->tail);
+ cwf->tail += cnt;
+ if (cwf->head == cwf->tail)
+ cwf->head = cwf->tail = 0;
+ return true;
+}
+
+static bool
+casewindow_file_get_case (void *cwf_, casenumber ofs, struct ccase *c)
+{
+ struct casewindow_file *cwf = cwf_;
+ return case_tmpfile_get (cwf->file, cwf->tail + ofs, c);
+}
+
+static casenumber
+casewindow_file_get_case_cnt (const void *cwf_)
+{
+ const struct casewindow_file *cwf = cwf_;
+ return cwf->head - cwf->tail;
+}
+
+static const struct casewindow_class casewindow_file_class =
+ {
+ casewindow_file_create,
+ casewindow_file_destroy,
+ casewindow_file_push_head,
+ casewindow_file_pop_tail,
+ casewindow_file_get_case,
+ casewindow_file_get_case_cnt,
+ };
Index: src/data/casewindow.h
===================================================================
RCS file: src/data/casewindow.h
diff -N src/data/casewindow.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casewindow.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,37 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEWINDOW_H
+#define DATA_CASEWINDOW_H 1
+
+#include <stddef.h>
+#include <data/case.h>
+
+struct casewindow *casewindow_create (size_t value_cnt,
+ casenumber max_in_core_cases);
+bool casewindow_destroy (struct casewindow *);
+
+void casewindow_push_head (struct casewindow *, struct ccase *);
+void casewindow_pop_tail (struct casewindow *, casenumber cnt);
+bool casewindow_get_case (const struct casewindow *, casenumber case_idx,
+ struct ccase *);
+size_t casewindow_get_value_cnt (const struct casewindow *);
+casenumber casewindow_get_case_cnt (const struct casewindow *);
+bool casewindow_error (const struct casewindow *);
+
+#endif /* data/casewindow.h */
Index: src/data/casewriter-private.h
===================================================================
RCS file: src/data/casewriter-private.h
diff -N src/data/casewriter-private.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casewriter-private.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,38 @@
+/* PSPP - computes sample statistics.
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEWRITER_PRIVATE_H
+#define DATA_CASEWRITER_PRIVATE_H 1
+
+#include <data/casewriter.h>
+
+struct casewriter_class
+ {
+ /* Mandatory. */
+ /* Ownership of the case is transferred to the callee. */
+ void (*write) (struct casewriter *, void *aux, struct ccase *);
+ bool (*destroy) (struct casewriter *, void *aux);
+
+ /* Optional. */
+ bool (*error) (const struct casewriter *, void *aux);
+ struct casereader *(*convert_to_reader) (struct casewriter *, void *aux);
+ };
+
+struct casewriter *casewriter_create (const struct casewriter_class *, void *);
+
+#endif /* data/casewriter-private.h */
Index: src/data/casewriter.c
===================================================================
RCS file: src/data/casewriter.c
diff -N src/data/casewriter.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casewriter.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,278 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casewriter.h>
+#include <data/casewriter-private.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <data/buffered-reader.h>
+#include <data/casereader.h>
+#include <data/casereader-private.h>
+#include <data/casewindow.h>
+#include <data/settings.h>
+#include <libpspp/compiler.h>
+
+#include "xalloc.h"
+
+struct casewriter
+ {
+ casenumber case_cnt;
+ const struct casewriter_class *class;
+ void *private;
+ };
+
+struct casewriter *
+casewriter_create (const struct casewriter_class *class, void *private)
+{
+ struct casewriter *writer = xmalloc (sizeof *writer);
+ writer->case_cnt = 0;
+ writer->class = class;
+ writer->private = private;
+ return writer;
+}
+
+struct casewriter *
+casewriter_rename (struct casewriter *old)
+{
+ struct casewriter *new = xmalloc (sizeof *old);
+ *new = *old;
+ free (old);
+ return new;
+}
+
+void
+casewriter_write (struct casewriter *writer, struct ccase *c)
+{
+ writer->class->write (writer, writer->private, c);
+}
+
+bool
+casewriter_error (const struct casewriter *writer)
+{
+ if (writer->class->error != NULL)
+ return writer->class->error (writer, writer->private);
+ else
+ return false;
+}
+
+bool
+casewriter_destroy (struct casewriter *writer)
+{
+ bool ok = true;
+ if (writer != NULL)
+ {
+ ok = writer->class->destroy (writer, writer->private);
+ free (writer);
+ }
+ return ok;
+}
+
+struct casereader *
+casewriter_make_reader (struct casewriter *writer)
+{
+ return writer->class->convert_to_reader (writer, writer->private);
+}
+
+void
+casewriter_transfer (struct casewriter *dst, struct casewriter *src)
+{
+ struct casereader *src_reader;
+ struct ccase c;
+
+ /* FIXME: error propagation? */
+ src_reader = casewriter_make_reader (src);
+ while (casereader_read (src_reader, &c))
+ casewriter_write (dst, &c);
+ casewriter_destroy (src);
+}
+
+static const struct casewriter_class casewriter_window_class;
+static const struct buffered_reader_class casereader_window_class;
+
+static struct casewriter *
+create_casewriter_window (size_t value_cnt, casenumber max_in_core_cases)
+{
+ return casewriter_create (&casewriter_window_class,
+ casewindow_create (value_cnt, max_in_core_cases));
+}
+
+struct casewriter *
+mem_writer_create (size_t value_cnt)
+{
+ return create_casewriter_window (value_cnt, CASENUMBER_MAX);
+}
+
+struct casewriter *
+tmpfile_writer_create (size_t value_cnt)
+{
+ return create_casewriter_window (value_cnt, 0);
+}
+
+struct casewriter *
+autopaging_writer_create (size_t value_cnt)
+{
+ return create_casewriter_window (value_cnt, get_workspace_cases (value_cnt));
+}
+
+static void
+casewriter_window_write (struct casewriter *writer UNUSED, void *window_,
+ struct ccase *c)
+{
+ struct casewindow *window = window_;
+ casewindow_push_head (window, c);
+}
+
+static bool
+casewriter_window_destroy (struct casewriter *writer UNUSED, void *window_)
+{
+ struct casewindow *window = window_;
+ return casewindow_destroy (window);
+}
+
+static bool
+casewriter_window_error (const struct casewriter *writer UNUSED,
+ void *window_)
+{
+ struct casewindow *window = window_;
+ return casewindow_error (window);
+}
+
+static struct casereader *
+casewriter_window_convert_to_reader (struct casewriter *writer UNUSED,
+ void *window_)
+{
+ struct casewindow *window = window_;
+ return buffered_reader_create (casewindow_get_value_cnt (window),
+ casewindow_get_case_cnt (window),
+ &casereader_window_class, window);
+}
+
+static bool
+casereader_window_read (void *window_, casenumber case_idx, struct ccase *c)
+{
+ struct casewindow *window = window_;
+ if (case_idx >= casewindow_get_case_cnt (window))
+ return false;
+ else
+ return casewindow_get_case (window, case_idx, c);
+}
+
+static bool
+casereader_window_error (void *window_)
+{
+ struct casewindow *window = window_;
+ return casewindow_error (window);
+}
+
+static bool
+casereader_window_destroy (void *window_)
+{
+ struct casewindow *window = window_;
+ return casewindow_destroy (window);
+}
+
+static void
+casereader_window_advance (void *window_, casenumber case_cnt)
+{
+ struct casewindow *window = window_;
+ casewindow_pop_tail (window, case_cnt);
+}
+
+static const struct casewriter_class casewriter_window_class =
+ {
+ casewriter_window_write,
+ casewriter_window_destroy,
+ casewriter_window_error,
+ casewriter_window_convert_to_reader,
+ };
+
+static const struct buffered_reader_class casereader_window_class =
+ {
+ casereader_window_read,
+ casereader_window_error,
+ casereader_window_destroy,
+ casereader_window_advance,
+ };
+
+struct casewriter_translator
+ {
+ struct casewriter *subwriter;
+
+ void (*translate) (const struct ccase *input, struct ccase *output,
+ void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ };
+
+static struct casewriter_class casewriter_translator_class;
+
+struct casewriter *
+casewriter_create_translator (struct casewriter *writer,
+ void (*translate) (const struct ccase *input,
+ struct ccase *output,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux)
+{
+ struct casewriter_translator *ct = xmalloc (sizeof *ct);
+ ct->subwriter = casewriter_rename (writer);
+ ct->translate = translate;
+ ct->destroy = destroy;
+ ct->aux = aux;
+ return casewriter_create (&casewriter_translator_class, ct);
+}
+
+static void
+casewriter_translator_write (struct casewriter *writer UNUSED,
+ void *ct_, struct ccase *c)
+{
+ struct casewriter_translator *ct = ct_;
+ struct ccase tmp;
+
+ ct->translate (c, &tmp, ct->aux);
+ casewriter_write (ct->subwriter, &tmp);
+}
+
+static bool
+casewriter_translator_destroy (struct casewriter *writer UNUSED, void *ct_)
+{
+ struct casewriter_translator *ct = ct_;
+ bool ok = casewriter_destroy (ct->subwriter);
+ ct->destroy (ct->aux);
+ free (ct);
+ return ok;
+}
+
+static bool
+casewriter_translator_error (const struct casewriter *writer UNUSED, void *ct_)
+{
+ struct casewriter_translator *ct = ct_;
+
+ return casewriter_error (ct->subwriter);
+}
+
+static struct casewriter_class casewriter_translator_class =
+ {
+ casewriter_translator_write,
+ casewriter_translator_destroy,
+ casewriter_translator_error,
+ };
Index: src/data/casewriter.h
===================================================================
RCS file: src/data/casewriter.h
diff -N src/data/casewriter.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/casewriter.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,49 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_CASEWRITER_H
+#define DATA_CASEWRITER_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <data/transformations.h>
+
+struct casewriter;
+
+struct casewriter *mem_writer_create (size_t value_cnt);
+struct casewriter *tmpfile_writer_create (size_t value_cnt);
+struct casewriter *autopaging_writer_create (size_t value_cnt);
+
+struct casewriter *casewriter_rename (struct casewriter *);
+
+void casewriter_write (struct casewriter *, struct ccase *);
+bool casewriter_destroy (struct casewriter *);
+
+bool casewriter_error (const struct casewriter *);
+struct casereader *casewriter_make_reader (struct casewriter *);
+void casewriter_transfer (struct casewriter *, struct casewriter *);
+
+struct casewriter *
+casewriter_create_translator (struct casewriter *,
+ void (*translate) (const struct ccase *input,
+ struct ccase *output,
+ void *aux),
+ bool (*destroy) (void *aux),
+ void *aux);
+
+#endif /* data/casewriter.h */
Index: src/data/datasheet.c
===================================================================
RCS file: src/data/datasheet.c
diff -N src/data/datasheet.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/datasheet.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,826 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/datasheet.h>
+
+#include <stdlib.h>
+
+#include <data/buffered-reader.h>
+#include <data/casereader.h>
+#include <data/case-tmpfile.h>
+#include <data/settings.h>
+#include <libpspp/assertion.h>
+#include <libpspp/fat-array.h>
+#include <libpspp/range-map.h>
+#include <libpspp/range-set.h>
+#include <libpspp/sparse-array.h>
+
+#include "xalloc.h"
+
+static struct axis *axis_create (void);
+static void axis_destroy (struct axis *);
+
+static bool axis_allocate (struct axis *, unsigned long int request,
+ unsigned long int *start,
+ unsigned long int *width);
+static void axis_extend (struct axis *, unsigned long int width);
+
+static unsigned long int axis_map (const struct axis *, unsigned long log_pos);
+
+static unsigned long axis_get_size (const struct axis *);
+static void axis_insert (struct axis *,
+ unsigned long int log_start,
+ unsigned long int phy_start,
+ unsigned long int cnt);
+static void axis_remove (struct axis *,
+ unsigned long int start, unsigned long int cnt);
+static void axis_move (struct axis *,
+ unsigned long int old_start,
+ unsigned long int new_start,
+ unsigned long int cnt);
+
+enum rw_op
+ {
+ OP_READ,
+ OP_WRITE
+ };
+
+static struct source *source_create_empty (size_t column_cnt);
+static struct source *source_create_from_casereader (struct casereader *,
+ casenumber *row_cnt,
+ size_t *column_cnt);
+static void source_destroy (struct source *);
+static bool source_rw (struct source *, enum rw_op,
+ casenumber row, size_t column,
+ union value *, size_t value_cnt);
+
+static struct sparse_cases *sparse_cases_create (size_t column_cnt);
+static void sparse_cases_destroy (struct sparse_cases *);
+static bool sparse_cases_rw (struct sparse_cases *, enum rw_op,
+ casenumber row, size_t column,
+ union value *, size_t value_cnt);
+
+/* A datasheet is internally composed from a set of data files,
+ called "sources". The sources that make up a datasheet must
+ have the same number of rows (cases), but their numbers of
+ columns (variables) may vary.
+
+ A datasheet's external view is produced by mapping (permuting
+ and selecting) its internal data. Thus, we can rearrange or
+ delete rows or columns simply by modifying the mapping. We
+ add rows by adding rows to each source and to the row mapping.
+ We add columns by adding a new source, then adding that source
+ to the column mapping.
+
+ Each source in a datasheet can be a casereader or a
+ casewindow. Casereaders are read-only, so when sources made
+ from casereaders need to be modified, it is done "virtually"
+ through being overlaid by a casewindow. */
+
+/* A datasheet. */
+struct datasheet
+ {
+ struct axis *columns;
+ struct axis *rows;
+ struct range_map sources;
+
+ /* Minimum number of columns to put in a new source we need
+ new columns and none are free. By increasing it
+ exponentially whenever we add a new source, we can keep
+ the number of file descriptors needed by the datasheet to
+ a minimum, reducing the likelihood of running out. */
+ unsigned column_min_alloc;
+ };
+
+struct source_info
+ {
+ struct range_map_node range;
+ struct source *source;
+ };
+
+struct datasheet *
+datasheet_create (struct casereader *reader)
+{
+ struct datasheet *ds;
+ struct source_info *si;
+ size_t column_cnt;
+ casenumber row_cnt;
+
+ ds = datasheet_create_empty ();
+
+ /* Add source_info for READER. */
+ si = xmalloc (sizeof *si);
+ si->source = source_create_from_casereader (reader, &row_cnt, &column_cnt);
+ range_map_insert (&ds->sources, 0, column_cnt, &si->range);
+
+ /* Add column and row mappings for READER. */
+ axis_insert (ds->columns, 0, 0, column_cnt);
+ axis_insert (ds->rows, 0, 0, row_cnt);
+
+ return ds;
+}
+
+struct datasheet *
+datasheet_create_empty (void)
+{
+ struct datasheet *ds = xmalloc (sizeof *ds);
+ ds->columns = axis_create ();
+ ds->rows = axis_create ();
+ range_map_init (&ds->sources);
+ ds->column_min_alloc = 1;
+ return ds;
+}
+
+void
+datasheet_destroy (struct datasheet *ds)
+{
+ if (ds == NULL)
+ return;
+
+ axis_destroy (ds->columns);
+ axis_destroy (ds->rows);
+ while (!range_map_is_empty (&ds->sources))
+ {
+ struct range_map_node *r = range_map_first (&ds->sources);
+ struct source_info *si = range_map_data (r, struct source_info, range);
+ range_map_delete (&ds->sources, r);
+ source_destroy (si->source);
+ free (si);
+ }
+ free (ds);
+}
+
+casenumber
+datasheet_get_case_cnt (const struct datasheet *ds)
+{
+ return axis_get_size (ds->rows);
+}
+
+size_t
+datasheet_get_value_cnt (const struct datasheet *ds)
+{
+ return axis_get_size (ds->columns);
+}
+
+void
+datasheet_insert_values (struct datasheet *ds,
+ const union value init_values[], size_t cnt,
+ size_t before)
+{
+ casenumber row_cnt = datasheet_get_case_cnt (ds);
+
+ while (cnt > 0)
+ {
+ unsigned long first_phy;
+ unsigned long phy_cnt;
+
+ if (!axis_allocate (ds->columns, cnt, &first_phy, &phy_cnt))
+ {
+ struct source_info *si;
+
+ axis_extend (ds->columns, MAX (cnt, ds->column_min_alloc));
+ if (!axis_allocate (ds->columns, cnt, &first_phy, &phy_cnt))
+ NOT_REACHED ();
+ if (ds->column_min_alloc < 65536)
+ ds->column_min_alloc *= 2;
+
+ si = xmalloc (sizeof *si);
+ si->source = source_create_empty (phy_cnt);
+ range_map_insert (&ds->sources, first_phy, phy_cnt, &si->range);
+ }
+
+ while (phy_cnt > 0)
+ {
+ struct range_map_node *r;
+ struct source_info *s;
+ size_t source_col_ofs;
+ size_t source_cnt;
+ casenumber lrow;
+
+ r = range_map_lookup (&ds->sources, first_phy);
+ s = range_map_data (r, struct source_info, range);
+ source_cnt = MIN (phy_cnt, range_map_node_get_end (r) - first_phy);
+ axis_insert (ds->columns, before, first_phy, source_cnt);
+
+ source_col_ofs = first_phy - range_map_node_get_start (r);
+ for (lrow = 0; lrow < row_cnt; lrow++)
+ {
+ casenumber prow = axis_map (ds->rows, lrow);
+ source_rw (s->source, true, prow, source_col_ofs,
+ (union value *) init_values, source_cnt);
+ }
+
+ phy_cnt -= source_cnt;
+ first_phy += source_cnt;
+ init_values += source_cnt;
+ cnt -= source_cnt;
+ before += source_cnt;
+ }
+ }
+}
+
+void
+datasheet_delete_values (struct datasheet *ds, size_t start, size_t cnt)
+{
+ axis_remove (ds->columns, start, cnt);
+}
+
+void
+datasheet_move_values (struct datasheet *ds,
+ size_t old_start, size_t new_start,
+ size_t cnt)
+{
+ axis_move (ds->columns, old_start, new_start, cnt);
+}
+
+static bool
+rw_case (struct datasheet *ds, enum rw_op op,
+ casenumber lrow, size_t start_column, size_t column_cnt,
+ union value data[])
+{
+ casenumber prow;
+ size_t lcol;
+
+ prow = axis_map (ds->rows, lrow);
+ for (lcol = 0; lcol < column_cnt; lcol++)
+ {
+ size_t pcol;
+ struct range_map_node *r;
+ struct source_info *s;
+
+ pcol = axis_map (ds->columns, lcol + start_column);
+ r = range_map_lookup (&ds->sources, lcol + start_column);
+ s = range_map_data (r, struct source_info, range);
+ source_rw (s->source, op,
+ prow, pcol - range_map_node_get_start (r),
+ &data[lcol], 1);
+ }
+ return true;
+}
+
+bool
+datasheet_get_case (struct datasheet *ds, casenumber lrow, struct ccase *c)
+{
+ size_t column_cnt = datasheet_get_value_cnt (ds);
+ case_create (c, column_cnt);
+ if (rw_case (ds, OP_READ, lrow, 0, column_cnt, case_data_all_rw (c)))
+ return true;
+ else
+ {
+ case_destroy (c);
+ return false;
+ }
+}
+
+bool
+datasheet_put_case (struct datasheet *ds, casenumber lrow, struct ccase *c)
+{
+ size_t column_cnt = datasheet_get_value_cnt (ds);
+ bool ok = rw_case (ds, OP_WRITE, lrow, 0, column_cnt,
+ (union value *) case_data_all (c));
+ case_destroy (c);
+ return ok;
+}
+
+bool
+datasheet_get_value (struct datasheet *ds, casenumber lrow, size_t column,
+ union value *value, int width)
+{
+ return rw_case (ds, OP_READ, lrow, column, value_cnt_from_width (width),
+ value);
+}
+
+bool
+datasheet_put_value (struct datasheet *ds, casenumber lrow, size_t column,
+ const union value *value, int width)
+{
+ return rw_case (ds, OP_WRITE, lrow, column, value_cnt_from_width (width),
+ (union value *) value);
+}
+
+bool
+datasheet_insert_cases (struct datasheet *ds,
+ casenumber before, struct ccase *c,
+ casenumber cnt)
+{
+ casenumber added = 0;
+ while (cnt > 0)
+ {
+ unsigned long first_phy;
+ unsigned long phy_cnt;
+ unsigned long i;
+
+ if (!axis_allocate (ds->rows, cnt, &first_phy, &phy_cnt))
+ {
+ axis_extend (ds->rows, cnt);
+ if (!axis_allocate (ds->rows, cnt, &first_phy, &phy_cnt))
+ NOT_REACHED ();
+ }
+
+ axis_insert (ds->rows, before, first_phy, phy_cnt);
+ for (i = 0; i < phy_cnt; i++)
+ if (!datasheet_put_case (ds, before + i, &c[i]))
+ {
+ while (++i < cnt)
+ case_destroy (&c[i]);
+ datasheet_delete_cases (ds, before - added, phy_cnt + added);
+ return false;
+ }
+
+ c += phy_cnt;
+ cnt -= phy_cnt;
+ before += phy_cnt;
+ added += phy_cnt;
+ }
+ return true;
+}
+
+void
+datasheet_delete_cases (struct datasheet *ds,
+ casenumber first, casenumber cnt)
+{
+ axis_remove (ds->rows, first, cnt);
+}
+
+static const struct buffered_reader_class datasheet_reader_class;
+
+static struct datasheet *
+datasheet_rename (struct datasheet *old)
+{
+ struct datasheet *new = xmemdup (old, sizeof *old);
+ free (old);
+ return new;
+}
+
+struct casereader *
+datasheet_make_reader (struct datasheet *ds)
+{
+ ds = datasheet_rename (ds);
+ return buffered_reader_create (datasheet_get_value_cnt (ds),
+ datasheet_get_case_cnt (ds),
+ &datasheet_reader_class, ds);
+}
+
+static bool
+datasheet_reader_read (void *ds_, casenumber case_idx, struct ccase *c)
+{
+ struct datasheet *ds = ds_;
+ if (case_idx >= datasheet_get_case_cnt (ds))
+ return false;
+ else
+ return datasheet_get_case (ds, case_idx, c);
+}
+
+static bool
+datasheet_reader_error (void *ds_)
+{
+ struct datasheet *ds = ds_;
+ return false; /* FIXME */
+}
+
+static bool
+datasheet_reader_destroy (void *ds_)
+{
+ struct datasheet *ds = ds_;
+ datasheet_destroy (ds);
+ return true; /* FIXME */
+}
+
+static void
+datasheet_reader_advance (void *ds_, casenumber case_cnt)
+{
+ struct datasheet *ds = ds_;
+ datasheet_delete_cases (ds, 0, case_cnt);
+}
+
+static const struct buffered_reader_class datasheet_reader_class =
+ {
+ datasheet_reader_read,
+ datasheet_reader_error,
+ datasheet_reader_destroy,
+ datasheet_reader_advance,
+ };
+
+struct axis
+ {
+ struct fat_array log_to_phy;
+ struct range_set *available;
+ unsigned long int phy_size;
+ };
+
+struct axis_group
+ {
+ struct fat_array_node logical;
+ unsigned long phy_start;
+ };
+
+static struct axis_group *
+axis_group_from_fat_array_node (struct fat_array_node *node)
+{
+ return fat_array_data (node, struct axis_group, logical);
+}
+
+struct axis *
+axis_create (void)
+{
+ struct axis *axis = xmalloc (sizeof *axis);
+ fat_array_init (&axis->log_to_phy);
+ axis->available = range_set_create ();
+ axis->phy_size = 0;
+ return axis;
+}
+
+void
+axis_destroy (struct axis *axis)
+{
+ if (axis == NULL)
+ return;
+
+ while (!fat_array_is_empty (&axis->log_to_phy))
+ {
+ struct fat_array_node *node = fat_array_first (&axis->log_to_phy);
+ struct axis_group *group = fat_array_data (node, struct axis_group,
+ logical);
+ fat_array_delete (&axis->log_to_phy, node);
+ free (group);
+ }
+
+ range_set_destroy (axis->available);
+ free (axis);
+}
+
+bool
+axis_allocate (struct axis *axis, unsigned long int request,
+ unsigned long int *start,
+ unsigned long int *width)
+{
+ return range_set_allocate (axis->available, request, start, width);
+}
+
+void
+axis_extend (struct axis *axis, unsigned long int width)
+{
+ range_set_insert (axis->available, axis->phy_size, width);
+ axis->phy_size += width;
+}
+
+unsigned long int
+axis_map (const struct axis *axis, unsigned long log_pos)
+{
+ struct fat_array_node *node;
+ struct axis_group *group;
+ unsigned long int group_start;
+
+ node = fat_array_lookup (&axis->log_to_phy, log_pos, &group_start);
+ group = fat_array_data (node, struct axis_group, logical);
+ return group->phy_start + (log_pos - group_start);
+}
+
+unsigned long
+axis_get_size (const struct axis *axis)
+{
+ return fat_array_size (&axis->log_to_phy);
+}
+
+static struct fat_array_node *
+make_axis_group (unsigned long phy_start)
+{
+ struct axis_group *group = xmalloc (sizeof *group);
+ group->phy_start = phy_start;
+ return &group->logical;
+}
+
+static struct fat_array_node *
+split_axis (struct axis *axis, unsigned long int where)
+{
+ unsigned long int group_start;
+ struct fat_array_node *group_node;
+ struct axis_group *group;
+
+ group_node = fat_array_lookup (&axis->log_to_phy, where, &group_start);
+ if (group_node == NULL)
+ return NULL;
+
+ group = axis_group_from_fat_array_node (group_node);
+ if (where > group_start)
+ {
+ unsigned long int size_1 = where - group_start;
+ unsigned long int size_2 = fat_array_node_get_width (group_node) -
size_1;
+ struct fat_array_node *next = fat_array_next (&axis->log_to_phy,
group_node);
+ struct fat_array_node *new = make_axis_group (group->phy_start + size_1);
+ fat_array_resize (&axis->log_to_phy, group_node, size_1);
+ fat_array_insert (&axis->log_to_phy, size_2, new, next);
+ return new;
+ }
+ else
+ return &group->logical;
+}
+
+void
+axis_insert (struct axis *axis,
+ unsigned long int log_start, unsigned long int phy_start,
+ unsigned long int cnt)
+{
+ struct fat_array_node *before = split_axis (axis, log_start);
+ struct fat_array_node *new = make_axis_group (phy_start);
+ fat_array_insert (&axis->log_to_phy, cnt, new, before);
+}
+
+void
+axis_remove (struct axis *axis,
+ unsigned long int start, unsigned long int cnt)
+{
+ if (cnt > 0)
+ {
+ struct fat_array_node *last = split_axis (axis, start + cnt);
+ struct fat_array_node *cur, *next;
+ for (cur = split_axis (axis, start); cur != last; cur = next)
+ {
+ next = fat_array_delete (&axis->log_to_phy, cur);
+ free (axis_group_from_fat_array_node (cur));
+ }
+ }
+}
+
+void
+axis_move (struct axis *axis,
+ unsigned long int old_start, unsigned long int new_start,
+ unsigned long int cnt)
+{
+ if (cnt > 0 && old_start != new_start)
+ {
+ struct fat_array_node *old_first, *old_last, *new_first;
+ struct fat_array tmp_array;
+
+ old_first = split_axis (axis, old_start);
+ old_last = split_axis (axis, old_start + cnt);
+ fat_array_init (&tmp_array);
+ fat_array_splice (&tmp_array, NULL,
+ &axis->log_to_phy, old_first, old_last);
+
+ new_first = split_axis (axis, new_start);
+ fat_array_splice (&axis->log_to_phy, new_first,
+ &tmp_array, old_first, NULL);
+ }
+}
+
+/* A source. */
+struct source
+ {
+ struct backing *backing;
+ struct sparse_cases *overlay;
+ };
+
+struct backing
+ {
+ struct casereader *reader;
+ struct range_set *rows;
+ };
+
+struct source *
+source_create_empty (size_t column_cnt)
+{
+ struct source *source = xmalloc (sizeof *source);
+ source->backing = NULL;
+ source->overlay = sparse_cases_create (column_cnt);
+ return source;
+}
+
+struct source *
+source_create_from_casereader (struct casereader *reader,
+ casenumber *row_cnt, size_t *column_cnt)
+{
+ struct source *source;
+
+ *column_cnt = casereader_get_value_cnt (reader);
+ *row_cnt = casereader_get_case_cnt (reader);
+ if (*row_cnt == CASENUMBER_INVALID)
+ {
+ struct casereader *clone;
+ struct ccase c;
+
+ *row_cnt = 0;
+ clone = casereader_clone (reader);
+ for (; casereader_read (clone, &c); case_destroy (&c))
+ (*row_cnt)++;
+ casereader_destroy (clone);
+ }
+
+ source = source_create_empty (*column_cnt);
+ source->backing = xmalloc (sizeof *source->backing);
+ source->backing->reader = reader;
+ source->backing->rows = range_set_create ();
+ range_set_insert (source->backing->rows, 0, *row_cnt);
+
+ return source;
+}
+
+static void
+source_destroy (struct source *source)
+{
+ if (source != NULL)
+ {
+ if (source->backing != NULL)
+ {
+ casereader_destroy (source->backing->reader);
+ range_set_destroy (source->backing->rows);
+ free (source->backing);
+ }
+ sparse_cases_destroy (source->overlay);
+ free (source);
+ }
+}
+
+bool
+source_rw (struct source *source, enum rw_op op,
+ casenumber row, size_t column,
+ union value *values, size_t value_cnt)
+{
+ assert (op == OP_READ || op == OP_WRITE);
+
+ if (source->backing != NULL
+ && range_set_contains (source->backing->rows, row))
+ {
+ /* Get the case from the reader. */
+ struct ccase c;
+ if (!casereader_peek (source->backing->reader, row, &c))
+ return false;
+
+ if (op == OP_READ)
+ {
+ /* Get the values from the case. */
+ size_t i;
+ for (i = 0; i < value_cnt; i++)
+ values[i] = *case_data_idx (&c, column + i);
+ case_destroy (&c);
+ return true;
+ }
+ else
+ {
+ /* Copy the case to the overlay, remove it from the
+ backing, and fall through to the "no backing"
+ case. */
+ sparse_cases_rw (source->overlay, OP_WRITE, row, 0,
+ (union value *)case_data_all (&c),
+ case_get_value_cnt (&c));
+ case_destroy (&c);
+ range_set_delete (source->backing->rows, row, 1);
+ if (range_set_is_empty (source->backing->rows))
+ {
+ casereader_destroy (source->backing->reader);
+ range_set_destroy (source->backing->rows);
+ free (source->backing);
+ source->backing = NULL;
+ }
+ }
+ }
+
+ return sparse_cases_rw (source->overlay, op, row, column, values, value_cnt);
+}
+
+struct sparse_cases
+ {
+ size_t column_cnt;
+ casenumber max_memory_cases;
+ struct sparse_array *memory;
+ struct case_tmpfile *disk;
+ };
+
+static struct sparse_cases *
+sparse_cases_create (size_t column_cnt)
+{
+ struct sparse_cases *sc = xmalloc (sizeof *sc);
+ sc->column_cnt = column_cnt;
+ sc->max_memory_cases = get_workspace_cases (column_cnt);
+ sc->memory = sparse_array_create (NULL, sizeof (struct ccase));
+ sc->disk = NULL;
+ return sc;
+}
+
+static void
+sparse_cases_destroy (struct sparse_cases *sc)
+{
+ if (sc != NULL)
+ {
+ if (sc->memory != NULL)
+ {
+ unsigned long int idx;
+ struct ccase *c;
+ for (c = sparse_array_scan (sc->memory, 0, &idx); c != NULL;
+ c = sparse_array_scan (sc->memory, idx + 1, &idx))
+ case_destroy (c);
+ sparse_array_destroy (sc->memory);
+ }
+ case_tmpfile_destroy (sc->disk);
+ free (sc);
+ }
+}
+
+static void
+dump_sparse_cases_to_disk (struct sparse_cases *sc)
+{
+ unsigned long int idx;
+ struct ccase *c;
+
+ assert (sc->memory != NULL);
+ assert (sc->disk == NULL);
+
+ sc->disk = case_tmpfile_create (sc->column_cnt);
+
+ for (c = sparse_array_scan (sc->memory, 0, &idx); c != NULL;
+ c = sparse_array_scan (sc->memory, idx + 1, &idx))
+ case_tmpfile_put (sc->disk, idx, c);
+ sparse_array_destroy (sc->memory);
+ sc->memory = NULL;
+}
+
+static void
+case_rw (enum rw_op op, struct ccase *c, size_t c_ofs,
+ union value *values, size_t value_cnt)
+{
+ size_t i;
+ if (op == OP_WRITE)
+ {
+ for (i = 0; i < value_cnt; i++)
+ *case_data_rw_idx (c, c_ofs + i) = values[i];
+ }
+ else
+ {
+ for (i = 0; i < value_cnt; i++)
+ values[i] = *case_data_idx (c, c_ofs + i);
+ }
+}
+
+static bool
+disk_sparse_cases_rw (struct sparse_cases *sc, enum rw_op op,
+ casenumber row, size_t column,
+ union value *values, size_t value_cnt)
+{
+ struct ccase c;
+
+ if (!case_tmpfile_get (sc->disk, row, &c))
+ return false;
+ case_rw (op, &c, column, values, value_cnt);
+ if (op == OP_WRITE)
+ return case_tmpfile_put (sc->disk, row, &c);
+ else
+ {
+ case_destroy (&c);
+ return true;
+ }
+}
+
+static bool
+memory_sparse_cases_rw (struct sparse_cases *sc, enum rw_op op,
+ casenumber row, size_t column,
+ union value *values, size_t value_cnt)
+{
+ struct ccase *c;
+
+ c = sparse_array_get (sc->memory, row);
+ if (c == NULL)
+ {
+ if (sparse_array_size (sc->memory) < sc->max_memory_cases)
+ {
+ assert (op == OP_WRITE);
+ c = sparse_array_insert (sc->memory, row);
+ case_create (c, sc->column_cnt);
+ }
+ else
+ {
+ dump_sparse_cases_to_disk (sc);
+ return disk_sparse_cases_rw (sc, op, row, column, values, value_cnt);
+ }
+ }
+
+ case_rw (op, c, column, values, value_cnt);
+
+ return true;
+}
+
+static bool
+sparse_cases_rw (struct sparse_cases *sc, enum rw_op op,
+ casenumber row, size_t column,
+ union value *values, size_t value_cnt)
+{
+ return (sc->memory != NULL
+ ? memory_sparse_cases_rw (sc, op, row, column, values, value_cnt)
+ : disk_sparse_cases_rw (sc, op, row, column, values, value_cnt));
+}
Index: src/data/datasheet.h
===================================================================
RCS file: src/data/datasheet.h
diff -N src/data/datasheet.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/data/datasheet.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,66 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef DATA_DATASHEET_H
+#define DATA_DATASHEET_H 1
+
+#include <data/case.h>
+#include <data/value.h>
+
+struct casereader;
+
+/* A datasheet is a 2-d array of data that may be stored in
+ memory or on disk. It efficiently supports data storage and
+ retrieval, as well as adding, removing, and rearranging both
+ rows and columns. */
+
+struct datasheet *datasheet_create_empty (void);
+struct datasheet *datasheet_create (struct casereader *);
+void datasheet_destroy (struct datasheet *);
+struct casereader *datasheet_make_reader (struct datasheet *);
+
+casenumber datasheet_get_case_cnt (const struct datasheet *);
+size_t datasheet_get_value_cnt (const struct datasheet *);
+
+/* Columns. */
+void datasheet_insert_values (struct datasheet *,
+ const union value[], size_t cnt,
+ size_t before);
+void datasheet_delete_values (struct datasheet *, size_t start, size_t cnt);
+void datasheet_move_values (struct datasheet *,
+ size_t old_start, size_t new_start,
+ size_t cnt);
+void datasheet_reorder_values (struct datasheet *,
+ size_t *ordering, size_t cnt);
+
+/* Rows. */
+bool datasheet_insert_cases (struct datasheet *,
+ casenumber before, struct ccase *,
+ casenumber cnt);
+void datasheet_delete_cases (struct datasheet *,
+ casenumber first, casenumber cnt);
+
+/* Data. */
+bool datasheet_get_case (struct datasheet *, casenumber, struct ccase *);
+bool datasheet_put_case (struct datasheet *, casenumber, struct ccase *);
+bool datasheet_get_value (struct datasheet *, casenumber, size_t column,
+ union value *, int width);
+bool datasheet_put_value (struct datasheet *, casenumber, size_t column,
+ const union value *, int width);
+
+#endif /* data/datasheet.h */
Index: src/libpspp/count.h
===================================================================
RCS file: src/libpspp/count.h
diff -N src/libpspp/count.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/count.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,24 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef LIBPSPP_COUNT_H
+#define LIBPSPP_COUNT_H 1
+
+typedef unsigned long count_type;
+
+#endif /* libpspp/count.h */
Index: src/libpspp/fat-array.h
===================================================================
RCS file: src/libpspp/fat-array.h
diff -N src/libpspp/fat-array.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/fat-array.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,69 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef LIBPSPP_FAT_ARRAY_H
+#define LIBPSPP_FAT_ARRAY_H
+
+#include <libpspp/abt.h>
+
+/* Returns the data structure corresponding to the given NODE,
+ assuming that NODE is embedded as the given MEMBER name in
+ data type STRUCT. */
+#define fat_array_data(NODE, STRUCT, MEMBER) \
+ ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+
+struct fat_array_node
+ {
+ struct abt_node abt_node;
+ unsigned long subtree_width;
+ unsigned long width;
+ };
+
+unsigned long fat_array_node_get_width (const struct fat_array_node *);
+
+struct fat_array
+ {
+ struct abt abt;
+ };
+
+
+void fat_array_init (struct fat_array *);
+
+bool fat_array_is_empty (const struct fat_array *);
+unsigned long fat_array_size (const struct fat_array *);
+
+struct fat_array_node *fat_array_lookup (const struct fat_array *,
+ unsigned long idx,
+ unsigned long *node_start);
+void fat_array_insert (struct fat_array *, unsigned long width,
+ struct fat_array_node *new,
+ struct fat_array_node *before);
+void fat_array_splice (struct fat_array *dst, struct fat_array_node *before,
+ struct fat_array *src,
+ struct fat_array_node *first,
+ struct fat_array_node *last);
+struct fat_array_node *fat_array_delete (struct fat_array *,
+ struct fat_array_node *);
+void fat_array_resize (struct fat_array *, struct fat_array_node *,
+ unsigned long new_width);
+struct fat_array_node *fat_array_first (struct fat_array *);
+struct fat_array_node *fat_array_next (struct fat_array *,
+ struct fat_array_node *);
+
+
+#endif /* libpspp/fat-array.h */
Index: src/libpspp/range-map.h
===================================================================
RCS file: src/libpspp/range-map.h
diff -N src/libpspp/range-map.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/range-map.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,64 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef LIBPSPP_RANGE_MAP_H
+#define LIBPSPP_RANGE_MAP_H
+
+#include <libpspp/abt.h>
+
+/* Returns the data structure corresponding to the given NODE,
+ assuming that NODE is embedded as the given MEMBER name in
+ data type STRUCT. */
+#define range_map_data(NODE, STRUCT, MEMBER) \
+ ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+
+struct range_map_node
+ {
+ struct abt_node abt_node;
+ unsigned long subtree_min_width;
+ unsigned long start;
+ unsigned long width;
+ };
+
+unsigned long range_map_node_get_start (const struct range_map_node *);
+unsigned long range_map_node_get_end (const struct range_map_node *);
+unsigned long range_map_node_get_width (const struct range_map_node *);
+
+struct range_map
+ {
+ struct abt abt;
+ };
+
+void range_map_init (struct range_map *);
+
+bool range_map_is_empty (const struct range_map *);
+
+struct range_map_node *range_map_lookup (const struct range_map *,
+ unsigned long int position);
+void range_map_insert (struct range_map *, unsigned long int start,
+ unsigned long int width,
+ struct range_map_node *new);
+void range_map_delete (struct range_map *, struct range_map_node *);
+void range_map_resize (struct range_map *, struct range_map_node *,
+ unsigned long new_width);
+struct range_map_node *range_map_first (struct range_map *);
+struct range_map_node *range_map_next (struct range_map *,
+ struct range_map_node *);
+
+
+#endif /* libpspp/range-map.h */
Index: src/libpspp/range-set.h
===================================================================
RCS file: src/libpspp/range-set.h
diff -N src/libpspp/range-set.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/range-set.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,40 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef LIBPSPP_RANGE_SET_H
+#define LIBPSPP_RANGE_SET_H
+
+#include <stdbool.h>
+
+struct range_set *range_set_create (void);
+void range_set_destroy (struct range_set *);
+
+void range_set_insert (struct range_set *,
+ unsigned long int start, unsigned long int width);
+void range_set_delete (struct range_set *,
+ unsigned long int start, unsigned long int width);
+bool range_set_allocate (struct range_set *, unsigned long int request,
+ unsigned long int *start, unsigned long int *width);
+bool range_set_contains (struct range_set *, unsigned long int index);
+
+bool range_set_is_empty (const struct range_set *);
+struct range_set_node *range_set_first (struct range_set *);
+struct range_set_node *range_set_next (struct range_set *,
+ struct range_set_node *);
+
+#endif /* libpspp/range-set.h */
Index: src/libpspp/sliding-window.h
===================================================================
RCS file: src/libpspp/sliding-window.h
diff -N src/libpspp/sliding-window.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/sliding-window.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,42 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef SLIDING_WINDOW_H
+#define SLIDING_WINDOW_H 1
+
+struct sliding_window
+ {
+ struct sliding_window_set *set;
+ struct heap_node heap_node;
+ casenumber left_edge;
+ };
+
+struct sliding_window_set
+ {
+ struct heap *windows;
+ };
+
+struct sliding_window *sliding_window_create (void);
+struct sliding_window *sliding_window_clone (const struct sliding_window *);
+void sliding_window_destroy (struct sliding_window *);
+count_type sliding_window_get_left_edge (const struct sliding_window *);
+count_type sliding_window_get_leftmost_edge (const struct sliding_window *);
+count_type sliding_window_advance (const struct sliding_window *,
+ count_type addend);
+
+#endif /* libpspp/sliding-window.h */
Index: src/libpspp/sparse-array.c
===================================================================
RCS file: src/libpspp/sparse-array.c
diff -N src/libpspp/sparse-array.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/sparse-array.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,215 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <libpspp/sparse-array.h>
+
+#define BITS_PER_LEVEL 6
+#define PTRS_PER_LEVEL (1u << BITS_PER_LEVEL)
+#define LEVEL_MASK ((1u << BITS_PER_LEVEL) - 1)
+#define LONG_BITS (sizeof (unsigned long int) * CHAR_BIT)
+#define MAX_HEIGHT DIV_RND_UP (LONG_BITS, BITS_PER_LEVEL)
+
+union pointer
+ {
+ struct internal_node *internal;
+ struct leaf_node *leaf;
+ };
+
+struct sparse_array
+ {
+ struct pool *pool;
+ size_t elem_size;
+ int height;
+ union pointer root;
+ };
+
+struct internal_node
+ {
+ int count;
+ union pointer down[PTRS_PER_LEVEL];
+ };
+
+struct leaf_node
+ {
+ unsigned long int in_use[DIV_RND_UP (PTRS_PER_LEVEL, LONG_BITS)];
+ /* element_type elements[PTRS_PER_LEVEL]; */
+ };
+
+#define SIZEOF_ALIGNED(X) (ROUND_UP (sizeof (X), sizeof (long int)))
+
+static inline unsigned long int
+max_index (int height)
+{
+ int bits = height * BITS_PER_LEVEL;
+ return bits < LONG_BITS ? (1u << bits) - 1 : ULONG_MAX;
+}
+
+static inline bool
+is_in_use (const struct leaf_node *leaf, unsigned int idx)
+{
+ return (leaf->in_use[idx / LONG_BITS] & (1ul << (idx % LONG_BITS))) != 0;
+}
+
+static inline bool
+any_in_use (const struct leaf_node *leaf)
+{
+ size_t i;
+ for (i = 0; i < sizeof leaf->in_use / sizeof *leaf->in_use; i++)
+ if (leaf->in_use[i])
+ return true;
+ return false;
+}
+
+static inline void
+set_in_use (struct leaf_node *leaf, unsigned int idx)
+{
+ leaf->in_use[idx / LONG_BITS] |= 1ul << (idx % LONG_BITS);
+}
+
+static inline void
+unset_in_use (struct leaf_node *leaf, unsigned int idx)
+{
+ leaf->in_use[idx / LONG_BITS] &= ~(1ul << (idx % LONG_BITS));
+}
+
+static inline void *
+leaf_element (const struct sparse_array *spar, struct leaf_node *leaf,
+ unsigned int idx)
+{
+ return (char *) leaf + SIZEOF_ALIGNED (leaf) + (spar->elem_size * idx);
+}
+
+struct sparse_array *
+sparse_array_create (struct pool *pool, size_t elem_size)
+{
+ struct sparse_array *spar;
+ int i;
+
+ spar = pool_malloc (pool, sizeof *spar);
+ spar->pool = pool;
+ spar->elem_size = SIZEOF_ALIGNED (elem_size);
+ spar->height = 0;
+ spar->root.leaf = NULL;
+ return spar;
+}
+
+void
+sparse_array_destroy (struct sparse_array *spar)
+{
+
+
+}
+
+void *
+sparse_array_insert (struct sparse_array *spar, unsigned long int idx)
+{
+
+
+}
+
+void *
+sparse_array_get (const struct sparse_array *spar, unsigned long int idx)
+{
+ union pointer *p;
+ int shift;
+
+ if (idx > max_index (spar->height))
+ return NULL;
+
+ p = &spar->root;
+ shift = (spar->height - 1) * BITS_PER_LEVEL;
+ while (shift != 0)
+ {
+ if (p->internal == NULL)
+ return NULL;
+ p = &p->internal->down[(idx >> shift) & LEVEL_MASK];
+ shift -= BITS_PER_LEVEL;
+ }
+
+ idx &= LEVEL_MASK;
+ return is_in_use (p->leaf, idx) ? leaf_element (spar, p->leaf, idx) : NULL;
+}
+
+void
+sparse_array_remove (struct sparse_array *spar, unsigned long int idx)
+{
+ struct pointer *stack[MAX_HEIGHT - 1];
+ struct pointer **top;
+ union pointer *p;
+ int shift;
+
+ if (idx > max_index (spar->height))
+ return;
+
+ p = &spar->root;
+ shift = (spar->height - 1) * BITS_PER_LEVEL;
+ top = stack;
+ while (shift != 0)
+ {
+ if (p->internal == NULL)
+ return;
+ *top++ = p;
+ p = &p->internal->down[(idx >> shift) & LEVEL_MASK];
+ shift -= BITS_PER_LEVEL;
+ }
+
+ idx &= LEVEL_MASK;
+ if (is_in_use (p->leaf, idx))
+ {
+ unset_in_use (p->leaf, idx);
+ if (!any_in_use (p->leaf))
+ {
+ pool_free (spar->pool, p->leaf);
+ p->leaf = NULL;
+ while (top > stack)
+ {
+ p = *--top;
+ if (--p->internal->count == 0)
+ {
+ if (p == spar->root)
+ p->height = 0;
+ pool_free (spar->pool, p->internal);
+ p->internal = NULL;
+ }
+ else
+ {
+ while (p == spar->root
+ && spar->height > 1
+ && p->internal->count == 1
+ && p->internal->down[0]->internal)
+ {
+ spar->height--;
+ spar->root = p->internal->down[0];
+ pool_free (spar->pool, p->internal);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void *
+sparse_array_scan (struct sparse_array *spar, unsigned long int start_idx,
+ unsigned long *idx)
+{
+
+
+}
Index: src/libpspp/sparse-array.h
===================================================================
RCS file: src/libpspp/sparse-array.h
diff -N src/libpspp/sparse-array.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/libpspp/sparse-array.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,37 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef LIBPSPP_SPARSE_ARRAY_H
+#define LIBPSPP_SPARSE_ARRAY_H 1
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#include <libpspp/hash.h>
+
+struct sparse_array *sparse_array_create (struct pool *, size_t elem_size);
+void sparse_array_destroy (struct sparse_array *);
+
+void *sparse_array_insert (struct sparse_array *, unsigned long int idx);
+void *sparse_array_get (const struct sparse_array *, unsigned long int idx);
+void sparse_array_remove (struct sparse_array *, unsigned long int idx);
+
+void *sparse_array_scan (struct sparse_array *, unsigned long int start_idx,
+ unsigned long *idx);
+
+#endif /* libpspp/sparse-array.h */
Index: src/math/merge.c
===================================================================
RCS file: src/math/merge.c
diff -N src/math/merge.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/math/merge.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,164 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* FIXME: error checking. */
+/* FIXME: merge pattern should be improved, this one causes a
+ performance regression. */
+#include <config.h>
+
+#include <math/merge.h>
+
+#include <data/case.h>
+#include <data/casereader.h>
+#include <data/casewriter.h>
+#include <libpspp/array.h>
+#include <libpspp/assertion.h>
+#include <math/ordering.h>
+
+#include "xalloc.h"
+
+#define MAX_MERGE_ORDER 7
+
+struct merge_input
+ {
+ struct casereader *reader;
+ struct ccase c;
+ };
+
+struct merge
+ {
+ struct case_ordering *ordering;
+ struct merge_input inputs[MAX_MERGE_ORDER];
+ size_t input_cnt;
+ bool ok;
+ };
+
+static void do_merge (struct merge *m);
+
+struct merge *
+merge_create (const struct case_ordering *ordering)
+{
+ struct merge *m = xmalloc (sizeof *m);
+ m->ordering = case_ordering_clone (ordering);
+ m->input_cnt = 0;
+ m->ok = true;
+ return m;
+}
+
+bool
+merge_destroy (struct merge *m)
+{
+ if (m != NULL)
+ {
+ bool ok = m->ok;
+ size_t i;
+
+ case_ordering_destroy (m->ordering);
+ for (i = 0; i < m->input_cnt; i++)
+ m->ok = casereader_destroy (m->inputs[i].reader) && m->ok;
+ free (m);
+ return ok;
+ }
+ else
+ return true;
+}
+
+void
+merge_append (struct merge *m, struct casereader *r)
+{
+ assert (m->input_cnt < MAX_MERGE_ORDER);
+ m->inputs[m->input_cnt++].reader = casereader_rename (r);
+ if (m->input_cnt >= MAX_MERGE_ORDER)
+ do_merge (m);
+}
+
+struct casereader *
+merge_make_reader (struct merge *m)
+{
+ struct casereader *r;
+
+ if (m->input_cnt > 1)
+ do_merge (m);
+
+ if (m->input_cnt == 1)
+ {
+ r = m->inputs[0].reader;
+ m->input_cnt = 0;
+ }
+ else if (m->input_cnt == 0)
+ {
+ size_t value_cnt = case_ordering_get_value_cnt (m->ordering);
+ struct casewriter *writer = mem_writer_create (value_cnt);
+ r = casewriter_make_reader (writer);
+ }
+ else if (!m->ok)
+ r = NULL;
+ else
+ NOT_REACHED ();
+
+ return r;
+}
+
+static bool
+read_input_case (struct merge *m, size_t idx)
+{
+ struct merge_input *i = &m->inputs[idx];
+
+ if (casereader_read (i->reader, &i->c))
+ return true;
+ else
+ {
+ casereader_destroy (i->reader);
+ remove_element (m->inputs, m->input_cnt, sizeof *m->inputs, idx);
+ m->input_cnt--;
+ return false;
+ }
+}
+
+static void
+do_merge (struct merge *m)
+{
+ struct casewriter *w;
+ size_t i;
+
+ assert (m->input_cnt > 1);
+
+ w = tmpfile_writer_create (case_ordering_get_value_cnt (m->ordering));
+
+ for (i = 0; i < m->input_cnt; )
+ if (read_input_case (m, i))
+ i++;
+
+ while (m->input_cnt > 0)
+ {
+ size_t min;
+
+ min = 0;
+ for (i = 1; i < m->input_cnt; i++)
+ if (case_ordering_compare_cases (&m->inputs[i].c, &m->inputs[min].c,
+ m->ordering) < 0)
+ min = i;
+
+ casewriter_write (w, &m->inputs[min].c);
+ read_input_case (m, min);
+ }
+
+ m->input_cnt = 1;
+ m->inputs[0].reader = casewriter_make_reader (w);
+}
+
Index: src/math/merge.h
===================================================================
RCS file: src/math/merge.h
diff -N src/math/merge.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/math/merge.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,32 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef MATH_MERGE_H
+#define MATH_MERGE_H 1
+
+#include <stdbool.h>
+
+struct case_ordering;
+struct casereader;
+
+struct merge *merge_create (const struct case_ordering *);
+bool merge_destroy (struct merge *);
+void merge_append (struct merge *, struct casereader *);
+struct casereader *merge_make_reader (struct merge *);
+
+#endif /* math/merge.h */
Index: src/math/ordering.c
===================================================================
RCS file: src/math/ordering.c
diff -N src/math/ordering.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/math/ordering.c 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,168 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include <config.h>
+
+#include <math/ordering.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <data/dictionary.h>
+#include <data/variable.h>
+
+#include "xalloc.h"
+
+/* One key used for sorting. */
+struct sort_key
+ {
+ struct variable *var; /* Variable. */
+ enum sort_direction dir; /* Sort direction. */
+ };
+
+/* A set of criteria for ordering cases. */
+struct case_ordering
+ {
+ size_t value_cnt; /* Number of `union value's per case. */
+
+ /* Sort keys. */
+ struct sort_key *keys;
+ size_t key_cnt;
+ };
+
+struct case_ordering *
+case_ordering_create (const struct dictionary *dict)
+{
+ struct case_ordering *co = xmalloc (sizeof *co);
+ co->value_cnt = dict_get_next_value_idx (dict);
+ co->keys = NULL;
+ co->key_cnt = 0;
+ return co;
+}
+
+struct case_ordering *
+case_ordering_clone (const struct case_ordering *orig)
+{
+ struct case_ordering *co = xmalloc (sizeof *co);
+ co->value_cnt = orig->value_cnt;
+ co->keys = xmemdup (orig->keys, orig->key_cnt * sizeof *orig->keys);
+ co->key_cnt = orig->key_cnt;
+ return co;
+}
+
+void
+case_ordering_destroy (struct case_ordering *co)
+{
+ if (co != NULL)
+ {
+ free (co->keys);
+ free (co);
+ }
+}
+
+size_t
+case_ordering_get_value_cnt (const struct case_ordering *co)
+{
+ return co->value_cnt;
+}
+
+int
+case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
+ const struct case_ordering *co)
+{
+ size_t i;
+
+ for (i = 0; i < co->key_cnt; i++)
+ {
+ const struct sort_key *key = &co->keys[i];
+ int width = var_get_width (key->var);
+ int cmp;
+
+ if (width == 0)
+ {
+ double af = case_num (a, key->var);
+ double bf = case_num (b, key->var);
+ if (af == bf)
+ continue;
+ cmp = af > bf ? 1 : -1;
+ }
+ else
+ {
+ const char *as = case_str (a, key->var);
+ const char *bs = case_str (b, key->var);
+ cmp = memcmp (as, bs, width);
+ if (cmp == 0)
+ continue;
+ }
+
+ return key->dir == SRT_ASCEND ? cmp : -cmp;
+ }
+ return 0;
+}
+
+bool
+case_ordering_add_var (struct case_ordering *co,
+ struct variable *var, enum sort_direction dir)
+{
+ struct sort_key *key;
+ size_t i;
+
+ for (i = 0; i < co->key_cnt; i++)
+ if (var_get_case_index (co->keys[i].var) == var_get_case_index (var))
+ return false;
+
+ co->keys = xnrealloc (co->keys, co->key_cnt + 1, sizeof *co->keys);
+ key = &co->keys[co->key_cnt++];
+ key->var = var;
+ key->dir = dir;
+ return true;
+}
+
+size_t
+case_ordering_get_var_cnt (const struct case_ordering *co)
+{
+ return co->key_cnt;
+}
+
+struct variable *
+case_ordering_get_var (const struct case_ordering *co, size_t idx)
+{
+ assert (idx < co->key_cnt);
+ return co->keys[idx].var;
+}
+
+enum sort_direction
+case_ordering_get_direction (const struct case_ordering *co, size_t idx)
+{
+ assert (idx < co->key_cnt);
+ return co->keys[idx].dir;
+}
+
+void
+case_ordering_get_vars (const struct case_ordering *co,
+ struct variable ***vars, size_t *var_cnt)
+{
+ size_t i;
+
+ *var_cnt = co->key_cnt;
+ *vars = xnmalloc (*var_cnt, sizeof **vars);
+ for (i = 0; i < co->key_cnt; i++)
+ (*vars)[i] = co->keys[i].var;
+}
+
Index: src/math/ordering.h
===================================================================
RCS file: src/math/ordering.h
diff -N src/math/ordering.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/math/ordering.h 19 Mar 2007 21:36:24 -0000 1.1.2.1
@@ -0,0 +1,51 @@
+/* PSPP - computes sample statistics.
+ Copyright (C) 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef MATH_ORDERING_H
+#define MATH_ORDERING_H 1
+
+#include <stddef.h>
+#include <data/case.h>
+
+struct dictionary;
+
+/* Sort direction. */
+enum sort_direction
+ {
+ SRT_ASCEND, /* A, B, C, ..., X, Y, Z. */
+ SRT_DESCEND /* Z, Y, X, ..., C, B, A. */
+ };
+
+struct case_ordering *case_ordering_create (const struct dictionary *);
+struct case_ordering *case_ordering_clone (const struct case_ordering *);
+void case_ordering_destroy (struct case_ordering *);
+
+size_t case_ordering_get_value_cnt (const struct case_ordering *);
+int case_ordering_compare_cases (const struct ccase *, const struct ccase *,
+ const struct case_ordering *);
+
+bool case_ordering_add_var (struct case_ordering *,
+ struct variable *, enum sort_direction);
+size_t case_ordering_get_var_cnt (const struct case_ordering *);
+struct variable *case_ordering_get_var (const struct case_ordering *, size_t);
+enum sort_direction case_ordering_get_direction (const struct case_ordering *,
+ size_t);
+void case_ordering_get_vars (const struct case_ordering *,
+ struct variable ***, size_t *);
+
+#endif /* math/ordering.h */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Pspp-cvs] pspp Smake configure.ac src/data/ChangeLog src/... [simpler-proc],
Ben Pfaff <=