Added support for reading Gnumeric spreadsheet files.
authorJohn Darrington <john@darrington.wattle.id.au>
Sat, 3 Nov 2007 03:43:10 +0000 (03:43 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 3 Nov 2007 03:43:10 +0000 (03:43 +0000)
Thanks to Ben for revieing this code.

22 files changed:
configure.ac
doc/files.texi
po/de.po
po/en_GB.po
po/pspp.pot
src/ChangeLog
src/data/automake.mk
src/data/gnumeric-reader.c [new file with mode: 0644]
src/data/gnumeric-reader.h [new file with mode: 0644]
src/language/data-io/ChangeLog
src/language/data-io/automake.mk
src/language/data-io/get-data.c [new file with mode: 0644]
src/language/data-io/get-data.h [new file with mode: 0644]
src/language/data-io/get.c
src/libpspp/ChangeLog
src/libpspp/i18n.c
src/libpspp/i18n.h
src/ui/terminal/automake.mk
tests/Book1.gnm.unzipped [new file with mode: 0644]
tests/ChangeLog
tests/automake.mk
tests/command/get-data-gnm.sh [new file with mode: 0755]

index f738c50b49f46d35c3210068ff7f177abd5c1d12..4fa093d71f8ce57133bf453fd0da87811fb12b9b 100644 (file)
@@ -45,6 +45,19 @@ if test x"$with_gui" != x"no" ; then
 fi
 AM_CONDITIONAL(WITHGUI, test x"$with_gui" != x"no")
 
+
+dnl Checks needed for gnumeric reader
+gnm_support=yes;
+PKG_CHECK_MODULES(LIBXML2, libxml-2.0,,
+                          [PSPP_OPTIONAL_PREREQ([libxml2]); gnm_support=no]);
+AC_SEARCH_LIBS(gzopen,z,,[PSPP_OPTIONAL_PREREQ([zlib]); gnm_support=no;])
+AC_CHECK_HEADERS(zlib.h,,[PSPP_OPTIONAL_PREREQ([zlib]); gnm_support=no;])
+
+if test x"$gnm_support" = x"yes" ; then 
+   AC_DEFINE([GNM_SUPPORT], 1,
+   [Define to 1 if building in support for reading Gnumeric files.])
+fi
+
 AC_ARG_WITH(
   gui_tools,
   [AS_HELP_STRING([--with-gui-tools], [build the gui developer tools])])
index 35bc7c98cfd07661aab65b8943dbdac89d440804..0910d26016f36c49e278b36651d0336c4474b18f 100644 (file)
@@ -8,6 +8,7 @@ portable files.
 * APPLY DICTIONARY::            Apply system file dictionary to active file.
 * EXPORT::                      Write to a portable file.
 * GET::                         Read from a system file.
+* GET DATA::                    Read from foreign files.
 * IMPORT::                      Read from a portable file.
 * MATCH FILES::                 Merge system files.
 * SAVE::                        Write to a system file.
@@ -156,6 +157,72 @@ is read later, when a procedure is executed.
 Use of @cmd{GET} to read a portable file or scratch file is a PSPP
 extension.
 
+@node GET DATA
+@section GET DATA
+@vindex GET DATA
+
+@display
+GET DATA /TYPE=gnm
+        /FILE=@{'file-name'@}
+        
+        /SHEET=@{NAME 'sheet-name', INDEX n@}
+        /CELLRANGE=@{RANGE 'range', FULL@}
+        /READNAMES=@{ON, OFF@}
+        /ASSUMEDVARWIDTH=n.
+@end display
+
+The @cmd{GET DATA} command is used to read files and other data sources 
+created by other applications. 
+When this command is executed, the current dictionary and active file are
+replaced  with variables and data read from the specified source.
+The TYPE subcommand is mandatory and determines the type of the file or source to read.
+Currently @samp{gnm} is the only supported type.
+
+@cindex Gnumeric
+@cindex spreadsheet files
+The @samp{gnm} type is used to read spreadsheet files created by 
+Gnumeric (@url{http://gnumeric.org}).
+With this type, the FILE subcommand must be used, to specify the
+spreadsheet file to read.  
+All other subcommands are optional.
+The format of each variable is determined by the format of the spreadsheet 
+cell containing the first datum for the variable.
+If this cell is of string (text) format, then the width of the variable is
+determined from the length of the string it contains, unless the 
+ASSUMEDVARWIDTH subcommand is given.
+
+The SHEET subcommand specifies the sheet within the spreadsheet file to read.
+There are two forms of the SHEET subcommand.
+In the first form,
+@samp{/SHEET=name @var{sheet-name}}, the string @var{sheet-name} is the
+name of the sheet to read.
+In the second form, @samp{/SHEET=index @var{idx}}, @var{idx} is a
+integer which is the index of the sheet to read.
+The first sheet has the index 1.
+If the SHEET subcommand is omitted, then the command will read the
+first sheet in the file.
+
+The CELLRANGE subcommand specifies the range of cells within the sheet to read.
+If the subcommand is given as @samp{/CELLRANGE=FULL}, then the entire
+sheet  is read.
+To read only part of a sheet, use the form 
+@samp{/CELLRANGE=range '@var{top-left-cell}:@var{bottom-right-cell}'}.
+For example, the subcommand @samp{/CELLRANGE=range 'C3:P19'} reads 
+columns C--P, and rows 3--19 inclusive.
+If no CELLRANGE subcommand is given, then the entire sheet is read.
+
+If @samp{/READNAMES=ON} is specified, then the contents of cells of
+the first row are used as the names of the variables in which to store
+the data from subsequent rows. 
+If the READNAMES command is omitted, or if @samp{/READNAMES=OFF} is
+used, then the variables  receive automatically assigned names.
+
+The ASSUMEDVARWIDTH subcommand specifies the maximum width of string
+variables read  from the file.
+If omitted, the default value is determined from the length of the 
+string in the first spreadsheet cell for each variable.
+
+
 @node IMPORT
 @section IMPORT
 @vindex IMPORT
index eedffd9e2e94ed3e592634906fa519a594132c0b..6053433e52131715ab26b461931c3a93bb77467f 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.4.3\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-10-17 20:48+0800\n"
+"POT-Creation-Date: 2007-11-03 12:36+0900\n"
 "PO-Revision-Date: 2006-07-28 19:32+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: German <pspp-dev@gnu.org>\n"
@@ -192,23 +192,23 @@ msgstr "Spalten"
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:466
+#: src/data/data-out.c:465
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:487
+#: src/data/data-out.c:486
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
 
-#: src/data/dictionary.c:747
+#: src/data/dictionary.c:758
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1048
+#: src/data/dictionary.c:1059
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
@@ -1210,21 +1210,21 @@ msgstr ""
 msgid "Handle for %s not allowed here."
 msgstr ""
 
-#: src/language/data-io/get.c:98
+#: src/language/data-io/get.c:105
 msgid "expecting COMM or TAPE"
 msgstr ""
 
-#: src/language/data-io/get.c:269 src/language/data-io/get.c:283
-#: src/language/data-io/get.c:308
+#: src/language/data-io/get.c:276 src/language/data-io/get.c:290
+#: src/language/data-io/get.c:315
 #, c-format
 msgid "expecting %s or %s"
 msgstr ""
 
-#: src/language/data-io/get.c:501 src/language/data-io/print.c:176
+#: src/language/data-io/get.c:508 src/language/data-io/print.c:176
 msgid "expecting a valid subcommand"
 msgstr ""
 
-#: src/language/data-io/get.c:534
+#: src/language/data-io/get.c:541
 #, c-format
 msgid ""
 "Cannot rename %s as %s because there already exists a variable named %s.  To "
@@ -1232,11 +1232,11 @@ msgid ""
 "as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, \"/RENAME (A B C=B C A)\"."
 msgstr ""
 
-#: src/language/data-io/get.c:560
+#: src/language/data-io/get.c:567
 msgid "`=' expected after variable list."
 msgstr ""
 
-#: src/language/data-io/get.c:567
+#: src/language/data-io/get.c:574
 #, c-format
 msgid ""
 "Number of variables on left side of `=' (%zu) does not match number of "
@@ -1244,55 +1244,55 @@ msgid ""
 "subcommand."
 msgstr ""
 
-#: src/language/data-io/get.c:580
+#: src/language/data-io/get.c:587
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr ""
 
-#: src/language/data-io/get.c:610
+#: src/language/data-io/get.c:617
 msgid "Cannot DROP all variables from dictionary."
 msgstr ""
 
-#: src/language/data-io/get.c:783
+#: src/language/data-io/get.c:790
 msgid "Cannot specify the active file since no active file has been defined."
 msgstr ""
 
-#: src/language/data-io/get.c:790
+#: src/language/data-io/get.c:797
 msgid ""
 "MATCH FILES may not be used after TEMPORARY when the active file is an input "
 "source.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/data-io/get.c:824
+#: src/language/data-io/get.c:831
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr ""
 
-#: src/language/data-io/get.c:868
+#: src/language/data-io/get.c:875
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:871
+#: src/language/data-io/get.c:878
 #, c-format
 msgid "Active file lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:941
+#: src/language/data-io/get.c:948
 msgid "BY is required when TABLE is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:946
+#: src/language/data-io/get.c:953
 msgid "BY is required when IN is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:1051
+#: src/language/data-io/get.c:1058
 #, c-format
 msgid ""
 "Variable name %s specified on %s subcommand duplicates an existing variable "
 "name."
 msgstr ""
 
-#: src/language/data-io/get.c:1297
+#: src/language/data-io/get.c:1304
 #, c-format
 msgid ""
 "Variable %s in file %s (%s) has different type or width from the same "
@@ -4412,6 +4412,7 @@ msgid "Jump to Variable"
 msgstr "Variableansicht"
 
 #: src/ui/gui/data-editor.c:653 src/ui/gui/data-editor.glade:438
+#: src/ui/gui/oneway.glade:179
 msgid "_Descriptives"
 msgstr ""
 
@@ -4972,46 +4973,50 @@ msgstr "Unpassend Wert für Variable"
 msgid "Incorrect range specification"
 msgstr "Falshe Spannweitebeschreibung"
 
-#: src/ui/gui/oneway-anova-dialog.c:317
+#: src/ui/gui/oneway-anova-dialog.c:337
 #, c-format
 msgid "Contrast %d of %d"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:34 src/ui/gui/x.glade:126
+#: src/ui/gui/oneway.glade:30
 msgid "_Factor:"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:70 src/ui/gui/x.glade:82
+#: src/ui/gui/oneway.glade:66
 #, fuzzy
-msgid "_Dependent Variable(s):"
+msgid "Dependent _Variable(s):"
 msgstr "Variableansicht"
 
-#: src/ui/gui/oneway.glade:172
-msgid "_Options..."
+#: src/ui/gui/oneway.glade:190
+msgid "_Homogeneity"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:183
+#: src/ui/gui/oneway.glade:207
+msgid "Statistics"
+msgstr ""
+
+#: src/ui/gui/oneway.glade:226
 msgid "_Contrasts..."
 msgstr ""
 
-#: src/ui/gui/oneway.glade:254
+#: src/ui/gui/oneway.glade:309
 msgid "gtk-go-back"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:265
+#: src/ui/gui/oneway.glade:320
 msgid "gtk-go-forward"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:288
+#: src/ui/gui/oneway.glade:343
 #, fuzzy
 msgid "_Coefficients:"
 msgstr "Spalten"
 
-#: src/ui/gui/oneway.glade:334
+#: src/ui/gui/oneway.glade:389
 msgid "Coefficient Total: "
 msgstr ""
 
-#: src/ui/gui/oneway.glade:367
+#: src/ui/gui/oneway.glade:422
 msgid "Contrast 1 of 1"
 msgstr ""
 
@@ -5101,7 +5106,7 @@ msgstr "Variableansicht"
 msgid "Current Status: "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:265
+#: src/ui/gui/psppire.glade:265 src/ui/gui/rank.glade:67
 #, fuzzy
 msgid "Variable(s):"
 msgstr "Variableansicht"
@@ -5339,6 +5344,111 @@ msgstr "Spezial"
 msgid "%d"
 msgstr ""
 
+#: src/ui/gui/rank.glade:111
+msgid "By:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:197
+msgid "_Smallest Value"
+msgstr ""
+
+#: src/ui/gui/rank.glade:209
+#, fuzzy
+msgid "_Largest Value"
+msgstr "Variableansicht"
+
+#: src/ui/gui/rank.glade:228
+msgid "Assign rank 1 to:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:246
+msgid "_Display summary tables"
+msgstr ""
+
+#: src/ui/gui/rank.glade:262
+#, fuzzy
+msgid "Rank T_ypes"
+msgstr "_Stecken"
+
+#: src/ui/gui/rank.glade:273
+msgid "_Ties..."
+msgstr ""
+
+#: src/ui/gui/rank.glade:343
+msgid "Ntiles"
+msgstr ""
+
+#: src/ui/gui/rank.glade:376
+msgid "Rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:386
+#, fuzzy
+msgid "Savage score"
+msgstr "Speichern unter"
+
+#: src/ui/gui/rank.glade:400
+msgid "Fractional rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:414
+msgid "Fractional rank as %"
+msgstr ""
+
+#: src/ui/gui/rank.glade:428
+msgid "Sum of case weights"
+msgstr ""
+
+#: src/ui/gui/rank.glade:450
+msgid "Proportion Estimates"
+msgstr ""
+
+#: src/ui/gui/rank.glade:460
+msgid "Normal Scores"
+msgstr ""
+
+#: src/ui/gui/rank.glade:495
+msgid "Blom"
+msgstr ""
+
+#: src/ui/gui/rank.glade:506
+msgid "Tukey"
+msgstr ""
+
+#: src/ui/gui/rank.glade:520
+msgid "Rankit"
+msgstr ""
+
+#: src/ui/gui/rank.glade:534
+msgid "Van der Wärden"
+msgstr ""
+
+#: src/ui/gui/rank.glade:551
+msgid "Proportion Estimation Formula"
+msgstr ""
+
+#: src/ui/gui/rank.glade:615
+msgid "_Mean"
+msgstr ""
+
+#: src/ui/gui/rank.glade:627
+#, fuzzy
+msgid "_Low"
+msgstr "_Tief:"
+
+#: src/ui/gui/rank.glade:643
+#, fuzzy
+msgid "_High"
+msgstr "_Hoch:"
+
+#: src/ui/gui/rank.glade:661
+msgid "_Sequential ranks to unique values"
+msgstr ""
+
+#: src/ui/gui/rank.glade:681
+msgid "Rank Assigned to Ties"
+msgstr ""
+
 #: src/ui/gui/select-cases-dialog.c:85
 #, c-format
 msgid "Approximately %3d%% of all cases."
index 8e8a78a3259a377394bec9680de88c62f2e2e93d..d92a7d831b8e5735f7fb7d632cd070c0eeb97016 100644 (file)
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PSPP 0.4.3\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-10-17 20:48+0800\n"
+"POT-Creation-Date: 2007-11-03 12:36+0900\n"
 "PO-Revision-Date: 2007-09-15 08:29+0800\n"
 "Last-Translator: John Darrington <john@darrington.wattle.id.au>\n"
 "Language-Team: John Darrington <john@darrington.wattle.id.au>\n"
@@ -189,23 +189,23 @@ msgstr ""
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:466
+#: src/data/data-out.c:465
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:487
+#: src/data/data-out.c:486
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
 
-#: src/data/dictionary.c:747
+#: src/data/dictionary.c:758
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1048
+#: src/data/dictionary.c:1059
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
@@ -1206,21 +1206,21 @@ msgstr ""
 msgid "Handle for %s not allowed here."
 msgstr ""
 
-#: src/language/data-io/get.c:98
+#: src/language/data-io/get.c:105
 msgid "expecting COMM or TAPE"
 msgstr ""
 
-#: src/language/data-io/get.c:269 src/language/data-io/get.c:283
-#: src/language/data-io/get.c:308
+#: src/language/data-io/get.c:276 src/language/data-io/get.c:290
+#: src/language/data-io/get.c:315
 #, c-format
 msgid "expecting %s or %s"
 msgstr ""
 
-#: src/language/data-io/get.c:501 src/language/data-io/print.c:176
+#: src/language/data-io/get.c:508 src/language/data-io/print.c:176
 msgid "expecting a valid subcommand"
 msgstr ""
 
-#: src/language/data-io/get.c:534
+#: src/language/data-io/get.c:541
 #, c-format
 msgid ""
 "Cannot rename %s as %s because there already exists a variable named %s.  To "
@@ -1228,11 +1228,11 @@ msgid ""
 "as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, \"/RENAME (A B C=B C A)\"."
 msgstr ""
 
-#: src/language/data-io/get.c:560
+#: src/language/data-io/get.c:567
 msgid "`=' expected after variable list."
 msgstr ""
 
-#: src/language/data-io/get.c:567
+#: src/language/data-io/get.c:574
 #, c-format
 msgid ""
 "Number of variables on left side of `=' (%zu) does not match number of "
@@ -1240,55 +1240,55 @@ msgid ""
 "subcommand."
 msgstr ""
 
-#: src/language/data-io/get.c:580
+#: src/language/data-io/get.c:587
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr ""
 
-#: src/language/data-io/get.c:610
+#: src/language/data-io/get.c:617
 msgid "Cannot DROP all variables from dictionary."
 msgstr ""
 
-#: src/language/data-io/get.c:783
+#: src/language/data-io/get.c:790
 msgid "Cannot specify the active file since no active file has been defined."
 msgstr ""
 
-#: src/language/data-io/get.c:790
+#: src/language/data-io/get.c:797
 msgid ""
 "MATCH FILES may not be used after TEMPORARY when the active file is an input "
 "source.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/data-io/get.c:824
+#: src/language/data-io/get.c:831
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr ""
 
-#: src/language/data-io/get.c:868
+#: src/language/data-io/get.c:875
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:871
+#: src/language/data-io/get.c:878
 #, c-format
 msgid "Active file lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:941
+#: src/language/data-io/get.c:948
 msgid "BY is required when TABLE is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:946
+#: src/language/data-io/get.c:953
 msgid "BY is required when IN is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:1051
+#: src/language/data-io/get.c:1058
 #, c-format
 msgid ""
 "Variable name %s specified on %s subcommand duplicates an existing variable "
 "name."
 msgstr ""
 
-#: src/language/data-io/get.c:1297
+#: src/language/data-io/get.c:1304
 #, c-format
 msgid ""
 "Variable %s in file %s (%s) has different type or width from the same "
@@ -4396,6 +4396,7 @@ msgid "Jump to Variable"
 msgstr ""
 
 #: src/ui/gui/data-editor.c:653 src/ui/gui/data-editor.glade:438
+#: src/ui/gui/oneway.glade:179
 msgid "_Descriptives"
 msgstr ""
 
@@ -4932,44 +4933,48 @@ msgstr ""
 msgid "Incorrect range specification"
 msgstr ""
 
-#: src/ui/gui/oneway-anova-dialog.c:317
+#: src/ui/gui/oneway-anova-dialog.c:337
 #, c-format
 msgid "Contrast %d of %d"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:34 src/ui/gui/x.glade:126
+#: src/ui/gui/oneway.glade:30
 msgid "_Factor:"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:70 src/ui/gui/x.glade:82
-msgid "_Dependent Variable(s):"
+#: src/ui/gui/oneway.glade:66
+msgid "Dependent _Variable(s):"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:172
-msgid "_Options..."
+#: src/ui/gui/oneway.glade:190
+msgid "_Homogeneity"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:183
+#: src/ui/gui/oneway.glade:207
+msgid "Statistics"
+msgstr ""
+
+#: src/ui/gui/oneway.glade:226
 msgid "_Contrasts..."
 msgstr ""
 
-#: src/ui/gui/oneway.glade:254
+#: src/ui/gui/oneway.glade:309
 msgid "gtk-go-back"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:265
+#: src/ui/gui/oneway.glade:320
 msgid "gtk-go-forward"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:288
+#: src/ui/gui/oneway.glade:343
 msgid "_Coefficients:"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:334
+#: src/ui/gui/oneway.glade:389
 msgid "Coefficient Total: "
 msgstr ""
 
-#: src/ui/gui/oneway.glade:367
+#: src/ui/gui/oneway.glade:422
 msgid "Contrast 1 of 1"
 msgstr ""
 
@@ -5055,7 +5060,7 @@ msgstr ""
 msgid "Current Status: "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:265
+#: src/ui/gui/psppire.glade:265 src/ui/gui/rank.glade:67
 msgid "Variable(s):"
 msgstr ""
 
@@ -5279,6 +5284,106 @@ msgstr ""
 msgid "%d"
 msgstr ""
 
+#: src/ui/gui/rank.glade:111
+msgid "By:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:197
+msgid "_Smallest Value"
+msgstr ""
+
+#: src/ui/gui/rank.glade:209
+msgid "_Largest Value"
+msgstr ""
+
+#: src/ui/gui/rank.glade:228
+msgid "Assign rank 1 to:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:246
+msgid "_Display summary tables"
+msgstr ""
+
+#: src/ui/gui/rank.glade:262
+msgid "Rank T_ypes"
+msgstr ""
+
+#: src/ui/gui/rank.glade:273
+msgid "_Ties..."
+msgstr ""
+
+#: src/ui/gui/rank.glade:343
+msgid "Ntiles"
+msgstr ""
+
+#: src/ui/gui/rank.glade:376
+msgid "Rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:386
+msgid "Savage score"
+msgstr ""
+
+#: src/ui/gui/rank.glade:400
+msgid "Fractional rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:414
+msgid "Fractional rank as %"
+msgstr ""
+
+#: src/ui/gui/rank.glade:428
+msgid "Sum of case weights"
+msgstr ""
+
+#: src/ui/gui/rank.glade:450
+msgid "Proportion Estimates"
+msgstr ""
+
+#: src/ui/gui/rank.glade:460
+msgid "Normal Scores"
+msgstr ""
+
+#: src/ui/gui/rank.glade:495
+msgid "Blom"
+msgstr ""
+
+#: src/ui/gui/rank.glade:506
+msgid "Tukey"
+msgstr ""
+
+#: src/ui/gui/rank.glade:520
+msgid "Rankit"
+msgstr ""
+
+#: src/ui/gui/rank.glade:534
+msgid "Van der Wärden"
+msgstr ""
+
+#: src/ui/gui/rank.glade:551
+msgid "Proportion Estimation Formula"
+msgstr ""
+
+#: src/ui/gui/rank.glade:615
+msgid "_Mean"
+msgstr ""
+
+#: src/ui/gui/rank.glade:627
+msgid "_Low"
+msgstr ""
+
+#: src/ui/gui/rank.glade:643
+msgid "_High"
+msgstr ""
+
+#: src/ui/gui/rank.glade:661
+msgid "_Sequential ranks to unique values"
+msgstr ""
+
+#: src/ui/gui/rank.glade:681
+msgid "Rank Assigned to Ties"
+msgstr ""
+
 #: src/ui/gui/select-cases-dialog.c:85
 #, c-format
 msgid "Approximately %3d%% of all cases."
index 0f2e779795775fdd09b188073bd3927ca8c1d326..7c814653a069acdc1496de91363517f7386e3b7a 100644 (file)
@@ -8,12 +8,12 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-10-17 20:48+0800\n"
+"POT-Creation-Date: 2007-11-03 12:36+0900\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
@@ -191,23 +191,23 @@ msgstr ""
 msgid "%s field) "
 msgstr ""
 
-#: src/data/data-out.c:466
+#: src/data/data-out.c:465
 #, c-format
 msgid "Weekday number %f is not between 1 and 7."
 msgstr ""
 
-#: src/data/data-out.c:487
+#: src/data/data-out.c:486
 #, c-format
 msgid "Month number %f is not between 1 and 12."
 msgstr ""
 
-#: src/data/dictionary.c:747
+#: src/data/dictionary.c:758
 msgid ""
 "At least one case in the data file had a weight value that was user-missing, "
 "system-missing, zero, or negative.  These case(s) were ignored."
 msgstr ""
 
-#: src/data/dictionary.c:1048
+#: src/data/dictionary.c:1059
 #, c-format
 msgid "Truncating document line to %d bytes."
 msgstr ""
@@ -1208,21 +1208,21 @@ msgstr ""
 msgid "Handle for %s not allowed here."
 msgstr ""
 
-#: src/language/data-io/get.c:98
+#: src/language/data-io/get.c:105
 msgid "expecting COMM or TAPE"
 msgstr ""
 
-#: src/language/data-io/get.c:269 src/language/data-io/get.c:283
-#: src/language/data-io/get.c:308
+#: src/language/data-io/get.c:276 src/language/data-io/get.c:290
+#: src/language/data-io/get.c:315
 #, c-format
 msgid "expecting %s or %s"
 msgstr ""
 
-#: src/language/data-io/get.c:501 src/language/data-io/print.c:176
+#: src/language/data-io/get.c:508 src/language/data-io/print.c:176
 msgid "expecting a valid subcommand"
 msgstr ""
 
-#: src/language/data-io/get.c:534
+#: src/language/data-io/get.c:541
 #, c-format
 msgid ""
 "Cannot rename %s as %s because there already exists a variable named %s.  To "
@@ -1230,11 +1230,11 @@ msgid ""
 "as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, \"/RENAME (A B C=B C A)\"."
 msgstr ""
 
-#: src/language/data-io/get.c:560
+#: src/language/data-io/get.c:567
 msgid "`=' expected after variable list."
 msgstr ""
 
-#: src/language/data-io/get.c:567
+#: src/language/data-io/get.c:574
 #, c-format
 msgid ""
 "Number of variables on left side of `=' (%zu) does not match number of "
@@ -1242,55 +1242,55 @@ msgid ""
 "subcommand."
 msgstr ""
 
-#: src/language/data-io/get.c:580
+#: src/language/data-io/get.c:587
 #, c-format
 msgid "Requested renaming duplicates variable name %s."
 msgstr ""
 
-#: src/language/data-io/get.c:610
+#: src/language/data-io/get.c:617
 msgid "Cannot DROP all variables from dictionary."
 msgstr ""
 
-#: src/language/data-io/get.c:783
+#: src/language/data-io/get.c:790
 msgid "Cannot specify the active file since no active file has been defined."
 msgstr ""
 
-#: src/language/data-io/get.c:790
+#: src/language/data-io/get.c:797
 msgid ""
 "MATCH FILES may not be used after TEMPORARY when the active file is an input "
 "source.  Temporary transformations will be made permanent."
 msgstr ""
 
-#: src/language/data-io/get.c:824
+#: src/language/data-io/get.c:831
 msgid "Multiple IN subcommands for a single FILE or TABLE."
 msgstr ""
 
-#: src/language/data-io/get.c:868
+#: src/language/data-io/get.c:875
 #, c-format
 msgid "File %s lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:871
+#: src/language/data-io/get.c:878
 #, c-format
 msgid "Active file lacks BY variable %s."
 msgstr ""
 
-#: src/language/data-io/get.c:941
+#: src/language/data-io/get.c:948
 msgid "BY is required when TABLE is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:946
+#: src/language/data-io/get.c:953
 msgid "BY is required when IN is specified."
 msgstr ""
 
-#: src/language/data-io/get.c:1051
+#: src/language/data-io/get.c:1058
 #, c-format
 msgid ""
 "Variable name %s specified on %s subcommand duplicates an existing variable "
 "name."
 msgstr ""
 
-#: src/language/data-io/get.c:1297
+#: src/language/data-io/get.c:1304
 #, c-format
 msgid ""
 "Variable %s in file %s (%s) has different type or width from the same "
@@ -4398,6 +4398,7 @@ msgid "Jump to Variable"
 msgstr ""
 
 #: src/ui/gui/data-editor.c:653 src/ui/gui/data-editor.glade:438
+#: src/ui/gui/oneway.glade:179
 msgid "_Descriptives"
 msgstr ""
 
@@ -4934,44 +4935,48 @@ msgstr ""
 msgid "Incorrect range specification"
 msgstr ""
 
-#: src/ui/gui/oneway-anova-dialog.c:317
+#: src/ui/gui/oneway-anova-dialog.c:337
 #, c-format
 msgid "Contrast %d of %d"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:34 src/ui/gui/x.glade:126
+#: src/ui/gui/oneway.glade:30
 msgid "_Factor:"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:70 src/ui/gui/x.glade:82
-msgid "_Dependent Variable(s):"
+#: src/ui/gui/oneway.glade:66
+msgid "Dependent _Variable(s):"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:172
-msgid "_Options..."
+#: src/ui/gui/oneway.glade:190
+msgid "_Homogeneity"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:183
+#: src/ui/gui/oneway.glade:207
+msgid "Statistics"
+msgstr ""
+
+#: src/ui/gui/oneway.glade:226
 msgid "_Contrasts..."
 msgstr ""
 
-#: src/ui/gui/oneway.glade:254
+#: src/ui/gui/oneway.glade:309
 msgid "gtk-go-back"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:265
+#: src/ui/gui/oneway.glade:320
 msgid "gtk-go-forward"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:288
+#: src/ui/gui/oneway.glade:343
 msgid "_Coefficients:"
 msgstr ""
 
-#: src/ui/gui/oneway.glade:334
+#: src/ui/gui/oneway.glade:389
 msgid "Coefficient Total: "
 msgstr ""
 
-#: src/ui/gui/oneway.glade:367
+#: src/ui/gui/oneway.glade:422
 msgid "Contrast 1 of 1"
 msgstr ""
 
@@ -5057,7 +5062,7 @@ msgstr ""
 msgid "Current Status: "
 msgstr ""
 
-#: src/ui/gui/psppire.glade:265
+#: src/ui/gui/psppire.glade:265 src/ui/gui/rank.glade:67
 msgid "Variable(s):"
 msgstr ""
 
@@ -5281,6 +5286,106 @@ msgstr ""
 msgid "%d"
 msgstr ""
 
+#: src/ui/gui/rank.glade:111
+msgid "By:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:197
+msgid "_Smallest Value"
+msgstr ""
+
+#: src/ui/gui/rank.glade:209
+msgid "_Largest Value"
+msgstr ""
+
+#: src/ui/gui/rank.glade:228
+msgid "Assign rank 1 to:"
+msgstr ""
+
+#: src/ui/gui/rank.glade:246
+msgid "_Display summary tables"
+msgstr ""
+
+#: src/ui/gui/rank.glade:262
+msgid "Rank T_ypes"
+msgstr ""
+
+#: src/ui/gui/rank.glade:273
+msgid "_Ties..."
+msgstr ""
+
+#: src/ui/gui/rank.glade:343
+msgid "Ntiles"
+msgstr ""
+
+#: src/ui/gui/rank.glade:376
+msgid "Rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:386
+msgid "Savage score"
+msgstr ""
+
+#: src/ui/gui/rank.glade:400
+msgid "Fractional rank"
+msgstr ""
+
+#: src/ui/gui/rank.glade:414
+msgid "Fractional rank as %"
+msgstr ""
+
+#: src/ui/gui/rank.glade:428
+msgid "Sum of case weights"
+msgstr ""
+
+#: src/ui/gui/rank.glade:450
+msgid "Proportion Estimates"
+msgstr ""
+
+#: src/ui/gui/rank.glade:460
+msgid "Normal Scores"
+msgstr ""
+
+#: src/ui/gui/rank.glade:495
+msgid "Blom"
+msgstr ""
+
+#: src/ui/gui/rank.glade:506
+msgid "Tukey"
+msgstr ""
+
+#: src/ui/gui/rank.glade:520
+msgid "Rankit"
+msgstr ""
+
+#: src/ui/gui/rank.glade:534
+msgid "Van der Wärden"
+msgstr ""
+
+#: src/ui/gui/rank.glade:551
+msgid "Proportion Estimation Formula"
+msgstr ""
+
+#: src/ui/gui/rank.glade:615
+msgid "_Mean"
+msgstr ""
+
+#: src/ui/gui/rank.glade:627
+msgid "_Low"
+msgstr ""
+
+#: src/ui/gui/rank.glade:643
+msgid "_High"
+msgstr ""
+
+#: src/ui/gui/rank.glade:661
+msgid "_Sequential ranks to unique values"
+msgstr ""
+
+#: src/ui/gui/rank.glade:681
+msgid "Rank Assigned to Ties"
+msgstr ""
+
 #: src/ui/gui/select-cases-dialog.c:85
 #, c-format
 msgid "Approximately %3d%% of all cases."
index bb818d6d6596f2267feed21ce679c68a57d7df9d..bba2afaa6411b24035633c02927e78334774b54f 100644 (file)
@@ -1,3 +1,7 @@
+2007-11-03 John Darrington <john@darrington.wattle.id.au>
+
+       * gnumeric-reader.c gnumeric-reader.h: New files.
+
 Thu May  4 21:47:48 2006  Ben Pfaff  <blp@gnu.org>
 
        Continue reforming procedure execution.  In this phase, move
index 3c73494cd3aae6b284593f8721a3a66301a3a522..112dc3b071d124d9db59baaf42eb6d499103f8b0 100644 (file)
@@ -1,6 +1,9 @@
 
 noinst_LIBRARIES += src/data/libdata.a
 
+src_data_libdata_a_CPPFLAGS = $(LIBXML2_CFLAGS) $(AM_CPPFLAGS)
+
+
 src_data_libdata_a_SOURCES = \
        src/data/any-reader.c \
        src/data/any-reader.h \
@@ -48,6 +51,8 @@ src_data_libdata_a_SOURCES = \
        src/data/format.c \
        src/data/format.h \
        src/data/format.def \
+       src/data/gnumeric-reader.c \
+       src/data/gnumeric-reader.h \
        src/data/identifier.c \
        src/data/identifier.h \
        src/data/lazy-casereader.c \
diff --git a/src/data/gnumeric-reader.c b/src/data/gnumeric-reader.c
new file mode 100644 (file)
index 0000000..c36a683
--- /dev/null
@@ -0,0 +1,701 @@
+/* PSPP - a program for statistical analysis.
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+
+
+#include <config.h>
+
+#include <libpspp/message.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
+
+
+#if !GNM_SUPPORT
+
+struct casereader *
+gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
+{
+  msg (ME, _("Support for Gnumeric files was not compiled into this installation of PSPP"));
+
+  return NULL;
+}
+
+#else
+
+#include <data/casereader-provider.h>
+#include <errno.h>
+#include <libpspp/str.h>
+#include <libpspp/i18n.h>
+#include <data/dictionary.h>
+#include <data/variable.h>
+#include <xalloc.h>
+
+#include <errno.h>
+#include <libxml/xmlreader.h>
+#include <zlib.h>
+#include <stdbool.h>
+
+#include <data/case.h>
+#include <data/value.h>
+
+#include <gl/mbswidth.h>
+
+#include "gnumeric-reader.h"
+#include <data/identifier.h>
+#include <assert.h>
+
+
+static void gnm_file_casereader_destroy (struct casereader *, void *);
+
+static bool gnm_file_casereader_read (struct casereader *, void *,
+                                     struct ccase *);
+
+static struct casereader_class gnm_file_casereader_class =
+  {
+    gnm_file_casereader_read,
+    gnm_file_casereader_destroy,
+    NULL,
+    NULL,
+  };
+
+/* Convert a string, which is an integer encoded in base26
+   IE, A=0, B=1, ... Z=25 to the integer it represents.
+   ... except that in this scheme, digits with an exponent
+   greater than 1 are implicitly incremented by 1, so
+   AA  = 0 + 1*26, AB = 1 + 1*26,
+   ABC = 2 + 2*26 + 1*26^2 ....
+*/
+static int
+pseudo_base26 (const char *str)
+{
+  int i;
+  int multiplier = 1;
+  int result = 0;
+  int len = strlen (str);
+
+  for ( i = len - 1 ; i >= 0; --i)
+    {
+      int mantissa = (str[i] - 'A');
+
+      if ( mantissa < 0 || mantissa > 25 )
+       return -1;
+
+      if ( i != len - 1)
+       mantissa++;
+
+      result += mantissa * multiplier;
+
+      multiplier *= 26;
+    }
+
+  return result;
+}
+
+
+
+/* Convert a cell reference in the form "A1:B2", to
+   integers.  A1 means column zero, row zero.
+   B1 means column 1 row 0. AA1 means column 26, row 0.
+*/
+static bool
+convert_cell_ref (const char *ref,
+                 int *col0, int *row0,
+                 int *coli, int *rowi)
+{
+  char startcol[5];
+  char stopcol [5];
+
+  int startrow;
+  int stoprow;
+
+  int n = sscanf (ref, "%4[a-zA-Z]%d:%4[a-zA-Z]%d",
+             startcol, &startrow,
+             stopcol, &stoprow);
+  if ( n != 4)
+    return false;
+
+  str_uppercase (startcol);
+  *col0 = pseudo_base26 (startcol);
+  str_uppercase (stopcol);
+  *coli = pseudo_base26 (stopcol);
+  *row0 = startrow - 1;
+  *rowi = stoprow - 1 ;
+
+  return true;
+}
+
+
+enum reader_state
+  {
+    STATE_INIT = 0,        /* Initial state */
+    STATE_SHEET_START,     /* Found the start of a sheet */
+    STATE_SHEET_NAME,      /* Found the sheet name */
+    STATE_MAXROW,
+    STATE_SHEET_FOUND,     /* Found the sheet that we actually want */
+    STATE_CELLS_START,     /* Found the start of the cell array */
+    STATE_CELL             /* Found a cell */
+  };
+
+
+struct gnumeric_reader
+{
+  xmlTextReaderPtr xtr;
+
+  enum reader_state state;
+  int row;
+  int col;
+  int node_type;
+  int sheet_index;
+
+
+  const xmlChar *target_sheet;
+  int target_sheet_index;
+
+  int start_row;
+  int start_col;
+  int stop_row;
+  int stop_col;
+
+
+  size_t value_cnt;
+  struct dictionary *dict;
+  struct ccase first_case;
+  bool used_first_case;
+};
+
+static void process_node (struct gnumeric_reader *r);
+
+#define _xml(X) (const xmlChar *)(X)
+
+#define _xmlchar_to_int(X) atoi((const char *)X)
+
+static void
+gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
+{
+  struct gnumeric_reader *r = r_;
+  if ( r == NULL)
+       return ;
+
+  if ( r->xtr)
+    xmlFreeTextReader (r->xtr);
+
+  if ( ! r->used_first_case )
+    case_destroy (&r->first_case);
+
+  free (r);
+}
+
+static void
+process_node (struct gnumeric_reader *r)
+{
+  xmlChar *name = xmlTextReaderName (r->xtr);
+  if (name == NULL)
+    name = xmlStrdup (_xml ("--"));
+
+
+  r->node_type = xmlTextReaderNodeType (r->xtr);
+
+  switch ( r->state)
+    {
+    case STATE_INIT:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) &&
+         XML_READER_TYPE_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_SHEET_START;
+       }
+      break;
+    case STATE_SHEET_START:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
+         XML_READER_TYPE_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_SHEET_NAME;
+       }
+      else if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
+              XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_INIT;
+       }
+      break;
+    case STATE_SHEET_NAME:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
+         XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_SHEET_START;
+       }
+      else if (XML_READER_TYPE_TEXT == r->node_type)
+       {
+         ++r->sheet_index;
+         if ( r->target_sheet != NULL)
+           {
+             xmlChar *value = xmlTextReaderValue (r->xtr);
+             if ( 0 == xmlStrcmp (value, r->target_sheet))
+               r->state = STATE_SHEET_FOUND;
+             free (value);
+           }
+         else if (r->target_sheet_index == r->sheet_index)
+           {
+             r->state = STATE_SHEET_FOUND;
+           }
+       }
+      break;
+    case STATE_SHEET_FOUND:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))  &&
+         XML_READER_TYPE_ELEMENT  == r->node_type)
+       {
+         if (! xmlTextReaderIsEmptyElement (r->xtr))
+           r->state = STATE_CELLS_START;
+       }
+      else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
+         XML_READER_TYPE_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_MAXROW;
+       }
+      else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet"))  &&
+         XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_INIT;
+       }
+      break;
+    case STATE_MAXROW:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
+         XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       {
+         r->state = STATE_SHEET_FOUND;
+       }
+    case STATE_CELLS_START:
+      if (0 == xmlStrcasecmp (name, _xml ("gnm:Cell"))  &&
+         XML_READER_TYPE_ELEMENT  == r->node_type)
+       {
+         xmlChar *attr = NULL;
+         r->state = STATE_CELL;
+
+         attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Col"));
+         r->col =  _xmlchar_to_int (attr);
+         free (attr);
+
+         attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Row"));
+         r->row = _xmlchar_to_int (attr);
+         free (attr);
+       }
+      else if (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))  &&
+              XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       r->state = STATE_SHEET_NAME;
+
+      break;
+    case STATE_CELL:
+      if (0 == xmlStrcasecmp (name, _xml("gnm:Cell"))  &&
+                             XML_READER_TYPE_END_ELEMENT  == r->node_type)
+       r->state = STATE_CELLS_START;
+      break;
+    default:
+      break;
+    };
+
+  xmlFree (name);
+}
+
+
+
+/*
+  Change SUGGESTION until it's a valid name that can be added to DICT.
+*/
+static void
+devise_name (const struct dictionary *dict, struct string *name, int *x)
+{
+  struct string basename;
+  if ( ds_is_empty (name))
+    ds_init_cstr (&basename, "var");
+  else
+    ds_init_string (&basename, name);
+  do
+    {
+      ds_clear (name);
+      ds_put_format (name, "%s%d", ds_cstr (&basename), ++(*x));
+    }
+  while (NULL != dict_lookup_var (dict, ds_cstr (name)) );
+
+  ds_destroy (&basename);
+}
+
+/*
+   Mutate NAME of a variable, which is gauranteed to be valid for the
+   dictionary DICT.
+*/
+static void
+munge_name (const struct dictionary *dict, struct string *name)
+{
+  int x = 0;
+
+  if (! ds_is_empty (name))
+    {
+      /* Change all the invalid characters to valid ones */
+      char *s;
+
+      s = ds_data (name);
+
+      if ( !lex_is_id1 (*s))
+       *s = '@';
+
+      s++;
+
+      while (s < ds_data (name) + ds_length (name))
+       {
+         if ( !lex_is_idn (*s))
+           *s = '_';
+         s++;
+       }
+
+      assert (var_is_valid_name (ds_cstr (name), false));
+    }
+
+  while (ds_is_empty (name) || NULL != dict_lookup_var (dict, ds_cstr (name)) )
+    {
+      devise_name (dict, name, &x);
+    }
+}
+
+
+/*
+   Sets the VAR of case C, to the value corresponding to the xml string XV
+ */
+static void
+convert_xml_string_to_value (struct ccase *c, const struct variable *var,
+                            const xmlChar *xv)
+{
+  char *text;
+  int n_bytes = 0;
+  union value *v = case_data_rw (c, var);
+
+  text = recode_string (CONV_UTF8_TO_PSPP, (const char *) xv, -1);
+
+  if ( text)
+    n_bytes = MIN (var_get_width (var), strlen (text));
+
+  if ( var_is_alpha (var))
+    {
+      memcpy (v->s, text, n_bytes);
+    }
+  else
+    {
+      char *endptr;
+      errno = 0;
+      v->f = strtod (text, &endptr);
+      if ( errno != 0 || endptr == text)
+       v->f = SYSMIS;
+    }
+
+  free (text);
+}
+
+struct var_spec
+{
+  char *name;
+  int width;
+  xmlChar *first_value;
+};
+
+struct casereader *
+gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
+{
+  int ret;
+  casenumber n_cases = CASENUMBER_MAX;
+  int i;
+  struct var_spec *var_spec = NULL;
+  int n_var_specs = 0;
+
+  struct gnumeric_reader *r = NULL;
+
+  gzFile gz = gzopen (gri->file_name, "r");
+
+  if ( NULL == gz)
+    {
+      msg (ME, _("Error opening \"%s\" for reading as a gnumeric file: %s."),
+           gri->file_name, strerror (errno));
+
+      goto error;
+    }
+
+  r = xzalloc (sizeof *r);
+
+  r->xtr = xmlReaderForIO ((xmlInputReadCallback) gzread, gzclose, gz,
+                          NULL, NULL, 0);
+
+  if ( r->xtr == NULL)
+    goto error;
+
+  if ( gri->cell_range )
+    {
+      if ( ! convert_cell_ref (gri->cell_range,
+                              &r->start_col, &r->start_row,
+                              &r->stop_col, &r->stop_row))
+       {
+         msg (SE, _("Invalid cell range \"%s\""),
+              gri->cell_range);
+         goto error;
+       }
+    }
+  else
+    {
+      r->start_col = 0;
+      r->start_row = 0;
+      r->stop_col = -1;
+      r->stop_row = -1;
+    }
+
+  r->state = STATE_INIT;
+  r->target_sheet = BAD_CAST gri->sheet_name;
+  r->target_sheet_index = gri->sheet_index;
+  r->row = r->col = -1;
+  r->sheet_index = 0;
+
+  /* Advance to the start of the cells for the target sheet */
+  while ( (r->state != STATE_CELL || r->row < r->start_row )
+         && 1 == (ret = xmlTextReaderRead (r->xtr)))
+    {
+      xmlChar *value ;
+      process_node (r);
+      value = xmlTextReaderValue (r->xtr);
+
+      if ( r->state == STATE_MAXROW  && r->node_type == XML_READER_TYPE_TEXT)
+       {
+         n_cases = 1 + _xmlchar_to_int (value) ;
+       }
+      free (value);
+    }
+
+
+  /* If a range has been given, then  use that to calculate the number
+     of cases */
+  if ( gri->cell_range)
+    {
+      n_cases = MIN (n_cases, r->stop_row - r->start_row + 1);
+    }
+
+  if ( gri->read_names )
+    {
+      r->start_row++;
+      n_cases --;
+    }
+
+  /* Read in the first row of cells,
+     including the headers if read_names was set */
+  while (
+        (( r->state == STATE_CELLS_START && r->row <= r->start_row) || r->state == STATE_CELL )
+        && (ret = xmlTextReaderRead (r->xtr))
+        )
+    {
+      int idx;
+      process_node (r);
+
+      if ( r->row > r->start_row ) break;
+
+      if ( r->col < r->start_col ||
+          (r->stop_col != -1 && r->col > r->stop_col))
+       continue;
+
+      idx = r->col - r->start_col;
+
+      if ( idx  >= n_var_specs )
+       {
+         n_var_specs =  idx + 1 ;
+         var_spec = realloc (var_spec, sizeof (*var_spec) * n_var_specs);
+         var_spec [idx].name = NULL;
+         var_spec [idx].width = -1;
+         var_spec [idx].first_value = NULL;
+       }
+
+      if ( r->node_type == XML_READER_TYPE_TEXT )
+       {
+         char *text ;
+         xmlChar *value = xmlTextReaderValue (r->xtr);
+
+         text = recode_string (CONV_UTF8_TO_PSPP, (const char *) value, -1);
+
+         if ( r->row < r->start_row)
+           {
+             if ( gri->read_names )
+               {
+                 var_spec [idx].name = strdup (text);
+               }
+           }
+         else
+           {
+             var_spec [idx].first_value = xmlStrdup (value);
+
+             if (-1 ==  var_spec [idx].width )
+               var_spec [idx].width = (gri->asw == -1) ?
+                 ROUND_UP (strlen(text), MAX_SHORT_STRING) : gri->asw;
+           }
+
+         free (value);
+         free (text);
+       }
+      else if ( r->node_type == XML_READER_TYPE_ELEMENT
+               && r->state == STATE_CELL)
+       {
+         if ( r->row == r->start_row )
+           {
+             xmlChar *attr =
+               xmlTextReaderGetAttribute (r->xtr, _xml ("ValueType"));
+
+             if ( 60 !=  _xmlchar_to_int (attr))
+               var_spec [idx].width = 0;
+
+             free (attr);
+           }
+       }
+    }
+
+
+  /* Create the dictionary and populate it */
+  *dict = r->dict = dict_create ();
+
+  r->value_cnt = 0;
+
+  for (i = 0 ; i < n_var_specs ; ++i )
+    {
+      struct string name;
+
+      /* Probably no data exists for this variable, so allocate a default width */
+      if ( var_spec[i].width == -1 )
+       var_spec[i].width = MAX_SHORT_STRING;
+
+      r->value_cnt += value_cnt_from_width (var_spec[i].width);
+
+      if (var_spec[i].name)
+       ds_init_cstr (&name, var_spec[i].name);
+      else
+       ds_init_empty (&name);
+
+      munge_name (r->dict, &name);
+
+
+      dict_create_var (r->dict, ds_cstr (&name), var_spec[i].width);
+
+      ds_destroy (&name);
+    }
+
+  /* Create the first case, and cache it */
+  r->used_first_case = false;
+
+  if ( n_var_specs ==  0 )
+    {
+      msg (MW, _("Selected sheet or range of spreadsheet \"%s\" is empty."),
+           gri->file_name);
+      goto error;
+    }
+
+  case_create (&r->first_case, r->value_cnt);
+  memset (case_data_rw_idx (&r->first_case, 0)->s,
+         ' ', MAX_SHORT_STRING * r->value_cnt);
+
+  for ( i = 0 ; i < n_var_specs ; ++i )
+    {
+      const struct variable *var = dict_get_var (r->dict, i);
+
+      convert_xml_string_to_value (&r->first_case, var,
+                                  var_spec[i].first_value);
+    }
+
+  for ( i = 0 ; i < n_var_specs ; ++i )
+    {
+      free (var_spec[i].first_value);
+      free (var_spec[i].name);
+    }
+
+  free (var_spec);
+
+  return casereader_create_sequential
+    (NULL,
+     r->value_cnt,
+     n_cases,
+     &gnm_file_casereader_class, r);
+
+
+ error:
+  for ( i = 0 ; i < n_var_specs ; ++i )
+    {
+      free (var_spec[i].first_value);
+      free (var_spec[i].name);
+    }
+
+  free (var_spec);
+
+  gnm_file_casereader_destroy (NULL, r);
+
+  return NULL;
+};
+
+
+/* Reads one case from READER's file into C.  Returns true only
+   if successful. */
+static bool
+gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_,
+                          struct ccase *c)
+{
+  int ret = 0;
+
+  struct gnumeric_reader *r = r_;
+  int current_row = r->row;
+
+  if ( !r->used_first_case )
+    {
+      *c = r->first_case;
+      r->used_first_case = true;
+      return true;
+    }
+
+  case_create (c, r->value_cnt);
+
+  memset (case_data_rw_idx (c, 0)->s, ' ', MAX_SHORT_STRING * r->value_cnt);
+
+  while ((r->state == STATE_CELL || r->state == STATE_CELLS_START )
+        && r->row == current_row && (ret = xmlTextReaderRead (r->xtr)))
+    {
+      process_node (r);
+
+      if ( r->col < r->start_col || (r->stop_col != -1 &&
+                                    r->col > r->stop_col))
+       continue;
+
+      if ( r->col - r->start_col >= r->value_cnt)
+       continue;
+
+      if ( r->stop_row != -1 && r->row > r->stop_row)
+       break;
+
+      if ( r->node_type == XML_READER_TYPE_TEXT )
+       {
+         xmlChar *value = xmlTextReaderValue (r->xtr);
+
+         const int idx = r->col - r->start_col;
+
+         const struct variable *var = dict_get_var (r->dict, idx);
+
+         convert_xml_string_to_value (c, var, value);
+
+         free (value);
+       }
+
+    }
+
+  return (ret == 1);
+}
+
+
+#endif /* GNM_SUPPORT */
diff --git a/src/data/gnumeric-reader.h b/src/data/gnumeric-reader.h
new file mode 100644 (file)
index 0000000..6bb5a6b
--- /dev/null
@@ -0,0 +1,40 @@
+/* PSPP - a program for statistical analysis.
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GNUMERIC_READ_H
+#define GNUMERIC_READ_H 1
+
+#include <stdbool.h>
+
+struct casereader;
+
+
+struct gnumeric_read_info
+{
+  char *sheet_name ;
+  char *file_name ;
+  char *cell_range ;
+  int sheet_index ;
+  bool read_names ;
+  int asw ;
+};
+
+struct dictionary;
+
+struct casereader * gnumeric_open_reader (struct gnumeric_read_info *, struct dictionary **);
+
+
+#endif
index ae8bb79fee5276f3a73ec730e6d8a1cf02b0efbb..7982916a82747cb27cd07cec7d040c7b7c00f670 100644 (file)
@@ -1,3 +1,10 @@
+2007-11-03 John Darrington <john@darrington.wattle.id.au>
+
+       * get.c: Add GET DATA command variant.
+
+       * get-data.c get-data.h (new files): Added support for
+        GET DATA /TYPE='gnm'  command.
+
 2007-09-23  Ben Pfaff  <blp@gnu.org>
 
        Bug #21111.  Reviewed by John Darrington.
index df51c631c8bed6d333421cbaae1fd181641c9677..dced683b3fea4a2048eb296ba6d541d074b554f0 100644 (file)
@@ -7,6 +7,8 @@ src_language_data_io_built_sources = \
 language_data_io_sources = \
        src/language/data-io/data-list.c \
        src/language/data-io/get.c \
+       src/language/data-io/get-data.c \
+       src/language/data-io/get-data.h \
        src/language/data-io/inpt-pgm.c \
        src/language/data-io/inpt-pgm.h \
        src/language/data-io/print.c \
diff --git a/src/language/data-io/get-data.c b/src/language/data-io/get-data.c
new file mode 100644 (file)
index 0000000..015815a
--- /dev/null
@@ -0,0 +1,159 @@
+/* PSPP - a program for statistical analysis.
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "get-data.h"
+
+#include <libpspp/message.h>
+#include <data/gnumeric-reader.h>
+
+#include <language/command.h>
+#include <language/lexer/lexer.h>
+#include <stdlib.h>
+#include <data/procedure.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) (msgid)
+
+static int parse_get_gnm (struct lexer *lexer, struct dataset *);
+
+int
+parse_get_data_command (struct lexer *lexer, struct dataset *ds)
+{
+  lex_force_match (lexer, '/');
+
+  if (!lex_force_match_id (lexer, "TYPE"))
+    return CMD_FAILURE;
+
+  lex_force_match (lexer, '=');
+
+  if (lex_match_id (lexer, "GNM"))
+    return parse_get_gnm (lexer, ds);
+
+  msg (SE, _("Unsupported TYPE %s"), lex_tokid (lexer));
+  return CMD_FAILURE;
+}
+
+
+static int
+parse_get_gnm (struct lexer *lexer, struct dataset *ds)
+{
+  struct gnumeric_read_info gri  = {NULL, NULL, NULL, 1, true, -1};
+
+  lex_force_match (lexer, '/');
+
+  if (!lex_force_match_id (lexer, "FILE"))
+    goto error;
+
+  lex_force_match (lexer, '=');
+
+  if (!lex_force_string (lexer))
+    goto error;
+
+  gri.file_name = strdup (ds_cstr (lex_tokstr (lexer)));
+
+  lex_get (lexer);
+
+  while (lex_match (lexer, '/') )
+    {
+      if ( lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
+       {
+         lex_match (lexer, '=');
+         gri.asw = lex_integer (lexer);
+       }
+      else if (lex_match_id (lexer, "SHEET"))
+       {
+         lex_match (lexer, '=');
+         if (lex_match_id (lexer, "NAME"))
+           {
+             if ( ! lex_force_string (lexer) )
+               goto error;
+
+             gri.sheet_name = strdup (ds_cstr (lex_tokstr (lexer)));
+             gri.sheet_index = -1;
+           }
+         else if (lex_match_id (lexer, "INDEX"))
+           {
+             gri.sheet_index = lex_integer (lexer);
+           }
+         else
+           goto error;
+       }
+      else if (lex_match_id (lexer, "CELLRANGE"))
+       {
+         lex_match (lexer, '=');
+
+         if (lex_match_id (lexer, "FULL"))
+           {
+             gri.cell_range = NULL;
+             lex_put_back (lexer, T_ID);
+           }
+         else if (lex_match_id (lexer, "RANGE"))
+           {
+             if ( ! lex_force_string (lexer) )
+               goto error;
+
+             gri.cell_range = strdup (ds_cstr (lex_tokstr (lexer)));
+           }
+         else
+           goto error;
+       }
+      else if (lex_match_id (lexer, "READNAMES"))
+       {
+         lex_match (lexer, '=');
+
+         if ( lex_match_id (lexer, "ON"))
+           {
+             gri.read_names = true;
+           }
+         else if (lex_match_id (lexer, "OFF"))
+           {
+             gri.read_names = false;
+           }
+         else
+           goto error;
+         lex_put_back (lexer, T_ID);
+       }
+      else
+       {
+         printf ("Unknown data file type \"\%s\"\n", lex_tokid (lexer));
+         goto error;
+       }
+      lex_get (lexer);
+    }
+
+  {
+    struct dictionary *dict = NULL;
+    struct casereader *reader = gnumeric_open_reader (&gri, &dict);
+
+    if ( reader )
+      proc_set_active_file (ds, reader, dict);
+  }
+
+  free (gri.file_name);
+  free (gri.sheet_name);
+  free (gri.cell_range);
+  return CMD_SUCCESS;
+
+ error:
+
+  free (gri.file_name);
+  free (gri.sheet_name);
+  free (gri.cell_range);
+  return CMD_FAILURE;
+}
diff --git a/src/language/data-io/get-data.h b/src/language/data-io/get-data.h
new file mode 100644 (file)
index 0000000..4d9c44e
--- /dev/null
@@ -0,0 +1,26 @@
+/* PSPP - a program for statistical analysis.
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GET_DATA_H
+#define GET_DATA_H
+
+struct lexer;
+struct dataset;
+
+int parse_get_data_command (struct lexer *lexer, struct dataset *ds);
+
+
+#endif
index 574656b9d62380a531b46b94f024f0401d3ecdb0..b861aca52ffef7df758d3eabfc506718795081eb 100644 (file)
@@ -45,6 +45,8 @@
 #include <libpspp/str.h>
 #include <libpspp/taint.h>
 
+#include "get-data.h"
+
 #include "xalloc.h"
 
 #include "gettext.h"
@@ -73,6 +75,11 @@ parse_read_command (struct lexer *lexer, struct dataset *ds, enum reader_command
   struct dictionary *dict = NULL;
   struct case_map *map = NULL;
 
+  if ( type == GET_CMD && lex_match_id (lexer, "DATA") )
+    {
+      return parse_get_data_command (lexer, ds);
+    }
+
   for (;;)
     {
       lex_match (lexer, '/');
index bd3bc5363ba7bfcc24efc678d3681b2429815486..4d9186f520f03325a438706745df8eed28f66ab2 100644 (file)
@@ -1,3 +1,8 @@
+2007-11-03 John Darrington <john@darrington.wattle.id.au>
+
+       * i18n.c i18n.h: Added convertor from UTF8 to system.
+       This is needed for reading gnumeric files (and possibly others).
+
 2007-10-11  Ben Pfaff  <blp@gnu.org>
 
        * xalloc.h: Removed.  Changed all users to include "xalloc.h" from
index d194634f654dfca804cfd5d22b29e57b46f42966..ba083fffe2f1a791dca465bd0c4a17b59b4cc63c 100644 (file)
@@ -177,6 +177,9 @@ set_pspp_locale (const char *l)
 
   iconv_close (convertor[CONV_SYSTEM_TO_PSPP]);
   convertor[CONV_SYSTEM_TO_PSPP] = create_iconv (charset, current_charset);
+
+  iconv_close (convertor[CONV_UTF8_TO_PSPP]);
+  convertor[CONV_UTF8_TO_PSPP] = create_iconv (charset, "UTF-8");
 }
 
 void
@@ -188,8 +191,9 @@ i18n_init (void)
   setlocale (LC_CTYPE, locale);
   charset = locale_charset ();
 
-  convertor[CONV_PSPP_TO_UTF8] = create_iconv ("UTF-8", charset);
+  convertor[CONV_PSPP_TO_UTF8]   = create_iconv ("UTF-8", charset);
   convertor[CONV_SYSTEM_TO_PSPP] = create_iconv (charset, charset);
+  convertor[CONV_UTF8_TO_PSPP]   = create_iconv (charset, "UTF-8");
 }
 
 
index 51ca28edb04a14d3ae14c7eff6eaeb5a4ee61e18..0633ebc82f807b9fb1d89429c3bf99fa9699930c 100644 (file)
 #ifndef I18N_H
 #define I18N_H
 
-const char * get_pspp_locale(void);
-void set_pspp_locale(const char *locale);
-const char * get_pspp_charset(void);
+const char * get_pspp_locale (void);
+void set_pspp_locale (const char *locale);
+const char * get_pspp_charset (void);
 
-void  i18n_done(void);
-void  i18n_init(void);
+void  i18n_done (void);
+void  i18n_init (void);
 
 enum conv_id
   {
     CONV_PSPP_TO_UTF8,
     CONV_SYSTEM_TO_PSPP,
+    CONV_UTF8_TO_PSPP,
     n_CONV
   };
 
 
-char * recode_string(enum conv_id how,  const char *text, int len);
+char * recode_string (enum conv_id how,  const char *text, int len);
 
 
 
index a6ea104a4cb8ceeff0f73bb21f8e56c10a7503f7..65cd23a33818f4b7b9f37e2c71ca33e8efd3e03e 100644 (file)
@@ -32,6 +32,7 @@ src_ui_terminal_pspp_LDADD = \
        lib/gsl-extras/libgsl-extras.a  \
        src/data/libdata.a \
        src/libpspp/libpspp.a \
+       $(LIBXML2_LIBS) \
        $(LIBICONV) \
        gl/libgl.la \
        @LIBINTL@ @LIBREADLINE@
diff --git a/tests/Book1.gnm.unzipped b/tests/Book1.gnm.unzipped
new file mode 100644 (file)
index 0000000..052783e
--- /dev/null
@@ -0,0 +1,535 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gnm:Workbook xmlns:gnm="http://www.gnumeric.org/v10.dtd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gnumeric.org/v8.xsd">
+  <gnm:Version Epoch="1" Major="6" Minor="3" Full="1.6.3"/>
+  <gnm:Attributes>
+    <gnm:Attribute>
+      <gnm:type>4</gnm:type>
+      <gnm:name>WorkbookView::show_horizontal_scrollbar</gnm:name>
+      <gnm:value>TRUE</gnm:value>
+    </gnm:Attribute>
+    <gnm:Attribute>
+      <gnm:type>4</gnm:type>
+      <gnm:name>WorkbookView::show_vertical_scrollbar</gnm:name>
+      <gnm:value>TRUE</gnm:value>
+    </gnm:Attribute>
+    <gnm:Attribute>
+      <gnm:type>4</gnm:type>
+      <gnm:name>WorkbookView::show_notebook_tabs</gnm:name>
+      <gnm:value>TRUE</gnm:value>
+    </gnm:Attribute>
+    <gnm:Attribute>
+      <gnm:type>4</gnm:type>
+      <gnm:name>WorkbookView::do_auto_completion</gnm:name>
+      <gnm:value>TRUE</gnm:value>
+    </gnm:Attribute>
+    <gnm:Attribute>
+      <gnm:type>4</gnm:type>
+      <gnm:name>WorkbookView::is_protected</gnm:name>
+      <gnm:value>FALSE</gnm:value>
+    </gnm:Attribute>
+  </gnm:Attributes>
+  <gnm:Summary>
+    <gnm:Item>
+      <gnm:name>application</gnm:name>
+      <gnm:val-string>gnumeric</gnm:val-string>
+    </gnm:Item>
+    <gnm:Item>
+      <gnm:name>author</gnm:name>
+      <gnm:val-string>John Darrington</gnm:val-string>
+    </gnm:Item>
+  </gnm:Summary>
+  <gnm:SheetNameIndex>
+    <gnm:SheetName>This</gnm:SheetName>
+    <gnm:SheetName>vars</gnm:SheetName>
+    <gnm:SheetName>That</gnm:SheetName>
+    <gnm:SheetName>Empty</gnm:SheetName>
+    <gnm:SheetName>Blank</gnm:SheetName>
+  </gnm:SheetNameIndex>
+  <gnm:Geometry Width="1278" Height="633"/>
+  <gnm:Sheets>
+    <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE">
+      <gnm:Name>This</gnm:Name>
+      <gnm:MaxCol>9</gnm:MaxCol>
+      <gnm:MaxRow>17</gnm:MaxRow>
+      <gnm:Zoom>1</gnm:Zoom>
+      <gnm:PrintInformation>
+        <gnm:Margins>
+          <gnm:top Points="120" PrefUnit="cm"/>
+          <gnm:bottom Points="120" PrefUnit="cm"/>
+        </gnm:Margins>
+        <gnm:Scale type="percentage" percentage="100"/>
+        <gnm:vcenter value="0"/>
+        <gnm:hcenter value="0"/>
+        <gnm:grid value="0"/>
+        <gnm:even_if_only_styles value="0"/>
+        <gnm:monochrome value="0"/>
+        <gnm:draft value="0"/>
+        <gnm:titles value="0"/>
+        <gnm:order>d_then_r</gnm:order>
+        <gnm:orientation>portrait</gnm:orientation>
+        <gnm:Header Left="" Middle="&amp;[TAB]" Right=""/>
+        <gnm:Footer Left="" Middle="Page &amp;[PAGE]" Right=""/>
+      </gnm:PrintInformation>
+      <gnm:Styles>
+        <gnm:StyleRegion startCol="0" startRow="0" endCol="255" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+      </gnm:Styles>
+      <gnm:Cols DefaultSizePts="48">
+        <gnm:ColInfo No="0" Unit="48" MarginA="2" MarginB="2" Count="10"/>
+      </gnm:Cols>
+      <gnm:Rows DefaultSizePts="12.75">
+        <gnm:RowInfo No="0" Unit="12.75" MarginA="0" MarginB="0" Count="15"/>
+        <gnm:RowInfo No="15" Unit="9.75" MarginA="0" MarginB="0" HardSize="1"/>
+        <gnm:RowInfo No="17" Unit="12.75" MarginA="0" MarginB="0"/>
+      </gnm:Rows>
+      <gnm:Selections CursorCol="7" CursorRow="7">
+        <gnm:Selection startCol="7" startRow="7" endCol="7" endRow="7"/>
+      </gnm:Selections>
+      <gnm:Cells>
+        <gnm:Cell Col="0" Row="0" ValueType="60">numeral</gnm:Cell>
+        <gnm:Cell Col="1" Row="0" ValueType="60">eng_name</gnm:Cell>
+        <gnm:Cell Col="2" Row="0" ValueType="60">xxx</gnm:Cell>
+        <gnm:Cell Col="0" Row="1" ValueType="30">1</gnm:Cell>
+        <gnm:Cell Col="1" Row="1" ValueType="60">One</gnm:Cell>
+        <gnm:Cell Col="2" Row="1" ValueType="60">Eins</gnm:Cell>
+        <gnm:Cell Col="0" Row="2" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="1" Row="2" ValueType="60">Two</gnm:Cell>
+        <gnm:Cell Col="2" Row="2" ValueType="60">Zwei</gnm:Cell>
+        <gnm:Cell Col="0" Row="3" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="1" Row="3" ValueType="60">Three</gnm:Cell>
+        <gnm:Cell Col="2" Row="3" ValueType="60">Drei</gnm:Cell>
+        <gnm:Cell Col="2" Row="4" ValueType="60">Vier</gnm:Cell>
+        <gnm:Cell Col="5" Row="6" ValueType="60">XY</gnm:Cell>
+        <gnm:Cell Col="6" Row="6" ValueType="60">xxx</gnm:Cell>
+        <gnm:Cell Col="7" Row="6" ValueType="60">xxxx</gnm:Cell>
+        <gnm:Cell Col="8" Row="6" ValueType="60">xxxx</gnm:Cell>
+        <gnm:Cell Col="5" Row="7" ValueType="60">yyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="7" ValueType="60">V1</gnm:Cell>
+        <gnm:Cell Col="7" Row="7" ValueType="60">V2</gnm:Cell>
+        <gnm:Cell Col="5" Row="8" ValueType="60">yyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="8" ValueType="30">0</gnm:Cell>
+        <gnm:Cell Col="7" Row="8" ValueType="60">fred</gnm:Cell>
+        <gnm:Cell Col="8" Row="8" ValueType="30">20</gnm:Cell>
+        <gnm:Cell Col="9" Row="8" ValueType="60">$$$$</gnm:Cell>
+        <gnm:Cell Col="5" Row="9" ValueType="60">yyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="9" ValueType="30">1</gnm:Cell>
+        <gnm:Cell Col="7" Row="9" ValueType="30">11</gnm:Cell>
+        <gnm:Cell Col="8" Row="9" ValueType="30">21</gnm:Cell>
+        <gnm:Cell Col="9" Row="9" ValueType="60">$$$$</gnm:Cell>
+        <gnm:Cell Col="5" Row="10" ValueType="60">yyyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="10" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="7" Row="10" ValueType="60">twelve</gnm:Cell>
+        <gnm:Cell Col="8" Row="10" ValueType="30">22</gnm:Cell>
+        <gnm:Cell Col="9" Row="10" ValueType="60">$$$$</gnm:Cell>
+        <gnm:Cell Col="5" Row="11" ValueType="60">yyyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="11" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="7" Row="11" ValueType="30">13</gnm:Cell>
+        <gnm:Cell Col="8" Row="11" ValueType="30">23</gnm:Cell>
+        <gnm:Cell Col="9" Row="11" ValueType="60">$$$$</gnm:Cell>
+        <gnm:Cell Col="1" Row="12" ValueType="60">Eleven</gnm:Cell>
+        <gnm:Cell Col="5" Row="12" ValueType="60">yyyy</gnm:Cell>
+        <gnm:Cell Col="6" Row="12" ValueType="30">4</gnm:Cell>
+        <gnm:Cell Col="7" Row="12" ValueType="30">14</gnm:Cell>
+        <gnm:Cell Col="8" Row="12" ValueType="30">24</gnm:Cell>
+        <gnm:Cell Col="9" Row="12" ValueType="60">$$$$</gnm:Cell>
+        <gnm:Cell Col="5" Row="13" ValueType="60">zzz</gnm:Cell>
+        <gnm:Cell Col="6" Row="13" ValueType="60">zzz</gnm:Cell>
+        <gnm:Cell Col="7" Row="13" ValueType="60">zzz</gnm:Cell>
+        <gnm:Cell Col="8" Row="13" ValueType="60">zzz</gnm:Cell>
+        <gnm:Cell Col="9" Row="13" ValueType="60">zzz</gnm:Cell>
+        <gnm:Cell Col="1" Row="17" ValueType="60">Seventeen</gnm:Cell>
+      </gnm:Cells>
+      <gnm:SheetLayout TopLeft="A1"/>
+      <gnm:Solver ProblemType="1" Inputs="" MaxTime="0" MaxIter="0" NonNeg="1" Discr="0" AutoScale="0" ShowIter="0" AnswerR="0" SensitivityR="0" LimitsR="0" PerformR="0" ProgramR="0"/>
+    </gnm:Sheet>
+    <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE">
+      <gnm:Name>vars</gnm:Name>
+      <gnm:MaxCol>4</gnm:MaxCol>
+      <gnm:MaxRow>8</gnm:MaxRow>
+      <gnm:Zoom>1</gnm:Zoom>
+      <gnm:PrintInformation>
+        <gnm:Margins>
+          <gnm:top Points="120" PrefUnit="cm"/>
+          <gnm:bottom Points="120" PrefUnit="cm"/>
+        </gnm:Margins>
+        <gnm:Scale type="percentage" percentage="100"/>
+        <gnm:vcenter value="0"/>
+        <gnm:hcenter value="0"/>
+        <gnm:grid value="0"/>
+        <gnm:even_if_only_styles value="0"/>
+        <gnm:monochrome value="0"/>
+        <gnm:draft value="0"/>
+        <gnm:titles value="0"/>
+        <gnm:order>d_then_r</gnm:order>
+        <gnm:orientation>portrait</gnm:orientation>
+        <gnm:Header Left="" Middle="&amp;[TAB]" Right=""/>
+        <gnm:Footer Left="" Middle="Page &amp;[PAGE]" Right=""/>
+      </gnm:PrintInformation>
+      <gnm:Styles>
+        <gnm:StyleRegion startCol="0" startRow="0" endCol="255" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+      </gnm:Styles>
+      <gnm:Cols DefaultSizePts="48">
+        <gnm:ColInfo No="0" Unit="48" MarginA="2" MarginB="2" Count="5"/>
+      </gnm:Cols>
+      <gnm:Rows DefaultSizePts="12.75">
+        <gnm:RowInfo No="0" Unit="12.75" MarginA="0" MarginB="0" Count="5"/>
+      </gnm:Rows>
+      <gnm:Selections CursorCol="0" CursorRow="0">
+        <gnm:Selection startCol="0" startRow="0" endCol="0" endRow="0"/>
+      </gnm:Selections>
+      <gnm:Cells>
+        <gnm:Cell Col="0" Row="0" ValueType="60">1v12</gnm:Cell>
+        <gnm:Cell Col="1" Row="0" ValueType="60">var&amp;x@</gnm:Cell>
+        <gnm:Cell Col="2" Row="0" ValueType="60">a(43)</gnm:Cell>
+        <gnm:Cell Col="3" Row="0" ValueType="60">varx</gnm:Cell>
+        <gnm:Cell Col="4" Row="0" ValueType="60">varx</gnm:Cell>
+        <gnm:Cell Col="0" Row="1" ValueType="30">1</gnm:Cell>
+        <gnm:Cell Col="1" Row="1" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="2" Row="1" ValueType="30">23</gnm:Cell>
+        <gnm:Cell Col="3" Row="1" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="4" Row="1" ValueType="30">4</gnm:Cell>
+        <gnm:Cell Col="0" Row="2" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="1" Row="2" ValueType="30">4</gnm:Cell>
+        <gnm:Cell Col="2" Row="2" ValueType="30">23</gnm:Cell>
+        <gnm:Cell Col="3" Row="2" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="4" Row="2" ValueType="30">4</gnm:Cell>
+        <gnm:Cell Col="1" Row="8" ValueType="10"></gnm:Cell>
+      </gnm:Cells>
+      <gnm:SheetLayout TopLeft="A1"/>
+      <gnm:Solver ProblemType="1" Inputs="" MaxTime="0" MaxIter="0" NonNeg="1" Discr="0" AutoScale="0" ShowIter="0" AnswerR="0" SensitivityR="0" LimitsR="0" PerformR="0" ProgramR="0"/>
+    </gnm:Sheet>
+    <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE">
+      <gnm:Name>That</gnm:Name>
+      <gnm:MaxCol>3</gnm:MaxCol>
+      <gnm:MaxRow>4</gnm:MaxRow>
+      <gnm:Zoom>1</gnm:Zoom>
+      <gnm:PrintInformation>
+        <gnm:Margins>
+          <gnm:top Points="120" PrefUnit="cm"/>
+          <gnm:bottom Points="120" PrefUnit="cm"/>
+        </gnm:Margins>
+        <gnm:Scale type="percentage" percentage="100"/>
+        <gnm:vcenter value="0"/>
+        <gnm:hcenter value="0"/>
+        <gnm:grid value="0"/>
+        <gnm:even_if_only_styles value="0"/>
+        <gnm:monochrome value="0"/>
+        <gnm:draft value="0"/>
+        <gnm:titles value="0"/>
+        <gnm:order>d_then_r</gnm:order>
+        <gnm:orientation>portrait</gnm:orientation>
+        <gnm:Header Left="" Middle="&amp;[TAB]" Right=""/>
+        <gnm:Footer Left="" Middle="Page &amp;[PAGE]" Right=""/>
+      </gnm:PrintInformation>
+      <gnm:Styles>
+        <gnm:StyleRegion startCol="0" startRow="4096" endCol="63" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="4" startRow="0" endCol="15" endRow="255">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="0" startRow="16" endCol="3" endRow="255">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="16" startRow="0" endCol="63" endRow="4095">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="64" startRow="0" endCol="255" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="3" startRow="0" endCol="3" endRow="15">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="2" startRow="5" endCol="2" endRow="15">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="2" startRow="1" endCol="2" endRow="4">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="0.00">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="0" startRow="256" endCol="15" endRow="4095">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="0" startRow="0" endCol="1" endRow="15">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+        <gnm:StyleRegion startCol="2" startRow="0" endCol="2" endRow="0">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+      </gnm:Styles>
+      <gnm:Cols DefaultSizePts="48">
+        <gnm:ColInfo No="0" Unit="48" MarginA="2" MarginB="2" Count="2"/>
+        <gnm:ColInfo No="2" Unit="90.75" MarginA="2" MarginB="2" HardSize="1"/>
+        <gnm:ColInfo No="3" Unit="81" MarginA="2" MarginB="2" HardSize="1"/>
+      </gnm:Cols>
+      <gnm:Rows DefaultSizePts="12.75">
+        <gnm:RowInfo No="0" Unit="12.75" MarginA="0" MarginB="0" Count="5"/>
+      </gnm:Rows>
+      <gnm:Selections CursorCol="0" CursorRow="5">
+        <gnm:Selection startCol="0" startRow="5" endCol="0" endRow="5"/>
+      </gnm:Selections>
+      <gnm:Cells>
+        <gnm:Cell Col="0" Row="0" ValueType="60">name</gnm:Cell>
+        <gnm:Cell Col="1" Row="0" ValueType="60">id</gnm:Cell>
+        <gnm:Cell Col="2" Row="0" ValueType="60">height</gnm:Cell>
+        <gnm:Cell Col="0" Row="1" ValueType="60">fred</gnm:Cell>
+        <gnm:Cell Col="1" Row="1" ValueType="30">0</gnm:Cell>
+        <gnm:Cell Col="2" Row="1" ValueType="40">23.4</gnm:Cell>
+        <gnm:Cell Col="0" Row="2" ValueType="60">bert </gnm:Cell>
+        <gnm:Cell Col="1" Row="2" ValueType="30">1</gnm:Cell>
+        <gnm:Cell Col="2" Row="2" ValueType="40">0.56</gnm:Cell>
+        <gnm:Cell Col="0" Row="3" ValueType="60">charlie</gnm:Cell>
+        <gnm:Cell Col="1" Row="3" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="2" Row="3" ValueType="60">n/a</gnm:Cell>
+        <gnm:Cell Col="0" Row="4" ValueType="60">dick</gnm:Cell>
+        <gnm:Cell Col="1" Row="4" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="2" Row="4" ValueType="40" ValueFormat="0.00">-34.09</gnm:Cell>
+      </gnm:Cells>
+      <gnm:SheetLayout TopLeft="A1"/>
+      <gnm:Solver ProblemType="1" Inputs="" MaxTime="0" MaxIter="0" NonNeg="1" Discr="0" AutoScale="0" ShowIter="0" AnswerR="0" SensitivityR="0" LimitsR="0" PerformR="0" ProgramR="0"/>
+    </gnm:Sheet>
+    <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE">
+      <gnm:Name>Empty</gnm:Name>
+      <gnm:MaxCol>-1</gnm:MaxCol>
+      <gnm:MaxRow>-1</gnm:MaxRow>
+      <gnm:Zoom>1</gnm:Zoom>
+      <gnm:PrintInformation>
+        <gnm:Margins>
+          <gnm:top Points="120" PrefUnit="cm"/>
+          <gnm:bottom Points="120" PrefUnit="cm"/>
+        </gnm:Margins>
+        <gnm:Scale type="percentage" percentage="100"/>
+        <gnm:vcenter value="0"/>
+        <gnm:hcenter value="0"/>
+        <gnm:grid value="0"/>
+        <gnm:even_if_only_styles value="0"/>
+        <gnm:monochrome value="0"/>
+        <gnm:draft value="0"/>
+        <gnm:titles value="0"/>
+        <gnm:order>d_then_r</gnm:order>
+        <gnm:orientation>portrait</gnm:orientation>
+        <gnm:Header Left="" Middle="&amp;[TAB]" Right=""/>
+        <gnm:Footer Left="" Middle="Page &amp;[PAGE]" Right=""/>
+      </gnm:PrintInformation>
+      <gnm:Styles>
+        <gnm:StyleRegion startCol="0" startRow="0" endCol="255" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+      </gnm:Styles>
+      <gnm:Cols DefaultSizePts="48"/>
+      <gnm:Rows DefaultSizePts="12.75"/>
+      <gnm:Selections CursorCol="0" CursorRow="0">
+        <gnm:Selection startCol="0" startRow="0" endCol="0" endRow="0"/>
+      </gnm:Selections>
+      <gnm:Cells/>
+      <gnm:SheetLayout TopLeft="A1"/>
+      <gnm:Solver ProblemType="1" Inputs="" MaxTime="0" MaxIter="0" NonNeg="1" Discr="0" AutoScale="0" ShowIter="0" AnswerR="0" SensitivityR="0" LimitsR="0" PerformR="0" ProgramR="0"/>
+    </gnm:Sheet>
+    <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE">
+      <gnm:Name>Blank</gnm:Name>
+      <gnm:MaxCol>3</gnm:MaxCol>
+      <gnm:MaxRow>2</gnm:MaxRow>
+      <gnm:Zoom>1</gnm:Zoom>
+      <gnm:PrintInformation>
+        <gnm:Margins>
+          <gnm:top Points="120" PrefUnit="cm"/>
+          <gnm:bottom Points="120" PrefUnit="cm"/>
+        </gnm:Margins>
+        <gnm:Scale type="percentage" percentage="100"/>
+        <gnm:vcenter value="0"/>
+        <gnm:hcenter value="0"/>
+        <gnm:grid value="0"/>
+        <gnm:even_if_only_styles value="0"/>
+        <gnm:monochrome value="0"/>
+        <gnm:draft value="0"/>
+        <gnm:titles value="0"/>
+        <gnm:order>d_then_r</gnm:order>
+        <gnm:orientation>portrait</gnm:orientation>
+        <gnm:Header Left="" Middle="&amp;[TAB]" Right=""/>
+        <gnm:Footer Left="" Middle="Page &amp;[PAGE]" Right=""/>
+      </gnm:PrintInformation>
+      <gnm:Styles>
+        <gnm:StyleRegion startCol="0" startRow="0" endCol="255" endRow="65535">
+          <gnm:Style HAlign="1" VAlign="2" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General">
+            <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font>
+            <gnm:StyleBorder>
+              <gnm:Top Style="0"/>
+              <gnm:Bottom Style="0"/>
+              <gnm:Left Style="0"/>
+              <gnm:Right Style="0"/>
+              <gnm:Diagonal Style="0"/>
+              <gnm:Rev-Diagonal Style="0"/>
+            </gnm:StyleBorder>
+          </gnm:Style>
+        </gnm:StyleRegion>
+      </gnm:Styles>
+      <gnm:Cols DefaultSizePts="48">
+        <gnm:ColInfo No="0" Unit="48" MarginA="2" MarginB="2" Count="4"/>
+      </gnm:Cols>
+      <gnm:Rows DefaultSizePts="12.75">
+        <gnm:RowInfo No="0" Unit="12.75" MarginA="0" MarginB="0" Count="3"/>
+      </gnm:Rows>
+      <gnm:Selections CursorCol="3" CursorRow="1">
+        <gnm:Selection startCol="3" startRow="1" endCol="3" endRow="1"/>
+      </gnm:Selections>
+      <gnm:Cells>
+        <gnm:Cell Col="0" Row="0" ValueType="60">vone</gnm:Cell>
+        <gnm:Cell Col="1" Row="0" ValueType="60">vtwo</gnm:Cell>
+        <gnm:Cell Col="2" Row="0" ValueType="60">vthree</gnm:Cell>
+        <gnm:Cell Col="3" Row="0" ValueType="60">v4</gnm:Cell>
+        <gnm:Cell Col="0" Row="1" ValueType="30">1</gnm:Cell>
+        <gnm:Cell Col="1" Row="1" ValueType="30">3</gnm:Cell>
+        <gnm:Cell Col="3" Row="1" ValueType="30">5</gnm:Cell>
+        <gnm:Cell Col="0" Row="2" ValueType="30">2</gnm:Cell>
+        <gnm:Cell Col="1" Row="2" ValueType="30">4</gnm:Cell>
+        <gnm:Cell Col="3" Row="2" ValueType="30">6</gnm:Cell>
+      </gnm:Cells>
+      <gnm:SheetLayout TopLeft="A1"/>
+      <gnm:Solver ProblemType="1" Inputs="" MaxTime="0" MaxIter="0" NonNeg="1" Discr="0" AutoScale="0" ShowIter="0" AnswerR="0" SensitivityR="0" LimitsR="0" PerformR="0" ProgramR="0"/>
+    </gnm:Sheet>
+  </gnm:Sheets>
+  <gnm:UIData SelectedTab="4"/>
+  <gnm:Calculation ManualRecalc="0" EnableIteration="1" MaxIterations="100" IterationTolerance="0.001"/>
+</gnm:Workbook>
index c98f53e23157cdb03cd45a447414bc901602c6d5..555e24cf373a409205fbe8b54d7da45ac665b55c 100644 (file)
@@ -1,3 +1,8 @@
+2007-11-03  John Darrington <john@darrington.wattle.id.au>
+
+       * Book1.gnm.unzipped command/get-data-gnm.sh: New test and data
+       for reading gnumeric files.
+
 2007-10-08  Ben Pfaff  <blp@gnu.org>
 
        Bug #21280.  Thanks to John Darrington for review.
index 58400ac0749c8e7da4d7b6a86c33907104c583f5..b673bef33f91ccccc0af21d4e966d6914f5795c2 100644 (file)
@@ -20,6 +20,7 @@ dist_TESTS = \
        tests/command/file-handle.sh \
        tests/command/filter.sh \
        tests/command/flip.sh \
+       tests/command/get-data-gnm.sh \
        tests/command/import-export.sh \
        tests/command/input-program.sh \
        tests/command/insert.sh \
@@ -238,6 +239,7 @@ tests_formats_inexactify_SOURCES = tests/formats/inexactify.c
 
 EXTRA_DIST += \
        $(dist_TESTS) \
+        tests/Book1.gnm.unzipped \
        tests/weighting.data tests/data-list.data tests/list.data \
        tests/no_case_size.sav \
        tests/coverage.sh tests/test_template \
diff --git a/tests/command/get-data-gnm.sh b/tests/command/get-data-gnm.sh
new file mode 100755 (executable)
index 0000000..2cad373
--- /dev/null
@@ -0,0 +1,236 @@
+#!/bin/sh
+
+# This program tests that pspp can read gnumeric files
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+# ensure that top_srcdir and top_builddir  are absolute
+if [ -z "$top_srcdir" ] ; then top_srcdir=. ; fi
+if [ -z "$top_builddir" ] ; then top_builddir=. ; fi
+top_srcdir=`cd $top_srcdir; pwd`
+top_builddir=`cd $top_builddir; pwd`
+
+PSPP=$top_builddir/src/ui/terminal/pspp
+
+STAT_CONFIG_PATH=$top_srcdir/config
+export STAT_CONFIG_PATH
+
+LANG=C
+export LANG
+
+
+cleanup()
+{
+     if [ x"$PSPP_TEST_NO_CLEANUP" != x ] ; then 
+       echo "NOT cleaning $TEMPDIR"
+       return ; 
+     fi
+     rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+    echo $activity
+    echo FAILED
+    cleanup;
+    exit 1;
+}
+
+
+no_result()
+{
+    echo $activity
+    echo NO RESULT;
+    cleanup;
+    exit 2;
+}
+
+pass()
+{
+    cleanup;
+    exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+activity="zip the gnm file and place it in the test directory"
+gzip -c $top_srcdir/tests/Book1.gnm.unzipped > $TEMPDIR/Book1.gnumeric
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="create program 1"
+cat > $TESTFILE <<EOF
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric'  /READNAMES=off /SHEET=name 'This' /CELLRANGE=range 'g9:i13' .
+DISPLAY VARIABLES.
+LIST.
+
+
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric'  /READNAMES=on /SHEET=name 'This' /CELLRANGE=range 'g8:i13' .
+DISPLAY VARIABLES.
+LIST.
+
+
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric' /SHEET=index 3.
+DISPLAY VARIABLES.
+LIST.
+
+* This sheet has no data in one of its variables
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric' /READNAMES=on /SHEET=index 5.
+DISPLAY VARIABLES.
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 1"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="compare output 1"
+diff $TEMPDIR/pspp.list - <<EOF
+1.1 DISPLAY.  
++--------+-------------------------------------------+--------+
+|Variable|Description                                |Position|
+#========#===========================================#========#
+|var1    |Format: F8.2                               |       1|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|var2    |Format: A8                                 |       2|
+|        |Measure: Nominal                           |        |
+|        |Display Alignment: Left                    |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|var3    |Format: F8.2                               |       3|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+
+    var1     var2     var3
+-------- -------- --------
+     .00 fred        20.00 
+    1.00 11          21.00 
+    2.00 twelve      22.00 
+    3.00 13          23.00 
+    4.00 14          24.00 
+
+2.1 DISPLAY.  
++--------+-------------------------------------------+--------+
+|Variable|Description                                |Position|
+#========#===========================================#========#
+|V1      |Format: F8.2                               |       1|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|V2      |Format: A8                                 |       2|
+|        |Measure: Nominal                           |        |
+|        |Display Alignment: Left                    |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|var1    |Format: F8.2                               |       3|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+
+      V1       V2     var1
+-------- -------- --------
+     .00 fred        20.00 
+    1.00 11          21.00 
+    2.00 twelve      22.00 
+    3.00 13          23.00 
+    4.00 14          24.00 
+
+3.1 DISPLAY.  
++--------+-------------------------------------------+--------+
+|Variable|Description                                |Position|
+#========#===========================================#========#
+|name    |Format: A8                                 |       1|
+|        |Measure: Nominal                           |        |
+|        |Display Alignment: Left                    |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|id      |Format: F8.2                               |       2|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|height  |Format: F8.2                               |       3|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+
+    name       id   height
+-------- -------- --------
+fred          .00    23.40 
+bert         1.00      .56 
+charlie      2.00      .   
+dick         3.00   -34.09 
+
+4.1 DISPLAY.  
++--------+-------------------------------------------+--------+
+|Variable|Description                                |Position|
+#========#===========================================#========#
+|vone    |Format: F8.2                               |       1|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|vtwo    |Format: F8.2                               |       2|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|vthree  |Format: A8                                 |       3|
+|        |Measure: Nominal                           |        |
+|        |Display Alignment: Left                    |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+|v4      |Format: F8.2                               |       4|
+|        |Measure: Scale                             |        |
+|        |Display Alignment: Right                   |        |
+|        |Display Width: 8                           |        |
++--------+-------------------------------------------+--------+
+
+    vone     vtwo   vthree       v4
+-------- -------- -------- --------
+    1.00     3.00              5.00 
+    2.00     4.00              6.00 
+
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+activity="create program 2"
+cat > $TESTFILE <<EOF
+* This sheet is empty
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric' /SHEET=name 'Empty'.
+
+
+* This sheet doesnt exist
+GET DATA /TYPE=gnm /FILE='$TEMPDIR/Book1.gnumeric' /SHEET=name 'foobarxx'.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 2"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -ne 0 ] ; then fail ; fi
+
+activity="compare output 2"
+diff $TEMPDIR/pspp.list - <<EOF
+warning: Selected sheet or range of spreadsheet "$TEMPDIR/Book1.gnumeric" is empty.
+warning: Selected sheet or range of spreadsheet "$TEMPDIR/Book1.gnumeric" is empty.
+
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass;