message: Introduce underlining for error message regions.
[pspp] / src / language / control / repeat.c
index 68e69a4f225853d68d9859a86f629723311c39db..8876c8fb9e2efeb9bbe9a90a5b284616e83d801c 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2007, 2009-2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2007, 2009-2012 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/segment.h"
 #include "language/lexer/token.h"
 #include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
 #include "libpspp/cast.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/str.h"
+#include "libpspp/misc.h"
 
 #include "gl/ftoastr.h"
 #include "gl/minmax.h"
 #include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -43,6 +47,7 @@ struct dummy_var
   {
     struct hmap_node hmap_node;
     char *name;
+    size_t name_len;
     char **values;
     size_t n_values;
   };
@@ -76,7 +81,7 @@ cmd_do_repeat (struct lexer *lexer, struct dataset *ds)
 static unsigned int
 hash_dummy (const char *name, size_t name_len)
 {
-  return hash_case_bytes (name, name_len, 0);
+  return utf8_hash_case_bytes (name, name_len, 0);
 }
 
 static const struct dummy_var *
@@ -86,7 +91,7 @@ find_dummy_var (struct hmap *hmap, const char *name, size_t name_len)
 
   HMAP_FOR_EACH_WITH_HASH (dv, struct dummy_var, hmap_node,
                            hash_dummy (name, name_len), hmap)
-    if (strcasecmp (dv->name, name))
+    if (!utf8_strncasecmp (dv->name, dv->name_len, name, name_len))
       return dv;
 
   return NULL;
@@ -114,7 +119,9 @@ parse_specification (struct lexer *lexer, struct dictionary *dict,
       if (dict_lookup_var (dict, name))
         msg (SW, _("Dummy variable name `%s' hides dictionary variable `%s'."),
              name, name);
-      if (find_dummy_var (dummies, name, strlen (name)))
+
+      size_t name_len = strlen (name);
+      if (find_dummy_var (dummies, name, name_len))
         {
           msg (SE, _("Dummy variable name `%s' is given twice."), name);
           goto error;
@@ -122,7 +129,8 @@ parse_specification (struct lexer *lexer, struct dictionary *dict,
 
       /* Make a new macro. */
       dv = xmalloc (sizeof *dv);
-      dv->name = xstrdup (name);
+      dv->name = xmemdup0 (name, name_len);
+      dv->name_len = name_len;
       dv->values = NULL;
       dv->n_values = 0;
       hmap_insert (dummies, &dv->hmap_node, hash_dummy (name, strlen (name)));
@@ -189,20 +197,17 @@ count_values (struct hmap *dummies)
 }
 
 static void
-do_parse_commands (struct substring s, enum lex_syntax_mode syntax_mode,
+do_parse_commands (struct substring s, enum segmenter_mode mode,
                    struct hmap *dummies,
                    struct string *outputs, size_t n_outputs)
 {
-  struct segmenter segmenter;
-
-  segmenter_init (&segmenter, syntax_mode);
-
+  struct segmenter segmenter = segmenter_init (mode, false);
   while (!ss_is_empty (s))
     {
       enum segment_type type;
       int n;
 
-      n = segmenter_push (&segmenter, s.string, s.length, &type);
+      n = segmenter_push (&segmenter, s.string, s.length, true, &type);
       assert (n >= 0);
 
       if (type == SEG_DO_REPEAT_COMMAND)
@@ -212,14 +217,14 @@ do_parse_commands (struct substring s, enum lex_syntax_mode syntax_mode,
               int k;
 
               k = segmenter_push (&segmenter, s.string + n, s.length - n,
-                                  &type);
+                                  true, &type);
               if (type != SEG_NEWLINE && type != SEG_DO_REPEAT_COMMAND)
                 break;
 
               n += k;
             }
 
-          do_parse_commands (ss_head (s, n), syntax_mode, dummies,
+          do_parse_commands (ss_head (s, n), mode, dummies,
                              outputs, n_outputs);
         }
       else if (type != SEG_END)
@@ -246,10 +251,8 @@ parse_commands (struct lexer *lexer, struct hmap *dummies)
 {
   struct string *outputs;
   struct string input;
-  size_t input_len;
   size_t n_values;
   char *file_name;
-  int line_number;
   bool ok;
   size_t i;
 
@@ -257,7 +260,7 @@ parse_commands (struct lexer *lexer, struct hmap *dummies)
     file_name = xstrdup (lex_get_file_name (lexer));
   else
     file_name = NULL;
-  line_number = lex_get_first_line_number (lexer, 0);
+  int line_number = lex_ofs_start_point (lexer, lex_ofs (lexer)).line;
 
   ds_init_empty (&input);
   while (lex_is_string (lexer))
@@ -266,10 +269,6 @@ parse_commands (struct lexer *lexer, struct hmap *dummies)
       ds_put_byte (&input, '\n');
       lex_get (lexer);
     }
-  if (ds_is_empty (&input))
-    ds_put_byte (&input, '\n');
-  ds_put_byte (&input, '\0');
-  input_len = ds_length (&input);
 
   n_values = count_values (dummies);
   outputs = xmalloc (n_values * sizeof *outputs);
@@ -294,14 +293,14 @@ parse_commands (struct lexer *lexer, struct hmap *dummies)
   for (i = 0; i < n_values; i++)
     {
       struct string *output = &outputs[n_values - i - 1];
-      struct lex_reader *reader;
-
-      reader = lex_reader_for_substring_nocopy (ds_ss (output));
+      const char *encoding = lex_get_encoding (lexer);
+      struct lex_reader *reader = lex_reader_for_substring_nocopy (ds_ss (output), encoding);
       lex_reader_set_file_name (reader, file_name);
       reader->line_number = line_number;
       lex_include (lexer, reader);
     }
   free (file_name);
+  free (outputs);
 
   return ok;
 }
@@ -358,23 +357,20 @@ parse_numbers (struct lexer *lexer, struct dummy_var *dv)
 
       if (lex_next_token (lexer, 1) == T_TO)
         {
-          long int a, b;
-          long int i;
-
           if (!lex_is_integer (lexer))
            {
              msg (SE, _("Ranges may only have integer bounds."));
              return false;
            }
 
-          a = lex_integer (lexer);
+          long a = lex_integer (lexer);
           lex_get (lexer);
           lex_get (lexer);
 
-          if (!lex_force_int (lexer))
+          if (!lex_force_int_range (lexer, NULL, a, LONG_MAX))
             return false;
 
-         b = lex_integer (lexer);
+         long b = lex_integer (lexer);
           if (b < a)
             {
               msg (SE, _("%ld TO %ld is an invalid range."), a, b);
@@ -382,14 +378,14 @@ parse_numbers (struct lexer *lexer, struct dummy_var *dv)
             }
          lex_get (lexer);
 
-          for (i = a; i <= b; i++)
+          for (long i = a; i <= b; i++)
             add_replacement (dv, xasprintf ("%ld", i), &allocated);
         }
       else
         {
           char s[DBL_BUFSIZE_BOUND];
 
-          dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
+          c_dtoastr (s, sizeof s, 0, 0, lex_number (lexer));
           add_replacement (dv, xstrdup (s), &allocated);
           lex_get (lexer);
         }
@@ -411,7 +407,6 @@ parse_strings (struct lexer *lexer, struct dummy_var *dv)
     {
       if (!lex_force_string (lexer))
        {
-         msg (SE, _("String expected."));
          return false;
        }
 
@@ -428,6 +423,6 @@ parse_strings (struct lexer *lexer, struct dummy_var *dv)
 int
 cmd_end_repeat (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
 {
-  msg (SE, _("No matching DO REPEAT."));
+  msg (SE, _("No matching %s."), "DO REPEAT");
   return CMD_CASCADING_FAILURE;
 }