]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
libgettextpo: Add API for the workflow flags and the sticky flags.
authorBruno Haible <bruno@clisp.org>
Tue, 30 Sep 2025 13:35:06 +0000 (15:35 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 30 Sep 2025 13:35:06 +0000 (15:35 +0200)
Reported by Alexander Potashev <aspotashev@gmail.com>
at <https://savannah.gnu.org/bugs/?67470>.

* gettext-tools/src/message.h (format_flag, not_format_p): New declarations.
* gettext-tools/src/message.c (format_flag): New variable.
(not_format_p): New function.
* gettext-tools/src/write-po.c (make_format_description_string): Add comments.
(significant_format_p): Likewise.
* gettext-tools/libgettextpo/gettext-po.in.h (po_flag_iterator_t): New type.
(po_message_has_workflow_flag, po_message_set_workflow_flag,
po_message_workflow_flags_iterator): New declarations.
(po_message_has_sticky_flag, po_message_set_sticky_flag,
po_message_sticky_flags_iterator): New declarations.
(po_flag_iterator_free, po_flag_next): New declarations.
* gettext-tools/libgettextpo/gettext-po.c (struct po_flag_iterator): New type.
(po_message_has_workflow_flag, po_message_set_workflow_flag,
po_message_workflow_flags_iterator): New functions.
(po_message_get_format): Simplify by using not_format_p.
(po_message_has_sticky_flag, po_message_set_sticky_flag,
po_message_sticky_flags_iterator): New functions.
(po_flag_iterator_free, po_flag_next): New functions.
* gettext-tools/tests/gettextpo-1-prg.c (main): Add more test cases.
* gettext-tools/doc/gettext.texi (po_message_t API): Document the new functions.
(po_flag_iterator_t API): New subsection.
* NEWS: Mention the new functions.

NEWS
gettext-tools/doc/gettext.texi
gettext-tools/libgettextpo/gettext-po.c
gettext-tools/libgettextpo/gettext-po.in.h
gettext-tools/src/message.c
gettext-tools/src/message.h
gettext-tools/src/write-po.c
gettext-tools/tests/gettextpo-1-prg.c

diff --git a/NEWS b/NEWS
index c28890deb755f71e21577807a7bc4b038150e188..235284577fd70dc08a271945b8563262dfd26707 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,16 @@ Version 0.27 - September 2025
 # libgettextpo library:
   * The function 'po_message_get_format' now supports distinguishing whether
     a negative format string mark, such as 'no-c-format', is set or not.
+  * The new functions
+      po_message_has_workflow_flag
+      po_message_set_workflow_flag
+      po_message_workflow_flags_iterator, po_flag_next, po_flag_iterator_free
+    can be used to manipulate or inspect the workflow flags of a message.
+  * The new functions
+      po_message_has_sticky_flag
+      po_message_set_sticky_flag
+      po_message_sticky_flags_iterator, po_flag_next, po_flag_iterator_free
+    can be used to manipulate or inspect the sticky flags of a messsage.
 
 Version 0.26 - July 2025
 
index b8e8ff12a8d17e5a8d515c67336c7c14700ab063..9571c6070bd7719beca51e9ad90d6bad708c088a 100644 (file)
@@ -6206,6 +6206,7 @@ without caring about the other threads.
 * PO Header Entry API::         Meta information of the file
 * po_filepos_t API::            References to the sources
 * Format Type API::             Supported format types
+* po_flag_iterator_t API::      Flag iteration
 * Checking API::                Enforcing constraints
 @end menu
 
@@ -6552,6 +6553,34 @@ The @code{po_message_set_fuzzy} function changes the fuzzy mark of
 @var{message}.
 @end deftypefun
 
+@deftypefun {int} po_message_has_workflow_flag (po_message_t@tie{}@var{message}, const@tie{}char@tie{}*@var{workflow_flag})
+The @code{po_message_has_workflow_flag} function returns true
+when @var{message} is marked with a given workflow flag.
+
+When the argument @var{workflow_flag} is @code{"fuzzy"},
+this function corresponds to the @code{po_message_is_fuzzy} function.
+@end deftypefun
+
+@deftypefun {void} po_message_set_workflow_flag (po_message_t@tie{}@var{message}, const@tie{}char@tie{}*@var{workflow_flag}, int@tie{}@var{value})
+The @code{po_message_set_workflow_flag} function changes
+a given workflow flag on @var{message}:
+If the @var{value} argument is non-zero, it sets it.
+If the @var{value} argument is zero, it unsets it.
+
+When the argument @var{workflow_flag} is @code{"fuzzy"},
+this function corresponds to the @code{po_message_set_fuzzy} function.
+@end deftypefun
+
+@deftypefun {po_flag_iterator_t} po_message_workflow_flags_iterator (po_message_t@tie{}@var{message})
+The @code{po_message_workflow_flags_iterator} function returns an iterator
+across the workflow flags of @var{message}.
+This includes the @code{"fuzzy"} flag.
+This iterator returns the workflow flags set on @var{message},
+one by one, through the function @code{po_flag_next}.
+When done, you should free the iterator,
+through the function @code{po_flag_iterator_free}.
+@end deftypefun
+
 @deftypefun {int} po_message_is_format (po_message_t@tie{}@var{message}, const@tie{}char@tie{}*@var{format_type})
 The @code{po_message_is_format} function returns true when the message
 is marked as being a format string of @var{format_type}.
@@ -6578,6 +6607,43 @@ or @var{value} = -1
 to remove the format string mark and its opposite.
 @end deftypefun
 
+@deftypefun {int} po_message_has_sticky_flag (po_message_t@tie{}@var{message}, const@tie{}char@tie{}*@var{sticky_flag})
+The @code{po_message_has_sticky_flag} function returns true
+when @var{message} is marked with a given sticky flag.
+
+This function is a generalization of the
+@code{po_message_is_format} and @code{po_message_get_format} format functions.
+@end deftypefun
+
+@deftypefun {void} po_message_set_sticky_flag (po_message_t@tie{}@var{message}, const@tie{}char@tie{}*@var{sticky_flag}, int@tie{}@var{value})
+The @code{po_message_set_sticky_flag} function changes
+a given sticky flag on @var{message}:
+If the @var{value} argument is non-zero, it sets it.
+If the @var{value} argument is zero, it unsets it.
+
+This function is a generalization of the @code{po_message_set_format} function.
+
+Note that a message cannot have the sticky flags
+@code{@var{language}-format} and @code{no-@var{language}-format}
+at the same time.
+Therefore, setting the @code{@var{language}-format} flag for some @var{language}
+has the side effect of unsetting the @code{no-@var{language}-format} flag,
+and vice versa.
+@end deftypefun
+
+@deftypefun {po_flag_iterator_t} po_message_sticky_flags_iterator (po_message_t@tie{}@var{message})
+The @code{po_message_sticky_flags_iterator} function returns an iterator
+across the sticky flags of @var{message}.
+This includes the various
+@code{@var{language}-format} and @code{no-@var{language}-format} flags,
+as well as the @code{no-wrap} flag.
+It does @emph{not} include the @code{"range"}, because that is not a flag.
+This iterator returns the sticky flags set on @var{message},
+one by one, through the function @code{po_flag_next}.
+When done, you should free the iterator,
+through the function @code{po_flag_iterator_free}.
+@end deftypefun
+
 @deftypefun {int} po_message_is_range (po_message_t@tie{}@var{message}, int@tie{}*@var{minp}, int@tie{}*@var{maxp})
 The @code{po_message_is_range} function returns true when the message
 has a numeric range set, and stores the minimum and maximum value in the
@@ -6658,6 +6724,23 @@ it returns ``C#'' when @var{format_type} is ``csharp_format''.
 Return @code{NULL} if @var{format_type} is not a supported format type.
 @end deftypefun
 
+@node po_flag_iterator_t API
+@subsection po_flag_iterator_t API
+
+The following functions apply to a @code{po_flag_iterator_t} object,
+as returned by the functions @code{po_message_workflow_flags_iterator}
+and @code{po_message_sticky_flags_iterator}.
+
+@deftypefun {void} po_flag_iterator_free (po_flag_iterator_t@tie{}@var{iterator})
+The @code{po_flag_iterator_free} function frees the given @var{iterator}.
+@end deftypefun
+
+@deftypefun {const char *} po_flag_next (po_flag_iterator_t@tie{}@var{iterator})
+The @code{po_flag_next} function returns
+the next flag of the given kind on the given message.
+At the end of the list of flags, it returns @code{NULL}.
+@end deftypefun
+
 @node Checking API
 @subsection Checking API
 
index c364ae00313ca6527c5ca59615569810e5a3ce04..5fbb00c7cd99ece85e333327f74feb84a21151e7 100644 (file)
@@ -59,6 +59,13 @@ struct po_message_iterator
 
 /* A po_filepos_t is actually a 'lex_pos_ty *'.  */
 
+struct po_flag_iterator
+{
+  po_message_t message;
+  int kind; /* 0: workflow flags, 1: sticky flags */
+  size_t index;
+};
+
 
 /* Version number: (major<<16) + (minor<<8) + subminor */
 int libgettextpo_version = LIBGETTEXTPO_VERSION;
@@ -935,6 +942,44 @@ po_message_set_fuzzy (po_message_t message, int fuzzy)
 }
 
 
+/* Return true if the message has a given workflow flag.
+   This function is a generalization of po_message_is_fuzzy.  */
+
+int
+po_message_has_workflow_flag (po_message_t message, const char *workflow_flag)
+{
+  if (strcmp (workflow_flag, "fuzzy") == 0)
+    return po_message_is_fuzzy (message);
+  return 0;
+}
+
+
+/* Set or unset a given workflow flag on a message.
+   This function is a generalization of po_message_set_fuzzy.    */
+
+void
+po_message_set_workflow_flag (po_message_t message, const char *workflow_flag, int value)
+{
+  if (strcmp (workflow_flag, "fuzzy") == 0)
+    po_message_set_fuzzy (message, value);
+}
+
+
+/* Create an iterator for traversing the list of workflow flags of a message.
+   This includes the "fuzzy" flag.  */
+
+po_flag_iterator_t
+po_message_workflow_flags_iterator (po_message_t message)
+{
+  po_flag_iterator_t iterator = XMALLOC (struct po_flag_iterator);
+  iterator->message = message;
+  iterator->kind = 0;
+  iterator->index = 0;
+
+  return iterator;
+}
+
+
 /* Return true if the message is marked as being a format string of the given
    type (e.g. "c-format").  */
 
@@ -976,10 +1021,9 @@ po_message_get_format (po_message_t message, const char *format_type)
           enum is_format is_format = mp->is_format[i];
           /* See significant_format_p and make_format_description_string
              in write-po.c.  */
-          if (is_format != undecided && is_format != impossible)
-            return (possible_format_p (is_format) ? 1 : 0);
-          else
-            return -1;
+          return (possible_format_p (is_format) ? 1 :
+                  not_format_p (is_format) ? 0 :
+                  -1);
         }
   return -1;
 }
@@ -1003,6 +1047,109 @@ po_message_set_format (po_message_t message, const char *format_type, int value)
 }
 
 
+/* Return true if the message has a given sticky flag.
+   This function is a generalization of po_message_is_format and
+   po_message_get_format.  */
+
+int
+po_message_has_sticky_flag (po_message_t message, const char *sticky_flag)
+{
+  message_ty *mp = (message_ty *) message;
+  size_t len = strlen (sticky_flag);
+
+  if (len >= 7 && memcmp (sticky_flag + len - 7, "-format", 7) == 0)
+    {
+      if (len >= 3 + 7 && memcmp (sticky_flag, "no-", 3) == 0)
+        {
+          size_t i;
+          for (i = 0; i < NFORMATS; i++)
+            if (strlen (format_language[i]) == len - 3 - 7
+                && memcmp (format_language[i], sticky_flag + 3, len - 3 - 7) == 0)
+              /* The given sticky_flag corresponds to the opposite of
+                 (enum format_type) i.  */
+              return not_format_p (mp->is_format[i]);
+        }
+      else
+        {
+          size_t i;
+          for (i = 0; i < NFORMATS; i++)
+            if (strlen (format_language[i]) == len - 7
+                && memcmp (format_language[i], sticky_flag, len - 7) == 0)
+              /* The given sticky_flag corresponds to (enum format_type) i.  */
+              return possible_format_p (mp->is_format[i]);
+        }
+    }
+  else if (strcmp (sticky_flag, "no-wrap") == 0)
+    return mp->do_wrap == no;
+  return 0;
+}
+
+
+/* Set or unset a given sticky flag on a message.
+   This function is a generalization of po_message_set_format.  */
+
+void
+po_message_set_sticky_flag (po_message_t message, const char *sticky_flag, int value)
+{
+  message_ty *mp = (message_ty *) message;
+  size_t len = strlen (sticky_flag);
+
+  if (len >= 7 && memcmp (sticky_flag + len - 7, "-format", 7) == 0)
+    {
+      if (len >= 3 + 7 && memcmp (sticky_flag, "no-", 3) == 0)
+        {
+          size_t i;
+          for (i = 0; i < NFORMATS; i++)
+            if (strlen (format_language[i]) == len - 3 - 7
+                && memcmp (format_language[i], sticky_flag + 3, len - 3 - 7) == 0)
+              /* The given sticky_flag corresponds to the opposite of
+                 (enum format_type) i.  */
+              {
+                if (value)
+                  mp->is_format[i] = no;
+                else
+                  if (!possible_format_p (mp->is_format[i]))
+                    mp->is_format[i] = undecided;
+              }
+        }
+      else
+        {
+          size_t i;
+          for (i = 0; i < NFORMATS; i++)
+            if (strlen (format_language[i]) == len - 7
+                && memcmp (format_language[i], sticky_flag, len - 7) == 0)
+              /* The given sticky_flag corresponds to (enum format_type) i.  */
+              {
+                if (value)
+                  mp->is_format[i] = yes;
+                else
+                  if (!not_format_p (mp->is_format[i]))
+                    mp->is_format[i] = undecided;
+              }
+        }
+    }
+  else if (strcmp (sticky_flag, "no-wrap") == 0)
+    mp->do_wrap = (value ? no : yes);
+}
+
+
+/* Create an iterator for traversing the list of sticky flags of a message.
+   This includes the "*-format" and "no-*-format" flags, as well as the
+   "no-wrap" flag.
+   It does *not* include the "range", because that is not a flag.  */
+
+po_flag_iterator_t
+po_message_sticky_flags_iterator (po_message_t message)
+{
+  po_flag_iterator_t iterator = XMALLOC (struct po_flag_iterator);
+  iterator->message = message;
+  iterator->kind = 1;
+  iterator->index = 0;
+
+  return iterator;
+}
+
+
 /* If a numeric range of a message is set, return true and store the minimum
    and maximum value in *MINP and *MAXP.  */
 
@@ -1115,6 +1262,73 @@ po_format_pretty_name (const char *format_type)
 }
 
 
+/* Free an iterator.  */
+
+void
+po_flag_iterator_free (po_flag_iterator_t iterator)
+{
+  free (iterator);
+}
+
+
+/* Return the next flag, and advance the iterator.
+   Return NULL at the end of the list of flags.  */
+const char *
+po_flag_next (po_flag_iterator_t iterator)
+{
+  message_ty *mp = (message_ty *) iterator->message;
+
+  if (mp != NULL)
+    switch (iterator->kind)
+      {
+      case 0:
+        /* Return the next workflow flag.  */
+        if (iterator->index == 0)
+          {
+            iterator->index++;
+            if (mp->is_fuzzy)
+              return "fuzzy";
+          }
+        /* Here iterator->index == 1.  */
+        return NULL;
+
+      case 1:
+        /* Return the next sticky flag.  */
+        while (iterator->index < 2 * NFORMATS + 1)
+          {
+            size_t i = iterator->index;
+            iterator->index++;
+            if (i < 2 * NFORMATS)
+              {
+                if ((i % 2) == 0)
+                  {
+                    i = i / 2;
+                    if (possible_format_p (mp->is_format[i]))
+                      return format_flag[i] + 3; /* without "no-" prefix */
+                  }
+                else
+                  {
+                    i = i / 2;
+                    if (not_format_p (mp->is_format[i]))
+                      return format_flag[i] + 0; /* with "no-" prefix */
+                  }
+              }
+            else if (i == 2 * NFORMATS)
+              {
+                if (mp->do_wrap == no)
+                  return "no-wrap";
+              }
+          }
+        /* Here iterator->index == 2 * NFORMATS + 1.  */
+        return NULL;
+
+      default:
+        abort ();
+      }
+  return NULL;
+}
+
+
 /* Test whether an entire file PO file is valid, like msgfmt does it.
    If it is invalid, pass the reasons to the handler.  */
 
index 8b2887f39e6a539db73a53f8d29ed0ff2541a766..a1f727871c38778092aa9cab784b266ec4cc56bb 100644 (file)
@@ -46,6 +46,10 @@ typedef struct po_message *po_message_t;
 /* A po_filepos_t represents a string's position within a source file.  */
 typedef struct po_filepos *po_filepos_t;
 
+/* A po_flag_iterator_t represents an iterator through the workflow flags or
+   the sticky flags of a message.  */
+typedef struct po_flag_iterator *po_flag_iterator_t;
+
 /* A po_error_handler handles error situations.  No longer used.  */
 struct po_error_handler
 {
@@ -192,6 +196,7 @@ extern void po_message_insert (po_message_iterator_t iterator, po_message_t mess
    To finish initializing the message, you must set the msgid and msgstr.  */
 extern po_message_t po_message_create (void);
 
+
 /* Return the context of a message, or NULL for a message not restricted to a
    context.  */
 extern const char * po_message_msgctxt (po_message_t message);
@@ -200,6 +205,7 @@ extern const char * po_message_msgctxt (po_message_t message);
    context.  */
 extern void po_message_set_msgctxt (po_message_t message, const char *msgctxt);
 
+
 /* Return the msgid (untranslated English string) of a message.  */
 extern const char * po_message_msgid (po_message_t message);
 
@@ -214,6 +220,7 @@ extern const char * po_message_msgid_plural (po_message_t message);
    NULL means a message without plural.  */
 extern void po_message_set_msgid_plural (po_message_t message, const char *msgid_plural);
 
+
 /* Return the msgstr (translation) of a message.
    Return the empty string for an untranslated message.  */
 extern const char * po_message_msgstr (po_message_t message);
@@ -230,6 +237,7 @@ extern const char * po_message_msgstr_plural (po_message_t message, int index);
    Use a NULL value at the end to reduce the number of plural forms.  */
 extern void po_message_set_msgstr_plural (po_message_t message, int index, const char *msgstr);
 
+
 /* Return the comments for a message.  */
 extern const char * po_message_comments (po_message_t message);
 
@@ -237,6 +245,7 @@ extern const char * po_message_comments (po_message_t message);
    comments should be a multiline string, ending in a newline, or empty.  */
 extern void po_message_set_comments (po_message_t message, const char *comments);
 
+
 /* Return the extracted comments for a message.  */
 extern const char * po_message_extracted_comments (po_message_t message);
 
@@ -244,6 +253,7 @@ extern const char * po_message_extracted_comments (po_message_t message);
    comments should be a multiline string, ending in a newline, or empty.  */
 extern void po_message_set_extracted_comments (po_message_t message, const char *comments);
 
+
 /* Return the i-th file position for a message, or NULL if i is out of
    range.  */
 extern po_filepos_t po_message_filepos (po_message_t message, int i);
@@ -260,6 +270,7 @@ extern void po_message_remove_filepos (po_message_t message, int i);
    line number is available.  */
 extern void po_message_add_filepos (po_message_t message, const char *file, size_t start_line);
 
+
 /* Return the previous context of a message, or NULL for none.  */
 extern const char * po_message_prev_msgctxt (po_message_t message);
 
@@ -282,18 +293,33 @@ extern const char * po_message_prev_msgid_plural (po_message_t message);
    message.  NULL is allowed.  */
 extern void po_message_set_prev_msgid_plural (po_message_t message, const char *prev_msgid_plural);
 
+
 /* Return true if the message is marked obsolete.  */
 extern int po_message_is_obsolete (po_message_t message);
 
 /* Change the obsolete mark of a message.  */
 extern void po_message_set_obsolete (po_message_t message, int obsolete);
 
+
 /* Return true if the message is marked fuzzy.  */
 extern int po_message_is_fuzzy (po_message_t message);
 
 /* Change the fuzzy mark of a message.  */
 extern void po_message_set_fuzzy (po_message_t message, int fuzzy);
 
+/* Return true if the message has a given workflow flag.
+   This function is a generalization of po_message_is_fuzzy.  */
+extern int po_message_has_workflow_flag (po_message_t message, const char *workflow_flag);
+
+/* Set or unset a given workflow flag on a message.
+   This function is a generalization of po_message_set_fuzzy.    */
+extern void po_message_set_workflow_flag (po_message_t message, const char *workflow_flag, int value);
+
+/* Create an iterator for traversing the list of workflow flags of a message.
+   This includes the "fuzzy" flag.  */
+extern po_flag_iterator_t po_message_workflow_flags_iterator (po_message_t message);
+
+
 /* Return true if the message is marked as being a format string of the given
    type (e.g. "c-format").  */
 extern int po_message_is_format (po_message_t message, const char *format_type);
@@ -311,6 +337,22 @@ extern int po_message_get_format (po_message_t message, const char *format_type)
    or value = -1 to remove the format string mark and its opposite.  */
 extern void po_message_set_format (po_message_t message, const char *format_type, int value);
 
+/* Return true if the message has a given sticky flag.
+   This function is a generalization of po_message_is_format and
+   po_message_get_format.  */
+extern int po_message_has_sticky_flag (po_message_t message, const char *sticky_flag);
+
+/* Set or unset a given sticky flag on a message.
+   This function is a generalization of po_message_set_format.  */
+extern void po_message_set_sticky_flag (po_message_t message, const char *sticky_flag, int value);
+
+/* Create an iterator for traversing the list of sticky flags of a message.
+   This includes the "*-format" and "no-*-format" flags, as well as the
+   "no-wrap" flag.
+   It does *not* include the "range", because that is not a flag.  */
+extern po_flag_iterator_t po_message_sticky_flags_iterator (po_message_t message);
+
+
 /* If a numeric range of a message is set, return true and store the minimum
    and maximum value in *MINP and *MAXP.  */
 extern int po_message_is_range (po_message_t message, int *minp, int *maxp);
@@ -342,6 +384,16 @@ extern const char * const * po_format_list (void);
 extern const char * po_format_pretty_name (const char *format_type);
 
 
+/* ========================= po_flag_iterator_t API ========================= */
+
+/* Free an iterator.  */
+extern void po_flag_iterator_free (po_flag_iterator_t iterator);
+
+/* Return the next flag, and advance the iterator.
+   Return NULL at the end of the list of flags.  */
+extern const char * po_flag_next (po_flag_iterator_t iterator);
+
+
 /* ============================= Checking API ============================== */
 
 /* Test whether an entire file PO file is valid, like msgfmt does it.
index bc2885e5e7a87a3fa582a975d24571c2d34e97a8..4e893664b4f05204712e0b66ed997179d0ff0377 100644 (file)
@@ -112,6 +112,47 @@ const char *const format_language_pretty[NFORMATS] =
   /* format_ycp */              "YCP"
 };
 
+const char *const format_flag[NFORMATS] =
+{
+  /* format_c */                "no-" "c"             "-format",
+  /* format_objc */             "no-" "objc"          "-format",
+  /* format_cplusplus_brace */  "no-" "c++"           "-format",
+  /* format_python */           "no-" "python"        "-format",
+  /* format_python_brace */     "no-" "python-brace"  "-format",
+  /* format_java */             "no-" "java"          "-format",
+  /* format_java_printf */      "no-" "java-printf"   "-format",
+  /* format_csharp */           "no-" "csharp"        "-format",
+  /* format_javascript */       "no-" "javascript"    "-format",
+  /* format_scheme */           "no-" "scheme"        "-format",
+  /* format_lisp */             "no-" "lisp"          "-format",
+  /* format_elisp */            "no-" "elisp"         "-format",
+  /* format_librep */           "no-" "librep"        "-format",
+  /* format_rust */             "no-" "rust"          "-format",
+  /* format_go */               "no-" "go"            "-format",
+  /* format_ruby */             "no-" "ruby"          "-format",
+  /* format_sh */               "no-" "sh"            "-format",
+  /* format_sh_printf */        "no-" "sh-printf"     "-format",
+  /* format_awk */              "no-" "awk"           "-format",
+  /* format_lua */              "no-" "lua"           "-format",
+  /* format_pascal */           "no-" "object-pascal" "-format",
+  /* format_modula2 */          "no-" "modula2"       "-format",
+  /* format_d */                "no-" "d"             "-format",
+  /* format_ocaml */            "no-" "ocaml"         "-format",
+  /* format_smalltalk */        "no-" "smalltalk"     "-format",
+  /* format_qt */               "no-" "qt"            "-format",
+  /* format_qt_plursl */        "no-" "qt-plural"     "-format",
+  /* format_kde */              "no-" "kde"           "-format",
+  /* format_kde_kuit */         "no-" "kde-kuit"      "-format",
+  /* format_boost */            "no-" "boost"         "-format",
+  /* format_tcl */              "no-" "tcl"           "-format",
+  /* format_perl */             "no-" "perl"          "-format",
+  /* format_perl_brace */       "no-" "perl-brace"    "-format",
+  /* format_php */              "no-" "php"           "-format",
+  /* format_gcc_internal */     "no-" "gcc-internal"  "-format",
+  /* format_gfc_internal */     "no-" "gfc-internal"  "-format",
+  /* format_ycp */              "no-" "ycp"           "-format"
+};
+
 
 bool
 possible_format_p (enum is_format is_format)
@@ -122,6 +163,13 @@ possible_format_p (enum is_format is_format)
 }
 
 
+bool
+not_format_p (enum is_format is_format)
+{
+  return is_format == no;
+}
+
+
 const char *const syntax_check_name[NSYNTAXCHECKS] =
 {
   /* sc_ellipsis_unicode */     "ellipsis-unicode",
index 147bbd864d209605ffc36b6a8c77647732bb1fdb..b37e4890cdf6ce242794103e927a9334bede0eed 100644 (file)
@@ -84,6 +84,7 @@ enum format_type
 #define NFORMATS 37     /* Number of format_type enum values.  */
 extern LIBGETTEXTSRC_DLL_VARIABLE const char *const format_language[NFORMATS];
 extern LIBGETTEXTSRC_DLL_VARIABLE const char *const format_language_pretty[NFORMATS];
+extern LIBGETTEXTSRC_DLL_VARIABLE const char *const format_flag[NFORMATS];
 
 /* Is current msgid a format string?  */
 enum is_format
@@ -99,6 +100,9 @@ enum is_format
 extern bool
        possible_format_p (enum is_format);
 
+extern bool
+       not_format_p (enum is_format);
+
 
 /* Range of an unsigned integer argument.  */
 struct argument_range
index b2b2a6d30106ebe4fdc79118da03a6977b272a5d..02d6d3b82e02af3c258a5d61de64f5817fb907bd 100644 (file)
@@ -68,6 +68,7 @@ make_format_description_string (enum is_format is_format, const char *lang,
 
   switch (is_format)
     {
+    /* Cf. possible_format_p.  */
     case possible:
       if (debug)
         {
@@ -79,6 +80,7 @@ make_format_description_string (enum is_format is_format, const char *lang,
     case yes:
       result = xasprintf ("%s-format", lang);
       break;
+    /* Cf. not_format_p.  */
     case no:
       result = xasprintf ("no-%s-format", lang);
       break;
@@ -92,7 +94,9 @@ make_format_description_string (enum is_format is_format, const char *lang,
 }
 
 
-/* Return true if IS_FORMAT is worth mentioning in a #, flags list.  */
+/* Return true if IS_FORMAT is worth mentioning in a #, flags list.
+   This is the same as
+     possible_format_p (is_format) || not_format_p (is_format).  */
 
 bool
 significant_format_p (enum is_format is_format)
index eb652366296332501abcfe1f675271e900ebe984..55a0fd9a1eed53a1c37260e368404df6f2075052 100644 (file)
@@ -257,6 +257,21 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == -1);
         ASSERT (po_message_get_format (msg, "java-format") == -1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -288,6 +303,23 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == 1);
         ASSERT (po_message_get_format (msg, "java-format") == -1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -331,6 +363,22 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == 1);
         ASSERT (po_message_get_format (msg, "java-format") == -1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -355,6 +403,21 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == -1);
         ASSERT (po_message_get_format (msg, "java-format") == -1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -386,6 +449,22 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == -1);
         ASSERT (po_message_get_format (msg, "java-format") == 1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -409,6 +488,21 @@ main (int argc, char *argv[])
         ASSERT (po_message_get_format (msg, "c-format") == -1);
         ASSERT (po_message_get_format (msg, "java-format") == -1);
         ASSERT (!po_message_is_range (msg, &min, &max));
+        ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+        {
+          po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
+        ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+        ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+        {
+          po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+          ASSERT (po_flag_next (fiter) == NULL);
+          po_flag_iterator_free (fiter);
+        }
       }
       {
         po_message_t msg = po_next_message (iter);
@@ -908,12 +1002,96 @@ main (int argc, char *argv[])
   {
     po_message_t msg = po_message_create ();
     ASSERT (!po_message_is_fuzzy (msg));
+    ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
     po_message_set_fuzzy (msg, 1);
     ASSERT (po_message_is_fuzzy (msg));
+    ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
     po_message_set_fuzzy (msg, 1);
     ASSERT (po_message_is_fuzzy (msg));
+    ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
     po_message_set_fuzzy (msg, 0);
     ASSERT (!po_message_is_fuzzy (msg));
+    ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+  }
+
+  /* Test po_message_set_workflow_flag.  */
+  {
+    po_message_t msg = po_message_create ();
+    ASSERT (!po_message_is_fuzzy (msg));
+    ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_workflow_flag (msg, "fuzzy", 1);
+    ASSERT (po_message_is_fuzzy (msg));
+    ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_workflow_flag (msg, "fuzzy", 1);
+    ASSERT (po_message_is_fuzzy (msg));
+    ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_workflow_flag (msg, "review", 1);
+    ASSERT (po_message_is_fuzzy (msg));
+    ASSERT (po_message_has_workflow_flag (msg, "fuzzy"));
+    /* This will change in 2027.  */
+    ASSERT (!po_message_has_workflow_flag (msg, "review"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "fuzzy") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_workflow_flag (msg, "fuzzy", 0);
+    ASSERT (!po_message_is_fuzzy (msg));
+    ASSERT (!po_message_has_workflow_flag (msg, "fuzzy"));
+    {
+      po_flag_iterator_t fiter = po_message_workflow_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+  }
+  {
+    po_flag_iterator_t fiter = po_message_workflow_flags_iterator (NULL);
+    ASSERT (po_flag_next (fiter) == NULL);
+    po_flag_iterator_free (fiter);
   }
 
   /* Test po_message_set_format.  */
@@ -925,6 +1103,17 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == -1);
     ASSERT (po_message_get_format (msg, "java-format") == -1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "c-format", 1);
     ASSERT (po_message_is_format (msg, "c-format"));
@@ -933,6 +1122,18 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 1);
     ASSERT (po_message_get_format (msg, "java-format") == -1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "c-format", 1);
     ASSERT (po_message_is_format (msg, "c-format"));
@@ -941,6 +1142,18 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 1);
     ASSERT (po_message_get_format (msg, "java-format") == -1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "java-format", 1);
     ASSERT (po_message_is_format (msg, "c-format"));
@@ -949,6 +1162,19 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 1);
     ASSERT (po_message_get_format (msg, "java-format") == 1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "c-format", 0);
     ASSERT (!po_message_is_format (msg, "c-format"));
@@ -957,6 +1183,19 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 0);
     ASSERT (po_message_get_format (msg, "java-format") == 1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "xyzzy-format", 1);
     ASSERT (!po_message_is_format (msg, "c-format"));
@@ -965,6 +1204,20 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 0);
     ASSERT (po_message_get_format (msg, "java-format") == 1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    /* This will change in 2027.  */
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
 
     po_message_set_format (msg, "java-format", -1);
     ASSERT (!po_message_is_format (msg, "c-format"));
@@ -973,6 +1226,228 @@ main (int argc, char *argv[])
     ASSERT (po_message_get_format (msg, "c-format") == 0);
     ASSERT (po_message_get_format (msg, "java-format") == -1);
     ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+  }
+
+  /* Test po_message_set_sticky_flag.  */
+  {
+    po_message_t msg = po_message_create ();
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (!po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == -1);
+    ASSERT (po_message_get_format (msg, "java-format") == -1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "c-format", 1);
+    ASSERT (po_message_is_format (msg, "c-format"));
+    ASSERT (!po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 1);
+    ASSERT (po_message_get_format (msg, "java-format") == -1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "c-format", 1);
+    ASSERT (po_message_is_format (msg, "c-format"));
+    ASSERT (!po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 1);
+    ASSERT (po_message_get_format (msg, "java-format") == -1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "java-format", 1);
+    ASSERT (po_message_is_format (msg, "c-format"));
+    ASSERT (po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 1);
+    ASSERT (po_message_get_format (msg, "java-format") == 1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "no-c-format", 1);
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 0);
+    ASSERT (po_message_get_format (msg, "java-format") == 1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "no-wrap", 1);
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 0);
+    ASSERT (po_message_get_format (msg, "java-format") == 1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "no-wrap") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "python-format", 0);
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "python-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 0);
+    ASSERT (po_message_get_format (msg, "java-format") == 1);
+    ASSERT (po_message_get_format (msg, "python-format") == -1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "python-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-python-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "no-wrap") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "xyzzy-format", 1);
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 0);
+    ASSERT (po_message_get_format (msg, "java-format") == 1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    /* This will change in 2027.  */
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "java-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "no-wrap") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+
+    po_message_set_sticky_flag (msg, "java-format", 0);
+    ASSERT (!po_message_is_format (msg, "c-format"));
+    ASSERT (!po_message_is_format (msg, "java-format"));
+    ASSERT (!po_message_is_format (msg, "xyzzy-format"));
+    ASSERT (po_message_get_format (msg, "c-format") == 0);
+    ASSERT (po_message_get_format (msg, "java-format") == -1);
+    ASSERT (po_message_get_format (msg, "xyzzy-format") == -1);
+    ASSERT (!po_message_has_sticky_flag (msg, "c-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-c-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-java-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "xyzzy-format"));
+    ASSERT (!po_message_has_sticky_flag (msg, "no-xyzzy-format"));
+    ASSERT (po_message_has_sticky_flag (msg, "no-wrap"));
+    {
+      po_flag_iterator_t fiter = po_message_sticky_flags_iterator (msg);
+      ASSERT (strcmp (po_flag_next (fiter), "no-c-format") == 0);
+      ASSERT (strcmp (po_flag_next (fiter), "no-wrap") == 0);
+      ASSERT (po_flag_next (fiter) == NULL);
+      po_flag_iterator_free (fiter);
+    }
+  }
+  {
+    po_flag_iterator_t fiter = po_message_sticky_flags_iterator (NULL);
+    ASSERT (po_flag_next (fiter) == NULL);
+    po_flag_iterator_free (fiter);
   }
 
   /* Test po_message_set_range.  */