]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Refactor the formatstring code.
authorBruno Haible <bruno@clisp.org>
Thu, 30 Nov 2023 07:43:16 +0000 (08:43 +0100)
committerBruno Haible <bruno@clisp.org>
Thu, 30 Nov 2023 10:40:20 +0000 (11:40 +0100)
* gettext-tools/src/xg-formatstring.h (NXFORMATS, XFORMAT_PRIMARY,
XFORMAT_SECONDARY, XFORMAT_TERTIARY, XFORMAT_FOURTH): New macros.
(current_formatstring_parser1, current_formatstring_parser2,
current_formatstring_parser3, current_formatstring_parser4): Remove
declarations.
(current_formatstring_parser): New declaration.
* gettext-tools/src/xg-formatstring.c (current_formatstring_parser1,
current_formatstring_parser2, current_formatstring_parser3,
current_formatstring_parser4): Remove variables.
(current_formatstring_parser): New variable.
* gettext-tools/src/xg-arglist-context.h: Include xg-formatstring.h.
(struct formatstring_context_ty): New type.
(struct flag_context_ty): Replace individual fields with an array.
(flag_context_list_table_add): Rename parameter 'index' to 'fi'.
* gettext-tools/src/xg-arglist-context.c (null_context, passthrough_context):
Update.
(inherited_context): Loop over the four formatstring types.
(passthrough_context_circular_list): Update.
(set_flags_for_formatstring_type): Simplify.
(flag_context_list_table_add): Rename parameter 'index' to 'fi'.
* gettext-tools/src/xg-arglist-parser.c (arglist_parser_done): Update.
* gettext-tools/src/xg-message.c (set_format_flags_from_context): Loop over the
four formatstring types.
(is_relevant): New function.
(decide_is_format, remember_a_message_plural): Use it.
* gettext-tools/src/xgettext.c (struct extractor_ty): Replace individual fields
with an array.
(main): Update.
(flag_context_list_table_insert): Rename parameter 'index' to 'fi'.
(xgettext_record_flag): Use XFORMAT_* macros.
(extract_from_file): Loop over the four formatstring types.
(recognize_qt_formatstrings): Update.
(language_to_extractor): Use XFORMAT_* macros and a loop.

gettext-tools/src/xg-arglist-context.c
gettext-tools/src/xg-arglist-context.h
gettext-tools/src/xg-arglist-parser.c
gettext-tools/src/xg-formatstring.c
gettext-tools/src/xg-formatstring.h
gettext-tools/src/xg-message.c
gettext-tools/src/xgettext.c

index 282e1008c9e22480c625e0523adf4e3171f68517..d31d077181335938b84087f41a270ddd4a0d21df 100644 (file)
 /* Null context.  */
 flag_context_ty null_context =
   {
-    undecided, false,
-    undecided, false,
-    undecided, false,
-    undecided, false
+    {
+      { undecided, false },
+      { undecided, false },
+      { undecided, false },
+      { undecided, false }
+    }
   };
 
 /* Transparent context.  */
 flag_context_ty passthrough_context =
   {
-    undecided, true,
-    undecided, true,
-    undecided, true,
-    undecided, true
+    {
+      { undecided, true },
+      { undecided, true },
+      { undecided, true },
+      { undecided, true }
+    }
   };
 
 
@@ -54,26 +58,12 @@ inherited_context (flag_context_ty outer_context,
 {
   flag_context_ty result = modifier_context;
 
-  if (result.pass_format1)
-    {
-      result.is_format1 = outer_context.is_format1;
-      result.pass_format1 = false;
-    }
-  if (result.pass_format2)
-    {
-      result.is_format2 = outer_context.is_format2;
-      result.pass_format2 = false;
-    }
-  if (result.pass_format3)
-    {
-      result.is_format3 = outer_context.is_format3;
-      result.pass_format3 = false;
-    }
-  if (result.pass_format4)
-    {
-      result.is_format4 = outer_context.is_format4;
-      result.pass_format4 = false;
-    }
+  for (size_t fi = 0; fi < NXFORMATS; fi++)
+    if (result.for_formatstring[fi].pass_format)
+      {
+        result.for_formatstring[fi].is_format = outer_context.for_formatstring[fi].is_format;
+        result.for_formatstring[fi].pass_format = false;
+      }
   return result;
 }
 
@@ -85,7 +75,14 @@ flag_context_list_iterator_ty null_context_list_iterator = { 1, NULL };
 static flag_context_list_ty passthrough_context_circular_list =
   {
     1,
-    { undecided, true, undecided, true, undecided, true, undecided, true },
+    {
+      {
+        { undecided, true },
+        { undecided, true },
+        { undecided, true },
+        { undecided, true }
+      }
+    },
     &passthrough_context_circular_list
   };
 flag_context_list_iterator_ty passthrough_context_list_iterator =
@@ -146,39 +143,20 @@ flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
 }
 
 
-/* In the FLAGS, set the pair (is_formatX, pass_formatX) with X = INDEX+1
-   to (VALUE, PASS).  */
+/* In the FLAGS, set the pair (is_format, pass_format) for the format string
+   type FI to (VALUE, PASS).  */
 static void
-set_flags_for_formatstring_type (flag_context_ty *flags, unsigned int index,
+set_flags_for_formatstring_type (flag_context_ty *flags, size_t fi,
                                  enum is_format value, bool pass)
 {
-  switch (index)
-    {
-    case 0:
-      flags->is_format1 = value;
-      flags->pass_format1 = pass;
-      break;
-    case 1:
-      flags->is_format2 = value;
-      flags->pass_format2 = pass;
-      break;
-    case 2:
-      flags->is_format3 = value;
-      flags->pass_format3 = pass;
-      break;
-    case 3:
-      flags->is_format4 = value;
-      flags->pass_format4 = pass;
-      break;
-    default:
-      abort ();
-    }
+  flags->for_formatstring[fi].is_format = value;
+  flags->for_formatstring[fi].pass_format = pass;
 }
 
 
 void
 flag_context_list_table_add (flag_context_list_table_ty *table,
-                             unsigned int index,
+                             size_t fi,
                              const char *name_start, const char *name_end,
                              int argnum, enum is_format value, bool pass)
 {
@@ -193,7 +171,7 @@ flag_context_list_table_add (flag_context_list_table_ty *table,
         flag_context_list_ty *list = XMALLOC (flag_context_list_ty);
         list->argnum = argnum;
         memset (&list->flags, '\0', sizeof (list->flags));
-        set_flags_for_formatstring_type (&list->flags, index, value, pass);
+        set_flags_for_formatstring_type (&list->flags, fi, value, pass);
         list->next = NULL;
         hash_insert_entry (table, name_start, name_end - name_start, list);
       }
@@ -214,7 +192,7 @@ flag_context_list_table_add (flag_context_list_table_ty *table,
         if (list != NULL && list->argnum == argnum)
           {
             /* Add this flag to the current argument number.  */
-            set_flags_for_formatstring_type (&list->flags, index, value, pass);
+            set_flags_for_formatstring_type (&list->flags, fi, value, pass);
           }
         else if (lastp != NULL)
           {
@@ -222,7 +200,7 @@ flag_context_list_table_add (flag_context_list_table_ty *table,
             list = XMALLOC (flag_context_list_ty);
             list->argnum = argnum;
             memset (&list->flags, '\0', sizeof (list->flags));
-            set_flags_for_formatstring_type (&list->flags, index, value, pass);
+            set_flags_for_formatstring_type (&list->flags, fi, value, pass);
             list->next = *lastp;
             *lastp = list;
           }
@@ -237,7 +215,7 @@ flag_context_list_table_add (flag_context_list_table_ty *table,
 
             list->argnum = argnum;
             memset (&list->flags, '\0', sizeof (list->flags));
-            set_flags_for_formatstring_type (&list->flags, index, value, pass);
+            set_flags_for_formatstring_type (&list->flags, fi, value, pass);
             list->next = copy;
           }
       }
index ab73011e73c93c197fd6e9e65b2ab218eb78357e..8c32cac497f47f3aa37496a2ddbacd8249232425 100644 (file)
 
 #include "mem-hash-map.h"
 #include "message.h"
+#include "xg-formatstring.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 
+/* Context representing some flags w.r.t. a specific format string type.  */
+struct formatstring_context_ty
+{
+  /*enum is_format*/ unsigned int is_format    : 3;
+  /*bool*/           unsigned int pass_format  : 1;
+};
+
 /* Context representing some flags.  */
 typedef struct flag_context_ty flag_context_ty;
 struct flag_context_ty
 {
-  /* Regarding the primary formatstring type.  */
-  /*enum is_format*/ unsigned int is_format1    : 3;
-  /*bool*/           unsigned int pass_format1  : 1;
-  /* Regarding the secondary formatstring type.  */
-  /*enum is_format*/ unsigned int is_format2    : 3;
-  /*bool*/           unsigned int pass_format2  : 1;
-  /* Regarding the tertiary formatstring type.  */
-  /*enum is_format*/ unsigned int is_format3    : 3;
-  /*bool*/           unsigned int pass_format3  : 1;
-  /* Regarding the fourth-ranked formatstring type.  */
-  /*enum is_format*/ unsigned int is_format4    : 3;
-  /*bool*/           unsigned int pass_format4  : 1;
+  struct formatstring_context_ty for_formatstring[NXFORMATS];
 };
 /* Null context.  */
 extern flag_context_ty null_context;
 /* Transparent context.  */
 extern flag_context_ty passthrough_context;
 /* Compute an inherited context.
-   The outer_context is assumed to have all pass_format* flags = false.
-   The result will then also have all pass_format* flags = false.  */
+   The outer_context is assumed to have all pass_format flags = false.
+   The result will then also have all pass_format flags = false.  */
 extern flag_context_ty
        inherited_context (flag_context_ty outer_context,
                           flag_context_ty modifier_context);
@@ -87,12 +84,12 @@ typedef hash_table /* char[] -> flag_context_list_ty * */
 extern flag_context_list_ty *
        flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
                                        const void *key, size_t keylen);
-/* Insert the pair (VALUE, PASS) as (is_formatX, pass_formatX) with X = INDEX+1
-   in the flags of the element numbered ARGNUM of the list corresponding to NAME
-   in the TABLE.  */
+/* Insert the pair (VALUE, PASS) as (is_format, pass_format) for the format
+   string type FI in the flags of the element numbered ARGNUM of the list
+   corresponding to NAME in the TABLE.  */
 extern void
        flag_context_list_table_add (flag_context_list_table_ty *table,
-                                    unsigned int index,
+                                    size_t fi,
                                     const char *name_start, const char *name_end,
                                     int argnum, enum is_format value, bool pass);
 
index a96776f1cda7087a5465305513989957bcd8ec1d..42bc2c11b654112cd28330466e73da79e45708f8 100644 (file)
@@ -407,8 +407,8 @@ arglist_parser_done (struct arglist_parser *ap, int argnum)
           if (recognize_qt_formatstrings ()
               && best_cp->msgid_plural == best_cp->msgid)
             {
-              msgid_context.is_format4 = yes_according_to_context;
-              msgid_plural_context.is_format4 = yes_according_to_context;
+              msgid_context.for_formatstring[XFORMAT_FOURTH].is_format = yes_according_to_context;
+              msgid_plural_context.for_formatstring[XFORMAT_FOURTH].is_format = yes_according_to_context;
             }
 
           best_msgctxt =
index ecc2ecbf4dd1ec8f4ea1cd817e925d16f001f88c..998896c2bcfd5447f41f7fc16302d3c29a217231 100644 (file)
@@ -24,7 +24,4 @@
 
 /* Language dependent format string parser.
    NULL if the language has no notion of format strings.  */
-struct formatstring_parser *current_formatstring_parser1;
-struct formatstring_parser *current_formatstring_parser2;
-struct formatstring_parser *current_formatstring_parser3;
-struct formatstring_parser *current_formatstring_parser4;
+struct formatstring_parser *current_formatstring_parser[NXFORMATS];
index 406bab953bba6b01906c720fef1d68a4be3cd2f9..4e9e626eea439fa4e225e256f8cbae306dc49b64 100644 (file)
@@ -22,12 +22,23 @@ extern "C" {
 #endif
 
 
+/* Maximum number of format string parsers needed for any particular
+   language.  */
+#define NXFORMATS 4
+
+/* Instead of indices, use these macros, for easier cross-referencing.  */
+/* Primary format string type.  */
+#define XFORMAT_PRIMARY    0
+/* Secondary format string type.  */
+#define XFORMAT_SECONDARY  1
+/* Tertiary format string type.  */
+#define XFORMAT_TERTIARY   2
+/* Fourth-ranked format string type.  */
+#define XFORMAT_FOURTH     3
+
 /* Language dependent format string parser.
    NULL if the language has no notion of format strings.  */
-extern struct formatstring_parser *current_formatstring_parser1;
-extern struct formatstring_parser *current_formatstring_parser2;
-extern struct formatstring_parser *current_formatstring_parser3;
-extern struct formatstring_parser *current_formatstring_parser4;
+extern struct formatstring_parser *current_formatstring_parser[NXFORMATS];
 
 
 #ifdef __cplusplus
index 53e64afd6dd65e2d447e5dc57fcc3730ef5826d5..7b3b9830b1c22ea4a908c9ca0adeb7d6750e0dc1 100644 (file)
@@ -51,29 +51,20 @@ set_format_flags_from_context (enum is_format is_format[NFORMATS],
                                flag_context_ty context, const char *string,
                                lex_pos_ty *pos, const char *pretty_msgstr)
 {
-  size_t i;
+  bool some_undecided;
+
+  some_undecided = false;
+  for (size_t fi = 0; fi < NXFORMATS; fi++)
+    some_undecided |= (context.for_formatstring[fi].is_format != undecided);
 
-  if (context.is_format1 != undecided
-      || context.is_format2 != undecided
-      || context.is_format3 != undecided
-      || context.is_format4 != undecided)
-    for (i = 0; i < NFORMATS; i++)
+  if (some_undecided)
+    for (size_t i = 0; i < NFORMATS; i++)
       {
         if (is_format[i] == undecided)
-          {
-            if (formatstring_parsers[i] == current_formatstring_parser1
-                && context.is_format1 != undecided)
-              is_format[i] = (enum is_format) context.is_format1;
-            if (formatstring_parsers[i] == current_formatstring_parser2
-                && context.is_format2 != undecided)
-              is_format[i] = (enum is_format) context.is_format2;
-            if (formatstring_parsers[i] == current_formatstring_parser3
-                && context.is_format3 != undecided)
-              is_format[i] = (enum is_format) context.is_format3;
-            if (formatstring_parsers[i] == current_formatstring_parser4
-                && context.is_format4 != undecided)
-              is_format[i] = (enum is_format) context.is_format4;
-          }
+          for (size_t fi = 0; fi < NXFORMATS; fi++)
+            if (formatstring_parsers[i] == current_formatstring_parser[fi]
+                && context.for_formatstring[fi].is_format != undecided)
+              is_format[i] = (enum is_format) context.for_formatstring[fi].is_format;
         if (possible_format_p (is_format[i]))
           {
             struct formatstring_parser *parser = formatstring_parsers[i];
@@ -102,6 +93,17 @@ set_format_flags_from_context (enum is_format is_format[NFORMATS],
 }
 
 
+/* Returns true if PARSER is relevant for the current language.  */
+static bool
+is_relevant (struct formatstring_parser *parser)
+{
+  for (size_t fi = 0; fi < NXFORMATS; fi++)
+    if (parser == current_formatstring_parser[fi])
+      return true;
+  return false;
+}
+
+
 void
 decide_is_format (message_ty *mp)
 {
@@ -112,10 +114,7 @@ decide_is_format (message_ty *mp)
   for (i = 0; i < NFORMATS; i++)
     {
       if (mp->is_format[i] == undecided
-          && (formatstring_parsers[i] == current_formatstring_parser1
-              || formatstring_parsers[i] == current_formatstring_parser2
-              || formatstring_parsers[i] == current_formatstring_parser3
-              || formatstring_parsers[i] == current_formatstring_parser4)
+          && is_relevant (formatstring_parsers[i])
           /* But avoid redundancy: objc-format is stronger than c-format.  */
           && !(i == format_c && possible_format_p (mp->is_format[format_objc]))
           && !(i == format_objc && possible_format_p (mp->is_format[format_c]))
@@ -567,10 +566,7 @@ remember_a_message_plural (message_ty *mp, char *string, bool is_utf8,
          the msgid, whether the msgid is a format string, examine the
          msgid_plural.  This is a heuristic.  */
       for (i = 0; i < NFORMATS; i++)
-        if ((formatstring_parsers[i] == current_formatstring_parser1
-             || formatstring_parsers[i] == current_formatstring_parser2
-             || formatstring_parsers[i] == current_formatstring_parser3
-             || formatstring_parsers[i] == current_formatstring_parser4)
+        if (is_relevant (formatstring_parsers[i])
             && (mp->is_format[i] == undecided || mp->is_format[i] == possible)
             /* But avoid redundancy: objc-format is stronger than c-format.  */
             && !(i == format_c
index 8ab5f9573e264f0496880fd1ce1c6306fc0bfdfd..083ccb08a62eca8af1d95289aa25da3d7925d7b0 100644 (file)
@@ -302,10 +302,7 @@ struct extractor_ty
   extract_from_stream_func extract_from_stream;
   extract_from_file_func extract_from_file;
   flag_context_list_table_ty *flag_table;
-  struct formatstring_parser *formatstring_parser1;
-  struct formatstring_parser *formatstring_parser2;
-  struct formatstring_parser *formatstring_parser3;
-  struct formatstring_parser *formatstring_parser4;
+  struct formatstring_parser *formatstring_parser[NXFORMATS];
 };
 
 
@@ -343,7 +340,7 @@ main (int argc, char *argv[])
   string_list_ty *file_list;
   char *output_file = NULL;
   const char *language = NULL;
-  extractor_ty extractor = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+  extractor_ty extractor = { NULL, NULL, NULL, { NULL, NULL, NULL, NULL } };
   int cnt;
   size_t i;
 
@@ -845,7 +842,7 @@ xgettext cannot work without keywords to look for"));
          is an output file and therefore should not be searched for.  */
       void *saved_directory_list = dir_list_save_reset ();
       extractor_ty po_extractor =
-        { extract_po, NULL, NULL, NULL, NULL, NULL, NULL };
+        { extract_po, NULL, NULL, { NULL, NULL, NULL, NULL } };
 
       extract_from_file (file_name, po_extractor, mdlp);
       if (!is_ascii_msgdomain_list (mdlp))
@@ -1352,7 +1349,7 @@ read_exclusion_file (char *filename)
 
 static void
 flag_context_list_table_insert (flag_context_list_table_ty *table,
-                                unsigned int index,
+                                size_t fi,
                                 const char *name_start, const char *name_end,
                                 int argnum, enum is_format value, bool pass)
 {
@@ -1380,7 +1377,7 @@ flag_context_list_table_insert (flag_context_list_table_ty *table,
         name_start += 2;
     }
 
-  flag_context_list_table_add (table, index, name_start, name_end,
+  flag_context_list_table_add (table, fi, name_start, name_end,
                                argnum, value, pass);
 
   if (allocated_name != NULL)
@@ -1501,129 +1498,129 @@ xgettext_record_flag (const char *optionstring)
                        &formatstring_java, &formatstring_java_printf
                      }
                    Therefore here, we have to associate
-                     format_java          with   flag_table_java at index 0,
-                     format_java_printf   with   flag_table_java at index 1.  */
+                     format_java          with   flag_table_java at index XFORMAT_PRIMARY,
+                     format_java_printf   with   flag_table_java at index XFORMAT_SECONDARY.  */
                 switch (type)
                   {
                   case format_c:
                     if (backend == NULL || strcmp (backend, "C") == 0
                         || strcmp (backend, "C++") == 0)
                       {
-                        flag_context_list_table_insert (&flag_table_c, 0,
+                        flag_context_list_table_insert (&flag_table_c, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
                       }
                     if (backend == NULL || strcmp (backend, "C++") == 0)
                       {
-                        flag_context_list_table_insert (&flag_table_cxx_qt, 0,
+                        flag_context_list_table_insert (&flag_table_cxx_qt, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
-                        flag_context_list_table_insert (&flag_table_cxx_kde, 0,
+                        flag_context_list_table_insert (&flag_table_cxx_kde, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
-                        flag_context_list_table_insert (&flag_table_cxx_boost, 0,
+                        flag_context_list_table_insert (&flag_table_cxx_boost, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
                       }
                     if (backend == NULL || strcmp (backend, "ObjectiveC") == 0)
                       {
-                        flag_context_list_table_insert (&flag_table_objc, 0,
+                        flag_context_list_table_insert (&flag_table_objc, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
                       }
                     if (backend == NULL || strcmp (backend, "Vala") == 0)
                       {
-                        flag_context_list_table_insert (&flag_table_vala, 0,
+                        flag_context_list_table_insert (&flag_table_vala, XFORMAT_PRIMARY,
                                                         name_start, name_end,
                                                         argnum, value, pass);
                       }
                     break;
                   case format_cplusplus_brace:
-                    flag_context_list_table_insert (&flag_table_c, 1,
+                    flag_context_list_table_insert (&flag_table_c, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
-                    flag_context_list_table_insert (&flag_table_cxx_qt, 1,
+                    flag_context_list_table_insert (&flag_table_cxx_qt, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
-                    flag_context_list_table_insert (&flag_table_cxx_kde, 1,
+                    flag_context_list_table_insert (&flag_table_cxx_kde, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
-                    flag_context_list_table_insert (&flag_table_cxx_boost, 1,
+                    flag_context_list_table_insert (&flag_table_cxx_boost, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_objc:
-                    flag_context_list_table_insert (&flag_table_objc, 1,
+                    flag_context_list_table_insert (&flag_table_objc, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_python:
-                    flag_context_list_table_insert (&flag_table_python, 0,
+                    flag_context_list_table_insert (&flag_table_python, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_python_brace:
-                    flag_context_list_table_insert (&flag_table_python, 1,
+                    flag_context_list_table_insert (&flag_table_python, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_java:
-                    flag_context_list_table_insert (&flag_table_java, 0,
+                    flag_context_list_table_insert (&flag_table_java, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_java_printf:
-                    flag_context_list_table_insert (&flag_table_java, 1,
+                    flag_context_list_table_insert (&flag_table_java, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_csharp:
-                    flag_context_list_table_insert (&flag_table_csharp, 0,
+                    flag_context_list_table_insert (&flag_table_csharp, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_javascript:
-                    flag_context_list_table_insert (&flag_table_javascript, 0,
+                    flag_context_list_table_insert (&flag_table_javascript, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_scheme:
-                    flag_context_list_table_insert (&flag_table_scheme, 0,
+                    flag_context_list_table_insert (&flag_table_scheme, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_lisp:
-                    flag_context_list_table_insert (&flag_table_lisp, 0,
+                    flag_context_list_table_insert (&flag_table_lisp, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_elisp:
-                    flag_context_list_table_insert (&flag_table_elisp, 0,
+                    flag_context_list_table_insert (&flag_table_elisp, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_librep:
-                    flag_context_list_table_insert (&flag_table_librep, 0,
+                    flag_context_list_table_insert (&flag_table_librep, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_ruby:
-                    flag_context_list_table_insert (&flag_table_ruby, 0,
+                    flag_context_list_table_insert (&flag_table_ruby, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_sh:
-                    flag_context_list_table_insert (&flag_table_sh, 0,
+                    flag_context_list_table_insert (&flag_table_sh, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_awk:
-                    flag_context_list_table_insert (&flag_table_awk, 0,
+                    flag_context_list_table_insert (&flag_table_awk, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_lua:
-                    flag_context_list_table_insert (&flag_table_lua, 0,
+                    flag_context_list_table_insert (&flag_table_lua, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
@@ -1632,62 +1629,62 @@ xgettext_record_flag (const char *optionstring)
                   case format_smalltalk:
                     break;
                   case format_qt:
-                    flag_context_list_table_insert (&flag_table_cxx_qt, 2,
+                    flag_context_list_table_insert (&flag_table_cxx_qt, XFORMAT_TERTIARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_qt_plural:
-                    flag_context_list_table_insert (&flag_table_cxx_qt, 3,
+                    flag_context_list_table_insert (&flag_table_cxx_qt, XFORMAT_FOURTH,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_kde:
-                    flag_context_list_table_insert (&flag_table_cxx_kde, 2,
+                    flag_context_list_table_insert (&flag_table_cxx_kde, XFORMAT_TERTIARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_kde_kuit:
-                    flag_context_list_table_insert (&flag_table_cxx_kde, 3,
+                    flag_context_list_table_insert (&flag_table_cxx_kde, XFORMAT_FOURTH,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_boost:
-                    flag_context_list_table_insert (&flag_table_cxx_boost, 2,
+                    flag_context_list_table_insert (&flag_table_cxx_boost, XFORMAT_TERTIARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_tcl:
-                    flag_context_list_table_insert (&flag_table_tcl, 0,
+                    flag_context_list_table_insert (&flag_table_tcl, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_perl:
-                    flag_context_list_table_insert (&flag_table_perl, 0,
+                    flag_context_list_table_insert (&flag_table_perl, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_perl_brace:
-                    flag_context_list_table_insert (&flag_table_perl, 1,
+                    flag_context_list_table_insert (&flag_table_perl, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_php:
-                    flag_context_list_table_insert (&flag_table_php, 0,
+                    flag_context_list_table_insert (&flag_table_php, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_gcc_internal:
-                    flag_context_list_table_insert (&flag_table_gcc_internal, 0,
+                    flag_context_list_table_insert (&flag_table_gcc_internal, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_gfc_internal:
-                    flag_context_list_table_insert (&flag_table_gcc_internal, 1,
+                    flag_context_list_table_insert (&flag_table_gcc_internal, XFORMAT_SECONDARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
                   case format_ycp:
-                    flag_context_list_table_insert (&flag_table_ycp, 0,
+                    flag_context_list_table_insert (&flag_table_ycp, XFORMAT_PRIMARY,
                                                     name_start, name_end,
                                                     argnum, value, pass);
                     break;
@@ -1929,10 +1926,8 @@ extract_from_file (const char *file_name, extractor_ty extractor,
   char *logical_file_name;
   char *real_file_name;
 
-  current_formatstring_parser1 = extractor.formatstring_parser1;
-  current_formatstring_parser2 = extractor.formatstring_parser2;
-  current_formatstring_parser3 = extractor.formatstring_parser3;
-  current_formatstring_parser4 = extractor.formatstring_parser4;
+  for (size_t fi = 0; fi < NXFORMATS; fi++)
+    current_formatstring_parser[fi] = extractor.formatstring_parser[fi];
 
   if (extractor.extract_from_stream)
     {
@@ -1966,10 +1961,8 @@ extract_from_file (const char *file_name, extractor_ty extractor,
   free (logical_file_name);
   free (real_file_name);
 
-  current_formatstring_parser1 = NULL;
-  current_formatstring_parser2 = NULL;
-  current_formatstring_parser3 = NULL;
-  current_formatstring_parser4 = NULL;
+  for (size_t fi = 0; fi < NXFORMATS; fi++)
+    current_formatstring_parser[fi] = NULL;
 }
 
 static message_ty *
@@ -2037,7 +2030,7 @@ bool
 recognize_qt_formatstrings (void)
 {
   return recognize_format_qt
-         && current_formatstring_parser4 == &formatstring_qt_plural;
+         && current_formatstring_parser[XFORMAT_FOURTH] == &formatstring_qt_plural;
 }
 
 
@@ -2250,10 +2243,10 @@ language_to_extractor (const char *name)
         result.extract_from_stream = tp->extract_from_stream;
         result.extract_from_file = tp->extract_from_file;
         result.flag_table = tp->flag_table;
-        result.formatstring_parser1 = tp->formatstring_parser1;
-        result.formatstring_parser2 = tp->formatstring_parser2;
-        result.formatstring_parser3 = NULL;
-        result.formatstring_parser4 = NULL;
+        result.formatstring_parser[XFORMAT_PRIMARY]   = tp->formatstring_parser1;
+        result.formatstring_parser[XFORMAT_SECONDARY] = tp->formatstring_parser2;
+        for (size_t fi = 2; fi < NXFORMATS; fi++)
+          result.formatstring_parser[fi] = NULL;
 
         /* Handle --qt.  It's preferrable to handle this facility here rather
            than through an option --language=C++/Qt because the latter would
@@ -2261,21 +2254,21 @@ language_to_extractor (const char *name)
         if (recognize_format_qt && strcmp (tp->name, "C++") == 0)
           {
             result.flag_table = &flag_table_cxx_qt;
-            result.formatstring_parser3 = &formatstring_qt;
-            result.formatstring_parser4 = &formatstring_qt_plural;
+            result.formatstring_parser[XFORMAT_TERTIARY] = &formatstring_qt;
+            result.formatstring_parser[XFORMAT_FOURTH]   = &formatstring_qt_plural;
           }
         /* Likewise for --kde.  */
         if (recognize_format_kde && strcmp (tp->name, "C++") == 0)
           {
             result.flag_table = &flag_table_cxx_kde;
-            result.formatstring_parser3 = &formatstring_kde;
-            result.formatstring_parser4 = &formatstring_kde_kuit;
+            result.formatstring_parser[XFORMAT_TERTIARY] = &formatstring_kde;
+            result.formatstring_parser[XFORMAT_FOURTH]   = &formatstring_kde_kuit;
           }
         /* Likewise for --boost.  */
         if (recognize_format_boost && strcmp (tp->name, "C++") == 0)
           {
             result.flag_table = &flag_table_cxx_boost;
-            result.formatstring_parser3 = &formatstring_boost;
+            result.formatstring_parser[XFORMAT_TERTIARY] = &formatstring_boost;
           }
 
         return result;
@@ -2284,7 +2277,7 @@ language_to_extractor (const char *name)
   error (EXIT_FAILURE, 0, _("language '%s' unknown"), name);
   /* NOTREACHED */
   {
-    extractor_ty result = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+    extractor_ty result = { NULL, NULL, NULL, { NULL, NULL, NULL, NULL } };
     return result;
   }
 }