]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Refactor --keyword value checking.
authorBruno Haible <bruno@clisp.org>
Fri, 8 May 2026 20:44:03 +0000 (22:44 +0200)
committerBruno Haible <bruno@clisp.org>
Fri, 8 May 2026 20:45:11 +0000 (22:45 +0200)
* autogen.sh (GNULIB_MODULES_TOOLS_FOR_SRC): Add memrchr.
* gettext-tools/src/xg-arglist-callshape.h (split_keywordspec_ok,
split_keywordspec_ok2, split_keywordspec_ok_lisp): New declarations.
* gettext-tools/src/xg-arglist-callshape.c (split_keywordspec_ok,
split_keywordspec_ok2, split_keywordspec_ok_lisp): New functions.
* gettext-tools/src/x-awk.c (x_awk_keyword): Call split_keywordspec_ok.
* gettext-tools/src/x-c.c (add_keyword): Likewise.
* gettext-tools/src/x-csharp.c (x_csharp_keyword): Likewise.
* gettext-tools/src/x-d.c (x_d_keyword): Likewise.
* gettext-tools/src/x-elisp.c (x_elisp_keyword): Likewise.
* gettext-tools/src/x-go.c (x_go_keyword): Likewise.
* gettext-tools/src/x-java.c (x_java_keyword): Likewise.
* gettext-tools/src/x-javascript.c (x_javascript_keyword): Likewise.
* gettext-tools/src/x-librep.c (x_librep_keyword): Likewise.
* gettext-tools/src/x-lua.c (x_lua_keyword): Likewise.
* gettext-tools/src/x-modula2.c (x_modula2_keyword): Likewise.
* gettext-tools/src/x-ocaml.c (x_ocaml_keyword): Likewise.
* gettext-tools/src/x-perl.c (x_perl_keyword): Likewise.
* gettext-tools/src/x-php.c (x_php_keyword): Likewise.
* gettext-tools/src/x-python.c (x_python_keyword): Likewise.
* gettext-tools/src/x-rust.c (x_rust_keyword): Likewise.
* gettext-tools/src/x-sh.c (x_sh_keyword): Likewise.
* gettext-tools/src/x-typescript-impl.h (NOTE_OPTION_KEYWORD): Likewise.
* gettext-tools/src/x-vala.c (add_keyword): Likewise.
* gettext-tools/src/x-tcl.c (x_tcl_keyword): Call split_keywordspec_ok2.
* gettext-tools/src/x-lisp.c (x_lisp_keyword): Call split_keywordspec_ok_lisp.
* gettext-tools/src/x-scheme.c (x_scheme_keyword): Likewise.

25 files changed:
autogen.sh
gettext-tools/src/x-awk.c
gettext-tools/src/x-c.c
gettext-tools/src/x-csharp.c
gettext-tools/src/x-d.c
gettext-tools/src/x-elisp.c
gettext-tools/src/x-go.c
gettext-tools/src/x-java.c
gettext-tools/src/x-javascript.c
gettext-tools/src/x-librep.c
gettext-tools/src/x-lisp.c
gettext-tools/src/x-lua.c
gettext-tools/src/x-modula2.c
gettext-tools/src/x-ocaml.c
gettext-tools/src/x-perl.c
gettext-tools/src/x-php.c
gettext-tools/src/x-python.c
gettext-tools/src/x-rust.c
gettext-tools/src/x-scheme.c
gettext-tools/src/x-sh.c
gettext-tools/src/x-tcl.c
gettext-tools/src/x-typescript-impl.h
gettext-tools/src/x-vala.c
gettext-tools/src/xg-arglist-callshape.c
gettext-tools/src/xg-arglist-callshape.h

index 92b8055e41dc0753c1805b2a7122e95f52c830a4..54524eb41c1545a69c958483adf5fa512d856e8b 100755 (executable)
@@ -239,6 +239,7 @@ if ! $skip_gnulib; then
     memchr
     memeq
     memmove
+    memrchr
     memset
     minmax
     mkdir
index c9848154fb0fa6a0758ade79b47ddfc841b08e49..a63682b6ea3d87f2d25c2c813b93979769030523 100644 (file)
@@ -81,11 +81,9 @@ x_awk_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 38986c32aa59bcce0d6cad62ac2da3902b731af0..b0c32e61b95edfd916ddc5b866c5dd7f29082ead 100644 (file)
@@ -129,11 +129,9 @@ add_keyword (const char *name, hash_table *keywords)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (keywords, name, end - name, &shape);
     }
 }
index f5592447625f18ee7d9b68db15e82802cc4545c0..22b259f64bf786bcef0fb11b081b3402812a5bf0 100644 (file)
@@ -91,12 +91,9 @@ x_csharp_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C#
-         identifier sequence with dots.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid C#
+           identifier sequence with dots.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index e5be658af9696c805be02bc20ad62c0fb286eaad..34e080e1027abfa93960e3a82a9241a2bfc42a1c 100644 (file)
@@ -112,13 +112,10 @@ x_d_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid identifier,
-         possibly with a trailing '!'.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
         {
+          /* The characters between name and end should form a valid identifier,
+             possibly with a trailing '!'.  */
           if (end > name && end[-1] == '!')
             insert_keyword_callshape (&template_keywords, name, end - 1 - name,
                                       &shape);
index 409f690025bb4b613688f033ce818d08d6039130..aa809e744262bf116307a0aabe80371e609eb168 100644 (file)
@@ -94,11 +94,9 @@ x_elisp_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Lisp
-         symbol.  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid Lisp
+           symbol.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 5145db57c7ca549a828bcde000730f42f2905521..dd5650b7c0f981aae4d3d6c5d1a0b6529aecb3be 100644 (file)
@@ -683,10 +683,7 @@ x_go_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
         {
           /* The characters between name and end should form
                - either a valid Go identifier,
index 8bb265f4b627758e9487b1eb44fc55447deecc91..4b7e4293ed1315c4f7fa086dcddbc96a74f7fc93 100644 (file)
@@ -94,12 +94,9 @@ x_java_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Java
-         identifier sequence with dots.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid Java
+           identifier sequence with dots.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 08338a82711fc61bd786dc96d83e02f750818ca5..7c47262904a3198959925533f176c667e19b3ac5 100644 (file)
@@ -101,11 +101,9 @@ x_javascript_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 4d74ec2c9960c2b12011a090cbc3b3900549c50f..98a3c9f91dd60ea39e4c27f01c3b254f6d3bdb6c 100644 (file)
@@ -95,11 +95,9 @@ x_librep_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Lisp
-         symbol.  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid Lisp
+           symbol.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 184c9d9ec0b4c016508ea5aa4849f4a26b634712..797f81c7d42345c7696b5ac12161d7f5b2579208 100644 (file)
@@ -136,28 +136,24 @@ x_lisp_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Lisp symbol.
-         Extract the symbol name part.  */
-      const char *colon = strchr (name, ':');
-      if (colon != NULL && colon < end)
+      if (split_keywordspec_ok_lisp (name, end - name))
         {
-          name = colon + 1;
-          if (name < end && *name == ':')
-            name++;
-          colon = strchr (name, ':');
-          if (colon != NULL && colon < end)
-            return;
+          /* The characters between name and end should form a valid Lisp
+             symbol.  */
+          /* Extract the symbol name part.  */
+          const char *colon = memrchr (name, ':', end - name);
+          if (colon != NULL)
+            name = colon + 1;
+
+          /* Uppercase it.  */
+          size_t len = end - name;
+          char *symname = XNMALLOC (len, char);
+          for (size_t i = 0; i < len; i++)
+            symname[i] =
+              (name[i] >= 'a' && name[i] <= 'z' ? name[i] - 'a' + 'A' : name[i]);
+
+          insert_keyword_callshape (&keywords, symname, len, &shape);
         }
-
-      /* Uppercase it.  */
-      size_t len = end - name;
-      char *symname = XNMALLOC (len, char);
-      for (size_t i = 0; i < len; i++)
-        symname[i] =
-          (name[i] >= 'a' && name[i] <= 'z' ? name[i] - 'a' + 'A' : name[i]);
-
-      insert_keyword_callshape (&keywords, symname, len, &shape);
     }
 }
 
index 7cea7688b9d46277fac37f481d64909f58cf4583..61b54f681dbcad6b4d00ea384e2d8f5cf6cc49a9 100644 (file)
@@ -82,11 +82,9 @@ x_lua_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 521fb83d0d264195ebe59e65d89c5143267e5030..02b3e12d806f3d2d12bfb8f1808e074870a16a81 100644 (file)
@@ -83,12 +83,9 @@ x_modula2_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Modula-2
-         identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid Modula-2
+           identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index a425e99c06246430e6a59e8280583fd2bb278c06..d8d8e81bb55b7da371f5822e0eb703ecd71251c2 100644 (file)
@@ -97,11 +97,9 @@ x_ocaml_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 937021cef263945b0221843c6410faf7e794460a..337434251dceff26ccd29e1483a4ad456b765738 100644 (file)
@@ -100,11 +100,9 @@ x_perl_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 071e188b171da183af5320b025fd9c076c4a3c8d..497544afdd06cb452e3bc485c5e54b968ae60ce7 100644 (file)
@@ -88,11 +88,9 @@ x_php_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 66e54d110899badac763035975d05b3a3a7af3a5..92615209d767b145aa7f0fd835b983e5340a0024 100644 (file)
@@ -101,11 +101,9 @@ x_python_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 687d3657f42bb9e2ff2bed9b934982655338f816..c3a8e99ff94698e065ccd3f70c8bdb002f9e9917 100644 (file)
@@ -95,13 +95,10 @@ x_rust_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Rust
-         identifier, possibly with a trailing '!'.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
         {
+          /* The characters between name and end should form a valid Rust
+             identifier, possibly with a trailing '!'.  */
           if (end > name && end[-1] == '!')
             insert_keyword_callshape (&macro_keywords, name, end - 1 - name,
                                       &shape);
index d2cca18640d223d70ff9c90dcfae4c6a26e517ce..6b7a50b9f3e335143ecd8b803c83e4fffb0ae7c7 100644 (file)
@@ -127,21 +127,17 @@ x_scheme_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid Lisp symbol.
-         Extract the symbol name part.  */
-      const char *colon = strchr (name, ':');
-      if (colon != NULL && colon < end)
+      if (split_keywordspec_ok_lisp (name, end - name))
         {
-          name = colon + 1;
-          if (name < end && *name == ':')
-            name++;
-          colon = strchr (name, ':');
-          if (colon != NULL && colon < end)
-            return;
+          /* The characters between name and end should form a valid Lisp
+             symbol.  */
+          /* Extract the symbol name part.  */
+          const char *colon = memrchr (name, ':', end - name);
+          if (colon != NULL)
+            name = colon + 1;
+
+          insert_keyword_callshape (&keywords, name, end - name, &shape);
         }
-
-      insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
 
index 48fb15e30968c10feb4726c7c37857349e1a6626..80c22a13095168225ebee2d29e8b01ac80feea5c 100644 (file)
@@ -101,11 +101,9 @@ x_sh_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 944efccf4afa382e165be5f278fc9764085e3fbc..4e3be4c9e83d5baeb64bdf839faea195d81c5b63 100644 (file)
@@ -100,13 +100,15 @@ x_tcl_keyword (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
+      if (split_keywordspec_ok2 (name, end - name))
+        {
+          /* The characters between name and end should form a valid Tcl
+             function name.  A leading "::" is redundant.  */
+          if (end - name >= 2 && name[0] == ':' && name[1] == ':')
+            name += 2;
 
-      /* The characters between name and end should form a valid Tcl
-         function name.  A leading "::" is redundant.  */
-      if (end - name >= 2 && name[0] == ':' && name[1] == ':')
-        name += 2;
-
-      insert_keyword_callshape (&keywords, name, end - name, &shape);
+          insert_keyword_callshape (&keywords, name, end - name, &shape);
+        }
     }
 }
 
index c3d97a8a5e72dd811859d66883bc0f5528a1b239..c617e285e10c5f036222a55b2bd0703e9c486fac 100644 (file)
@@ -87,11 +87,9 @@ NOTE_OPTION_KEYWORD (const char *name)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           identifier.  */
         insert_keyword_callshape (&keywords, name, end - name, &shape);
     }
 }
index 14046c2eaa3a1899fcce4f1211a7bf904d9c8741..b3905e39607b820ea688b009e5a92c5adede34ea 100644 (file)
@@ -92,11 +92,9 @@ add_keyword (const char *name, hash_table *keywords)
       const char *end;
       struct callshape shape;
       split_keywordspec (name, &end, &shape);
-
-      /* The characters between name and end should form a valid C identifier.
-         A colon means an invalid parse in split_keywordspec().  */
-      const char *colon = strchr (name, ':');
-      if (colon == NULL || colon >= end)
+      if (split_keywordspec_ok (name, end - name))
+        /* The characters between name and end should form a valid
+           C identifier.  */
         insert_keyword_callshape (keywords, name, end - name, &shape);
     }
 }
index cd92f6f4baf4911ecbefff29adf9d8966594f1db..a6197c09ffc620cd34d9ef8125471cc2cc9fcd91 100644 (file)
@@ -163,6 +163,48 @@ split_keywordspec (const char *spec,
   string_list_destroy (&xcomments);
 }
 
+bool
+split_keywordspec_ok (const char *keyword, size_t keyword_len)
+{
+  /* If the keyword contains a colon, it means an invalid parse
+     in split_keywordspec().  */
+  return memchr (keyword, ':', keyword_len) == NULL;
+}
+
+bool
+split_keywordspec_ok2 (const char *keyword, size_t keyword_len)
+{
+  /* If the keyword contains a colon that is not part of a colon pair,
+     it means an invalid parse in split_keywordspec().  */
+  const char *keyword_end = keyword + keyword_len;
+  for (const char *p = keyword; p < keyword_end; )
+    {
+      const char *colon = memchr (p, ':', keyword_end - p);
+      if (colon == NULL)
+        break;
+      if (!(colon + 1 < keyword_end && colon[1] == ':'))
+        /* Found a colon that is not part of a colon pair.  */
+        return false;
+      /* Found a colon pair.  */
+      p = colon + 2;
+    }
+  return true;
+}
+
+bool
+split_keywordspec_ok_lisp (const char *keyword, size_t keyword_len)
+{
+  /* If the keyword contains more than a single colon or a colon pair,
+     it means an invalid parse in split_keywordspec().  */
+  const char *keyword_end = keyword + keyword_len;
+  const char *colon = memchr (keyword, ':', keyword_end - keyword);
+  if (colon == NULL)
+    return true;
+  if (colon + 1 < keyword_end && colon[1] == ':')
+    colon++;
+  return memchr (colon, ':', keyword_end - colon) == NULL;
+}
+
 
 void
 insert_keyword_callshape (hash_table *table,
index b58301a0bb790ab8f81fde71a9042f6fad116de8..d5cfc9407d0d831a21df688a7f830792a783639a 100644 (file)
@@ -49,6 +49,21 @@ struct callshape
 extern void split_keywordspec (const char *spec, const char **endp,
                                struct callshape *shapep);
 
+/* Test whether the preceding split_keywordspec call was successful,
+   assuming a programming language in which a keyword cannot contain
+   colons.  */
+extern bool split_keywordspec_ok (const char *keyword, size_t keyword_len);
+
+/* Test whether the preceding split_keywordspec call was successful,
+   assuming a programming language in which a keyword cannot contain colons,
+   except in pairs (such as e.g. in C++).  */
+extern bool split_keywordspec_ok2 (const char *keyword, size_t keyword_len);
+
+/* Test whether the preceding split_keywordspec call was successful,
+   assuming a programming language in which a keyword cannot contain colons,
+   except a single colon or a pair of colons (such as e.g. in Common Lisp).  */
+extern bool split_keywordspec_ok_lisp (const char *keyword, size_t keyword_len);
+
 /* Set of alternative calling conventions for a given keyword.  */
 struct callshapes
 {