Fixed bug #11843
authorJohn Darrington <john@darrington.wattle.id.au>
Mon, 7 Feb 2005 02:12:01 +0000 (02:12 +0000)
committerJohn Darrington <john@darrington.wattle.id.au>
Mon, 7 Feb 2005 02:12:01 +0000 (02:12 +0000)
doc/q2c.texi
src/ChangeLog
src/crosstabs.q
src/examine.q
src/oneway.q
src/q2c.c
tests/Makefile.am
tests/bugs/curtailed.sh [new file with mode: 0755]

index b24a8ee0e17222974355865a08c216d1ccb2226b..0e25019b468e6b796a1517a605c5b8c55ef8c81a 100644 (file)
@@ -129,6 +129,7 @@ sbc-options ::=
             ::= sbc-options sbc-options
 sbc-option ::= *
            ::= +
+           ::= ^
 sbc-defn ::= opt-prefix = specifiers
          ::= [ ID ] = array-sbc
          ::= opt-prefix = sbc-special-form
@@ -142,6 +143,8 @@ keyword used for the default subcommand can be omitted in the PSPP
 syntax file.  A plus sign (@samp{+}) is used to indicate that a
 subcommand can appear more than once; if it is not present then that
 subcommand can appear no more than once.
+A carat sign (@samp{^}) is used to indicate that a subcommand must appear
+at least once.
 
 The subcommand name appears after the option characters.
 
index ad276e8cc3bf46fe4f2bf64434a24dbdab9b35f0..cbdc0059907469f66a3a30b5990cc144d91a133d 100644 (file)
@@ -1,3 +1,8 @@
+Mon Feb  7 09:58:15 WST 2005 John Darrington <john@darrington.wattle.id.au>
+
+       crosstabs.q examine.q oneway.q q2c.c:  Added a q2c feature to 
+       declare subcommands as mandatory.  Closed bug #11843
+
 Sat Feb  5 20:35:10 WST 2005 John Darrington <john@darrington.wattle.id.au>
        
        * getline.c command.[ch] command.def:  Added (very rudimentary)
index 9c17ed0297379c06887ada4803d55de8bad91543..e61eb07f5189b073a3df253cdfafee449dad42e0 100644 (file)
@@ -59,7 +59,7 @@
 
 /* (specification)
    crosstabs (crs_):
-     *tables=custom;
+     *^tables=custom;
      +variables=custom;
      +missing=miss:!table/include/report;
      +write[wr_]=none,cells,all;
index 3454b66f927a82696d64bbed727625512a593abc..f92bba1fd2160709f263a860b9bd0dd22699e38d 100644 (file)
@@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 /* (specification)
    "EXAMINE" (xmn_):
-   *variables=custom;
+   *^variables=custom;
    +total=custom;
    +nototal=custom;
    +missing=miss:pairwise/!listwise,
index 7277b79a2fe4aa2e8773e0e2a4de8ec453c83e84..16a1e90803d87823b1f1fd42b6eab51f4e17d3dc 100644 (file)
@@ -47,7 +47,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
 /* (specification)
    "ONEWAY" (oneway_):
-   *variables=custom;
+   *^variables=custom;
    +missing=miss:!analysis/listwise,
    incl:include/!exclude;
    contrast= double list;
index 1361320491b25a614fb90bc13d5a9c12e89b9aa6..37ec08f033093d74f203c9560767df9032105175 100644 (file)
--- a/src/q2c.c
+++ b/src/q2c.c
@@ -535,6 +535,13 @@ typedef enum
   }
 subcommand_type;
 
+typedef enum
+  {
+    ARITY_ONCE_EXACTLY,  /* must occur exactly once */
+    ARITY_ONCE_ONLY,     /* zero or once */
+    ARITY_MANY           /* 0, 1, ... , inf */
+  }subcommand_arity;
+
 /* A single subcommand. */
 typedef struct subcommand subcommand;
 struct subcommand
@@ -542,7 +549,7 @@ struct subcommand
     subcommand *next;          /* Next in the chain. */
     char *name;                        /* Subcommand name. */
     subcommand_type type;      /* One of SBC_*. */
-    int once;                  /* 1=Subcommand may appear only once. */
+    subcommand_arity arity;    /* How many times should the subcommand occur*/
     int narray;                        /* Index of next array element. */
     const char *prefix;                /* Prefix for variable and constant names. */
     specifier *spec;           /* Array of specifiers. */
@@ -759,6 +766,8 @@ parse_specifiers (subcommand *sbc)
 static void
 parse_subcommand (subcommand *sbc)
 {
+  sbc->arity = ARITY_MANY;
+
   if (match_token ('*'))
     {
       if (def)
@@ -766,7 +775,11 @@ parse_subcommand (subcommand *sbc)
       def = sbc;
     }
 
-  sbc->once = match_token ('+');
+  if ( match_token('+'))
+    sbc->arity = ARITY_ONCE_ONLY ;
+  else if (match_token('^'))
+    sbc->arity = ARITY_ONCE_EXACTLY ;
+
 
   force_id ();
   sbc->name = xstrdup (tokstr);
@@ -1805,7 +1818,7 @@ dump_parser (int persistent)
 
        dump (0, "lex_match ('=');");
        dump (0, "p->sbc_%s++;", st_lower (sbc->name));
-       if (sbc->once)
+       if (sbc->arity != ARITY_MANY)
          {
            dump (1, "if (p->sbc_%s > 1)", st_lower (sbc->name));
            dump (1, "{");
@@ -1820,6 +1833,8 @@ dump_parser (int persistent)
        outdent ();
       }
   }
+
+
   /* Now deal with the /ALGORITHM subcommand implicit to all commands */
   dump(1,"else if ( get_syntax() != COMPATIBLE && lex_match_id(\"ALGORITHM\"))");
   dump(1,"{");
@@ -1835,6 +1850,7 @@ dump_parser (int persistent)
   dump (-1, "}");
   outdent ();
 
+
   
   dump (1, "if (!lex_match ('/'))");
   dump (0, "break;");
@@ -1847,6 +1863,29 @@ dump_parser (int persistent)
   dump (0, "goto lossage;");
   dump (-1, "}");
   dump (0, nullstr);
+
+  outdent ();
+
+  {
+    /*  Check that mandatory subcommands have been specified  */
+    subcommand *sbc;
+
+    for (sbc = subcommands; sbc; sbc = sbc->next)
+      {
+
+       if ( sbc->arity == ARITY_ONCE_EXACTLY ) 
+         {
+           dump (0, "if ( 0 == p->sbc_%s)", st_lower (sbc->name));
+           dump (1, "{");
+           dump (0, "msg (SE, _(\"%s subcommand must be given.\"));",
+                 sbc->name);
+           dump (0, "goto lossage;");
+           dump (-1, "}");
+           dump (0, nullstr);
+         }
+      }
+  }
+
   dump (-1, "return 1;");
   dump (0, nullstr);
   dump (-1, "lossage:");
index 6cad09085045731eee40da7f96bc5c0f31d3fb4f..b211891befb0f1715b782d69c907a8877f5693c8 100644 (file)
@@ -48,6 +48,7 @@ TESTS = \
        bugs/comment-at-eof.sh \
        bugs/compute-fmt.sh \
        bugs/crosstabs.sh \
+       bugs/curtailed.sh \
        bugs/data-crash.sh \
        bugs/double-frequency.sh \
        bugs/get.sh \
diff --git a/tests/bugs/curtailed.sh b/tests/bugs/curtailed.sh
new file mode 100755 (executable)
index 0000000..a004ce5
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+# This program tests for a bug which crashed pspp when given certain
+# invalid input
+
+TEMPDIR=/tmp/pspp-tst-$$
+TESTFILE=$TEMPDIR/`basename $0`.sps
+
+here=`pwd`;
+
+# ensure that top_srcdir is absolute
+cd $top_srcdir; top_srcdir=`pwd`
+
+export STAT_CONFIG_PATH=$top_srcdir/config
+
+
+cleanup()
+{
+     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 program"
+cat > $TESTFILE <<EOF
+DATA LIST LIST /x *.
+BEGIN DATA.
+1
+2
+3
+END DATA.
+
+EXAMINE.
+ONEWAY.
+CROSSTABS.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+#This must fail
+activity="run program"
+$SUPERVISOR $here/../src/pspp $TESTFILE > /dev/null
+if [ $? -ne 1 ] ; then fail ; fi
+
+
+pass;