* Programming languages support:
- Shell:
+
xgettext now also supports shell scripts. It recognizes invocations of
the programs 'gettext', 'ngettext', the functions 'eval_gettext',
'eval_ngettext', as well as the deprecated GNU bash builtin syntax $"...".
envsubst - substitutes environment variables in shell format strings.
- Perl:
+
xgettext now also supports Perl.
- PHP:
+
"xgettext --language=PHP" now supports the plural handling functions
ngettext, dngettext, dcngettext (introduced in PHP 4.2.0).
+ - ObjectiveC:
+
+ "xgettext --language=ObjectiveC" now supports the @"..." string syntax,
+ the NSLocalizedString function and the ObjectiveC specific format strings.
+
+ All the tools that manipulate PO files can work with .strings files
+ as well, if given the --stringtable-input and/or --stringtable-output
+ option. To create a .strings file from a PO or POT file, use
+ "msgcat --stringtable-output". To create a PO or POT file from a
+ .strings file, use "xgettext".
+
- GCC-source:
xgettext's --language option now supports the value "GCC-source". This
+2003-10-13 Bruno Haible <bruno@clisp.org>
+
+ * gettext.texi (PO Files): Mention objc-format, sh-format, perl-format,
+ perl-brace-format.
+ (objc-format): New subsection.
+
2003-10-12 Bruno Haible <bruno@clisp.org>
* msgattrib.texi: Document --stringtable-input and --stringtable-output
The Translator's View
* c-format:: C Format Strings
+* objc-format:: Objective C Format Strings
* sh-format:: Shell Format Strings
* python-format:: Python Format Strings
* lisp-format:: Lisp Format Strings
does some more tests to check to validity of the translation.
@xref{msgfmt Invocation}, @ref{c-format Flag} and @ref{c-format}.
+@item objc-format
+@kwindex objc-format@r{ flag}
+@itemx no-objc-format
+@kwindex no-objc-format@r{ flag}
+Likewise for Objective C, see @ref{objc-format}.
+
+@item sh-format
+@kwindex sh-format@r{ flag}
+@itemx no-sh-format
+@kwindex no-sh-format@r{ flag}
+Likewise for Shell, see @ref{sh-format}.
+
@item python-format
@kwindex python-format@r{ flag}
@itemx no-python-format
@kwindex no-tcl-format@r{ flag}
Likewise for Tcl, see @ref{tcl-format}.
+@item perl-format
+@kwindex perl-format@r{ flag}
+@itemx no-perl-format
+@kwindex no-perl-format@r{ flag}
+Likewise for Perl, see @ref{perl-format}.
+
+@item perl-brace-format
+@kwindex perl-brace-format@r{ flag}
+@itemx no-perl-brace-format
+@kwindex no-perl-brace-format@r{ flag}
+Likewise for Perl brace, see @ref{perl-format}.
+
@item php-format
@kwindex php-format@r{ flag}
@itemx no-php-format
@menu
* c-format:: C Format Strings
+* objc-format:: Objective C Format Strings
* sh-format:: Shell Format Strings
* python-format:: Python Format Strings
* lisp-format:: Lisp Format Strings
* gcc-internal-format:: GCC internal Format Strings
@end menu
-@node c-format, sh-format, Translators for other Languages, Translators for other Languages
+@node c-format, objc-format, Translators for other Languages, Translators for other Languages
@subsection C Format Strings
C format strings are described in POSIX (IEEE P1003.1 2001), section
or @file{libintl.so} provides replacement functions, and GNU @code{<libintl.h>}
activates these replacement functions automatically.
-@node sh-format, python-format, c-format, Translators for other Languages
+@node objc-format, sh-format, c-format, Translators for other Languages
+@subsection Objective C Format Strings
+
+Objective C format strings are like C format strings. They support an
+additional format directive: "$@@", which when executed consumes an argument
+of type @code{Object *}.
+
+@node sh-format, python-format, objc-format, Translators for other Languages
@subsection Shell Format Strings
Shell format strings, as supported by GNU gettext and the @samp{envsubst}
+2003-10-13 Bruno Haible <bruno@clisp.org>
+
+ Support and recognize Objective C specific format strings.
+ * message.h (enum format_type): New item format_objc.
+ (NFORMATS): Increment.
+ * message.c (format_language): Add an entry for format_objc.
+ (format_language_pretty): Likewise.
+ * format.h (formatstring_objc): New declaration.
+ * format-c.c (enum format_arg_type): New item FAT_OBJC_OBJECT.
+ (format_parse): Add objc_extensions argument. Handle %@ in ObjC mode.
+ (format_c_parse, format_objc_parse): New functions.
+ (formatstring_c): Use format_c_parse instead of format_parse.
+ (formatstring_objc): New variable.
+ (get_c99_format_directives): Update.
+ * format.c (formatstring_parsers): Add an entry for format_objc.
+ * write-mo.c (write_table): Look for system dependent strings also in
+ ObjectiveC format strings.
+ * x-c.h (SCANNERS_C): Use separate flag_table for ObjectiveC.
+ (x_objc_keyword, init_flag_table_objc): New declarations.
+ (x_c_any_keywords): Remove declaration.
+ * x-c.c (c_keywords): Renamed from keywords.
+ (objc_keywords): New variable.
+ (add_keyword): Renamed from x_c_keyword. Add keywords table argument.
+ (x_c_keyword, x_objc_keyword): New functions.
+ (x_c_any_keywords): Remove function.
+ (init_keywords): Also initialize ObjectiveC keyword table.
+ (init_flag_table_objc): New function.
+ (enum token_type_ty): New item token_type_colon.
+ (phase5_get): Recognize colon.
+ (enum xgettext_token_type_ty): New item xgettext_token_type_colon.
+ (x_c_lex): Use keywords table depending on objc_extensions. Handle
+ colon.
+ (extract_parenthesized): Change the context_iter and inner_context
+ after a keyword/symbol followed by a colon was seen.
+ * xgettext.c (flag_table_objc): New variable.
+ (main): Invoke init_flag_table_objc, x_objc_keyword. Watch out for
+ keywords arguments, instead of calling x_c_any_keywords().
+ (flag_context_list_table_insert): New function, extracted from
+ xgettext_record_flag.
+ (xgettext_record_flag): Call it. For format_c, insert the flags also
+ in the flag_table_objc. Handle format_objc.
+ (remember_a_message): Don't add a heuristic c-format flag to an entry
+ that already carries objc-format.
+ (remember_a_message_plural): Likewise.
+
2003-10-18 Bruno Haible <bruno@clisp.org>
Support for GNUstep .strings format.
FAT_DOUBLE = 2,
FAT_CHAR = 3,
FAT_STRING = 4,
- FAT_POINTER = 5,
- FAT_COUNT_POINTER = 6,
+ FAT_OBJC_OBJECT = 5,
+ FAT_POINTER = 6,
+ FAT_COUNT_POINTER = 7,
/* Flags */
FAT_UNSIGNED = 1 << 3,
FAT_SIZE_SHORT = 1 << 4,
xasprintf (_("In the directive number %u, the token after '<' is not the name of a format specifier macro. The valid macro names are listed in ISO C 99 section 7.8.1."), directive_number)
static void *
-format_parse (const char *format, char **invalid_reason)
+format_parse (const char *format, bool objc_extensions, char **invalid_reason)
{
struct spec spec;
unsigned int numbered_arg_count;
type = FAT_DOUBLE;
type |= (size & FAT_SIZE_LONGLONG);
break;
+ case '@':
+ if (objc_extensions)
+ {
+ type = FAT_OBJC_OBJECT;
+ break;
+ }
+ goto other;
case 'p':
type = FAT_POINTER;
break;
type = FAT_COUNT_POINTER;
type |= (size & FAT_SIZE_MASK);
break;
+ other:
default:
*invalid_reason =
(*format == '\0'
return NULL;
}
+static void *
+format_c_parse (const char *format, char **invalid_reason)
+{
+ return format_parse (format, false, invalid_reason);
+}
+
+static void *
+format_objc_parse (const char *format, char **invalid_reason)
+{
+ return format_parse (format, true, invalid_reason);
+}
+
static void
format_free (void *descr)
{
struct formatstring_parser formatstring_c =
{
- format_parse,
+ format_c_parse,
+ format_free,
+ format_get_number_of_directives,
+ format_check
+};
+
+
+struct formatstring_parser formatstring_objc =
+{
+ format_objc_parse,
format_free,
format_get_number_of_directives,
format_check
get_c99_format_directives (const char *string,
struct interval **intervalsp, size_t *lengthp)
{
+ /* Parse the format string with all possible extensions turned on. (The
+ caller has already verified that the format string is valid for the
+ particular language.) */
char *invalid_reason = NULL;
- struct spec *descr = (struct spec *) format_parse (string, &invalid_reason);
+ struct spec *descr =
+ (struct spec *) format_parse (string, true, &invalid_reason);
if (descr != NULL && descr->c99_directives_count > 0)
{
case FAT_STRING:
printf ("s");
break;
+ case FAT_OBJC_OBJECT:
+ printf ("@");
+ break;
case FAT_POINTER:
printf ("p");
break;
line[--line_len] = '\0';
invalid_reason = NULL;
- descr = format_parse (line, &invalid_reason);
+ descr = format_c_parse (line, &invalid_reason);
format_print (descr);
printf ("\n");
struct formatstring_parser *formatstring_parsers[NFORMATS] =
{
/* format_c */ &formatstring_c,
+ /* format_objc */ &formatstring_objc,
/* format_sh */ &formatstring_sh,
/* format_python */ &formatstring_python,
/* format_lisp */ &formatstring_lisp,
/* Format string parsers, each defined in its own file. */
extern DLL_VARIABLE struct formatstring_parser formatstring_c;
+extern DLL_VARIABLE struct formatstring_parser formatstring_objc;
extern DLL_VARIABLE struct formatstring_parser formatstring_sh;
extern DLL_VARIABLE struct formatstring_parser formatstring_python;
extern DLL_VARIABLE struct formatstring_parser formatstring_lisp;
const char *const format_language[NFORMATS] =
{
/* format_c */ "c",
+ /* format_objc */ "objc",
/* format_sh */ "sh",
/* format_python */ "python",
/* format_lisp */ "lisp",
const char *const format_language_pretty[NFORMATS] =
{
/* format_c */ "C",
+ /* format_objc */ "Objective C",
/* format_sh */ "Shell",
/* format_python */ "Python",
/* format_lisp */ "Lisp",
enum format_type
{
format_c,
+ format_objc,
format_sh,
format_python,
format_lisp,
format_php,
format_gcc_internal
};
-#define NFORMATS 16 /* Number of format_type enum values. */
+#define NFORMATS 17 /* Number of format_type enum values. */
extern DLL_VARIABLE const char *const format_language[NFORMATS];
extern DLL_VARIABLE const char *const format_language_pretty[NFORMATS];
/* Test if mp contains system dependent strings and thus
requires the use of the .mo file minor revision 1. */
- if (possible_format_p (mp->is_format[format_c]))
+ if (possible_format_p (mp->is_format[format_c])
+ || possible_format_p (mp->is_format[format_objc]))
{
/* Check whether msgid or msgstr contain ISO C 99 <inttypes.h>
format string directives. No need to check msgid_plural, because
/* If true extract all strings. */
static bool extract_all = false;
-static hash_table keywords;
+static hash_table c_keywords;
+static hash_table objc_keywords;
static bool default_keywords = true;
}
-void
-x_c_keyword (const char *name)
+static void
+add_keyword (const char *name, hash_table *keywords)
{
if (name == NULL)
default_keywords = false;
int argnum2;
const char *colon;
- if (keywords.table == NULL)
- init_hash (&keywords, 100);
+ if (keywords->table == NULL)
+ init_hash (keywords, 100);
split_keywordspec (name, &end, &argnum1, &argnum2);
{
if (argnum1 == 0)
argnum1 = 1;
- insert_entry (&keywords, name, end - name,
+ insert_entry (keywords, name, end - name,
(void *) (long) (argnum1 + (argnum2 << 10)));
}
}
}
-bool
-x_c_any_keywords ()
+void
+x_c_keyword (const char *name)
{
- return (keywords.filled > 0) || default_keywords;
+ add_keyword (name, &c_keywords);
}
-/* Finish initializing the keywords hash table.
+void
+x_objc_keyword (const char *name)
+{
+ add_keyword (name, &objc_keywords);
+}
+
+/* Finish initializing the keywords hash tables.
Called after argument processing, before each file is processed. */
static void
init_keywords ()
x_c_keyword ("dngettext:2,3");
x_c_keyword ("dcngettext:2,3");
x_c_keyword ("gettext_noop");
+
+ x_objc_keyword ("gettext");
+ x_objc_keyword ("dgettext:2");
+ x_objc_keyword ("dcgettext:2");
+ x_objc_keyword ("ngettext:1,2");
+ x_objc_keyword ("dngettext:2,3");
+ x_objc_keyword ("dcngettext:2,3");
+ x_objc_keyword ("gettext_noop");
+ x_objc_keyword ("NSLocalizedString"); /* similar to gettext */
+ x_objc_keyword ("_"); /* similar to gettext */
+ x_objc_keyword ("NSLocalizedStaticString"); /* similar to gettext_noop */
+ x_objc_keyword ("__"); /* similar to gettext_noop */
+
default_keywords = false;
}
}
#endif
}
+void
+init_flag_table_objc ()
+{
+ /* Since the settings done in init_flag_table_c() also have an effect for
+ the ObjectiveC parser, we don't have to repeat them here. */
+ xgettext_record_flag ("gettext:1:pass-objc-format");
+ xgettext_record_flag ("dgettext:2:pass-objc-format");
+ xgettext_record_flag ("dcgettext:2:pass-objc-format");
+ xgettext_record_flag ("ngettext:1:pass-objc-format");
+ xgettext_record_flag ("ngettext:2:pass-objc-format");
+ xgettext_record_flag ("dngettext:2:pass-objc-format");
+ xgettext_record_flag ("dngettext:3:pass-objc-format");
+ xgettext_record_flag ("dcngettext:2:pass-objc-format");
+ xgettext_record_flag ("dcngettext:3:pass-objc-format");
+ xgettext_record_flag ("gettext_noop:1:pass-objc-format");
+ xgettext_record_flag ("NSLocalizedString:1:pass-c-format");
+ xgettext_record_flag ("NSLocalizedString:1:pass-objc-format");
+ xgettext_record_flag ("_:1:pass-c-format");
+ xgettext_record_flag ("_:1:pass-objc-format");
+ xgettext_record_flag ("stringWithFormat::1:objc-format");
+ xgettext_record_flag ("initWithFormat::1:objc-format");
+ xgettext_record_flag ("stringByAppendingFormat::1:objc-format");
+ xgettext_record_flag ("localizedStringWithFormat::1:objc-format");
+ xgettext_record_flag ("appendFormat::1:objc-format");
+}
+
void
init_flag_table_gcc_internal ()
{
token_type_lparen, /* ( */
token_type_rparen, /* ) */
token_type_comma, /* , */
+ token_type_colon, /* : */
token_type_name, /* abc */
token_type_number, /* 2.7 */
token_type_string_literal, /* "abc" */
tp->type = token_type_hash;
return;
+ case ':':
+ tp->type = token_type_colon;
+ return;
+
case '@':
if (objc_extensions)
{
xgettext_token_type_lparen,
xgettext_token_type_rparen,
xgettext_token_type_comma,
+ xgettext_token_type_colon,
xgettext_token_type_string_literal,
xgettext_token_type_other
};
case token_type_name:
last_non_comment_line = newline_count;
- if (find_entry (&keywords, token.string, strlen (token.string),
- &keyword_value)
+ if (find_entry (objc_extensions ? &objc_keywords : &c_keywords,
+ token.string, strlen (token.string), &keyword_value)
== 0)
{
tp->type = xgettext_token_type_keyword;
tp->type = xgettext_token_type_comma;
return;
+ case token_type_colon:
+ last_non_comment_line = newline_count;
+
+ tp->type = xgettext_token_type_colon;
+ return;
+
case token_type_string_literal:
last_non_comment_line = newline_count;
/* Context iterator that will be used if the next token is a '('. */
flag_context_list_iterator_ty next_context_iter =
passthrough_context_list_iterator;
+ /* Context iterator that will be used if the next token is a ':'.
+ (Objective C selector syntax.) */
+ flag_context_list_iterator_ty selectorcall_context_iter =
+ passthrough_context_list_iterator;
/* Current context. */
flag_context_ty inner_context =
inherited_context (outer_context,
next_commas_to_skip = token.argnum1 - 1;
next_plural_commas = (token.argnum2 > token.argnum1
? token.argnum2 - token.argnum1 : 0);
- next_context_iter =
- flag_context_list_iterator (
- flag_context_list_table_lookup (
- flag_context_list_table,
- token.string, strlen (token.string)));
- free (token.string);
state = 1;
- continue;
+ goto keyword_or_symbol;
case xgettext_token_type_symbol:
+ state = 0;
+ keyword_or_symbol:
next_context_iter =
flag_context_list_iterator (
flag_context_list_table_lookup (
flag_context_list_table,
token.string, strlen (token.string)));
+ if (objc_extensions)
+ {
+ size_t token_string_len = strlen (token.string);
+ token.string = xrealloc (token.string, token_string_len + 2);
+ token.string[token_string_len] = ':';
+ token.string[token_string_len + 1] = '\0';
+ selectorcall_context_iter =
+ flag_context_list_iterator (
+ flag_context_list_table_lookup (
+ flag_context_list_table,
+ token.string, token_string_len + 1));
+ }
free (token.string);
- state = 0;
continue;
case xgettext_token_type_lparen:
state ? next_plural_commas : 0))
return true;
next_context_iter = null_context_list_iterator;
+ selectorcall_context_iter = null_context_list_iterator;
state = 0;
continue;
flag_context_list_iterator_advance (
&context_iter));
next_context_iter = passthrough_context_list_iterator;
+ selectorcall_context_iter = passthrough_context_list_iterator;
+ state = 0;
+ continue;
+
+ case xgettext_token_type_colon:
+ if (objc_extensions)
+ {
+ context_iter = selectorcall_context_iter;
+ inner_context =
+ inherited_context (inner_context,
+ flag_context_list_iterator_advance (
+ &context_iter));
+ next_context_iter = passthrough_context_list_iterator;
+ selectorcall_context_iter = passthrough_context_list_iterator;
+ }
+ else
+ {
+ next_context_iter = null_context_list_iterator;
+ selectorcall_context_iter = null_context_list_iterator;
+ }
state = 0;
continue;
free (token.string);
}
next_context_iter = null_context_list_iterator;
+ selectorcall_context_iter = null_context_list_iterator;
state = 0;
continue;
case xgettext_token_type_other:
next_context_iter = null_context_list_iterator;
+ selectorcall_context_iter = null_context_list_iterator;
state = 0;
continue;
{ "C++", extract_c, \
&flag_table_c, &formatstring_c, NULL }, \
{ "ObjectiveC", extract_objc, \
- &flag_table_c, &formatstring_c, NULL }, \
+ &flag_table_objc, &formatstring_c, &formatstring_objc }, \
{ "GCC-source", extract_c, \
&flag_table_gcc_internal, &formatstring_gcc_internal, NULL }, \
extern void x_c_extract_all (void);
extern void x_c_keyword (const char *name);
-extern bool x_c_any_keywords (void);
+extern void x_objc_keyword (const char *name);
extern void x_c_trigraphs (void);
extern void init_flag_table_c (void);
+extern void init_flag_table_objc (void);
extern void init_flag_table_gcc_internal (void);
/* Table of flag_context_list_ty tables. */
static flag_context_list_table_ty flag_table_c;
+static flag_context_list_table_ty flag_table_objc;
static flag_context_list_table_ty flag_table_gcc_internal;
static flag_context_list_table_ty flag_table_sh;
static flag_context_list_table_ty flag_table_python;
bool do_version = false;
msgdomain_list_ty *mdlp;
bool join_existing = false;
+ bool no_default_keywords = false;
+ bool some_additional_keywords = false;
bool sort_by_msgid = false;
bool sort_by_filepos = false;
const char *file_name;
default_domain = MESSAGE_DOMAIN_DEFAULT;
xgettext_global_source_encoding = po_charset_ascii;
init_flag_table_c ();
+ init_flag_table_objc ();
init_flag_table_gcc_internal ();
init_flag_table_sh ();
init_flag_table_python ();
if (optarg == NULL || *optarg != '\0')
{
x_c_keyword (optarg);
+ x_objc_keyword (optarg);
x_sh_keyword (optarg);
x_python_keyword (optarg);
x_lisp_keyword (optarg);
x_perl_keyword (optarg);
x_php_keyword (optarg);
x_glade_keyword (optarg);
+ if (optarg == NULL)
+ no_default_keywords = true;
+ else
+ some_additional_keywords = true;
}
break;
case 'l':
error (EXIT_FAILURE, 0, _("\
--join-existing cannot be used when output is written to stdout"));
- if (!x_c_any_keywords ())
+ if (no_default_keywords && !some_additional_keywords)
{
error (0, 0, _("\
xgettext cannot work without keywords to look for"));
}
+static void
+flag_context_list_table_insert (flag_context_list_table_ty *table,
+ unsigned int index,
+ const char *name_start, const char *name_end,
+ int argnum, enum is_format value, bool pass)
+{
+ if (table == &flag_table_lisp)
+ {
+ /* Convert NAME to upper case. */
+ size_t name_len = name_end - name_start;
+ char *name = (char *) alloca (name_len);
+ size_t i;
+
+ for (i = 0; i < name_len; i++)
+ name[i] = (name_start[i] >= 'a' && name_start[i] <= 'z'
+ ? name_start[i] - 'a' + 'A'
+ : name_start[i]);
+ name_start = name;
+ name_end = name + name_len;
+ }
+ else if (table == &flag_table_tcl)
+ {
+ /* Remove redundant "::" prefix. */
+ if (name_end - name_start > 2
+ && name_start[0] == ':' && name_start[1] == ':')
+ name_start += 2;
+ }
+
+ /* Insert the pair (VALUE, PASS) at INDEX in the element numbered ARGNUM
+ of the list corresponding to NAME in the TABLE. */
+ if (table->table == NULL)
+ init_hash (table, 100);
+ {
+ void *entry;
+
+ if (find_entry (table, name_start, name_end - name_start, &entry) != 0)
+ {
+ /* Create new hash table entry. */
+ flag_context_list_ty *list =
+ (flag_context_list_ty *) xmalloc (sizeof (flag_context_list_ty));
+ list->argnum = argnum;
+ memset (&list->flags, '\0', sizeof (list->flags));
+ switch (index)
+ {
+ case 0:
+ list->flags.is_format1 = value;
+ list->flags.pass_format1 = pass;
+ break;
+ case 1:
+ list->flags.is_format2 = value;
+ list->flags.pass_format2 = pass;
+ break;
+ default:
+ abort ();
+ }
+ list->next = NULL;
+ insert_entry (table, name_start, name_end - name_start, list);
+ }
+ else
+ {
+ flag_context_list_ty *list = (flag_context_list_ty *)entry;
+ flag_context_list_ty **lastp = NULL;
+
+ while (list != NULL && list->argnum < argnum)
+ {
+ lastp = &list->next;
+ list = *lastp;
+ }
+ if (list != NULL && list->argnum == argnum)
+ {
+ /* Add this flag to the current argument number. */
+ switch (index)
+ {
+ case 0:
+ list->flags.is_format1 = value;
+ list->flags.pass_format1 = pass;
+ break;
+ case 1:
+ list->flags.is_format2 = value;
+ list->flags.pass_format2 = pass;
+ break;
+ default:
+ abort ();
+ }
+ }
+ else if (lastp != NULL)
+ {
+ /* Add a new list entry for this argument number. */
+ list =
+ (flag_context_list_ty *) xmalloc (sizeof (flag_context_list_ty));
+ list->argnum = argnum;
+ memset (&list->flags, '\0', sizeof (list->flags));
+ switch (index)
+ {
+ case 0:
+ list->flags.is_format1 = value;
+ list->flags.pass_format1 = pass;
+ break;
+ case 1:
+ list->flags.is_format2 = value;
+ list->flags.pass_format2 = pass;
+ break;
+ default:
+ abort ();
+ }
+ list->next = *lastp;
+ *lastp = list;
+ }
+ else
+ {
+ /* Add a new list entry for this argument number, at the beginning
+ of the list. Since we don't have an API for replacing the
+ value of a key in the hash table, we have to copy the first
+ list element. */
+ flag_context_list_ty *copy =
+ (flag_context_list_ty *) xmalloc (sizeof (flag_context_list_ty));
+ *copy = *list;
+
+ list->argnum = argnum;
+ memset (&list->flags, '\0', sizeof (list->flags));
+ switch (index)
+ {
+ case 0:
+ list->flags.is_format1 = value;
+ list->flags.pass_format1 = pass;
+ break;
+ case 1:
+ list->flags.is_format2 = value;
+ list->flags.pass_format2 = pass;
+ break;
+ default:
+ abort ();
+ }
+ list->next = copy;
+ }
+ }
+ }
+}
+
+
void
xgettext_record_flag (const char *optionstring)
{
if (strlen (format_language[type]) == n
&& memcmp (format_language[type], p, n) == 0)
{
- flag_context_list_table_ty *table;
- unsigned int index;
-
- index = 0;
switch (type)
{
case format_c:
- table = &flag_table_c;
+ flag_context_list_table_insert (&flag_table_c, 0,
+ name_start, name_end,
+ argnum, value, pass);
+ flag_context_list_table_insert (&flag_table_objc, 0,
+ name_start, name_end,
+ argnum, value, pass);
+ break;
+ case format_objc:
+ flag_context_list_table_insert (&flag_table_objc, 1,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_sh:
- table = &flag_table_sh;
+ flag_context_list_table_insert (&flag_table_sh, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_python:
- table = &flag_table_python;
+ flag_context_list_table_insert (&flag_table_python, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_lisp:
- table = &flag_table_lisp;
+ flag_context_list_table_insert (&flag_table_lisp, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_elisp:
- table = &flag_table_elisp;
+ flag_context_list_table_insert (&flag_table_elisp, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_librep:
- table = &flag_table_librep;
+ flag_context_list_table_insert (&flag_table_librep, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_smalltalk:
- return;
+ break;
case format_java:
- table = &flag_table_java;
+ flag_context_list_table_insert (&flag_table_java, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_awk:
- table = &flag_table_awk;
+ flag_context_list_table_insert (&flag_table_awk, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_pascal:
- return;
+ break;
case format_ycp:
- table = &flag_table_ycp;
+ flag_context_list_table_insert (&flag_table_ycp, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_tcl:
- table = &flag_table_tcl;
+ flag_context_list_table_insert (&flag_table_tcl, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_perl:
- table = &flag_table_perl;
+ flag_context_list_table_insert (&flag_table_perl, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_perl_brace:
- index = 1;
- table = &flag_table_perl;
+ flag_context_list_table_insert (&flag_table_perl, 1,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_php:
- table = &flag_table_php;
+ flag_context_list_table_insert (&flag_table_php, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
case format_gcc_internal:
- table = &flag_table_gcc_internal;
+ flag_context_list_table_insert (&flag_table_gcc_internal, 0,
+ name_start, name_end,
+ argnum, value, pass);
break;
default:
abort ();
}
-
- if (table == &flag_table_lisp)
- {
- /* Convert NAME to upper case. */
- size_t name_len = name_end - name_start;
- char *name = (char *) alloca (name_len);
- size_t i;
-
- for (i = 0; i < name_len; i++)
- name[i] = (name_start[i] >= 'a' && name_start[i] <= 'z'
- ? name_start[i] - 'a' + 'A'
- : name_start[i]);
- name_start = name;
- name_end = name + name_len;
- }
- else if (table == &flag_table_tcl)
- {
- /* Remove redundant "::" prefix. */
- if (name_end - name_start > 2
- && name_start[0] == ':' && name_start[1] == ':')
- name_start += 2;
- }
-
- /* Insert the pair (VALUE, PASS) at INDEX in the element
- numbered ARGNUM of the list corresponding to NAME in the
- TABLE. */
- if (table->table == NULL)
- init_hash (table, 100);
- {
- void *entry;
-
- if (find_entry (table, name_start, name_end - name_start,
- &entry) != 0)
- {
- /* Create new hash table entry. */
- flag_context_list_ty *list =
- (flag_context_list_ty *)
- xmalloc (sizeof (flag_context_list_ty));
- list->argnum = argnum;
- memset (&list->flags, '\0', sizeof (list->flags));
- switch (index)
- {
- case 0:
- list->flags.is_format1 = value;
- list->flags.pass_format1 = pass;
- break;
- case 1:
- list->flags.is_format2 = value;
- list->flags.pass_format2 = pass;
- break;
- default:
- abort ();
- }
- list->next = NULL;
- insert_entry (table, name_start, name_end - name_start,
- list);
- }
- else
- {
- flag_context_list_ty *list =
- (flag_context_list_ty *)entry;
- flag_context_list_ty **lastp = NULL;
-
- while (list != NULL && list->argnum < argnum)
- {
- lastp = &list->next;
- list = *lastp;
- }
- if (list != NULL && list->argnum == argnum)
- {
- /* Add this flag to the current argument number. */
- switch (index)
- {
- case 0:
- list->flags.is_format1 = value;
- list->flags.pass_format1 = pass;
- break;
- case 1:
- list->flags.is_format2 = value;
- list->flags.pass_format2 = pass;
- break;
- default:
- abort ();
- }
- }
- else if (lastp != NULL)
- {
- /* Add a new list entry for this argument number. */
- list =
- (flag_context_list_ty *)
- xmalloc (sizeof (flag_context_list_ty));
- list->argnum = argnum;
- memset (&list->flags, '\0', sizeof (list->flags));
- switch (index)
- {
- case 0:
- list->flags.is_format1 = value;
- list->flags.pass_format1 = pass;
- break;
- case 1:
- list->flags.is_format2 = value;
- list->flags.pass_format2 = pass;
- break;
- default:
- abort ();
- }
- list->next = *lastp;
- *lastp = list;
- }
- else
- {
- /* Add a new list entry for this argument number,
- at the beginning of the list. Since we don't
- have an API for replacing the value of a key
- in the hash table, we have to copy the first
- list element. */
- flag_context_list_ty *copy =
- (flag_context_list_ty *)
- xmalloc (sizeof (flag_context_list_ty));
- *copy = *list;
-
- list->argnum = argnum;
- memset (&list->flags, '\0', sizeof (list->flags));
- switch (index)
- {
- case 0:
- list->flags.is_format1 = value;
- list->flags.pass_format1 = pass;
- break;
- case 1:
- list->flags.is_format2 = value;
- list->flags.pass_format2 = pass;
- break;
- default:
- abort ();
- }
- list->next = copy;
- }
- }
- }
return;
}
/* If the flag is not among the valid values, the optionstring is
{
if (is_format[i] == undecided
&& (formatstring_parsers[i] == current_formatstring_parser1
- || formatstring_parsers[i] == current_formatstring_parser2))
+ || formatstring_parsers[i] == current_formatstring_parser2)
+ /* But avoid redundancy: objc-format is stronger than c-format. */
+ && !(i == format_c && possible_format_p (is_format[format_objc]))
+ && !(i == format_objc && possible_format_p (is_format[format_c])))
{
struct formatstring_parser *parser = formatstring_parsers[i];
char *invalid_reason = NULL;
for (i = 0; i < NFORMATS; i++)
if ((formatstring_parsers[i] == current_formatstring_parser1
|| formatstring_parsers[i] == current_formatstring_parser2)
- && (mp->is_format[i] == undecided || mp->is_format[i] == possible))
+ && (mp->is_format[i] == undecided || mp->is_format[i] == possible)
+ /* 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])))
{
struct formatstring_parser *parser = formatstring_parsers[i];
char *invalid_reason = NULL;