}
+static struct remembered_message_list_ty *
+remembered_message_list_alloc ()
+{
+ struct remembered_message_list_ty *list = XMALLOC (struct remembered_message_list_ty);
+ list->refcount = 1;
+ list->item = NULL;
+ list->nitems = 0;
+ list->nitems_max = 0;
+ return list;
+}
+
+void
+remembered_message_list_append (struct remembered_message_list_ty *list,
+ struct remembered_message_ty element)
+{
+ if (list->nitems >= list->nitems_max)
+ {
+ size_t nbytes;
+
+ list->nitems_max = list->nitems_max * 2 + 4;
+ nbytes = list->nitems_max * sizeof (struct remembered_message_ty);
+ list->item = xrealloc (list->item, nbytes);
+ }
+ list->item[list->nitems++] = element;
+}
+
+static struct remembered_message_list_ty *
+remembered_message_list_ref (struct remembered_message_list_ty *list)
+{
+ if (list != NULL)
+ list->refcount++;
+ return list;
+}
+
+static void
+remembered_message_list_unref (struct remembered_message_list_ty *list)
+{
+ if (list != NULL)
+ {
+ if (list->refcount > 1)
+ list->refcount--;
+ else
+ free (list);
+ }
+}
+
+
/* We don't need to remember messages that were processed in the null context
region. Therefore the null context region can be a singleton. This
reduces the number of needed calls to unref_region. */
{
1,
{
- { undecided },
- { undecided },
- { undecided },
- { undecided }
+ { undecided, NULL },
+ { undecided, NULL },
+ { undecided, NULL },
+ { undecided, NULL }
}
};
for (size_t fi = 0; fi < NXFORMATS; fi++)
{
if (modifier_context.for_formatstring[fi].pass_format)
- region->for_formatstring[fi].is_format = outer_region->for_formatstring[fi].is_format;
+ {
+ region->for_formatstring[fi].is_format = outer_region->for_formatstring[fi].is_format;
+ region->for_formatstring[fi].remembered =
+ (current_formatstring_parser[fi] != NULL
+ ? (outer_region->for_formatstring[fi].remembered != NULL
+ ? remembered_message_list_ref (outer_region->for_formatstring[fi].remembered)
+ : remembered_message_list_alloc ())
+ : NULL);
+ }
else
- region->for_formatstring[fi].is_format = modifier_context.for_formatstring[fi].is_format;
+ {
+ region->for_formatstring[fi].is_format = modifier_context.for_formatstring[fi].is_format;
+ region->for_formatstring[fi].remembered =
+ (current_formatstring_parser[fi] != NULL
+ ? remembered_message_list_alloc ()
+ : NULL);
+ }
}
return region;
if (region->refcount > 1)
region->refcount--;
else
- free (region);
+ {
+ for (size_t fi = 0; fi < NXFORMATS; fi++)
+ remembered_message_list_unref (region->for_formatstring[fi].remembered);
+ free (region);
+ }
}
}
int argnum, enum is_format value, bool pass);
+/* A set of arguments to pass to set_format_flag_from_context. */
+struct remembered_message_ty
+{
+ message_ty *mp;
+ bool plural;
+ lex_pos_ty pos;
+};
+
+/* A list of 'struct remembered_message_ty'. */
+struct remembered_message_list_ty
+{
+ unsigned int refcount;
+ struct remembered_message_ty *item;
+ size_t nitems;
+ size_t nitems_max;
+};
+
+/* Adds an element to a list of 'struct remembered_message_ty'. */
+extern void
+ remembered_message_list_append (struct remembered_message_list_ty *list,
+ struct remembered_message_ty element);
+
/* Context representing some flags w.r.t. a specific format string type,
as effective in a region of the input file. */
struct formatstring_region_ty
{
enum is_format is_format;
+ /* Messages that were remembered in this context.
+ This messages list is shared with sub-regions when pass_format was true
+ in inheriting_region. */
+ struct remembered_message_list_ty *remembered;
};
/* A region of the input file, in which a given context is in effect, together
pos->line_number);
+/* Validates the modified value of mp->is_format[i]. */
+static void
+validate_is_format (message_ty *mp, bool plural, lex_pos_ty *pos, size_t i)
+{
+ if (possible_format_p (mp->is_format[i]))
+ {
+ const char *string = (plural ? mp->msgid_plural : mp->msgid);
+ const char *pretty_msgstr = (plural ? "msgid_plural" : "msgid");
+ struct formatstring_parser *parser = formatstring_parsers[i];
+ char *invalid_reason = NULL;
+ void *descr = parser->parse (string, false, NULL, &invalid_reason);
+
+ if (descr != NULL)
+ parser->free (descr);
+ else
+ {
+ /* The string is not a valid format string. */
+ if (mp->is_format[i] != possible)
+ if_error (IF_SEVERITY_WARNING,
+ pos->file_name, pos->line_number, (size_t)(-1), true,
+ mp->is_format[i] == yes_according_to_context
+ ? _("Although being used in a format string position, the %s is not a valid %s format string. Reason: %s\n")
+ : _("Although declared as such, the %s is not a valid %s format string. Reason: %s\n"),
+ pretty_msgstr, format_language_pretty[i],
+ invalid_reason);
+
+ mp->is_format[i] = impossible;
+ free (invalid_reason);
+ }
+ }
+}
+
/* Update the is_format[] flags depending on the information given in the
region's context. */
static void
-set_format_flags_from_context (enum is_format is_format[NFORMATS],
- flag_region_ty const *region, const char *string,
- lex_pos_ty *pos, const char *pretty_msgstr)
+set_format_flags_from_context (message_ty *mp, bool plural, lex_pos_ty *pos,
+ flag_region_ty const *region)
{
- bool some_undecided;
-
- some_undecided = false;
+ bool some_undecided = false;
for (size_t fi = 0; fi < NXFORMATS; fi++)
some_undecided |= (region->for_formatstring[fi].is_format != undecided);
if (some_undecided)
for (size_t i = 0; i < NFORMATS; i++)
{
- if (is_format[i] == undecided)
+ if (mp->is_format[i] == undecided)
for (size_t fi = 0; fi < NXFORMATS; fi++)
if (formatstring_parsers[i] == current_formatstring_parser[fi]
&& region->for_formatstring[fi].is_format != undecided)
- is_format[i] = region->for_formatstring[fi].is_format;
- if (possible_format_p (is_format[i]))
- {
- struct formatstring_parser *parser = formatstring_parsers[i];
- char *invalid_reason = NULL;
- void *descr = parser->parse (string, false, NULL, &invalid_reason);
-
- if (descr != NULL)
- parser->free (descr);
- else
- {
- /* The string is not a valid format string. */
- if (is_format[i] != possible)
- if_error (IF_SEVERITY_WARNING,
- pos->file_name, pos->line_number, (size_t)(-1), true,
- is_format[i] == yes_according_to_context
- ? _("Although being used in a format string position, the %s is not a valid %s format string. Reason: %s\n")
- : _("Although declared as such, the %s is not a valid %s format string. Reason: %s\n"),
- pretty_msgstr, format_language_pretty[i],
- invalid_reason);
-
- is_format[i] = impossible;
- free (invalid_reason);
- }
- }
+ mp->is_format[i] = region->for_formatstring[fi].is_format;
+ validate_is_format (mp, plural, pos, i);
}
+
+ /* Prepare for doing the same thing in a delayed manner.
+ This is useful for methods named 'printf' on a class 'String'. */
+ for (size_t fi = 0; fi < NXFORMATS; fi++)
+ if (current_formatstring_parser[fi] != NULL
+ && region->for_formatstring[fi].remembered != NULL)
+ remembered_message_list_append (region->for_formatstring[fi].remembered,
+ (struct remembered_message_ty) { mp, plural, *pos });
+}
+
+void
+set_format_flag_from_context (message_ty *mp, bool plural, lex_pos_ty *pos,
+ size_t fi, flag_region_ty const *region)
+{
+ if (region->for_formatstring[fi].is_format != undecided)
+ for (size_t i = 0; i < NFORMATS; i++)
+ if (formatstring_parsers[i] == current_formatstring_parser[fi])
+ {
+ mp->is_format[i] = region->for_formatstring[fi].is_format;
+ validate_is_format (mp, plural, pos, i);
+ }
}
/* Determine whether the context specifies that the msgid is a format
string. */
- set_format_flags_from_context (mp->is_format, region, mp->msgid, pos, "msgid");
+ set_format_flags_from_context (mp, false, pos, region);
/* Ask the lexer for the comments it has seen. */
{
/* Determine whether the context specifies that the msgid_plural is a
format string. */
- set_format_flags_from_context (mp->is_format, region, mp->msgid_plural,
- pos, "msgid_plural");
+ set_format_flags_from_context (mp, true, pos, region);
/* If it is not already decided, through programmer comments or
the msgid, whether the msgid is a format string, examine the