preprocessor-collate
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Sun, 14 Jan 2018 10:24:48 +0000 (10:24 +0000)
committerAurelien Jarno <aurel32@debian.org>
Sun, 14 Jan 2018 10:24:48 +0000 (10:24 +0000)
Allow preprocessor-like directives.  These keywords were already
defined in locale/programs/locfile-kw.h, an implementation for
'define', 'undef', 'ifdef', 'else' and 'endif' is now provided in
locale/programs/ld-collate.c.  For the moment, 'ifndef' and 'elif'
are not implemented because they do not appear in locfile-kw.h.
This patch is harmless, it only adds new keywords.

# DP: Dpatch author: Denis Barbier
# DP: Patch author: Denis Barbier
# DP: Upstream status: BZ686
# DP: Date: 2006-01-08

Gbp-Pq: Topic locale
Gbp-Pq: Name preprocessor-collate.diff

locale/programs/ld-collate.c

index 553116cd278bf810336b89f6308419d6941c1646..a6b7e7320d94ff901f98c7a3e642de8ae1a23b0c 100644 (file)
@@ -164,6 +164,24 @@ struct symbol_t
   size_t line;
 };
 
+/* Data type for toggles.  */
+struct toggle_list_t;
+
+struct toggle_list_t
+{
+  const char *name;
+
+  /* Predecessor in the list.  */
+  struct toggle_list_t *last;
+
+  /* This flag is set when a keyword is undefined.  */
+  int is_undefined;
+
+  /* Where does the branch come from.  */
+  const char *file;
+  size_t line;
+};
+
 /* Sparse table of struct element_t *.  */
 #define TABLE wchead_table
 #define ELEMENT struct element_t *
@@ -219,6 +237,9 @@ struct locale_collate_t
   /* This value is used when handling ellipsis.  */
   struct element_t ellipsis_weight;
 
+  /* This is a stack of .  */
+  struct toggle_list_t *flow_control;
+
   /* Known collating elements.  */
   hash_table elem_table;
 
@@ -1467,6 +1488,56 @@ order for `%.*s' already defined at %s:%Zu"),
 }
 
 
+static struct token *
+flow_skip (struct linereader *ldfile, const struct charmap_t *charmap,
+          struct locale_collate_t *collate)
+{
+  int level = 0;
+  struct token *now;
+  enum token_t nowtok;
+  while (1)
+    {
+      lr_ignore_rest (ldfile, 0);
+      now = lr_token (ldfile, charmap, NULL, NULL, 0);
+      nowtok = now->tok;
+      if (nowtok == tok_eof)
+       break;
+      else if (nowtok == tok_ifdef || nowtok == tok_ifndef)
+       ++level ;
+      else if (nowtok == tok_else)
+       {
+         if (strcmp (collate->flow_control->name, "else") == 0)
+           lr_error (ldfile,
+                     _("%s: `else' statement at `%s:%Zu' cannot be followed by another `else' statement"),
+                     "LC_COLLATE", collate->flow_control->name, collate->flow_control->line);
+         if (level == 0)
+           {
+             collate->flow_control->name = "else";
+             collate->flow_control->file = ldfile->fname;
+             collate->flow_control->line = ldfile->lineno;
+             break;
+           }
+       }
+      else if (nowtok == tok_endif)
+       {
+         if (level == 0)
+           {
+             collate->flow_control = collate->flow_control->last;
+             break;
+           }
+         --level ;
+       }
+    }
+  if (nowtok == tok_eof)
+    WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control beginning at %s:%Zu"),
+                                "LC_COLLATE", collate->flow_control->name,
+                                collate->flow_control->file,
+                                collate->flow_control->line));
+  return now;
+}
+
+
 static void
 collate_startup (struct linereader *ldfile, struct localedef_t *locale,
                 struct localedef_t *copy_locale, int ignore_content)
@@ -2504,6 +2575,8 @@ collate_read (struct linereader *ldfile, struct localedef_t *result,
   */
   int state = 0;
 
+  static struct toggle_list_t *defined_keywords = NULL;
+
   /* Get the repertoire we have to use.  */
   if (repertoire_name != NULL)
     repertoire = repertoire_read (repertoire_name);
@@ -2518,6 +2591,82 @@ collate_read (struct linereader *ldfile, struct localedef_t *result,
        }
       while (nowtok == tok_eol);
 
+  while (nowtok == tok_define || nowtok == tok_undef)
+    {
+      /* Ignore the rest of the line if we don't need the input of
+         this line.  */
+      if (ignore_content)
+        {
+          lr_ignore_rest (ldfile, 0);
+          now = lr_token (ldfile, charmap, result, NULL, verbose);
+          nowtok = now->tok;
+          continue;
+        }
+
+      arg = lr_token (ldfile, charmap, result, NULL, verbose);
+      if (arg->tok != tok_ident)
+        goto err_label;
+
+      if (nowtok == tok_define)
+        {
+         struct toggle_list_t *runp = defined_keywords;
+         char *name;
+
+         while (runp != NULL)
+           if (strncmp (runp->name, arg->val.str.startmb,
+                    arg->val.str.lenmb) == 0
+               && runp->name[arg->val.str.lenmb] == '\0')
+              SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+           else
+             runp = runp->last;
+
+         if (runp != NULL && runp->is_undefined == 0)
+           {
+             lr_ignore_rest (ldfile, 0);
+              SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+           }
+
+         if (runp == NULL)
+           {
+             runp = (struct toggle_list_t *) xcalloc (1, sizeof (*runp));
+             runp->last = defined_keywords;
+             defined_keywords = runp;
+           }
+         else
+           {
+             free ((char *) runp->name);
+             runp->is_undefined = 0;
+           }
+
+         name = (char *) xmalloc (arg->val.str.lenmb + 1);
+         memcpy (name, arg->val.str.startmb, arg->val.str.lenmb);
+         name[arg->val.str.lenmb] = '\0';
+         runp->name = name;
+        }
+      else
+        {
+         struct toggle_list_t *runp = defined_keywords;
+         while (runp != NULL)
+           if (strncmp (runp->name, arg->val.str.startmb,
+                    arg->val.str.lenmb) == 0
+               && runp->name[arg->val.str.lenmb] == '\0')
+           {
+             runp->is_undefined = 1;
+              SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");
+           }
+           else
+             runp = runp->last;
+        }
+
+      lr_ignore_rest (ldfile, 1);
+      do
+        {
+          now = lr_token (ldfile, charmap, result, NULL, verbose);
+          nowtok = now->tok;
+        }
+      while (nowtok == tok_eol);
+    }
+
   if (nowtok == tok_copy)
     {
       now = lr_token (ldfile, charmap, result, NULL, verbose);
@@ -3669,6 +3818,125 @@ error while adding equivalent collating symbol"));
                          repertoire, result, nowtok);
          break;
 
+       case tok_ifdef:
+         /* Ignore the rest of the line if we don't need the input of
+            this line.  */
+         if (ignore_content)
+           {
+             lr_ignore_rest (ldfile, 0);
+             break;
+           }
+
+         arg = lr_token (ldfile, charmap, result, NULL, verbose);
+         if (arg->tok != tok_ident)
+           goto err_label;
+         else
+           {
+             struct toggle_list_t *runp = defined_keywords;
+             struct toggle_list_t *flow = (struct toggle_list_t *) xcalloc (1, sizeof (*runp));
+             flow->name = "ifdef";
+             flow->file = ldfile->fname;
+             flow->line = ldfile->lineno;
+             flow->last = collate->flow_control;
+             collate->flow_control = flow;
+
+             while (runp != NULL)
+               if (strncmp (runp->name, arg->val.str.startmb,
+                            arg->val.str.lenmb) == 0
+                   && runp->name[arg->val.str.lenmb] == '\0')
+                 break;
+               else
+                 runp = runp->last;
+
+             if (runp == NULL)
+               {
+                 now = flow_skip(ldfile, charmap, collate);
+                 if (now->tok == tok_eof)
+                   WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name));
+               }
+           }
+         lr_ignore_rest (ldfile, 1);
+         break;
+
+       case tok_ifndef:
+         /* Ignore the rest of the line if we don't need the input of
+            this line.  */
+         if (ignore_content)
+           {
+             lr_ignore_rest (ldfile, 0);
+             break;
+           }
+
+         arg = lr_token (ldfile, charmap, result, NULL, verbose);
+         if (arg->tok != tok_ident)
+           goto err_label;
+         else
+           {
+             struct toggle_list_t *runp = defined_keywords;
+             struct toggle_list_t *flow = (struct toggle_list_t *) xcalloc (1, sizeof (*runp));
+             flow->name = "ifndef";
+             flow->file = ldfile->fname;
+             flow->line = ldfile->lineno;
+             flow->last = collate->flow_control;
+             collate->flow_control = flow;
+
+             while (runp != NULL)
+               if (strncmp (runp->name, arg->val.str.startmb,
+                            arg->val.str.lenmb) == 0
+                   && runp->name[arg->val.str.lenmb] == '\0')
+                 break;
+               else
+                 runp = runp->last;
+
+             if (runp != NULL)
+               {
+                 now = flow_skip(ldfile, charmap, collate);
+                 if (now->tok == tok_eof)
+                   WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name));
+               }
+           }
+         lr_ignore_rest (ldfile, 1);
+         break;
+
+       case tok_else:
+         /* Ignore the rest of the line if we don't need the input of
+            this line.  */
+         if (ignore_content)
+           {
+             lr_ignore_rest (ldfile, 0);
+             break;
+           }
+
+         if (strcmp (collate->flow_control->name, "else") == 0)
+           lr_error (ldfile,
+                     _("%s: `else' statement at `%s:%Zu' cannot be followed by another `else' statement"),
+                     "LC_COLLATE", collate->flow_control->name, collate->flow_control->line);
+         collate->flow_control->name = "else";
+         collate->flow_control->file = ldfile->fname;
+         collate->flow_control->line = ldfile->lineno;
+         now = flow_skip(ldfile, charmap, collate);
+         if (now->tok == tok_eof)
+           WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control"), "LC_COLLATE", collate->flow_control->name));
+         break;
+
+       case tok_endif:
+         /* Ignore the rest of the line if we don't need the input of
+            this line.  */
+         if (ignore_content)
+           {
+             lr_ignore_rest (ldfile, 0);
+             break;
+           }
+
+         if (collate->flow_control == NULL)
+           goto err_label;
+         else
+           collate->flow_control = collate->flow_control->last;
+         break;
+
        case tok_end:
          /* Next we assume `LC_COLLATE'.  */
          if (!ignore_content)
@@ -3698,6 +3966,13 @@ error while adding equivalent collating symbol"));
              else if (state == 5)
                WITH_CUR_LOCALE (error (0, 0, _("\
 %s: missing `reorder-sections-end' keyword"), "LC_COLLATE"));
+             if (collate->flow_control != NULL
+                 && strcmp(collate->flow_control->file, ldfile->fname) == 0)
+               WITH_CUR_LOCALE (error (0, 0, _("\
+%s: unterminated `%s' flow control beginning at %s:%Zu"),
+                                "LC_COLLATE", collate->flow_control->name,
+                                collate->flow_control->file,
+                                collate->flow_control->line));
            }
          arg = lr_token (ldfile, charmap, result, NULL, verbose);
          if (arg->tok == tok_eof)