Add a couple of extensions to GET DATA TYPE=TXT. Patch #6412. Thanks
authorBen Pfaff <blp@gnu.org>
Sun, 10 Feb 2008 08:17:49 +0000 (08:17 +0000)
committerBen Pfaff <blp@gnu.org>
Sun, 10 Feb 2008 08:17:49 +0000 (08:17 +0000)
to John Darrington for review.

16 files changed:
doc/files.texi
src/data/ChangeLog
src/data/data-in.c
src/data/data-in.h
src/language/data-io/data-parser.c
src/language/data-io/data-parser.h
src/language/data-io/get-data.c
src/language/expressions/operations.def
src/language/lexer/range-parser.c
src/language/xforms/recode.c
src/ui/gui/ChangeLog
src/ui/gui/find-dialog.c
src/ui/gui/helper.c
src/ui/gui/psppire-case-file.c
tests/ChangeLog
tests/command/get-data-txt-examples.sh

index ded40e7b9222aea362f9ee5b32f01ab4ec6cd24c..30a023aeb90d3a22793169e4a4cce20edaaed77a 100644 (file)
@@ -385,7 +385,7 @@ GET DATA /TYPE=TXT
         [/IMPORTCASE=@{ALL,FIRST max_cases,PERCENT percent@}]
 
         /DELIMITERS="delimiters"
         [/IMPORTCASE=@{ALL,FIRST max_cases,PERCENT percent@}]
 
         /DELIMITERS="delimiters"
-        [/QUALIFIER="quote"]
+        [/QUALIFIER="quotes" [/ESCAPE]]
         [/DELCASE=@{LINE,VARIABLES n_variables@}]
         /VARIABLES=del_var [del_var]@dots{}
 where each del_var takes the form:
         [/DELCASE=@{LINE,VARIABLES n_variables@}]
         /VARIABLES=del_var [del_var]@dots{}
 where each del_var takes the form:
@@ -417,11 +417,22 @@ delimiter, immediately following @samp{\t}.  To read a data file in
 which each field appears on a separate line, specify the empty string
 for DELIMITERS.
 
 which each field appears on a separate line, specify the empty string
 for DELIMITERS.
 
-The optional QUALIFIER subcommand names a character that can be used
-to quote values within fields in the input.  A field that begins with
-the specified quote character ends at the next match quote.
-Intervening delimiters become part of the field, instead of
-terminating it.
+The optional QUALIFIER subcommand names one or more characters that
+can be used to quote values within fields in the input.  A field that
+begins with one of the specified quote characters ends at the next
+matching quote.  Intervening delimiters become part of the field,
+instead of terminating it.  The ability to specify more than one quote
+character is a PSPP extension.
+
+By default, a character specified on QUALIFIER cannot itself be
+embedded within a field that it quotes, because the quote character
+always terminates the quoted field.  With ESCAPE, however, a doubled
+quote character within a quoted field inserts a single instance of the
+quote into the field.  For example, if @samp{'} is specified on
+QUALIFIER, then without ESCAPE @code{'a''b'} specifies a pair of
+fields that contain @samp{a} and @samp{b}, but with ESCAPE it
+specifies a single field that contains @samp{a'b}.  ESCAPE is a PSPP
+extension.
 
 The DELCASE subcommand controls how data may be broken across lines in
 the data file.  With LINE, the default setting, each line must contain
 
 The DELCASE subcommand controls how data may be broken across lines in
 the data file.  With LINE, the default setting, each line must contain
@@ -495,12 +506,12 @@ GET DATA /TYPE=TXT /FILE='cars.data' /DELIMITERS=' ' /FIRSTCASE=2
 Consider the following information on animals in a pet store:
 
 @example
 Consider the following information on animals in a pet store:
 
 @example
-"Pet Name", "Age", "Color", "Date Received", "Price", "Needs Walking", "Type"
+'Pet''s Name', "Age", "Color", "Date Received", "Price", "Height", "Type"
 , (Years), , , (Dollars), ,
 , (Years), , , (Dollars), ,
-"Rover", 4.5, Brown, "12 Feb 2004", 80, True, "Dog"
-"Charlie", , Gold, "5 Apr 2007", 12.3, False, "Fish"
-"Molly", 2, Black, "12 Dec 2006", 25, False, "Cat"
-"Gilly", , White, "10 Apr 2007", 10, False, "Guinea Pig"
+"Rover", 4.5, Brown, "12 Feb 2004", 80, '1''4"', "Dog"
+"Charlie", , Gold, "5 Apr 2007", 12.3, "3""", "Fish"
+"Molly", 2, Black, "12 Dec 2006", 25, '5"', "Cat"
+"Gilly", , White, "10 Apr 2007", 10, "3""", "Guinea Pig"
 @end example
 
 @noindent
 @end example
 
 @noindent
@@ -509,15 +520,15 @@ The following syntax can be used to read the pet store data:
 @c If you change this example, change the regression test in
 @c tests/command/get-data-txt-examples.sh to match.
 @example
 @c If you change this example, change the regression test in
 @c tests/command/get-data-txt-examples.sh to match.
 @example
-GET DATA /TYPE=TXT /FILE='pets.data' /DELIMITERS=', ' /QUALIFIER='"'
+GET DATA /TYPE=TXT /FILE='pets.data' /DELIMITERS=', ' /QUALIFIER='''"' /ESCAPE
         /FIRSTCASE=3
         /VARIABLES=name A10
                    age F3.1
                    color A5
                    received EDATE10
                    price F5.2
         /FIRSTCASE=3
         /VARIABLES=name A10
                    age F3.1
                    color A5
                    received EDATE10
                    price F5.2
-                   needs_walking A5
-                   type A10.
+                   height a5
+                   type a10.
 @end example
 
 @node GET DATA /TYPE=TXT /ARRANGEMENT=FIXED
 @end example
 
 @node GET DATA /TYPE=TXT /ARRANGEMENT=FIXED
index b3980052ae156f97a417e78fcc90cb41ec4bddcd..a154bd098c35dbc5c1dbc004f18fc0700522972b 100644 (file)
@@ -1,3 +1,23 @@
+2008-02-09  Ben Pfaff  <blp@gnu.org>
+
+       Add a couple of extensions to GET DATA TYPE=TXT.  Patch #6412.
+       Thanks to John Darrington for review.
+
+       * data-in.c (data_in): Add new argument to designate the last
+       column of the data field being parsed, for use in error messages.
+       Update all callers.
+
+       * data-parser (struct data_parser): New member `quote_escape'.
+       (data_parser_create): Initialize quote_escape.
+       (data_parser_set_quotes): New function.
+       (cut_field): Support escaped quotes.
+       (parse_delimited_span): Ditto.
+       (parse_delimited_no_span): Ditto.
+
+       * get-data.c (parse_get_txt): Support ESCAPE extension subcommand
+       in enhanced mode.  Only support multiple quote characters in
+       enhanced mode.
+
 2008-02-06  John Darrington <john@darrington.wattle.id.au>
 
        psql-reader.c psql-reader.h: Read more than one tuple at
 2008-02-06  John Darrington <john@darrington.wattle.id.au>
 
        psql-reader.c psql-reader.h: Read more than one tuple at
index 3f2f8074d800321647acad71805e8fab2ec0b856..96a6ce01fdeb8e971d97021854864a8b12d707aa 100644 (file)
@@ -90,13 +90,16 @@ static int hexit_value (int c);
    IMPLIED_DECIMALS decimal places are implied.  Specify 0 if no
    decimal places should be implied.
 
    IMPLIED_DECIMALS decimal places are implied.  Specify 0 if no
    decimal places should be implied.
 
-   If FIRST_COLUMN is nonzero, then it should be the 1-based
-   column number of the first character in INPUT, used in error
-   messages. */
+   If FIRST_COLUMN and LAST_COLUMN are nonzero, then they should
+   be the 1-based column number of the first and
+   one-past-the-last-character in INPUT, for use in error
+   messages.  (LAST_COLUMN cannot always be calculated from
+   FIRST_COLUMN plus the length of the input because of the
+   possibility of escaped quotes in strings, etc.) */
 bool
 data_in (struct substring input, enum legacy_encoding encoding,
          enum fmt_type format, int implied_decimals,
 bool
 data_in (struct substring input, enum legacy_encoding encoding,
          enum fmt_type format, int implied_decimals,
-         int first_column, union value *output, int width)
+         int first_column, int last_column, union value *output, int width)
 {
   static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
     {
 {
   static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
     {
@@ -131,7 +134,7 @@ data_in (struct substring input, enum legacy_encoding encoding,
   i.width = width;
 
   i.first_column = first_column;
   i.width = width;
 
   i.first_column = first_column;
-  i.last_column = first_column + ss_length (input) - 1;
+  i.last_column = last_column;
 
   if (!ss_is_empty (i.input))
     {
 
   if (!ss_is_empty (i.input))
     {
@@ -1167,11 +1170,11 @@ vdata_warning (const struct data_in *i, const char *format, va_list args)
   ds_put_char (&text, '(');
   if (i->first_column != 0)
     {
   ds_put_char (&text, '(');
   if (i->first_column != 0)
     {
-      if (i->first_column == i->last_column)
+      if (i->first_column == i->last_column - 1)
         ds_put_format (&text, _("column %d"), i->first_column);
       else
         ds_put_format (&text, _("columns %d-%d"),
         ds_put_format (&text, _("column %d"), i->first_column);
       else
         ds_put_format (&text, _("columns %d-%d"),
-                       i->first_column, i->last_column);
+                       i->first_column, i->last_column - 1);
       ds_put_cstr (&text, ", ");
     }
   ds_put_format (&text, _("%s field) "), fmt_name (i->format));
       ds_put_cstr (&text, ", ");
     }
   ds_put_format (&text, _("%s field) "), fmt_name (i->format));
index 52301c8cefe2a622092154ed5a7a09ef8b3ecd50..6ba9a5882216af9996e64d619eae97ee8c3463a9 100644 (file)
@@ -27,7 +27,8 @@
 
 union value;
 bool data_in (struct substring input, enum legacy_encoding,
 
 union value;
 bool data_in (struct substring input, enum legacy_encoding,
-              enum fmt_type, int implied_decimals, int first_column,
+              enum fmt_type, int implied_decimals,
+              int first_column, int last_column,
               union value *output, int width);
 
 #endif /* data/data-in.h */
               union value *output, int width);
 
 #endif /* data/data-in.h */
index 9a2ea769b26b76cb95fad86852276354ea2f86ce..dfc04be44c52b2cfc5f09a2b2dfc9432018ca10d 100644 (file)
@@ -54,6 +54,7 @@ struct data_parser
     bool span;                  /* May cases span multiple records? */
     bool empty_line_has_field;  /* Does an empty line have an (empty) field? */
     struct substring quotes;    /* Characters that can quote separators. */
     bool span;                  /* May cases span multiple records? */
     bool empty_line_has_field;  /* Does an empty line have an (empty) field? */
     struct substring quotes;    /* Characters that can quote separators. */
+    bool quote_escape;          /* Doubled quote acts as escape? */
     struct substring soft_seps; /* Two soft separators act like just one. */
     struct substring hard_seps; /* Two hard separators yield empty fields. */
     struct string any_sep;      /* Concatenation of soft_seps and hard_seps. */
     struct substring soft_seps; /* Two soft separators act like just one. */
     struct substring hard_seps; /* Two hard separators yield empty fields. */
     struct string any_sep;      /* Concatenation of soft_seps and hard_seps. */
@@ -94,6 +95,7 @@ data_parser_create (void)
   parser->span = true;
   parser->empty_line_has_field = false;
   ss_alloc_substring (&parser->quotes, ss_cstr ("\"'"));
   parser->span = true;
   parser->empty_line_has_field = false;
   ss_alloc_substring (&parser->quotes, ss_cstr ("\"'"));
+  parser->quote_escape = false;
   ss_alloc_substring (&parser->soft_seps, ss_cstr (CC_SPACES));
   ss_alloc_substring (&parser->hard_seps, ss_cstr (","));
   ds_init_empty (&parser->any_sep);
   ss_alloc_substring (&parser->soft_seps, ss_cstr (CC_SPACES));
   ss_alloc_substring (&parser->hard_seps, ss_cstr (","));
   ds_init_empty (&parser->any_sep);
@@ -218,6 +220,20 @@ data_parser_set_quotes (struct data_parser *parser, struct substring quotes)
   ss_alloc_substring (&parser->quotes, quotes);
 }
 
   ss_alloc_substring (&parser->quotes, quotes);
 }
 
+/* If ESCAPE is false (the default setting), a character used for
+   quoting cannot itself be embedded within a quoted field.  If
+   ESCAPE is true, then a quote character can be embedded within
+   a quoted field by doubling it.
+
+   This setting affects parsing of DP_DELIMITED files only, and
+   only when at least one quote character has been set (with
+   data_parser_set_quotes). */
+void
+data_parser_set_quote_escape (struct data_parser *parser, bool escape)
+{
+  parser->quote_escape = escape;
+}
+
 /* Sets PARSER's soft delimiters to DELIMITERS.  Soft delimiters
    separate fields, but consecutive soft delimiters do not yield
    empty fields.  (Ordinarily, only white space characters are
 /* Sets PARSER's soft delimiters to DELIMITERS.  Soft delimiters
    separate fields, but consecutive soft delimiters do not yield
    empty fields.  (Ordinarily, only white space characters are
@@ -401,6 +417,7 @@ data_parser_parse (struct data_parser *parser, struct dfm_reader *reader,
    beginning of the field on success. */
 static bool
 cut_field (const struct data_parser *parser, struct dfm_reader *reader,
    beginning of the field on success. */
 static bool
 cut_field (const struct data_parser *parser, struct dfm_reader *reader,
+           int *first_column, int *last_column, struct string *tmp,
            struct substring *field)
 {
   struct substring line, p;
            struct substring *field)
 {
   struct substring line, p;
@@ -422,16 +439,34 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
       else
         {
           *field = p;
       else
         {
           *field = p;
+          *first_column = dfm_column_start (reader);
+          *last_column = *first_column + 1;
           dfm_forward_columns (reader, 1);
           return true;
         }
     }
 
           dfm_forward_columns (reader, 1);
           return true;
         }
     }
 
+  *first_column = dfm_column_start (reader);
   if (ss_find_char (parser->quotes, ss_first (p)) != SIZE_MAX)
     {
       /* Quoted field. */
   if (ss_find_char (parser->quotes, ss_first (p)) != SIZE_MAX)
     {
       /* Quoted field. */
-      if (!ss_get_until (&p, ss_get_char (&p), field))
+      int quote = ss_get_char (&p);
+      if (!ss_get_until (&p, quote, field))
         msg (SW, _("Quoted string extends beyond end of line."));
         msg (SW, _("Quoted string extends beyond end of line."));
+      if (parser->quote_escape && ss_first (p) == quote)
+        {
+          ds_assign_substring (tmp, *field);
+          while (ss_match_char (&p, quote))
+            {
+              struct substring ss;
+              ds_put_char (tmp, quote);
+              if (!ss_get_until (&p, quote, &ss))
+                msg (SW, _("Quoted string extends beyond end of line."));
+              ds_put_substring (tmp, ss);
+            }
+          *field = ds_ss (tmp);
+        }
+      *last_column = dfm_column_start (reader);
 
       /* Skip trailing soft separator and a single hard separator
          if present. */
 
       /* Skip trailing soft separator and a single hard separator
          if present. */
@@ -444,6 +479,7 @@ cut_field (const struct data_parser *parser, struct dfm_reader *reader,
     {
       /* Regular field. */
       ss_get_chars (&p, ss_cspan (p, ds_ss (&parser->any_sep)), field);
     {
       /* Regular field. */
       ss_get_chars (&p, ss_cspan (p, ds_ss (&parser->any_sep)), field);
+      *last_column = dfm_column_start (reader);
       if (!ss_ltrim (&p, parser->soft_seps) || ss_is_empty (p))
         {
           /* Advance past a trailing hard separator,
       if (!ss_ltrim (&p, parser->soft_seps) || ss_is_empty (p))
         {
           /* Advance past a trailing hard separator,
@@ -491,7 +527,8 @@ parse_fixed (const struct data_parser *parser, struct dfm_reader *reader,
         data_in (ss_substr (line, f->first_column - 1,
                             f->format.w),
                  encoding, f->format.type, f->format.d,
         data_in (ss_substr (line, f->first_column - 1,
                             f->format.w),
                  encoding, f->format.type, f->format.d,
-                 f->first_column, case_data_rw_idx (c, f->case_idx),
+                 f->first_column, f->first_column + f->format.w,
+                 case_data_rw_idx (c, f->case_idx),
                  fmt_var_width (&f->format));
 
       dfm_forward_record (reader);
                  fmt_var_width (&f->format));
 
       dfm_forward_record (reader);
@@ -508,14 +545,17 @@ parse_delimited_span (const struct data_parser *parser,
                       struct dfm_reader *reader, struct ccase *c)
 {
   enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
                       struct dfm_reader *reader, struct ccase *c)
 {
   enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
+  struct string tmp = DS_EMPTY_INITIALIZER;
   struct field *f;
 
   for (f = parser->fields; f < &parser->fields[parser->field_cnt]; f++)
     {
       struct substring s;
   struct field *f;
 
   for (f = parser->fields; f < &parser->fields[parser->field_cnt]; f++)
     {
       struct substring s;
+      int first_column, last_column;
 
       /* Cut out a field and read in a new record if necessary. */
 
       /* Cut out a field and read in a new record if necessary. */
-      while (!cut_field (parser, reader, &s))
+      while (!cut_field (parser, reader,
+                         &first_column, &last_column, &tmp, &s))
        {
          if (!dfm_eof (reader))
             dfm_forward_record (reader);
        {
          if (!dfm_eof (reader))
             dfm_forward_record (reader);
@@ -524,15 +564,17 @@ parse_delimited_span (const struct data_parser *parser,
              if (f > parser->fields)
                msg (SW, _("Partial case discarded.  The first variable "
                            "missing was %s."), f->name);
              if (f > parser->fields)
                msg (SW, _("Partial case discarded.  The first variable "
                            "missing was %s."), f->name);
+              ds_destroy (&tmp);
              return false;
            }
        }
 
       data_in (s, encoding, f->format.type, 0,
              return false;
            }
        }
 
       data_in (s, encoding, f->format.type, 0,
-               dfm_get_column (reader, ss_data (s)),
+               first_column, last_column,
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
+  ds_destroy (&tmp);
   return true;
 }
 
   return true;
 }
 
@@ -544,6 +586,7 @@ parse_delimited_no_span (const struct data_parser *parser,
                          struct dfm_reader *reader, struct ccase *c)
 {
   enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
                          struct dfm_reader *reader, struct ccase *c)
 {
   enum legacy_encoding encoding = dfm_reader_get_legacy_encoding (reader);
+  struct string tmp = DS_EMPTY_INITIALIZER;
   struct substring s;
   struct field *f;
 
   struct substring s;
   struct field *f;
 
@@ -552,7 +595,8 @@ parse_delimited_no_span (const struct data_parser *parser,
 
   for (f = parser->fields; f < &parser->fields[parser->field_cnt]; f++)
     {
 
   for (f = parser->fields; f < &parser->fields[parser->field_cnt]; f++)
     {
-      if (!cut_field (parser, reader, &s))
+      int first_column, last_column;
+      if (!cut_field (parser, reader, &first_column, &last_column, &tmp, &s))
        {
          if (settings_get_undefined ())
            msg (SW, _("Missing value(s) for all variables from %s onward.  "
        {
          if (settings_get_undefined ())
            msg (SW, _("Missing value(s) for all variables from %s onward.  "
@@ -560,18 +604,13 @@ parse_delimited_no_span (const struct data_parser *parser,
                        "or blanks, as appropriate."),
                 f->name);
           for (; f < &parser->fields[parser->field_cnt]; f++)
                        "or blanks, as appropriate."),
                 f->name);
           for (; f < &parser->fields[parser->field_cnt]; f++)
-            {
-              int width = fmt_var_width (&f->format);
-              if (width == 0)
-                case_data_rw_idx (c, f->case_idx)->f = SYSMIS;
-              else
-                memset (case_data_rw_idx (c, f->case_idx)->s, ' ', width);
-            }
+            value_set_missing (case_data_rw_idx (c, f->case_idx),
+                               fmt_var_width (&f->format));
           goto exit;
        }
 
       data_in (s, encoding, f->format.type, 0,
           goto exit;
        }
 
       data_in (s, encoding, f->format.type, 0,
-               dfm_get_column (reader, ss_data (s)),
+               first_column, last_column,
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
                case_data_rw_idx (c, f->case_idx),
                fmt_var_width (&f->format));
     }
@@ -583,6 +622,7 @@ parse_delimited_no_span (const struct data_parser *parser,
 
 exit:
   dfm_forward_record (reader);
 
 exit:
   dfm_forward_record (reader);
+  ds_destroy (&tmp);
   return true;
 }
 \f
   return true;
 }
 \f
index 3ee1be8c9b4b079560e3c5e871344a996cd748cf..4976d3f42e69712ff52bc82f38d6432b5f5f3359 100644 (file)
@@ -54,6 +54,7 @@ void data_parser_set_span (struct data_parser *, bool may_cases_span_records);
 void data_parser_set_empty_line_has_field (struct data_parser *,
                                            bool empty_line_has_field);
 void data_parser_set_quotes (struct data_parser *, struct substring);
 void data_parser_set_empty_line_has_field (struct data_parser *,
                                            bool empty_line_has_field);
 void data_parser_set_quotes (struct data_parser *, struct substring);
+void data_parser_set_quote_escape (struct data_parser *, bool escape);
 void data_parser_set_soft_delimiters (struct data_parser *, struct substring);
 void data_parser_set_hard_delimiters (struct data_parser *, struct substring);
 
 void data_parser_set_soft_delimiters (struct data_parser *, struct substring);
 void data_parser_set_hard_delimiters (struct data_parser *, struct substring);
 
index bc09715bd81bdf056d3f5e382933ee79a4a8a32a..54bb5653ecc2086456624e7923b9a02443b77b57 100644 (file)
@@ -24,6 +24,7 @@
 #include <data/dictionary.h>
 #include <data/format.h>
 #include <data/procedure.h>
 #include <data/dictionary.h>
 #include <data/format.h>
 #include <data/procedure.h>
+#include <data/settings.h>
 #include <language/command.h>
 #include <language/data-io/data-parser.h>
 #include <language/data-io/data-reader.h>
 #include <language/command.h>
 #include <language/data-io/data-parser.h>
 #include <language/data-io/data-reader.h>
@@ -429,18 +430,29 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
 
           lex_get (lexer);
         }
 
           lex_get (lexer);
         }
-      else if (lex_match_id (lexer, "QUALIFIER"))
+      else if (lex_match_id (lexer, "QUALIFIERS"))
         {
         {
-          if (!set_type (parser, "QUALIFIER", DP_DELIMITED, &has_type))
+          if (!set_type (parser, "QUALIFIERS", DP_DELIMITED, &has_type))
             goto error;
           lex_match (lexer, '=');
 
           if (!lex_force_string (lexer))
             goto error;
 
             goto error;
           lex_match (lexer, '=');
 
           if (!lex_force_string (lexer))
             goto error;
 
+          if (settings_get_syntax () == COMPATIBLE
+              && ds_length (lex_tokstr (lexer)) != 1)
+            {
+              msg (SE, _("In compatible syntax mode, the QUALIFIER string "
+                         "must contain exactly one character."));
+              goto error;
+            }
+
           data_parser_set_quotes (parser, ds_ss (lex_tokstr (lexer)));
           lex_get (lexer);
         }
           data_parser_set_quotes (parser, ds_ss (lex_tokstr (lexer)));
           lex_get (lexer);
         }
+      else if (settings_get_syntax () == ENHANCED
+               && lex_match_id (lexer, "ESCAPE"))
+        data_parser_set_quote_escape (parser, true);
       else if (lex_match_id (lexer, "VARIABLES"))
         break;
       else
       else if (lex_match_id (lexer, "VARIABLES"))
         break;
       else
index 3056b886343c185f792876f4856a8f0da8f1439a..2ec03c34e88c06ad09d4c2ef5201a21fada479ea 100644 (file)
@@ -573,7 +573,7 @@ string function RTRIM (string s, string c)
 function NUMBER (string s, ni_format f)
 {
   union value out;
 function NUMBER (string s, ni_format f)
 {
   union value out;
-  data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, f->d, 0, &out, 0);
+  data_in (ss_head (s, f->w), LEGACY_NATIVE, f->type, f->d, 0, 0, &out, 0);
   return out.f;
 }
 
   return out.f;
 }
 
index 6a3af097bccf898f044bf1fbfeaae2eeebae63ce..c07dcdb0b9244a02df7d4cff4f4be34a6c673076 100644 (file)
@@ -99,7 +99,7 @@ parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
     {
       union value v;
       data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE,
     {
       union value v;
       data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE,
-               *format, 0, 0, &v, 0);
+               *format, 0, 0, 0, &v, 0);
       lex_get (lexer);
       *x = v.f;
       if (*x == SYSMIS)
       lex_get (lexer);
       *x = v.f;
       if (*x == SYSMIS)
index 85fcb9ea01f72bd8ece9ecc8b76807c96910daba..fb02c910a4ebfe29a3a85dd4a9c38631dc417abe 100644 (file)
@@ -608,7 +608,7 @@ find_src_string (struct recode_trns *trns, const char *value, int width)
 
             msg_disable ();
             match = data_in (ss_buffer (value, width), LEGACY_NATIVE,
 
             msg_disable ();
             match = data_in (ss_buffer (value, width), LEGACY_NATIVE,
-                             FMT_F, 0, 0, &uv, 0);
+                             FMT_F, 0, 0, 0, &uv, 0);
             msg_enable ();
             out->value.f = uv.f;
             break;
             msg_enable ();
             out->value.f = uv.f;
             break;
index 35ed6d860a3bcb63b13830730999b86f55317122..ded87d2bb6d0cdc529d4d64c6061f4f400d8b1a4 100644 (file)
@@ -1,3 +1,18 @@
+2008-02-09  Ben Pfaff  <blp@gnu.org>
+
+       Consolidate multiple messages into single message dialog.  Patch
+       #6405.  Thanks to John Darrington for review.
+
+       * automake.mk (dist_src_ui_gui_psppire_DATA): Add
+       message-dialog.glade.
+
+       * helper.c (give_help): Use GtkMessageDialog directly instead of
+       trying to reuse message-dialog code.
+
+       * message-dialog.c: Rewritten.
+
+       * message-dialog.glade: New file.
+
 2008-02-08  Jason Stover  <jhs@math.gcsu.edu>
 
        * crosstabs-dialog.c: New file.
 2008-02-08  Jason Stover  <jhs@math.gcsu.edu>
 
        * crosstabs-dialog.c: New file.
index 088cac8db69979535adaa024a307aa2898041d92..84bfa1be239bcbc264956519239b9fce7ad5872a 100644 (file)
@@ -600,7 +600,7 @@ value_comparator_create (const struct variable *var, const char *target)
   if ( ! data_in (ss_cstr (target),
                   LEGACY_NATIVE,
                  fmt->type,
   if ( ! data_in (ss_cstr (target),
                   LEGACY_NATIVE,
                  fmt->type,
-                 0, 0,
+                 0, 0, 0,
                  vc->pattern, width) )
     {
       free (vc);
                  vc->pattern, width) )
     {
       free (vc);
index bc197e63adcd2a7c7416a7b1da41f19522ed22ae..c96fddedc437089445bd197ad7675384948ba8b2 100644 (file)
@@ -91,7 +91,7 @@ text_to_value (const gchar *text, union value *v,
     }
 
   msg_disable ();
     }
 
   msg_disable ();
-  ok = data_in (ss_cstr (text), LEGACY_NATIVE, format.type, 0, 0,
+  ok = data_in (ss_cstr (text), LEGACY_NATIVE, format.type, 0, 0, 0,
                 v, fmt_var_width (&format));
   msg_enable ();
 
                 v, fmt_var_width (&format));
   msg_enable ();
 
index 0e5bfb4e2106540749e58432f9196d2b8350812b..08503ff96ec755a952fd247077ea5f8bde4da7e6 100644 (file)
@@ -366,7 +366,7 @@ psppire_case_file_data_in (PsppireCaseFile *cf, casenumber casenum, gint idx,
   width = fmt_var_width (fmt);
   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
   ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
   width = fmt_var_width (fmt);
   value = xmalloca (value_cnt_from_width (width) * sizeof *value);
   ok = (datasheet_get_value (cf->datasheet, casenum, idx, value, width)
-        && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, value, width)
+        && data_in (input, LEGACY_NATIVE, fmt->type, 0, 0, 0, value, width)
         && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
 
   if (ok)
         && datasheet_put_value (cf->datasheet, casenum, idx, value, width));
 
   if (ok)
index fa30dd5043b753b22d7018e6fc9885e020f98023..fce8b1bf69928b72bbd5080f545910ef5bdfaa65 100644 (file)
@@ -1,3 +1,9 @@
+2008-02-10  Ben Pfaff  <blp@gnu.org>
+
+       * command/get-data-txt-examples.sh: Update to match changes to
+       documentation (which were in turn updated to show how the escaped
+       quote feature works).
+
 2008-02-02  Ben Pfaff  <blp@gnu.org>
 
        * automake.mk: Add target for dissect-sysfile.
 2008-02-02  Ben Pfaff  <blp@gnu.org>
 
        * automake.mk: Add target for dissect-sysfile.
index 56cbd3b380c7f130cee1f619bb04bab31f94621d..d9fab7505e942a3e15bbfdc8cb53ad181f1e30ce 100755 (executable)
@@ -75,12 +75,12 @@ if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create pets.data"
 cat > pets.data <<'EOF'
 
 activity="create pets.data"
 cat > pets.data <<'EOF'
-"Pet Name", "Age", "Color", "Date Received", "Price", "Needs Walking", "Type"
+'Pet''s Name', "Age", "Color", "Date Received", "Price", "Height", "Type"
 , (Years), , , (Dollars), ,
 , (Years), , , (Dollars), ,
-"Rover", 4.5, Brown, "12 Feb 2004", 80, True, "Dog"
-"Charlie", , Gold, "5 Apr 2007", 12.3, False, "Fish"
-"Molly", 2, Black, "12 Dec 2006", 25, False, "Cat"
-"Gilly", , White, "10 Apr 2007", 10, False, "Guinea Pig"
+"Rover", 4.5, Brown, "12 Feb 2004", 80, '1''4"', "Dog"
+"Charlie", , Gold, "5 Apr 2007", 12.3, "3""", "Fish"
+"Molly", 2, Black, "12 Dec 2006", 25, '5"', "Cat"
+"Gilly", , White, "10 Apr 2007", 10, "3""", "Guinea Pig"
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
@@ -114,14 +114,14 @@ GET DATA /TYPE=TXT /FILE='cars.data' /ARRANGEMENT=FIXED /FIRSTCASE=2
                    age 40-47 F.
 LIST.
 
                    age 40-47 F.
 LIST.
 
-GET DATA /TYPE=TXT /FILE='pets.data' /DELIMITERS=', ' /QUALIFIER='"'
+GET DATA /TYPE=TXT /FILE='pets.data' /DELIMITERS=', ' /QUALIFIER='''"' /ESCAPE
         /FIRSTCASE=3
         /VARIABLES=name A10
                    age F3.1
                    color A5
                    received EDATE10
                    price F5.2
         /FIRSTCASE=3
         /VARIABLES=name A10
                    age F3.1
                    color A5
                    received EDATE10
                    price F5.2
-                   needs_walking a5
+                   height a5
                    type a10.
 LIST.
 EOF
                    type a10.
 LIST.
 EOF
@@ -152,12 +152,12 @@ Civic        2002    29883    15900 Si              2
 Civic        2003    13415    15900 EX              1
 Civic        1992   107000     3800 n/a            12
 Accord       2002    26613    17900 EX              1
 Civic        2003    13415    15900 EX              1
 Civic        1992   107000     3800 n/a            12
 Accord       2002    26613    17900 EX              1
-      name  age color   received  price needs_walking       type
----------- ---- ----- ---------- ------ ------------- ----------
-Rover       4.5 Brown 12.02.2004  80.00         True  Dog
-Charlie      .  Gold  05.04.2007  12.30         False Fish
-Molly       2.0 Black 12.12.2006  25.00         False Cat
-Gilly        .  White 10.04.2007  10.00         False Guinea Pig
+      name  age color   received  price height       type
+---------- ---- ----- ---------- ------ ------ ----------
+Rover       4.5 Brown 12.02.2004  80.00  1'4"  Dog
+Charlie      .  Gold  05.04.2007  12.30  3"    Fish
+Molly       2.0 Black 12.12.2006  25.00  5"    Cat
+Gilly        .  White 10.04.2007  10.00  3"    Guinea Pig
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 EOF
 if [ $? -ne 0 ] ; then fail ; fi