Implemented the INSERT command.
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 5 Sep 2007 06:23:01 +0000 (06:23 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Wed, 5 Sep 2007 06:23:01 +0000 (06:23 +0000)
24 files changed:
doc/language.texi
doc/utilities.texi
po/de.po
po/pspp.pot
src/language/ChangeLog
src/language/command.c
src/language/command.def
src/language/control/repeat.c
src/language/data-io/data-reader.c
src/language/lexer/lexer.c
src/language/lexer/lexer.h
src/language/syntax-file.c
src/language/syntax-file.h
src/language/syntax-string-source.c
src/language/utilities/include.c
src/libpspp/ChangeLog
src/libpspp/getl.c
src/libpspp/getl.h
src/ui/gui/helper.c
src/ui/gui/syntax-editor-source.c
src/ui/terminal/command-line.c
src/ui/terminal/read-line.c
tests/automake.mk
tests/command/insert.sh [new file with mode: 0755]

index 398f7642318ede8f973bac881479c718775ba5a2..1345433613d3f24e7c7b26cdac457f7132761834 100644 (file)
@@ -15,6 +15,7 @@ Later chapters will describe individual commands in detail.
 @menu
 * Tokens::                      Characters combine to form tokens.
 * Commands::                    Tokens combine to form commands.
+* Syntax Variants::             Batch vs. Interactive mode
 * Types of Commands::           Commands come in several flavors.
 * Order of Commands::           Commands combine to form syntax files.
 * Missing Observations::        Handling missing observations.
@@ -24,6 +25,7 @@ Later chapters will describe individual commands in detail.
 * BNF::                         How command syntax is described.
 @end menu
 
+
 @node Tokens
 @section Tokens
 @cindex language, lexical analysis
@@ -188,15 +190,34 @@ one that consists only of white space or comments, also ends a command
 by default, although you can use the NULLINE subcommand of @cmd{SET}
 to disable this feature (@pxref{SET}).
 
-In batch mode only, that is, when reading commands from a file instead
-of an interactive user, any line that contains a non-space character
-in the leftmost column begins a new command.  Thus, each command
-consists of a flush-left line followed by any number of lines indented
-from the left margin.  In this mode, a plus or minus sign
-(@samp{+}, @samp{@minus{}}) as the first character
-in a line is ignored and causes that line to begin a new command,
-which allows for visual indentation of a command without that command
-being considered part of the previous command.
+@node Syntax Variants
+@section Variants of syntax.
+
+@cindex Batch syntax
+@cindex Interactive syntax
+
+There are two variants of command syntax, @i{viz}: @dfn{batch} mode and
+@dfn{interactive} mode.
+Batch mode is the default when reading commands from a file.
+Interactive mode is the default when commands are typed at a prompt
+by a user.
+Certain commands, such as @cmd{INSERT} (@pxref{INSERT}), may explicitly
+change the syntax mode. 
+
+In batch mode, any line that contains a non-space character
+in the leftmost column begins a new command. 
+Thus, each command consists of a flush-left line followed by any
+number of lines indented from the left margin. 
+In this mode, a plus or minus sign (@samp{+}, @samp{@minus{}}) as the
+first character in a line is ignored and causes that line to begin a
+new command, which allows for visual indentation of a command without
+that command being considered part of the previous command. 
+The period terminating the end of a command is optional but recommended.
+
+In interactive mode, each command must  either be terminated with a period,
+or an empty line must follow the command.
+The use of (@samp{+} and @samp{@minus{}} as continuation characters is not
+permitted.
 
 @node Types of Commands
 @section Types of Commands
index ba5a5e8b0912a18c317a1e80195b724f188434fc..94fa50744d6a4c70d48befce93b2b57438c1d658 100644 (file)
@@ -23,6 +23,7 @@ encountered in the input.
 * FINISH::                      Terminate the PSPP session.
 * HOST::                        Temporarily return to the operating system.
 * INCLUDE::                     Include a file within the current one.
+* INSERT::                      Insert a file within the current one.
 * PERMISSIONS::                 Change permissions on a file.
 * SET::                         Adjust PSPP runtime parameters.
 * SHOW::                        Display runtime parameters.
@@ -220,23 +221,70 @@ This command cannot be used if the SAFER setting is active.
 @node INCLUDE
 @section INCLUDE
 @vindex INCLUDE
-@vindex @@
 
 @display
-Two possible syntaxes:
-        INCLUDE 'file-name'.
-        @@file-name.
+        INCLUDE [FILE=]'file-name'.
 @end display
 
 @cmd{INCLUDE} causes the PSPP command processor to read an
 additional command file as if it were included bodily in the current
 command file.
-
+If errors are encountered in the included file, then command processing will 
+stop and no more commands will be processed.
 Include files may be nested to any depth, up to the limit of available
 memory.
 
+
+The @cmd{INSERT} command (@pxref{INSERT}) may be used instead of
+@cmd{INCLUDE} if you require more flexible options.
+The syntax 
+@example
+INCLUDE FILE=@var{file-name}.
+@end example
+@noindent 
+functions identically to 
+@example
+INSERT FILE=@var{file-name} ERROR=STOP CD=NO SYNTAX=BATCH.
+@end example
+
+
+@node INSERT
+@section INSERT
+@vindex INSERT
+
+@display
+     INSERT [FILE=]'file-name'
+        [CD=@{NO,YES@}]
+        [ERROR=@{CONTINUE,STOP@}]
+        [SYNTAX=@{BATCH,INTERACTIVE@}].
+@end display
+
+@cmd{INSERT} is similar to @cmd{INCLUDE} (@pxref{INCLUDE}) 
+but somewhat more flexible.
+It causes the command processor to read a file as if it were embedded in the 
+current command file.
+
+If @samp{CD=YES} is specified, then before including the file, the
+current directory  will be changed to the directory of the included
+file.  
+The default setting is @samp{CD=NO}.
+Note that this directory will remain current until it is
+changed explicitly (with the @cmd{CD} command, or a subsequent
+@cmd{INSERT} command with the @samp{CD=YES} option).
+It will not revert to its original setting even after the included
+file is finished processing.
+
+If @samp{ERROR=STOP} is specified, errors encountered in the
+inserted file will cause processing to immediately cease.
+Otherwise processing will continue at the next command.
+The default setting is @samp{ERROR=CONTINUE}.
+
+If @samp{SYNTAX=INTERACTIVE} is specified then the syntax contained in
+the included file must conform to interactive syntax
+conventions. @xref{Syntax Variants}.
+The default setting is @samp{SYNTAX=BATCH}.
+
 @node PERMISSIONS
-@comment  node-name,  next,  previous,  up
 @section PERMISSIONS
 @vindex PERMISSIONS
 @cindex mode
index c92f367f24a7972e3135428242bff3ac5bb7e4c5..cad53f8a70edab5a96febe6f667d5e188ea1ac01 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-08-31 07:06+0800\n"
+"POT-Creation-Date: 2007-09-01 08:59+0800\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"
@@ -988,41 +988,41 @@ msgstr ""
 msgid "Only one index clause may be specified."
 msgstr ""
 
-#: src/language/control/repeat.c:168
+#: src/language/control/repeat.c:173
 #, c-format
 msgid "Dummy variable name \"%s\" hides dictionary variable \"%s\"."
 msgstr ""
 
-#: src/language/control/repeat.c:173
+#: src/language/control/repeat.c:178
 #, c-format
 msgid "Dummy variable name \"%s\" is given twice."
 msgstr ""
 
-#: src/language/control/repeat.c:219
+#: src/language/control/repeat.c:224
 #, c-format
 msgid ""
 "Dummy variable \"%.*s\" had %d substitutions, so \"%.*s\" must also, but %d "
 "were specified."
 msgstr ""
 
-#: src/language/control/repeat.c:331
+#: src/language/control/repeat.c:336
 msgid "DO REPEAT may not nest in compatibility mode."
 msgstr ""
 
-#: src/language/control/repeat.c:433
+#: src/language/control/repeat.c:438
 msgid "Ranges may only have integer bounds"
 msgstr ""
 
-#: src/language/control/repeat.c:442
+#: src/language/control/repeat.c:447
 #, c-format
 msgid "%g TO %g is an invalid range."
 msgstr ""
 
-#: src/language/control/repeat.c:477
+#: src/language/control/repeat.c:482
 msgid "String expected."
 msgstr ""
 
-#: src/language/control/repeat.c:496
+#: src/language/control/repeat.c:501
 msgid "No matching DO REPEAT."
 msgstr ""
 
@@ -1411,7 +1411,7 @@ msgid_plural "Writing %d records."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:464
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:471
 #: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:59
 msgid "expecting end of command"
 msgstr ""
@@ -1828,11 +1828,11 @@ msgid ""
 "s."
 msgstr ""
 
-#: src/language/dictionary/value-labels.c:156 src/language/lexer/lexer.c:608
+#: src/language/dictionary/value-labels.c:156 src/language/lexer/lexer.c:615
 msgid "expecting string"
 msgstr ""
 
-#: src/language/dictionary/value-labels.c:165 src/language/lexer/lexer.c:622
+#: src/language/dictionary/value-labels.c:165 src/language/lexer/lexer.c:629
 msgid "expecting integer"
 msgstr ""
 
@@ -2079,89 +2079,89 @@ msgstr ""
 msgid "expecting format type"
 msgstr ""
 
-#: src/language/lexer/lexer.c:270
+#: src/language/lexer/lexer.c:277
 #, c-format
 msgid "%s does not form a valid number."
 msgstr ""
 
-#: src/language/lexer/lexer.c:374
+#: src/language/lexer/lexer.c:381
 #, c-format
 msgid "Bad character in input: `%c'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:376
+#: src/language/lexer/lexer.c:383
 #, c-format
 msgid "Bad character in input: `\\%o'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:412
+#: src/language/lexer/lexer.c:419
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr ""
 
-#: src/language/lexer/lexer.c:420
+#: src/language/lexer/lexer.c:427
 #, c-format
 msgid "missing required subcommand %s"
 msgstr ""
 
-#: src/language/lexer/lexer.c:449
+#: src/language/lexer/lexer.c:456
 #, c-format
 msgid "Syntax error %s at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:452
+#: src/language/lexer/lexer.c:459
 #, c-format
 msgid "Syntax error at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:577 src/language/lexer/lexer.c:594
+#: src/language/lexer/lexer.c:584 src/language/lexer/lexer.c:601
 #, c-format
 msgid "expecting `%s'"
 msgstr ""
 
-#: src/language/lexer/lexer.c:635
+#: src/language/lexer/lexer.c:642
 msgid "expecting number"
 msgstr ""
 
-#: src/language/lexer/lexer.c:647
+#: src/language/lexer/lexer.c:654
 msgid "expecting identifier"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1045
+#: src/language/lexer/lexer.c:1048
 msgid "binary"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1050
+#: src/language/lexer/lexer.c:1053
 msgid "octal"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1055
+#: src/language/lexer/lexer.c:1058
 msgid "hex"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1065
+#: src/language/lexer/lexer.c:1068
 #, c-format
 msgid "String of %s digits has %d characters, which is not a multiple of %d."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1094
+#: src/language/lexer/lexer.c:1097
 #, c-format
 msgid "`%c' is not a valid %s digit."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1128
+#: src/language/lexer/lexer.c:1131
 msgid "Unterminated string constant."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1182
+#: src/language/lexer/lexer.c:1185
 msgid "Unexpected end of file in string concatenation."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1190
+#: src/language/lexer/lexer.c:1193
 msgid "String expected following `+'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1203
+#: src/language/lexer/lexer.c:1206
 #, c-format
 msgid "String exceeds 255 characters in length (%d characters)."
 msgstr ""
@@ -3494,7 +3494,7 @@ msgstr ""
 msgid "Reading `%s': %s."
 msgstr ""
 
-#: src/language/syntax-file.c:125
+#: src/language/syntax-file.c:124
 #, c-format
 msgid "Closing `%s': %s."
 msgstr ""
@@ -3550,15 +3550,32 @@ msgstr ""
 msgid "Only USE ALL is currently implemented."
 msgstr ""
 
-#: src/language/utilities/include.c:47
+#: src/language/utilities/include.c:47 src/language/utilities/insert.c:138
 msgid "expecting file name"
 msgstr ""
 
-#: src/language/utilities/include.c:62
+#: src/language/utilities/include.c:63 src/language/utilities/insert.c:149
 #, c-format
 msgid "Can't find `%s' in include file search path."
 msgstr ""
 
+#: src/language/utilities/insert.c:60
+msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
+msgstr ""
+
+#: src/language/utilities/insert.c:77
+msgid "Expecting YES or NO after CD."
+msgstr ""
+
+#: src/language/utilities/insert.c:94
+msgid "Expecting CONTINUE or STOP after ERROR."
+msgstr ""
+
+#: src/language/utilities/insert.c:101
+#, fuzzy, c-format
+msgid "Unexpected token: `%s'."
+msgstr "plotzlich ist der Datei beendet"
+
 #: src/language/utilities/permissions.c:73
 #, c-format
 msgid "Expecting %s or %s."
@@ -5280,7 +5297,7 @@ msgstr ""
 msgid "%s --- PSPP Output"
 msgstr "PSPP Dateiaufbereiter"
 
-#: src/ui/terminal/command-line.c:219
+#: src/ui/terminal/command-line.c:223
 #, c-format
 msgid ""
 "PSPP, a program for statistical analysis of sample data.\n"
@@ -5326,7 +5343,7 @@ msgid ""
 "\n"
 msgstr ""
 
-#: src/ui/terminal/command-line.c:254
+#: src/ui/terminal/command-line.c:258
 #, c-format
 msgid ""
 "\n"
index 5123ff96efe3761a0675840a47d0f112e95e1390..148a959c781e4ecfd7db34e9fc5357f716fa2154 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: pspp-dev@gnu.org\n"
-"POT-Creation-Date: 2007-08-31 07:06+0800\n"
+"POT-Creation-Date: 2007-09-01 08:59+0800\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"
@@ -982,41 +982,41 @@ msgstr ""
 msgid "Only one index clause may be specified."
 msgstr ""
 
-#: src/language/control/repeat.c:168
+#: src/language/control/repeat.c:173
 #, c-format
 msgid "Dummy variable name \"%s\" hides dictionary variable \"%s\"."
 msgstr ""
 
-#: src/language/control/repeat.c:173
+#: src/language/control/repeat.c:178
 #, c-format
 msgid "Dummy variable name \"%s\" is given twice."
 msgstr ""
 
-#: src/language/control/repeat.c:219
+#: src/language/control/repeat.c:224
 #, c-format
 msgid ""
 "Dummy variable \"%.*s\" had %d substitutions, so \"%.*s\" must also, but %d "
 "were specified."
 msgstr ""
 
-#: src/language/control/repeat.c:331
+#: src/language/control/repeat.c:336
 msgid "DO REPEAT may not nest in compatibility mode."
 msgstr ""
 
-#: src/language/control/repeat.c:433
+#: src/language/control/repeat.c:438
 msgid "Ranges may only have integer bounds"
 msgstr ""
 
-#: src/language/control/repeat.c:442
+#: src/language/control/repeat.c:447
 #, c-format
 msgid "%g TO %g is an invalid range."
 msgstr ""
 
-#: src/language/control/repeat.c:477
+#: src/language/control/repeat.c:482
 msgid "String expected."
 msgstr ""
 
-#: src/language/control/repeat.c:496
+#: src/language/control/repeat.c:501
 msgid "No matching DO REPEAT."
 msgstr ""
 
@@ -1405,7 +1405,7 @@ msgid_plural "Writing %d records."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:464
+#: src/language/data-io/print-space.c:73 src/language/lexer/lexer.c:471
 #: src/language/stats/autorecode.c:154 src/language/xforms/select-if.c:59
 msgid "expecting end of command"
 msgstr ""
@@ -1822,11 +1822,11 @@ msgid ""
 "s."
 msgstr ""
 
-#: src/language/dictionary/value-labels.c:156 src/language/lexer/lexer.c:608
+#: src/language/dictionary/value-labels.c:156 src/language/lexer/lexer.c:615
 msgid "expecting string"
 msgstr ""
 
-#: src/language/dictionary/value-labels.c:165 src/language/lexer/lexer.c:622
+#: src/language/dictionary/value-labels.c:165 src/language/lexer/lexer.c:629
 msgid "expecting integer"
 msgstr ""
 
@@ -2073,89 +2073,89 @@ msgstr ""
 msgid "expecting format type"
 msgstr ""
 
-#: src/language/lexer/lexer.c:270
+#: src/language/lexer/lexer.c:277
 #, c-format
 msgid "%s does not form a valid number."
 msgstr ""
 
-#: src/language/lexer/lexer.c:374
+#: src/language/lexer/lexer.c:381
 #, c-format
 msgid "Bad character in input: `%c'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:376
+#: src/language/lexer/lexer.c:383
 #, c-format
 msgid "Bad character in input: `\\%o'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:412
+#: src/language/lexer/lexer.c:419
 #, c-format
 msgid "Subcommand %s may only be specified once."
 msgstr ""
 
-#: src/language/lexer/lexer.c:420
+#: src/language/lexer/lexer.c:427
 #, c-format
 msgid "missing required subcommand %s"
 msgstr ""
 
-#: src/language/lexer/lexer.c:449
+#: src/language/lexer/lexer.c:456
 #, c-format
 msgid "Syntax error %s at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:452
+#: src/language/lexer/lexer.c:459
 #, c-format
 msgid "Syntax error at %s."
 msgstr ""
 
-#: src/language/lexer/lexer.c:577 src/language/lexer/lexer.c:594
+#: src/language/lexer/lexer.c:584 src/language/lexer/lexer.c:601
 #, c-format
 msgid "expecting `%s'"
 msgstr ""
 
-#: src/language/lexer/lexer.c:635
+#: src/language/lexer/lexer.c:642
 msgid "expecting number"
 msgstr ""
 
-#: src/language/lexer/lexer.c:647
+#: src/language/lexer/lexer.c:654
 msgid "expecting identifier"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1045
+#: src/language/lexer/lexer.c:1048
 msgid "binary"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1050
+#: src/language/lexer/lexer.c:1053
 msgid "octal"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1055
+#: src/language/lexer/lexer.c:1058
 msgid "hex"
 msgstr ""
 
-#: src/language/lexer/lexer.c:1065
+#: src/language/lexer/lexer.c:1068
 #, c-format
 msgid "String of %s digits has %d characters, which is not a multiple of %d."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1094
+#: src/language/lexer/lexer.c:1097
 #, c-format
 msgid "`%c' is not a valid %s digit."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1128
+#: src/language/lexer/lexer.c:1131
 msgid "Unterminated string constant."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1182
+#: src/language/lexer/lexer.c:1185
 msgid "Unexpected end of file in string concatenation."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1190
+#: src/language/lexer/lexer.c:1193
 msgid "String expected following `+'."
 msgstr ""
 
-#: src/language/lexer/lexer.c:1203
+#: src/language/lexer/lexer.c:1206
 #, c-format
 msgid "String exceeds 255 characters in length (%d characters)."
 msgstr ""
@@ -3487,7 +3487,7 @@ msgstr ""
 msgid "Reading `%s': %s."
 msgstr ""
 
-#: src/language/syntax-file.c:125
+#: src/language/syntax-file.c:124
 #, c-format
 msgid "Closing `%s': %s."
 msgstr ""
@@ -3543,15 +3543,32 @@ msgstr ""
 msgid "Only USE ALL is currently implemented."
 msgstr ""
 
-#: src/language/utilities/include.c:47
+#: src/language/utilities/include.c:47 src/language/utilities/insert.c:138
 msgid "expecting file name"
 msgstr ""
 
-#: src/language/utilities/include.c:62
+#: src/language/utilities/include.c:63 src/language/utilities/insert.c:149
 #, c-format
 msgid "Can't find `%s' in include file search path."
 msgstr ""
 
+#: src/language/utilities/insert.c:60
+msgid "Expecting BATCH or INTERACTIVE after SYNTAX."
+msgstr ""
+
+#: src/language/utilities/insert.c:77
+msgid "Expecting YES or NO after CD."
+msgstr ""
+
+#: src/language/utilities/insert.c:94
+msgid "Expecting CONTINUE or STOP after ERROR."
+msgstr ""
+
+#: src/language/utilities/insert.c:101
+#, c-format
+msgid "Unexpected token: `%s'."
+msgstr ""
+
 #: src/language/utilities/permissions.c:73
 #, c-format
 msgid "Expecting %s or %s."
@@ -5225,7 +5242,7 @@ msgstr ""
 msgid "%s --- PSPP Output"
 msgstr ""
 
-#: src/ui/terminal/command-line.c:219
+#: src/ui/terminal/command-line.c:223
 #, c-format
 msgid ""
 "PSPP, a program for statistical analysis of sample data.\n"
@@ -5271,7 +5288,7 @@ msgid ""
 "\n"
 msgstr ""
 
-#: src/ui/terminal/command-line.c:254
+#: src/ui/terminal/command-line.c:258
 #, c-format
 msgid ""
 "\n"
index 8949ff75c1b989290dd343e45de6772fa925804b..d25c2d0379b7210e1d71fcff6453ff465894161f 100644 (file)
@@ -1,3 +1,10 @@
+2007-09-05  John Darrington <john@darrington.wattle.id.au>
+
+       * command.c (do_parse_command): Translate CMD_FAILURE into
+       CMD_CASCADING_FAILURE, if the ERRMODE_STOP is set on the syntax
+       source. 
+       
+       
 2007-06-06  Ben Pfaff  <blp@gnu.org>
 
        * command.def: Add DEBUG DATASHEET command.  Remove DEBUG CASEFILE
index 40b8505eba7753d0d247c982ec22f7d3648f99bb..1688a10eb6e3472dc5fa7e3ae0a21134827fc006 100644 (file)
@@ -39,6 +39,7 @@
 #include <libpspp/str.h>
 #include <output/manager.h>
 #include <output/table.h>
+#include <libpspp/getl.h>
 
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
@@ -169,7 +170,8 @@ cmd_parse (struct lexer *lexer, struct dataset *ds)
 /* Parses an entire command, from command name to terminating
    dot. */
 static enum cmd_result
-do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state)
+do_parse_command (struct lexer *lexer,
+                 struct dataset *ds, enum cmd_state state)
 {
   const struct command *command;
   enum cmd_result result;
@@ -179,38 +181,50 @@ do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state)
   set_completion_state (state);
   lex_get (lexer);
   if (lex_token (lexer) == T_STOP)
-    return CMD_EOF;
+    {
+      result = CMD_EOF;
+      goto finish;
+    }
   else if (lex_token (lexer) == '.')
     {
       /* Null commands can result from extra empty lines. */
-      return CMD_SUCCESS;
+      result = CMD_SUCCESS;
+      goto finish;
     }
+
   prompt_set_style (PROMPT_LATER);
 
   /* Parse the command name. */
   command = parse_command_name (lexer);
   if (command == NULL)
-    return CMD_FAILURE;
+    {
+      result = CMD_FAILURE;
+      goto finish;
+    }
   else if (command->function == NULL)
     {
       msg (SE, _("%s is unimplemented."), command->name);
-      return CMD_NOT_IMPLEMENTED;
+      result = CMD_NOT_IMPLEMENTED;
+      goto finish;
     }
   else if ((command->flags & F_TESTING) && !get_testing_mode ())
     {
       msg (SE, _("%s may be used only in testing mode."), command->name);
-      return CMD_FAILURE;
+      result = CMD_FAILURE;
+      goto finish;
     }
   else if ((command->flags & F_ENHANCED) && get_syntax () != ENHANCED)
     {
       msg (SE, _("%s may be used only in enhanced syntax mode."),
            command->name);
-      return CMD_FAILURE;
+      result = CMD_FAILURE;
+      goto finish;
     }
   else if (!in_correct_state (command, state))
     {
       report_state_mismatch (command, state);
-      return CMD_FAILURE;
+      result = CMD_FAILURE;
+      goto finish;
     }
 
   /* Execute command. */
@@ -221,6 +235,19 @@ do_parse_command (struct lexer *lexer, struct dataset *ds, enum cmd_state state)
   msg_set_command_name (NULL);
 
   assert (cmd_result_is_valid (result));
+
+ finish:
+  if ( cmd_result_is_failure (result))
+    {
+      const struct source_stream *cs = lex_get_source_stream (lexer);
+
+      if ( source_stream_current_error_mode (cs) == ERRMODE_STOP )
+       {
+         msg (MW, _("Error encountered while ERROR=STOP is effective."));
+         result = CMD_CASCADING_FAILURE;
+       }
+    }
+
   return result;
 }
 
index 5967e5d28958bdbc49b97cb5787f898f70b3f2e0..7a89ae0a1631cab8384a82c7911b772ea6b74143 100644 (file)
@@ -26,6 +26,7 @@ DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "FILE LABEL", cmd_file_label)
 DEF_CMD (S_ANY, 0, "FINISH", cmd_finish)
 DEF_CMD (S_ANY, F_KEEP_FINAL_TOKEN, "HOST", cmd_host)
 DEF_CMD (S_ANY, 0, "INCLUDE", cmd_include)
+DEF_CMD (S_ANY, 0, "INSERT", cmd_insert)
 DEF_CMD (S_ANY, 0, "N OF CASES", cmd_n_of_cases)
 DEF_CMD (S_ANY, F_ABBREV, "N", cmd_n_of_cases)
 DEF_CMD (S_ANY, 0, "NEW FILE", cmd_new_file)
index ede37016ee816a05820c6e97a97ff0bbe873ec43..cd56d7c81164c44103693c5e3da2a7083be584b1 100644 (file)
@@ -49,7 +49,6 @@ struct repeat_line
     const char *file_name;      /* File name. */
     int line_number;            /* Line number. */
     struct substring text;     /* Contents. */
-    enum getl_syntax syntax;    /* Syntax mode. */
   };
 
 /* The type of substitution made for a DO REPEAT macro. */
@@ -103,9 +102,9 @@ static int parse_strings (struct lexer *, struct repeat_macro *,
                          struct pool *);
 
 static void do_repeat_filter (struct getl_interface *,
-                              struct string *, enum getl_syntax);
+                              struct string *);
 static bool do_repeat_read (struct getl_interface *,
-                            struct string *, enum getl_syntax *);
+                            struct string *);
 static void do_repeat_close (struct getl_interface *);
 static bool always_false (const struct getl_interface *);
 static const char *do_repeat_name (const struct getl_interface *);
@@ -136,7 +135,11 @@ cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
   block->parent.location = do_repeat_location;
 
   if (!ll_is_empty (&block->lines))
-    getl_include_source (lex_get_source_stream (lexer), &block->parent);
+    getl_include_source (lex_get_source_stream (lexer),
+                        &block->parent,
+                        lex_current_syntax_mode (lexer),
+                        lex_current_error_mode (lexer)
+                        );
   else
     pool_destroy (block->pool);
 
@@ -298,11 +301,10 @@ parse_lines (struct lexer *lexer, struct repeat_block *block)
       const char *cur_file_name;
       struct repeat_line *line;
       struct string text;
-      enum getl_syntax syntax;
       bool command_ends_before_line, command_ends_after_line;
 
       /* Retrieve an input line and make a copy of it. */
-      if (!lex_get_line_raw (lexer, &syntax))
+      if (!lex_get_line_raw (lexer))
         return false;
       ds_init_string (&text, lex_entire_line_ds (lexer));
 
@@ -318,11 +320,12 @@ parse_lines (struct lexer *lexer, struct repeat_block *block)
       line->file_name = previous_file_name;
       line->line_number = getl_source_location (lex_get_source_stream (lexer));
       ss_alloc_substring_pool (&line->text, ds_ss (&text), block->pool);
-      line->syntax = syntax;
+
 
       /* Check whether the line contains a DO REPEAT or END
          REPEAT command. */
-      lex_preprocess_line (&text, syntax,
+      lex_preprocess_line (&text,
+                          lex_current_syntax_mode (lexer),
                            &command_ends_before_line,
                            &command_ends_after_line);
       if (recognize_do_repeat (ds_ss (&text)))
@@ -510,7 +513,7 @@ find_substitution (struct repeat_block *block, struct substring name)
    repeated lines. */
 static void
 do_repeat_filter (struct getl_interface *block_,
-                  struct string *line, enum getl_syntax syntax UNUSED)
+                  struct string *line)
 {
   struct repeat_block *block = (struct repeat_block *) block_;
   bool in_apos, in_quote, dot;
@@ -566,7 +569,7 @@ current_line (const struct getl_interface *interface)
    was obtained, false if the source is exhausted. */
 static bool
 do_repeat_read  (struct getl_interface *interface,
-                 struct string *output, enum getl_syntax *syntax)
+                 struct string *output)
 {
   struct repeat_block *block = (struct repeat_block *) interface;
   struct repeat_line *line;
@@ -583,7 +586,6 @@ do_repeat_read  (struct getl_interface *interface,
 
   line = current_line (interface);
   ds_assign_substring (output, line->text);
-  *syntax = line->syntax;
   return true;
 }
 
index c752587b5b1354393de8442eb6efb47d579ed2c9..7176aed43a03f7c763a86747cf889cc69c9c10e2 100644 (file)
@@ -170,7 +170,7 @@ read_inline_record (struct dfm_reader *r)
       prompt_set_style (PROMPT_DATA);
     }
 
-  if (!lex_get_line_raw (r->lexer, NULL))
+  if (!lex_get_line_raw (r->lexer))
     {
       msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
                  "DATA.  This probably indicates "
index 4e10ec22478caf8c8e3579d9e8b8094b0b31f688..71597302032a48cbf31f4d12d028f54bbc009780 100644 (file)
@@ -43,6 +43,7 @@
 #define DUMP_TOKENS 0
 
 
+
 struct lexer
 {
   struct string line_buffer;
@@ -108,6 +109,18 @@ lex_get_source_stream (const struct lexer *lex)
   return lex->ss;
 }
 
+enum syntax_mode
+lex_current_syntax_mode (const struct lexer *lex)
+{
+  return source_stream_current_syntax_mode (lex->ss);
+}
+
+enum error_mode
+lex_current_error_mode (const struct lexer *lex)
+{
+  return source_stream_current_error_mode (lex->ss);
+}
+
 
 void
 lex_destroy (struct lexer *lexer)
@@ -832,7 +845,7 @@ strip_comments (struct string *string)
    *LINE_STARTS_COMMAND and *LINE_ENDS_COMMAND appropriately. */
 void
 lex_preprocess_line (struct string *line,
-                     enum getl_syntax syntax,
+                     enum syntax_mode syntax,
                      bool *line_starts_command,
                      bool *line_ends_command)
 {
@@ -854,15 +867,11 @@ lex_preprocess_line (struct string *line,
    Sets *SYNTAX, if SYNTAX is non-null, to the line's syntax
    mode. */
 bool
-lex_get_line_raw (struct lexer *lexer, enum getl_syntax *syntax)
+lex_get_line_raw (struct lexer *lexer)
 {
-  enum getl_syntax dummy;
-  bool ok;
-
-  if (syntax == NULL)
-    syntax = &dummy;
-  ok = getl_read_line (lexer->ss, &lexer->line_buffer, syntax);
-  journal_write (*syntax == GETL_BATCH, ds_cstr (&lexer->line_buffer));
+  bool ok = getl_read_line (lexer->ss, &lexer->line_buffer);
+  enum syntax_mode mode = lex_current_syntax_mode (lexer);
+  journal_write (mode == GETL_BATCH, ds_cstr (&lexer->line_buffer));
 
   return ok;
 }
@@ -874,15 +883,15 @@ bool
 lex_get_line (struct lexer *lexer)
 {
   bool line_starts_command;
-  enum getl_syntax syntax = GETL_BATCH;
 
-  if (!lex_get_line_raw (lexer, &syntax))
+  if (!lex_get_line_raw (lexer))
     {
       lexer->prog = NULL;
       return false;
     }
 
-  lex_preprocess_line (&lexer->line_buffer, syntax,
+  lex_preprocess_line (&lexer->line_buffer,
+                      lex_current_syntax_mode (lexer),
                        &line_starts_command, &lexer->dot);
 
   if (line_starts_command)
index 44be0e930d41fa2be6e2c78b8a70202698c8b92e..ada09ade9a89f1eb0d4f682a0d70c94cef9be04d 100644 (file)
@@ -30,8 +30,10 @@ struct lexer;
 struct lexer * lex_create (struct source_stream *);
 void lex_destroy (struct lexer *);
 
+/* State accessors */
 struct source_stream * lex_get_source_stream (const struct lexer *);
-
+enum syntax_mode lex_current_syntax_mode (const struct lexer *);
+enum error_mode lex_current_error_mode (const struct lexer *);
 
 /* Common functions. */
 void lex_get (struct lexer *);
@@ -71,7 +73,7 @@ const char *lex_entire_line (const struct lexer *);
 const struct string *lex_entire_line_ds (const struct lexer *);
 const char *lex_rest_of_line (const struct lexer *);
 bool lex_end_dot (const struct lexer *);
-void lex_preprocess_line (struct string *, enum getl_syntax,
+void lex_preprocess_line (struct string *, enum syntax_mode,
                           bool *line_starts_command,
                           bool *line_ends_command);
 void lex_discard_line (struct lexer *);
@@ -79,7 +81,7 @@ void lex_discard_rest_of_command (struct lexer *);
 
 /* Weird line reading functions. */
 bool lex_get_line (struct lexer *);
-bool lex_get_line_raw (struct lexer *, enum getl_syntax *);
+bool lex_get_line_raw (struct lexer *);
 
 /* Token names. */
 const char *lex_token_name (int);
index b3ae6f4aca17ec2154a95cd1f8c2886f1953af6d..dde807c37c9c4409cc54b2d6049bc859679ee137 100644 (file)
@@ -74,9 +74,9 @@ line_number (const struct getl_interface *s)
 
 /* Reads a line from syntax file source S into LINE.
    Returns true if successful, false at end of file. */
-bool
+static bool
 read_syntax_file (struct getl_interface *s,
-                  struct string *line, enum getl_syntax *syntax)
+                  struct string *line)
 {
   struct syntax_file_source *sfs = (struct syntax_file_source *) s;
 
@@ -112,7 +112,6 @@ read_syntax_file (struct getl_interface *s,
   if (get_echo ())
     tab_output_text (TAB_LEFT | TAB_FIX, ds_cstr (line));
 
-  *syntax = GETL_BATCH;
   return true;
 }
 
index c038a4327a080774aa15457cac8cf797e637db48..8044f3c04e242b213d023ece8cfec1045c1abc41 100644 (file)
 #if !SYNTAX_FILE
 #define SYNTAX_FILE 1
 
-#include <stdbool.h>
-#include <libpspp/getl.h>
-
-struct string;
-
-bool read_syntax_file (struct getl_interface *s,
-                       struct string *line, enum getl_syntax *syntax);
+struct getl_interface;
 
 /* Creates a syntax file source with file name FN. */
-struct getl_interface * create_syntax_file_source (const char *fn) ;
+struct getl_interface * create_syntax_file_source (const char *) ;
 
 #endif
index bcdcbd3767c5b671df04bf1ac2d46477f3d880e2..f80bca2e9edfe68a9b8cd1715d4809a941e6e756 100644 (file)
@@ -70,8 +70,7 @@ do_close (struct getl_interface *i )
 
 static bool
 read_single_line (struct getl_interface *i,
-                 struct string *line,
-                 enum getl_syntax *syntax_rules UNUSED)
+                 struct string *line)
 {
   struct syntax_string_source *sss = (struct syntax_string_source *) i;
 
index 0ef9d463d7393b1488dc0d768d012671dcde2b84..26c718a42de419ada022a35cb07b199dc2fd7406 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 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
 #include <language/lexer/lexer.h>
 #include <libpspp/str.h>
 #include <data/file-name.h>
+#include <dirname.h>
+#include <canonicalize.h>
 
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+static int parse_insert (struct lexer *lexer, char **filename);
+
+
 int
 cmd_include (struct lexer *lexer, struct dataset *ds UNUSED)
 {
-  struct source_stream *ss;
-  char *found_fn;
+  char *filename = NULL;
+  int status = parse_insert (lexer, &filename);
+
+  if ( CMD_SUCCESS != status)
+    return status;
+
+  lex_get (lexer);
+
+  status = lex_end_of_command (lexer);
+
+  if ( status == CMD_SUCCESS)
+    {
+      struct source_stream *ss = lex_get_source_stream (lexer);
+
+      assert (filename);
+      getl_include_source (ss, create_syntax_file_source (filename),
+                          GETL_BATCH, ERRMODE_STOP);
+      free (filename);
+    }
+
+  return status;
+}
+
+
+int
+cmd_insert (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+  enum syntax_mode syntax_mode = GETL_INTERACTIVE;
+  enum error_mode error_mode = ERRMODE_CONTINUE;
+  char *filename = NULL;
+  int status = parse_insert (lexer, &filename);
+  bool cd = false;
+
+  if ( CMD_SUCCESS != status)
+    return status;
+
+  lex_get (lexer);
+
+  while ( '.' != lex_token (lexer))
+    {
+      if (lex_match_id (lexer, "SYNTAX"))
+       {
+         lex_match (lexer, '=');
+         if ( lex_match_id (lexer, "INTERACTIVE") )
+           syntax_mode = GETL_INTERACTIVE;
+         else if ( lex_match_id (lexer, "BATCH"))
+           syntax_mode = GETL_BATCH;
+         else
+           {
+             lex_error(lexer,
+                       _("Expecting BATCH or INTERACTIVE after SYNTAX."));
+             return CMD_FAILURE;
+           }
+       }
+      else if (lex_match_id (lexer, "CD"))
+       {
+         lex_match (lexer, '=');
+         if ( lex_match_id (lexer, "YES") )
+           {
+             cd = true;
+           }
+         else if ( lex_match_id (lexer, "NO"))
+           {
+             cd = false;
+           }
+         else
+           {
+             lex_error (lexer, _("Expecting YES or NO after CD."));
+             return CMD_FAILURE;
+           }
+       }
+      else if (lex_match_id (lexer, "ERROR"))
+       {
+         lex_match (lexer, '=');
+         if ( lex_match_id (lexer, "CONTINUE") )
+           {
+             error_mode = ERRMODE_CONTINUE;
+           }
+         else if ( lex_match_id (lexer, "STOP"))
+           {
+             error_mode = ERRMODE_STOP;
+           }
+         else
+           {
+             lex_error (lexer, _("Expecting CONTINUE or STOP after ERROR."));
+             return CMD_FAILURE;
+           }
+       }
+
+      else
+       {
+         lex_error (lexer, _("Unexpected token: `%s'."),
+                    lex_token_representation (lexer));
+
+         return CMD_FAILURE;
+       }
+    }
+
+  status = lex_end_of_command (lexer);
+
+  if ( status == CMD_SUCCESS)
+    {
+      struct source_stream *ss = lex_get_source_stream (lexer);
+
+      assert (filename);
+      getl_include_source (ss, create_syntax_file_source (filename),
+                          syntax_mode,
+                          error_mode);
+
+      if ( cd )
+       {
+         char *directory = dir_name (filename);
+         chdir (directory);
+         free (directory);
+       }
+
+      free (filename);
+    }
+
+  return status;
+}
+
+
+static int
+parse_insert (struct lexer *lexer, char **filename)
+{
   char *target_fn;
+  char *relative_filename;
 
   /* Skip optional FILE=. */
   if (lex_match_id (lexer, "FILE"))
@@ -45,23 +175,24 @@ cmd_include (struct lexer *lexer, struct dataset *ds UNUSED)
   if (lex_token (lexer) != T_ID && lex_token (lexer) != T_STRING)
     {
       lex_error (lexer, _("expecting file name"));
-      return CMD_CASCADING_FAILURE;
+      return CMD_FAILURE;
     }
 
   target_fn = ds_cstr (lex_tokstr (lexer));
 
-  ss = lex_get_source_stream (lexer);
-  found_fn = fn_search_path (target_fn, getl_include_path ( ss ));
+  relative_filename =
+    fn_search_path (target_fn,
+                   getl_include_path (lex_get_source_stream (lexer)));
 
-  if (found_fn != NULL)
+  if ( ! relative_filename)
     {
-      getl_include_source (ss, create_syntax_file_source (found_fn));
-      free (found_fn);
-    }
-  else
-    msg (SE, _("Can't find `%s' in include file search path."),
+      msg (SE, _("Can't find `%s' in include file search path."),
         target_fn);
+      return CMD_FAILURE;
+    }
 
-  lex_get (lexer);
-  return lex_end_of_command (lexer);
+  *filename = canonicalize_file_name (relative_filename);
+  free (relative_filename);
+
+  return CMD_SUCCESS;
 }
index 6f3ddf519d23e9068b6cc970962eff23ac905dc5..9c1b654d9cd6d35bb19b671da60dbd823a8a55c0 100644 (file)
@@ -1,3 +1,8 @@
+2007-09-05 John Darrington <john@darrington.wattle.id.au>
+
+       * getl.c: Add extra members to struct getl_source, to maintain the
+       error mode and the syntax_mode. 
+
 2007-07-25  Ben Pfaff  <blp@gnu.org>
 
        * getl.c (getl_append_source): Add source to *end* of list.
index b4617122677840ecd65a9670a3d424e3f03964d6..4d6338ce023155b28277b2efc5d94687daea1eb6 100644 (file)
@@ -32,6 +32,8 @@ struct getl_source
     struct ll  ll;   /* Element in the sources list */
 
     struct getl_interface *interface;
+    enum syntax_mode syntax_mode;
+    enum error_mode error_mode;
   };
 
 struct source_stream
@@ -54,6 +56,26 @@ current_source (const struct source_stream *ss)
   return ll_data (ll, struct getl_source, ll );
 }
 
+enum syntax_mode
+source_stream_current_syntax_mode (const struct source_stream *ss)
+{
+  struct getl_source *cs = current_source (ss);
+
+  return cs->syntax_mode;
+}
+
+
+
+enum error_mode
+source_stream_current_error_mode (const struct source_stream *ss)
+{
+  struct getl_source *cs = current_source (ss);
+
+  return cs->error_mode;
+}
+
+
+
 /* Initialize getl. */
 struct source_stream *
 create_source_stream (const char *initial_include_path)
@@ -88,18 +110,26 @@ getl_add_include_dir (struct source_stream *ss, const char *path)
 
 /* Appends source S to the list of source files. */
 void
-getl_append_source (struct source_stream *ss, struct getl_interface *i)
+getl_append_source (struct source_stream *ss,
+                   struct getl_interface *i,
+                   enum syntax_mode syntax_mode,
+                   enum error_mode err_mode)
 {
   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
 
   s->interface = i ;
+  s->syntax_mode = syntax_mode;
+  s->error_mode = err_mode;
 
   ll_push_tail (&ss->sources, &s->ll);
 }
 
 /* Nests source S within the current source file. */
 void
-getl_include_source (struct source_stream *ss, struct getl_interface *i)
+getl_include_source (struct source_stream *ss,
+                    struct getl_interface *i,
+                    enum syntax_mode syntax_mode,
+                    enum error_mode err_mode)
 {
   struct getl_source *current = current_source (ss);
   struct getl_source *s = xzalloc (sizeof ( struct getl_source ));
@@ -108,6 +138,8 @@ getl_include_source (struct source_stream *ss, struct getl_interface *i)
 
   s->included_from = current ;
   s->includes  = NULL;
+  s->syntax_mode  = syntax_mode;
+  s->error_mode = err_mode;
   current->includes = s;
 
   ll_push_head (&ss->sources, &s->ll);
@@ -205,10 +237,9 @@ destroy_source_stream (struct source_stream *ss)
 
 /* Reads a single line into LINE.
    Returns true when a line has been read, false at end of input.
-   On success, sets *SYNTAX to the style of the syntax read. */
+*/
 bool
-getl_read_line (struct source_stream *ss, struct string *line,
-               enum getl_syntax *syntax)
+getl_read_line (struct source_stream *ss, struct string *line)
 {
   assert (ss != NULL);
   while (!ll_is_empty (&ss->sources))
@@ -216,12 +247,12 @@ getl_read_line (struct source_stream *ss, struct string *line,
       struct getl_source *s = current_source (ss);
 
       ds_clear (line);
-      if (s->interface->read (s->interface, line, syntax))
+      if (s->interface->read (s->interface, line))
         {
           while (s)
            {
              if (s->interface->filter)
-               s->interface->filter (s->interface, line, *syntax);
+               s->interface->filter (s->interface, line);
              s = s->included_from;
            }
 
index 26c0649cfe8da63c5f1a7704892a2356af0fc95e..c0399377982bf556ce588cabfcdf0b4cdd1e571e 100644 (file)
@@ -25,7 +25,7 @@ struct string;
 struct getl_source;
 
 /* Syntax rules that apply to a given source line. */
-enum getl_syntax
+enum syntax_mode
   {
     /* Each line that begins in column 1 starts a new command.  A
        `+' or `-' in column 1 is ignored to allow visual
@@ -38,6 +38,16 @@ enum getl_syntax
     GETL_INTERACTIVE
   };
 
+enum error_mode
+  {
+    /* When errors are encountered, report the error and continue to
+       the next command. */
+    ERRMODE_CONTINUE,
+
+    /* When errors are encountered, abort the current stream. */
+    ERRMODE_STOP
+  };
+
 /* An abstract base class for objects which act as line buffers for the
    PSPP.  Ie anything which might contain content for the lexer */
 struct getl_interface
@@ -51,7 +61,7 @@ struct getl_interface
        Returns true if succesful, false on failure or at end of
        input. */
     bool  (*read)  (struct getl_interface *,
-                    struct string *, enum getl_syntax *);
+                    struct string *);
 
     /* Close and destroy the interface */
     void  (*close) (struct getl_interface *);
@@ -59,7 +69,7 @@ struct getl_interface
     /* Filter for current and all included sources, which may
        modify the line.  Usually null.  */
     void  (*filter) (struct getl_interface *,
-                     struct string *line, enum getl_syntax);
+                     struct string *line);
 
     /* Returns the name of the source */
     const char * (*name) (const struct getl_interface *);
@@ -71,6 +81,15 @@ struct getl_interface
 struct source_stream;
 
 struct source_stream * create_source_stream (const char *);
+
+enum syntax_mode source_stream_current_syntax_mode
+   (const struct source_stream *);
+
+
+enum error_mode source_stream_current_error_mode
+   (const struct source_stream *);
+
+
 void destroy_source_stream (struct source_stream *);
 
 void getl_clear_include_path (struct source_stream *);
@@ -80,11 +99,13 @@ const char * getl_include_path (const struct source_stream *);
 void getl_abort_noninteractive (struct source_stream *);
 bool getl_is_interactive (const struct source_stream *);
 
-bool getl_read_line (struct source_stream *, struct string *,
-                    enum getl_syntax *);
+bool getl_read_line (struct source_stream *, struct string *);
+
+void getl_append_source (struct source_stream *, struct getl_interface *s,
+                        enum syntax_mode, enum error_mode) ;
 
-void getl_append_source (struct source_stream *, struct getl_interface *s) ;
-void getl_include_source (struct source_stream *, struct getl_interface *s) ;
+void getl_include_source (struct source_stream *, struct getl_interface *s,
+                         enum syntax_mode, enum error_mode) ;
 
 const char * getl_source_name (const struct source_stream *);
 int getl_source_location (const struct source_stream *);
index 6259965aaf3abfdd168b30ca569471f5d0f5126a..1ca0df3e48dfd476fd33c1b5132c240774e50319 100644 (file)
@@ -178,7 +178,7 @@ execute_syntax (struct getl_interface *sss)
 
   lexer = lex_create (the_source_stream);
 
-  getl_append_source (the_source_stream, sss);
+  getl_append_source (the_source_stream, sss, GETL_BATCH, ERRMODE_CONTINUE);
 
   for (;;)
     {
index 1cee28886c2e04bfa6d6ff48040b72d6f58bf305..289bd37a0f5cd7537a0806f1a10ccfb40e935fb8 100644 (file)
@@ -67,8 +67,7 @@ location (const struct getl_interface *i)
 
 static bool
 read_line_from_buffer (struct getl_interface *i,
-                      struct string *line,
-                      enum getl_syntax *syntax_rules)
+                      struct string *line)
 {
   gchar *text;
   GtkTextIter next_line;
index e152f7009992eb55ad6194bddb62d4efd323488e..1205d4d5a4954d05cdcbae134af38970caaa987c 100644 (file)
@@ -189,7 +189,11 @@ parse_command_line (int argc, char **argv, struct source_stream *ss)
       char *pspprc_fn = fn_search_path ("rc", config_path);
       if (pspprc_fn != NULL)
         {
-         getl_append_source (ss, create_syntax_file_source (pspprc_fn));
+         getl_append_source (ss,
+                             create_syntax_file_source (pspprc_fn),
+                             GETL_BATCH,
+                             ERRMODE_CONTINUE
+                             );
 
           free (pspprc_fn);
         }
@@ -200,13 +204,20 @@ parse_command_line (int argc, char **argv, struct source_stream *ss)
       outp_configure_macro (argv[i]);
     else
       {
-       getl_append_source (ss, create_syntax_file_source (argv[i]));
+       getl_append_source (ss,
+                           create_syntax_file_source (argv[i]),
+                           GETL_BATCH,
+                           ERRMODE_CONTINUE
+                           );
         syntax_files++;
       }
 
   if (!syntax_files || interactive_mode)
     {
-      getl_append_source (ss, create_readln_source () );
+      getl_append_source (ss, create_readln_source (),
+                         GETL_INTERACTIVE,
+                         ERRMODE_CONTINUE
+                         );
       if (!cleared_device_defaults)
         outp_configure_add ("interactive");
     }
index 2529dee40b29ac1732a9292c9c54e8c95bc196ec..626b06353392f75c6941c6e1ac1e30f6096a0ef2 100644 (file)
@@ -101,12 +101,11 @@ readln_uninitialize (void)
 
 static bool
 read_interactive (struct getl_interface *s,
-                  struct string *line, enum getl_syntax *syntax)
+                  struct string *line)
 {
   struct readln_source *is  =
     (struct readln_source *) s ;
 
-  *syntax = GETL_INTERACTIVE;
   return is->interactive_func (line, prompt_get_style ());
 }
 
index a67be09c553bb0b3b4dafbad4c1002836ab446a5..d2648e5336abe11504fbe28775a2be71ee59ad1b 100644 (file)
@@ -20,6 +20,7 @@ dist_TESTS = \
        tests/command/filter.sh \
        tests/command/flip.sh \
        tests/command/import-export.sh \
+       tests/command/insert.sh \
        tests/command/lag.sh \
        tests/command/list.sh \
        tests/command/loop.sh \
diff --git a/tests/command/insert.sh b/tests/command/insert.sh
new file mode 100755 (executable)
index 0000000..ba4f543
--- /dev/null
@@ -0,0 +1,253 @@
+#!/bin/sh
+
+# This program tests the INSERT command
+
+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="create wrapper 1"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/foo.sps'
+  SYNTAX=INTERACTIVE
+  .
+
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+#The following syntax intentionally omits periods from some lines
+#It's an example of "batch" syntax
+activity="create insert"
+cat <<EOF > $TEMPDIR/foo.sps
+input program.
++  loop #i = 1 to 100.
++    compute z = #i
++    end case.
++  end loop
+end file.
+end input program.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+#This command should fail
+activity="run program 1"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -eq 0 ] ; then fail ; fi
+
+
+activity="create wrapper 2"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/foo.sps'
+  SYNTAX=BATCH
+  .
+
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 2"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+# Now test the CD subcommand
+
+activity="mkdir 1"
+mkdir $TEMPDIR/Dir1
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="create wrapper 3"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/Dir1/foo.sps'
+  CD=NO
+  .
+
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="create wrapper 4"
+cat <<EOF > $TEMPDIR/Dir1/foo.sps
+INSERT 
+  FILE='bar.sps'
+  CD=NO
+  .
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="create wrapper 5"
+cat <<EOF > $TEMPDIR/Dir1/bar.sps
+DATA LIST LIST /x *.
+BEGIN DATA.
+1
+2
+3
+END DATA.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+# This command should fail
+activity="run program 3"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -eq 0 ] ; then fail ; fi
+
+activity="create wrapper 6"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/Dir1/foo.sps'
+  CD=YES
+  .
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 4"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+# Now test the ERROR= feature
+
+activity="create wrapper 7"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/foo.sps'
+  ERROR=STOP.
+  .
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="create included file"
+cat <<EOF > $TEMPDIR/foo.sps
+DATA LIST NOTABLE LIST /x *.
+BEGIN DATA.
+1
+2
+3
+END DATA.
+
+* The following line is erroneous
+
+DISPLAY AKSDJ.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 5"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -ne 1 ] ; then no_result ; fi
+
+activity="examine output 1"
+diff $TEMPDIR/pspp.list - <<EOF
+$TEMPDIR/foo.sps:10: error: DISPLAY: AKSDJ is not a variable name.
+warning: Error encountered while ERROR=STOP is effective.
+$TEMPDIR/foo.sps:10: error: Stopping syntax file processing here to avoid a cascade of dependent command failures.
+
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+activity="create wrapper 8"
+cat <<EOF > $TESTFILE
+INSERT 
+  FILE='$TEMPDIR/foo.sps'
+  ERROR=CONTINUE.
+  .
+
+LIST.
+
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+activity="run program 6"
+$SUPERVISOR $PSPP --testing-mode -o raw-ascii $TESTFILE > /dev/null
+if [ $? -ne 1 ] ; then no_result ; fi
+
+activity="examine output 2"
+diff $TEMPDIR/pspp.list - <<EOF
+$TEMPDIR/foo.sps:10: error: DISPLAY: AKSDJ is not a variable name.
+
+       x
+--------
+    1.00 
+    2.00 
+    3.00 
+
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+
+
+pass;