/* Keeping track of the flags that apply to a string extracted
in a certain context.
- Copyright (C) 2001-2018, 2023 Free Software Foundation, Inc.
+ Copyright (C) 2001-2024 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "xmalloca.h"
#include "verify.h"
+#include "xg-message.h"
+
/* Null context. */
static flag_context_ty null_context =
{
1,
{
- { undecided, NULL },
- { undecided, NULL },
- { undecided, NULL },
- { undecided, NULL }
- }
+ { true, undecided, NULL },
+ { true, undecided, NULL },
+ { true, undecided, NULL },
+ { true, undecided, NULL }
+ },
+ NULL, 0, 0,
+ true
};
flag_region_ty *
region->refcount = 1;
for (size_t fi = 0; fi < NXFORMATS; fi++)
{
+ region->for_formatstring[fi].pass_format = modifier_context.for_formatstring[fi].pass_format;
if (modifier_context.for_formatstring[fi].pass_format)
{
region->for_formatstring[fi].is_format = outer_region->for_formatstring[fi].is_format;
: NULL);
}
}
+ region->subregion = NULL;
+ region->nsubregions = 0;
+ region->nsubregions_max = 0;
+ region->inherit_from_parent_region = true;
return region;
}
+flag_region_ty *
+new_sub_region (flag_region_ty *outer_region, flag_context_ty modifier_context)
+{
+ /* Create the new region. */
+ flag_region_ty *region = XMALLOC (flag_region_ty);
+
+ region->refcount = 1;
+ for (size_t fi = 0; fi < NXFORMATS; fi++)
+ {
+ region->for_formatstring[fi].pass_format = modifier_context.for_formatstring[fi].pass_format;
+ if (modifier_context.for_formatstring[fi].pass_format)
+ region->for_formatstring[fi].is_format = outer_region->for_formatstring[fi].is_format;
+ else
+ 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);
+ }
+ region->subregion = NULL;
+ region->nsubregions = 0;
+ region->nsubregions_max = 0;
+ /* Set to true initially. Can be set to false later during the parsing. */
+ region->inherit_from_parent_region = true;
+
+ if (outer_region != &the_null_context_region)
+ {
+ /* Register it as child of outer_region. */
+ if (outer_region->nsubregions >= outer_region->nsubregions_max)
+ {
+ size_t nbytes;
+
+ outer_region->nsubregions_max = outer_region->nsubregions_max * 2 + 4;
+ nbytes = outer_region->nsubregions_max * sizeof (struct flag_region_ty *);
+ outer_region->subregion = xrealloc (outer_region->subregion, nbytes);
+ }
+ outer_region->subregion[outer_region->nsubregions++] = region;
+ region->refcount++;
+ }
+
+ return region;
+}
+
flag_region_ty *
ref_region (flag_region_ty *region)
{
region->refcount--;
else
{
+ for (size_t i = 0; i < region->nsubregions; i++)
+ unref_region (region->subregion[i]);
+ free (region->subregion);
for (size_t fi = 0; fi < NXFORMATS; fi++)
remembered_message_list_unref (region->for_formatstring[fi].remembered);
free (region);
}
}
}
+
+
+void
+set_format_flag_on_region (flag_region_ty *region,
+ size_t fi, enum is_format value)
+{
+ size_t i;
+
+ /* First, on this region. */
+ region->for_formatstring[fi].is_format = value;
+ struct remembered_message_list_ty *rmlp =
+ region->for_formatstring[fi].remembered;
+ for (i = 0; i < rmlp->nitems; i++)
+ {
+ struct remembered_message_ty *rmp = &rmlp->item[i];
+ set_format_flag_from_context (rmp->mp, rmp->plural, &rmp->pos,
+ fi, region);
+ }
+
+ /* Then, recurse through the sub-regions that inherit. */
+ for (i = 0; i < region->nsubregions; i++)
+ {
+ flag_region_ty *sub_region = region->subregion[i];
+ if (sub_region->inherit_from_parent_region
+ && sub_region->for_formatstring[fi].pass_format)
+ set_format_flag_on_region (sub_region, fi, value);
+ }
+}
/* Keeping track of the flags that apply to a string extracted
in a certain context.
- Copyright (C) 2001-2018, 2020, 2023 Free Software Foundation, Inc.
+ Copyright (C) 2001-2024 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#endif
+/* ========================================================================== */
+
+/* The purpose of the format string flags is attach a flag such as 'c-format'
+ to a message, when appropriate. For example, when extracting (in C)
+ puts (_("foo"));
+ printf (_("foo"), _("bar"));
+ fprintf (fp, _("foo"), _("bar"));
+ - the context of puts establishes no flags,
+ - the context of printf establishes 'c-format' for the first argument,
+ - the context of fprintf establishes 'c-format' for the second argument. */
+
/* Context representing some flags w.r.t. a specific format string type. */
struct formatstring_context_ty
{
flag_context_list_ty *next;
};
+/* -------------------------------------------------------------------------- */
+
/* Iterator through a flag_context_list_ty. */
typedef struct flag_context_list_iterator_ty flag_context_list_iterator_ty;
struct flag_context_list_iterator_ty
int argnum; /* current argument number, > 0 */
const flag_context_list_ty* head; /* tail of list */
};
+
+/* The null context list iterator.
+ At each position, no flags are set. */
extern flag_context_list_iterator_ty null_context_list_iterator;
+
+/* The transparent context list iterator.
+ At each position, no flags are set but they are passed through from outside.
+ This transparent context list iterator is useful for parenthesized
+ expressions, because each of
+ printf (_("foo"), _("bar"));
+ printf ((_("foo")), _("bar"));
+ printf (((_("foo"))), _("bar"));
+ etc.
+ should extract "foo" with 'c-format' flag. */
extern flag_context_list_iterator_ty passthrough_context_list_iterator;
+
+/* Creates an iterator through an explicitly constructed list of contexts. */
extern flag_context_list_iterator_ty
flag_context_list_iterator (flag_context_list_ty *list);
+
+/* Returns the context at the current position of the iterator, and advances
+ it to the next position. */
extern flag_context_ty
flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter);
+/* ========================================================================== */
/* For nearly each backend, we have a separate table mapping a keyword to
a 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_format, pass_format) for the format
+/* Inserts 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
const char *name_start, const char *name_end,
int argnum, enum is_format value, bool pass);
+/* ========================================================================== */
+
+/* A region represents a portion of the input file and remembers the messages
+ that were encountered while processing this region. Typically a region
+ is not larger than a statement. Nested expressions correspond to nested
+ regions.
+
+ For example, for the input
+ return m (printf(_("foo"), _("aaa")), _("bar").printf(_("bbb")));
+ we have regions and sub-regions like this:
+ ----------------------------------------------------------------
+ -------------------------- -------------------------
+ -------- -------- -------- --------
+ ----- ----- ----- -----
+ return m (printf(_("foo"), _("aaa")), _("bar").printf(_("bbb")));
+
+ A. If a language has string formatting only through functions, the region
+ management is relatively simple: the list of remembered messages of a
+ sub-region can be shared with the list of remembered messages of the
+ parent region, because at the moment a message is seen, the flags that
+ apply are already known.
+
+ B. If a language has string formatting through functions and through methods,
+ the region management is more complicated. At the moment a message is seen,
+ the flags that apply are not yet known. They become known only once the
+ method invocation (in the example above: '.printf') is seen. Therefore,
+ in this case, each region and sub-region stores their messages separately,
+ so that when the method invocation is seen, an invocation of
+ set_format_flag_on_region can set a flag on each of the remembered messages
+ a posteriori.
+
+ In case A, regions are created through inheriting_region().
+ In case B, regions are created through new_sub_region().
+ */
/* A set of arguments to pass to set_format_flag_from_context. */
struct remembered_message_ty
as effective in a region of the input file. */
struct formatstring_region_ty
{
+ bool pass_format;
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
{
unsigned int refcount;
struct formatstring_region_ty for_formatstring[NXFORMATS];
+ /* Any number of subregions. They represent disjoint sub-intervals
+ of this region. */
+ struct flag_region_ty **subregion;
+ size_t nsubregions;
+ size_t nsubregions_max;
+ /* Whether this region, as a subregion, inherits its flags from its
+ parent region. */
+ bool inherit_from_parent_region;
};
/* Creates a region in which the null context is in effect. */
extern flag_region_ty *
null_context_region ();
-/* Creates a sub-region that inherits from an outer region. */
+/* Creates a sub-region that inherits from an outer region.
+ Only used in case A. */
extern flag_region_ty *
inheriting_region (flag_region_ty *outer_region,
flag_context_ty modifier_context);
+/* Creates a sub-region that is prepared for inheriting from an outer region.
+ But whether it actually does so, can be changed as the parsing goes on.
+ Only used in case B. */
+extern flag_region_ty *
+ new_sub_region (flag_region_ty *outer_region,
+ flag_context_ty modifier_context);
+
/* Adds a reference to a region. Returns the region. */
extern flag_region_ty *
ref_region (flag_region_ty *region);
unref_region (_prev_a); \
} while (0)
+/* Changes the is_format[] flag for the given format string index FI
+ to VALUE, updating all remembered messages in REGION in the process. */
+extern void
+ set_format_flag_on_region (flag_region_ty *region,
+ size_t fi, enum is_format value);
+
+/* ========================================================================== */
+
#ifdef __cplusplus
}