1 /* Extracts strings from C source file to Uniforum style .po file.
2 Copyright (C) 1995-1998, 2000-2012 Free Software Foundation, Inc.
3 Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, April 1995.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
37 #include "file-list.h"
40 #include "error-progname.h"
42 #include "relocatable.h"
45 #include "xvasprintf.h"
52 #include "concat-filename.h"
53 #include "c-strcase.h"
54 #include "open-catalog.h"
55 #include "read-catalog-abstract.h"
58 #include "po-charset.h"
59 #include "msgl-iconv.h"
60 #include "msgl-ascii.h"
62 #include "write-catalog.h"
64 #include "write-properties.h"
65 #include "write-stringtable.h"
68 #include "propername.h"
71 /* A convenience macro. I don't like writing gettext() every time. */
72 #define _(str) gettext (str)
83 #include "x-smalltalk.h"
85 #include "x-properties.h"
92 #include "x-stringtable.h"
96 #include "x-javascript.h"
100 /* If nonzero add all comments immediately preceding one of the keywords. */
101 static bool add_all_comments = false;
103 /* Tag used in comment of prevailing domain. */
104 static char *comment_tag;
106 /* Name of default domain file. If not set defaults to messages.po. */
107 static const char *default_domain;
109 /* If called with --debug option the output reflects whether format
110 string recognition is done automatically or forced by the user. */
113 /* Content of .po files with symbols to be excluded. */
114 message_list_ty *exclude;
116 /* Force output of PO file even if empty. */
119 /* Copyright holder of the output file and the translations. */
120 static const char *copyright_holder = "THE PACKAGE'S COPYRIGHT HOLDER";
123 static const char *package_name = NULL;
125 /* Package version. */
126 static const char *package_version = NULL;
128 /* Email address or URL for reports of bugs in msgids. */
129 static const char *msgid_bugs_address = NULL;
131 /* String used as prefix for msgstr. */
132 static const char *msgstr_prefix;
134 /* String used as suffix for msgstr. */
135 static const char *msgstr_suffix;
137 /* Directory in which output files are created. */
138 static char *output_dir;
140 /* The output syntax: .pot or .properties or .strings. */
141 static catalog_output_format_ty output_syntax = &output_format_po;
143 /* If nonzero omit header with information about this run. */
144 int xgettext_omit_header;
146 /* Table of flag_context_list_ty tables. */
147 static flag_context_list_table_ty flag_table_c;
148 static flag_context_list_table_ty flag_table_cxx_qt;
149 static flag_context_list_table_ty flag_table_cxx_kde;
150 static flag_context_list_table_ty flag_table_cxx_boost;
151 static flag_context_list_table_ty flag_table_objc;
152 static flag_context_list_table_ty flag_table_gcc_internal;
153 static flag_context_list_table_ty flag_table_sh;
154 static flag_context_list_table_ty flag_table_python;
155 static flag_context_list_table_ty flag_table_lisp;
156 static flag_context_list_table_ty flag_table_elisp;
157 static flag_context_list_table_ty flag_table_librep;
158 static flag_context_list_table_ty flag_table_scheme;
159 static flag_context_list_table_ty flag_table_java;
160 static flag_context_list_table_ty flag_table_csharp;
161 static flag_context_list_table_ty flag_table_awk;
162 static flag_context_list_table_ty flag_table_ycp;
163 static flag_context_list_table_ty flag_table_tcl;
164 static flag_context_list_table_ty flag_table_perl;
165 static flag_context_list_table_ty flag_table_php;
166 static flag_context_list_table_ty flag_table_lua;
167 static flag_context_list_table_ty flag_table_javascript;
168 static flag_context_list_table_ty flag_table_vala;
170 /* If true, recognize Qt format strings. */
171 static bool recognize_format_qt;
173 /* If true, recognize KDE format strings. */
174 static bool recognize_format_kde;
176 /* If true, recognize Boost format strings. */
177 static bool recognize_format_boost;
179 /* Canonicalized encoding name for all input files. */
180 const char *xgettext_global_source_encoding;
183 /* Converter from xgettext_global_source_encoding to UTF-8 (except from
184 ASCII or UTF-8, when this conversion is a no-op). */
185 iconv_t xgettext_global_source_iconv;
188 /* Canonicalized encoding name for the current input file. */
189 const char *xgettext_current_source_encoding;
192 /* Converter from xgettext_current_source_encoding to UTF-8 (except from
193 ASCII or UTF-8, when this conversion is a no-op). */
194 iconv_t xgettext_current_source_iconv;
198 static const struct option long_options[] =
200 { "add-comments", optional_argument, NULL, 'c' },
201 { "add-location", no_argument, &line_comment, 1 },
202 { "boost", no_argument, NULL, CHAR_MAX + 11 },
203 { "c++", no_argument, NULL, 'C' },
204 { "color", optional_argument, NULL, CHAR_MAX + 14 },
205 { "copyright-holder", required_argument, NULL, CHAR_MAX + 1 },
206 { "debug", no_argument, &do_debug, 1 },
207 { "default-domain", required_argument, NULL, 'd' },
208 { "directory", required_argument, NULL, 'D' },
209 { "escape", no_argument, NULL, 'E' },
210 { "exclude-file", required_argument, NULL, 'x' },
211 { "extract-all", no_argument, NULL, 'a' },
212 { "files-from", required_argument, NULL, 'f' },
213 { "flag", required_argument, NULL, CHAR_MAX + 8 },
214 { "force-po", no_argument, &force_po, 1 },
215 { "foreign-user", no_argument, NULL, CHAR_MAX + 2 },
216 { "from-code", required_argument, NULL, CHAR_MAX + 3 },
217 { "help", no_argument, NULL, 'h' },
218 { "indent", no_argument, NULL, 'i' },
219 { "join-existing", no_argument, NULL, 'j' },
220 { "kde", no_argument, NULL, CHAR_MAX + 10 },
221 { "keyword", optional_argument, NULL, 'k' },
222 { "language", required_argument, NULL, 'L' },
223 { "msgid-bugs-address", required_argument, NULL, CHAR_MAX + 5 },
224 { "msgstr-prefix", optional_argument, NULL, 'm' },
225 { "msgstr-suffix", optional_argument, NULL, 'M' },
226 { "no-escape", no_argument, NULL, 'e' },
227 { "no-location", no_argument, &line_comment, 0 },
228 { "no-wrap", no_argument, NULL, CHAR_MAX + 4 },
229 { "omit-header", no_argument, &xgettext_omit_header, 1 },
230 { "output", required_argument, NULL, 'o' },
231 { "output-dir", required_argument, NULL, 'p' },
232 { "package-name", required_argument, NULL, CHAR_MAX + 12 },
233 { "package-version", required_argument, NULL, CHAR_MAX + 13 },
234 { "properties-output", no_argument, NULL, CHAR_MAX + 6 },
235 { "qt", no_argument, NULL, CHAR_MAX + 9 },
236 { "sort-by-file", no_argument, NULL, 'F' },
237 { "sort-output", no_argument, NULL, 's' },
238 { "strict", no_argument, NULL, 'S' },
239 { "string-limit", required_argument, NULL, 'l' },
240 { "stringtable-output", no_argument, NULL, CHAR_MAX + 7 },
241 { "style", required_argument, NULL, CHAR_MAX + 15 },
242 { "trigraphs", no_argument, NULL, 'T' },
243 { "version", no_argument, NULL, 'V' },
244 { "width", required_argument, NULL, 'w', },
249 /* The extractors must all be functions returning void and taking three
250 arguments designating the input stream and one message domain list argument
251 in which to add the messages. */
252 typedef void (*extractor_func) (FILE *fp, const char *real_filename,
253 const char *logical_filename,
254 flag_context_list_table_ty *flag_table,
255 msgdomain_list_ty *mdlp);
257 typedef struct extractor_ty extractor_ty;
261 flag_context_list_table_ty *flag_table;
262 struct formatstring_parser *formatstring_parser1;
263 struct formatstring_parser *formatstring_parser2;
264 struct formatstring_parser *formatstring_parser3;
268 /* Forward declaration of local functions. */
269 static void usage (int status)
270 #if defined __GNUC__ && ((__GNUC__ == 2 && __GNUC_MINOR__ > 4) || __GNUC__ > 2)
271 __attribute__ ((noreturn))
274 static void read_exclusion_file (char *file_name);
275 static void extract_from_file (const char *file_name, extractor_ty extractor,
276 msgdomain_list_ty *mdlp);
277 static message_ty *construct_header (void);
278 static void finalize_header (msgdomain_list_ty *mdlp);
279 static extractor_ty language_to_extractor (const char *name);
280 static const char *extension_to_language (const char *extension);
284 main (int argc, char *argv[])
287 bool do_help = false;
288 bool do_version = false;
289 msgdomain_list_ty *mdlp;
290 bool join_existing = false;
291 bool no_default_keywords = false;
292 bool some_additional_keywords = false;
293 bool sort_by_msgid = false;
294 bool sort_by_filepos = false;
295 const char *file_name;
296 const char *files_from = NULL;
297 string_list_ty *file_list;
298 char *output_file = NULL;
299 const char *language = NULL;
300 extractor_ty extractor = { NULL, NULL, NULL, NULL };
304 /* Set program name for messages. */
305 set_program_name (argv[0]);
306 error_print_progname = maybe_print_progname;
308 #ifdef HAVE_SETLOCALE
309 /* Set locale via LC_ALL. */
310 setlocale (LC_ALL, "");
313 /* Set the text message domain. */
314 bindtextdomain (PACKAGE, relocate (LOCALEDIR));
315 bindtextdomain ("bison-runtime", relocate (BISON_LOCALEDIR));
316 textdomain (PACKAGE);
318 /* Ensure that write errors on stdout are detected. */
319 atexit (close_stdout);
321 /* Set initial value of variables. */
322 default_domain = MESSAGE_DOMAIN_DEFAULT;
323 xgettext_global_source_encoding = po_charset_ascii;
324 init_flag_table_c ();
325 init_flag_table_objc ();
326 init_flag_table_gcc_internal ();
327 init_flag_table_sh ();
328 init_flag_table_python ();
329 init_flag_table_lisp ();
330 init_flag_table_elisp ();
331 init_flag_table_librep ();
332 init_flag_table_scheme ();
333 init_flag_table_java ();
334 init_flag_table_csharp ();
335 init_flag_table_awk ();
336 init_flag_table_ycp ();
337 init_flag_table_tcl ();
338 init_flag_table_perl ();
339 init_flag_table_php ();
340 init_flag_table_lua ();
341 init_flag_table_javascript ();
342 init_flag_table_vala ();
344 while ((optchar = getopt_long (argc, argv,
345 "ac::Cd:D:eEf:Fhijk::l:L:m::M::no:p:sTVw:x:",
346 long_options, NULL)) != EOF)
349 case '\0': /* Long option. */
355 x_python_extract_all ();
356 x_lisp_extract_all ();
357 x_elisp_extract_all ();
358 x_librep_extract_all ();
359 x_scheme_extract_all ();
360 x_java_extract_all ();
361 x_csharp_extract_all ();
362 x_awk_extract_all ();
363 x_tcl_extract_all ();
364 x_perl_extract_all ();
365 x_php_extract_all ();
366 x_glade_extract_all ();
367 x_lua_extract_all ();
368 x_javascript_extract_all ();
369 x_vala_extract_all ();
375 add_all_comments = true;
380 add_all_comments = false;
381 comment_tag = optarg;
382 /* We ignore leading white space. */
383 while (isspace ((unsigned char) *comment_tag))
393 default_domain = optarg;
397 dir_list_append (optarg);
401 message_print_style_escape (false);
405 message_print_style_escape (true);
413 sort_by_filepos = true;
421 message_print_style_indent ();
425 join_existing = true;
429 if (optarg != NULL && *optarg == '\0')
430 /* Make "--keyword=" work like "--keyword" and "-k". */
432 x_c_keyword (optarg);
433 x_objc_keyword (optarg);
434 x_sh_keyword (optarg);
435 x_python_keyword (optarg);
436 x_lisp_keyword (optarg);
437 x_elisp_keyword (optarg);
438 x_librep_keyword (optarg);
439 x_scheme_keyword (optarg);
440 x_java_keyword (optarg);
441 x_csharp_keyword (optarg);
442 x_awk_keyword (optarg);
443 x_tcl_keyword (optarg);
444 x_perl_keyword (optarg);
445 x_php_keyword (optarg);
446 x_glade_keyword (optarg);
447 x_lua_keyword (optarg);
448 x_javascript_keyword (optarg);
449 x_vala_keyword (optarg);
451 no_default_keywords = true;
453 some_additional_keywords = true;
457 /* Accepted for backward compatibility with 0.10.35. */
465 /* -m takes an optional argument. If none is given "" is assumed. */
466 msgstr_prefix = optarg == NULL ? "" : optarg;
470 /* -M takes an optional argument. If none is given "" is assumed. */
471 msgstr_suffix = optarg == NULL ? "" : optarg;
479 output_file = optarg;
484 size_t len = strlen (optarg);
486 if (output_dir != NULL)
489 if (optarg[len - 1] == '/')
490 output_dir = xstrdup (optarg);
492 output_dir = xasprintf ("%s/", optarg);
497 sort_by_msgid = true;
501 message_print_style_uniforum ();
516 value = strtol (optarg, &endp, 10);
518 message_page_width_set (value);
523 read_exclusion_file (optarg);
526 case CHAR_MAX + 1: /* --copyright-holder */
527 copyright_holder = optarg;
530 case CHAR_MAX + 2: /* --foreign-user */
531 copyright_holder = "";
534 case CHAR_MAX + 3: /* --from-code */
535 xgettext_global_source_encoding = po_charset_canonicalize (optarg);
536 if (xgettext_global_source_encoding == NULL)
537 xgettext_global_source_encoding = po_charset_ascii;
540 case CHAR_MAX + 4: /* --no-wrap */
541 message_page_width_ignore ();
544 case CHAR_MAX + 5: /* --msgid-bugs-address */
545 msgid_bugs_address = optarg;
548 case CHAR_MAX + 6: /* --properties-output */
549 output_syntax = &output_format_properties;
552 case CHAR_MAX + 7: /* --stringtable-output */
553 output_syntax = &output_format_stringtable;
556 case CHAR_MAX + 8: /* --flag */
557 xgettext_record_flag (optarg);
560 case CHAR_MAX + 9: /* --qt */
561 recognize_format_qt = true;
564 case CHAR_MAX + 10: /* --kde */
565 recognize_format_kde = true;
568 case CHAR_MAX + 11: /* --boost */
569 recognize_format_boost = true;
572 case CHAR_MAX + 12: /* --package-name */
573 package_name = optarg;
576 case CHAR_MAX + 13: /* --package-version */
577 package_version = optarg;
580 case CHAR_MAX + 14: /* --color */
581 if (handle_color_option (optarg) || color_test_mode)
582 usage (EXIT_FAILURE);
585 case CHAR_MAX + 15: /* --style */
586 handle_style_option (optarg);
590 usage (EXIT_FAILURE);
594 /* Version information requested. */
597 printf ("%s (GNU %s) %s\n", basename (program_name), PACKAGE, VERSION);
598 /* xgettext: no-wrap */
599 printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
600 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
601 This is free software: you are free to change and redistribute it.\n\
602 There is NO WARRANTY, to the extent permitted by law.\n\
604 "1995-1998, 2000-2013");
605 printf (_("Written by %s.\n"), proper_name ("Ulrich Drepper"));
609 /* Help is requested. */
611 usage (EXIT_SUCCESS);
613 /* Verify selected options. */
614 if (!line_comment && sort_by_filepos)
615 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
616 "--no-location", "--sort-by-file");
618 if (sort_by_msgid && sort_by_filepos)
619 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
620 "--sort-output", "--sort-by-file");
622 /* We cannot support both Qt and KDE, or Qt and Boost, or KDE and Boost
623 format strings, because there are only two formatstring parsers per
624 language, and formatstring_c is the first one for C++. */
625 if (recognize_format_qt && recognize_format_kde)
626 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
628 if (recognize_format_qt && recognize_format_boost)
629 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
631 if (recognize_format_kde && recognize_format_boost)
632 error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
635 if (join_existing && strcmp (default_domain, "-") == 0)
636 error (EXIT_FAILURE, 0, _("\
637 --join-existing cannot be used when output is written to stdout"));
639 if (no_default_keywords && !some_additional_keywords)
642 xgettext cannot work without keywords to look for"));
643 usage (EXIT_FAILURE);
646 /* Test whether we have some input files given. */
647 if (files_from == NULL && optind >= argc)
649 error (EXIT_SUCCESS, 0, _("no input file given"));
650 usage (EXIT_FAILURE);
653 /* Determine extractor from language. */
654 if (language != NULL)
655 extractor = language_to_extractor (language);
657 /* Canonize msgstr prefix/suffix. */
658 if (msgstr_prefix != NULL && msgstr_suffix == NULL)
660 else if (msgstr_prefix == NULL && msgstr_suffix != NULL)
663 /* Default output directory is the current directory. */
664 if (output_dir == NULL)
667 /* Construct the name of the output file. If the default domain has
668 the special name "-" we write to stdout. */
671 if (IS_ABSOLUTE_PATH (output_file) || strcmp (output_file, "-") == 0)
672 file_name = xstrdup (output_file);
674 /* Please do NOT add a .po suffix! */
675 file_name = xconcatenated_filename (output_dir, output_file, NULL);
677 else if (strcmp (default_domain, "-") == 0)
680 file_name = xconcatenated_filename (output_dir, default_domain, ".po");
682 /* Determine list of files we have to process. */
683 if (files_from != NULL)
684 file_list = read_names_from_file (files_from);
686 file_list = string_list_alloc ();
687 /* Append names from command line. */
688 for (cnt = optind; cnt < argc; ++cnt)
689 string_list_append_unique (file_list, argv[cnt]);
691 /* Allocate converter from xgettext_global_source_encoding to UTF-8 (except
692 from ASCII or UTF-8, when this conversion is a no-op). */
693 if (xgettext_global_source_encoding != po_charset_ascii
694 && xgettext_global_source_encoding != po_charset_utf8)
699 /* Avoid glibc-2.1 bug with EUC-KR. */
700 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
701 && !defined _LIBICONV_VERSION
702 if (strcmp (xgettext_global_source_encoding, "EUC-KR") == 0)
706 cd = iconv_open (po_charset_utf8, xgettext_global_source_encoding);
707 if (cd == (iconv_t)(-1))
708 error (EXIT_FAILURE, 0, _("\
709 Cannot convert from \"%s\" to \"%s\". %s relies on iconv(), \
710 and iconv() does not support this conversion."),
711 xgettext_global_source_encoding, po_charset_utf8,
712 basename (program_name));
713 xgettext_global_source_iconv = cd;
715 error (EXIT_FAILURE, 0, _("\
716 Cannot convert from \"%s\" to \"%s\". %s relies on iconv(). \
717 This version was built without iconv()."),
718 xgettext_global_source_encoding, po_charset_utf8,
719 basename (program_name));
723 /* Allocate a message list to remember all the messages. */
724 mdlp = msgdomain_list_alloc (true);
726 /* Generate a header, so that we know how and when this PO file was
728 if (!xgettext_omit_header)
729 message_list_append (mdlp->item[0]->messages, construct_header ());
731 /* Read in the old messages, so that we can add to them. */
734 /* Temporarily reset the directory list to empty, because file_name
735 is an output file and therefore should not be searched for. */
736 void *saved_directory_list = dir_list_save_reset ();
737 extractor_ty po_extractor = { extract_po, NULL, NULL, NULL };
739 extract_from_file (file_name, po_extractor, mdlp);
740 if (!is_ascii_msgdomain_list (mdlp))
741 mdlp = iconv_msgdomain_list (mdlp, "UTF-8", true, file_name);
743 dir_list_restore (saved_directory_list);
746 /* Process all input files. */
747 for (i = 0; i < file_list->nitems; i++)
749 const char *filename;
750 extractor_ty this_file_extractor;
752 filename = file_list->item[i];
755 this_file_extractor = extractor;
760 const char *extension;
761 const char *language;
763 base = strrchr (filename, '/');
767 reduced = xstrdup (base);
768 /* Remove a trailing ".in" - it's a generic suffix. */
769 if (strlen (reduced) >= 3
770 && memcmp (reduced + strlen (reduced) - 3, ".in", 3) == 0)
771 reduced[strlen (reduced) - 3] = '\0';
773 /* Work out what the file extension is. */
774 extension = strrchr (reduced, '.');
780 /* Derive the language from the extension, and the extractor
781 function from the language. */
782 language = extension_to_language (extension);
783 if (language == NULL)
786 warning: file '%s' extension '%s' is unknown; will try C"), filename, extension);
789 this_file_extractor = language_to_extractor (language);
794 /* Extract the strings from the file. */
795 extract_from_file (filename, this_file_extractor, mdlp);
797 string_list_free (file_list);
799 /* Finalize the constructed header. */
800 if (!xgettext_omit_header)
801 finalize_header (mdlp);
803 /* Free the allocated converter. */
805 if (xgettext_global_source_encoding != po_charset_ascii
806 && xgettext_global_source_encoding != po_charset_utf8)
807 iconv_close (xgettext_global_source_iconv);
810 /* Sorting the list of messages. */
812 msgdomain_list_sort_by_filepos (mdlp);
813 else if (sort_by_msgid)
814 msgdomain_list_sort_by_msgid (mdlp);
816 /* Write the PO file. */
817 msgdomain_list_print (mdlp, file_name, output_syntax, force_po, do_debug);
823 /* Display usage information and exit. */
827 if (status != EXIT_SUCCESS)
828 fprintf (stderr, _("Try '%s --help' for more information.\n"),
833 Usage: %s [OPTION] [INPUTFILE]...\n\
837 Extract translatable strings from given input files.\n\
840 /* xgettext: no-wrap */
842 Mandatory arguments to long options are mandatory for short options too.\n\
843 Similarly for optional arguments.\n\
847 Input file location:\n"));
849 INPUTFILE ... input files\n"));
851 -f, --files-from=FILE get list of input files from FILE\n"));
853 -D, --directory=DIRECTORY add DIRECTORY to list for input files search\n"));
855 If input file is -, standard input is read.\n"));
858 Output file location:\n"));
860 -d, --default-domain=NAME use NAME.po for output (instead of messages.po)\n"));
862 -o, --output=FILE write output to specified file\n"));
864 -p, --output-dir=DIR output files will be placed in directory DIR\n"));
866 If output file is -, output is written to standard output.\n"));
869 Choice of input file language:\n"));
871 -L, --language=NAME recognise the specified language\n\
872 (C, C++, ObjectiveC, PO, Shell, Python, Lisp,\n\
873 EmacsLisp, librep, Scheme, Smalltalk, Java,\n\
874 JavaProperties, C#, awk, YCP, Tcl, Perl, PHP,\n\
875 GCC-source, NXStringTable, RST, Glade, Lua,\n\
876 JavaScript, Vala)\n"));
878 -C, --c++ shorthand for --language=C++\n"));
880 By default the language is guessed depending on the input file name extension.\n"));
883 Input file interpretation:\n"));
885 --from-code=NAME encoding of input files\n\
886 (except for Python, Tcl, Glade)\n"));
888 By default the input files are assumed to be in ASCII.\n"));
891 Operation mode:\n"));
893 -j, --join-existing join messages with existing file\n"));
895 -x, --exclude-file=FILE.po entries from FILE.po are not extracted\n"));
897 -cTAG, --add-comments=TAG place comment blocks starting with TAG and\n\
898 preceding keyword lines in output file\n\
899 -c, --add-comments place all comment blocks preceding keyword lines\n\
903 Language specific options:\n"));
905 -a, --extract-all extract all strings\n"));
907 (only languages C, C++, ObjectiveC, Shell,\n\
908 Python, Lisp, EmacsLisp, librep, Scheme, Java,\n\
909 C#, awk, Tcl, Perl, PHP, GCC-source, Glade,\n\
910 Lua, JavaScript, Vala)\n"));
912 -kWORD, --keyword=WORD look for WORD as an additional keyword\n\
913 -k, --keyword do not to use default keywords\n"));
915 (only languages C, C++, ObjectiveC, Shell,\n\
916 Python, Lisp, EmacsLisp, librep, Scheme, Java,\n\
917 C#, awk, Tcl, Perl, PHP, GCC-source, Glade,\n\
918 Lua, JavaScript, Vala)\n"));
920 --flag=WORD:ARG:FLAG additional flag for strings inside the argument\n\
921 number ARG of keyword WORD\n"));
923 (only languages C, C++, ObjectiveC, Shell,\n\
924 Python, Lisp, EmacsLisp, librep, Scheme, Java,\n\
925 C#, awk, YCP, Tcl, Perl, PHP, GCC-source,\n\
926 Lua, JavaScript, Vala)\n"));
928 -T, --trigraphs understand ANSI C trigraphs for input\n"));
930 (only languages C, C++, ObjectiveC)\n"));
932 --qt recognize Qt format strings\n"));
934 (only language C++)\n"));
936 --kde recognize KDE 4 format strings\n"));
938 (only language C++)\n"));
940 --boost recognize Boost format strings\n"));
942 (only language C++)\n"));
944 --debug more detailed formatstring recognition result\n"));
947 Output details:\n"));
949 --color use colors and other text attributes always\n\
950 --color=WHEN use colors and other text attributes if WHEN.\n\
951 WHEN may be 'always', 'never', 'auto', or 'html'.\n"));
953 --style=STYLEFILE specify CSS style rule file for --color\n"));
955 -e, --no-escape do not use C escapes in output (default)\n"));
957 -E, --escape use C escapes in output, no extended chars\n"));
959 --force-po write PO file even if empty\n"));
961 -i, --indent write the .po file using indented style\n"));
963 --no-location do not write '#: filename:line' lines\n"));
965 -n, --add-location generate '#: filename:line' lines (default)\n"));
967 --strict write out strict Uniforum conforming .po file\n"));
969 --properties-output write out a Java .properties file\n"));
971 --stringtable-output write out a NeXTstep/GNUstep .strings file\n"));
973 -w, --width=NUMBER set output page width\n"));
975 --no-wrap do not break long message lines, longer than\n\
976 the output page width, into several lines\n"));
978 -s, --sort-output generate sorted output\n"));
980 -F, --sort-by-file sort output by file location\n"));
982 --omit-header don't write header with 'msgid \"\"' entry\n"));
984 --copyright-holder=STRING set copyright holder in output\n"));
986 --foreign-user omit FSF copyright in output for foreign user\n"));
988 --package-name=PACKAGE set package name in output\n"));
990 --package-version=VERSION set package version in output\n"));
992 --msgid-bugs-address=EMAIL@ADDRESS set report address for msgid bugs\n"));
994 -m[STRING], --msgstr-prefix[=STRING] use STRING or \"\" as prefix for msgstr\n\
997 -M[STRING], --msgstr-suffix[=STRING] use STRING or \"\" as suffix for msgstr\n\
1001 Informative output:\n"));
1003 -h, --help display this help and exit\n"));
1005 -V, --version output version information and exit\n"));
1007 /* TRANSLATORS: The placeholder indicates the bug-reporting address
1008 for this package. Please add _another line_ saying
1009 "Report translation bugs to <...>\n" with the address for translation
1010 bugs (typically your translation team's web or email address). */
1011 fputs (_("Report bugs to <bug-gnu-gettext@gnu.org>.\n"),
1020 exclude_directive_domain (abstract_catalog_reader_ty *pop, char *name)
1022 po_gram_error_at_line (&gram_pos,
1023 _("this file may not contain domain directives"));
1028 exclude_directive_message (abstract_catalog_reader_ty *pop,
1031 lex_pos_ty *msgid_pos,
1033 char *msgstr, size_t msgstr_len,
1034 lex_pos_ty *msgstr_pos,
1037 char *prev_msgid_plural,
1038 bool force_fuzzy, bool obsolete)
1042 /* See if this message ID has been seen before. */
1043 if (exclude == NULL)
1044 exclude = message_list_alloc (true);
1045 mp = message_list_search (exclude, msgctxt, msgid);
1050 mp = message_alloc (msgctxt, msgid, msgid_plural, "", 1, msgstr_pos);
1051 /* Do not free msgid. */
1052 message_list_append (exclude, mp);
1055 /* All we care about is the msgid. Throw the msgstr away.
1056 Don't even check for duplicate msgids. */
1061 /* So that the one parser can be used for multiple programs, and also
1062 use good data hiding and encapsulation practices, an object
1063 oriented approach has been taken. An object instance is allocated,
1064 and all actions resulting from the parse will be through
1065 invocations of method functions of that object. */
1067 static abstract_catalog_reader_class_ty exclude_methods =
1069 sizeof (abstract_catalog_reader_ty),
1070 NULL, /* constructor */
1071 NULL, /* destructor */
1072 NULL, /* parse_brief */
1073 NULL, /* parse_debrief */
1074 exclude_directive_domain,
1075 exclude_directive_message,
1077 NULL, /* comment_dot */
1078 NULL, /* comment_filepos */
1079 NULL, /* comment_special */
1084 read_exclusion_file (char *filename)
1086 char *real_filename;
1087 FILE *fp = open_catalog_file (filename, &real_filename, true);
1088 abstract_catalog_reader_ty *pop;
1090 pop = catalog_reader_alloc (&exclude_methods);
1091 catalog_reader_parse (pop, fp, real_filename, filename, &input_format_po);
1092 catalog_reader_free (pop);
1100 split_keywordspec (const char *spec,
1101 const char **endp, struct callshape *shapep)
1107 bool argnum1_glib_context = false;
1108 bool argnum2_glib_context = false;
1110 string_list_ty xcomments;
1112 string_list_init (&xcomments);
1114 /* Start parsing from the end. */
1115 p = spec + strlen (spec);
1118 if (isdigit ((unsigned char) p[-1])
1119 || ((p[-1] == 'c' || p[-1] == 'g' || p[-1] == 't')
1120 && p - 1 > spec && isdigit ((unsigned char) p[-2])))
1122 bool contextp = (p[-1] == 'c');
1123 bool glibp = (p[-1] == 'g');
1124 bool totalp = (p[-1] == 't');
1128 while (p > spec && isdigit ((unsigned char) p[-1]));
1130 if (p > spec && (p[-1] == ',' || p[-1] == ':'))
1133 int arg = strtol (p, &dummy, 10);
1138 /* Only one context argument can be given. */
1145 /* Only one total number of arguments can be given. */
1152 /* At most two normal arguments can be given. */
1155 argnum2_glib_context = argnum1_glib_context;
1157 argnum1_glib_context = glibp;
1163 else if (p[-1] == '"')
1165 const char *xcomment_end;
1170 while (p > spec && p[-1] != '"')
1173 if (p > spec /* && p[-1] == '"' */)
1175 const char *xcomment_start;
1179 if (p > spec && (p[-1] == ',' || p[-1] == ':'))
1181 size_t xcomment_len = xcomment_end - xcomment_start;
1182 char *xcomment = XNMALLOC (xcomment_len + 1, char);
1184 memcpy (xcomment, xcomment_start, xcomment_len);
1185 xcomment[xcomment_len] = '\0';
1186 string_list_append (&xcomments, xcomment);
1197 /* Here an element of the comma-separated list has been parsed. */
1198 if (!(p > spec && (p[-1] == ',' || p[-1] == ':')))
1205 if (argnum1 == 0 && argnum2 == 0)
1206 /* At least one non-context argument must be given. */
1209 && (argnum1_glib_context || argnum2_glib_context))
1210 /* Incompatible ways to specify the context. */
1213 shapep->argnum1 = (argnum1 > 0 ? argnum1 : 1);
1214 shapep->argnum2 = argnum2;
1215 shapep->argnumc = argnumc;
1216 shapep->argnum1_glib_context = argnum1_glib_context;
1217 shapep->argnum2_glib_context = argnum2_glib_context;
1218 shapep->argtotal = argtotal;
1219 /* Reverse the order of the xcomments. */
1220 string_list_init (&shapep->xcomments);
1221 for (i = xcomments.nitems; i > 0; )
1222 string_list_append (&shapep->xcomments, xcomments.item[--i]);
1223 string_list_destroy (&xcomments);
1228 /* Couldn't parse the desired syntax. */
1229 *endp = spec + strlen (spec);
1230 shapep->argnum1 = 1;
1231 shapep->argnum2 = 0;
1232 shapep->argnumc = 0;
1233 shapep->argnum1_glib_context = false;
1234 shapep->argnum2_glib_context = false;
1235 shapep->argtotal = 0;
1236 string_list_init (&shapep->xcomments);
1237 string_list_destroy (&xcomments);
1242 insert_keyword_callshape (hash_table *table,
1243 const char *keyword, size_t keyword_len,
1244 const struct callshape *shape)
1248 if (hash_find_entry (table, keyword, keyword_len, &old_value))
1250 /* Create a one-element 'struct callshapes'. */
1251 struct callshapes *shapes = XMALLOC (struct callshapes);
1252 shapes->nshapes = 1;
1253 shapes->shapes[0] = *shape;
1255 (const char *) hash_insert_entry (table, keyword, keyword_len, shapes);
1256 if (keyword == NULL)
1258 shapes->keyword = keyword;
1259 shapes->keyword_len = keyword_len;
1263 /* Found a 'struct callshapes'. See whether it already contains the
1265 struct callshapes *old_shapes = (struct callshapes *) old_value;
1270 for (i = 0; i < old_shapes->nshapes; i++)
1271 if (old_shapes->shapes[i].argnum1 == shape->argnum1
1272 && old_shapes->shapes[i].argnum2 == shape->argnum2
1273 && old_shapes->shapes[i].argnumc == shape->argnumc
1274 && old_shapes->shapes[i].argnum1_glib_context
1275 == shape->argnum1_glib_context
1276 && old_shapes->shapes[i].argnum2_glib_context
1277 == shape->argnum2_glib_context
1278 && old_shapes->shapes[i].argtotal == shape->argtotal)
1280 old_shapes->shapes[i].xcomments = shape->xcomments;
1287 /* Replace the existing 'struct callshapes' with a new one. */
1288 struct callshapes *shapes =
1289 (struct callshapes *)
1290 xmalloc (xsum (sizeof (struct callshapes),
1291 xtimes (old_shapes->nshapes,
1292 sizeof (struct callshape))));
1294 shapes->keyword = old_shapes->keyword;
1295 shapes->keyword_len = old_shapes->keyword_len;
1296 shapes->nshapes = old_shapes->nshapes + 1;
1297 for (i = 0; i < old_shapes->nshapes; i++)
1298 shapes->shapes[i] = old_shapes->shapes[i];
1299 shapes->shapes[i] = *shape;
1300 if (hash_set_value (table, keyword, keyword_len, shapes))
1309 flag_context_ty null_context = { undecided, false, undecided, false };
1311 /* Transparent context. */
1312 flag_context_ty passthrough_context = { undecided, true, undecided, true };
1316 inherited_context (flag_context_ty outer_context,
1317 flag_context_ty modifier_context)
1319 flag_context_ty result = modifier_context;
1321 if (result.pass_format1)
1323 result.is_format1 = outer_context.is_format1;
1324 result.pass_format1 = false;
1326 if (result.pass_format2)
1328 result.is_format2 = outer_context.is_format2;
1329 result.pass_format2 = false;
1331 if (result.pass_format3)
1333 result.is_format3 = outer_context.is_format3;
1334 result.pass_format3 = false;
1340 /* Null context list iterator. */
1341 flag_context_list_iterator_ty null_context_list_iterator = { 1, NULL };
1343 /* Transparent context list iterator. */
1344 static flag_context_list_ty passthrough_context_circular_list =
1347 { undecided, true, undecided, true },
1348 &passthrough_context_circular_list
1350 flag_context_list_iterator_ty passthrough_context_list_iterator =
1353 &passthrough_context_circular_list
1357 flag_context_list_iterator_ty
1358 flag_context_list_iterator (flag_context_list_ty *list)
1360 flag_context_list_iterator_ty result;
1369 flag_context_list_iterator_advance (flag_context_list_iterator_ty *iter)
1371 if (iter->head == NULL)
1372 return null_context;
1373 if (iter->argnum == iter->head->argnum)
1375 flag_context_ty result = iter->head->flags;
1377 /* Special casing of circular list. */
1378 if (iter->head != iter->head->next)
1380 iter->head = iter->head->next;
1389 return null_context;
1394 flag_context_list_ty *
1395 flag_context_list_table_lookup (flag_context_list_table_ty *flag_table,
1396 const void *key, size_t keylen)
1400 if (flag_table->table != NULL
1401 && hash_find_entry (flag_table, key, keylen, &entry) == 0)
1402 return (flag_context_list_ty *) entry;
1409 flag_context_list_table_insert (flag_context_list_table_ty *table,
1411 const char *name_start, const char *name_end,
1412 int argnum, enum is_format value, bool pass)
1414 char *allocated_name = NULL;
1416 if (table == &flag_table_lisp)
1418 /* Convert NAME to upper case. */
1419 size_t name_len = name_end - name_start;
1420 char *name = allocated_name = (char *) xmalloca (name_len);
1423 for (i = 0; i < name_len; i++)
1424 name[i] = (name_start[i] >= 'a' && name_start[i] <= 'z'
1425 ? name_start[i] - 'a' + 'A'
1428 name_end = name + name_len;
1430 else if (table == &flag_table_tcl)
1432 /* Remove redundant "::" prefix. */
1433 if (name_end - name_start > 2
1434 && name_start[0] == ':' && name_start[1] == ':')
1438 /* Insert the pair (VALUE, PASS) at INDEX in the element numbered ARGNUM
1439 of the list corresponding to NAME in the TABLE. */
1440 if (table->table == NULL)
1441 hash_init (table, 100);
1445 if (hash_find_entry (table, name_start, name_end - name_start, &entry) != 0)
1447 /* Create new hash table entry. */
1448 flag_context_list_ty *list = XMALLOC (flag_context_list_ty);
1449 list->argnum = argnum;
1450 memset (&list->flags, '\0', sizeof (list->flags));
1454 list->flags.is_format1 = value;
1455 list->flags.pass_format1 = pass;
1458 list->flags.is_format2 = value;
1459 list->flags.pass_format2 = pass;
1462 list->flags.is_format3 = value;
1463 list->flags.pass_format3 = pass;
1469 hash_insert_entry (table, name_start, name_end - name_start, list);
1473 flag_context_list_ty *list = (flag_context_list_ty *)entry;
1474 flag_context_list_ty **lastp = NULL;
1475 /* Invariant: list == (lastp != NULL ? *lastp : entry). */
1477 while (list != NULL && list->argnum < argnum)
1479 lastp = &list->next;
1482 if (list != NULL && list->argnum == argnum)
1484 /* Add this flag to the current argument number. */
1488 list->flags.is_format1 = value;
1489 list->flags.pass_format1 = pass;
1492 list->flags.is_format2 = value;
1493 list->flags.pass_format2 = pass;
1496 list->flags.is_format3 = value;
1497 list->flags.pass_format3 = pass;
1503 else if (lastp != NULL)
1505 /* Add a new list entry for this argument number. */
1506 list = XMALLOC (flag_context_list_ty);
1507 list->argnum = argnum;
1508 memset (&list->flags, '\0', sizeof (list->flags));
1512 list->flags.is_format1 = value;
1513 list->flags.pass_format1 = pass;
1516 list->flags.is_format2 = value;
1517 list->flags.pass_format2 = pass;
1520 list->flags.is_format3 = value;
1521 list->flags.pass_format3 = pass;
1526 list->next = *lastp;
1531 /* Add a new list entry for this argument number, at the beginning
1532 of the list. Since we don't have an API for replacing the
1533 value of a key in the hash table, we have to copy the first
1535 flag_context_list_ty *copy = XMALLOC (flag_context_list_ty);
1538 list->argnum = argnum;
1539 memset (&list->flags, '\0', sizeof (list->flags));
1543 list->flags.is_format1 = value;
1544 list->flags.pass_format1 = pass;
1547 list->flags.is_format2 = value;
1548 list->flags.pass_format2 = pass;
1551 list->flags.is_format3 = value;
1552 list->flags.pass_format3 = pass;
1562 if (allocated_name != NULL)
1563 freea (allocated_name);
1568 xgettext_record_flag (const char *optionstring)
1570 /* Check the string has at least two colons. (Colons in the name are
1571 allowed, needed for the Lisp and the Tcl backends.) */
1575 for (colon2 = optionstring + strlen (optionstring); ; )
1577 if (colon2 == optionstring)
1583 for (colon1 = colon2; ; )
1585 if (colon1 == optionstring)
1592 const char *name_start = optionstring;
1593 const char *name_end = colon1;
1594 const char *argnum_start = colon1 + 1;
1595 const char *argnum_end = colon2;
1596 const char *flag = colon2 + 1;
1599 /* Check the parts' syntax. */
1600 if (name_end == name_start)
1602 if (argnum_end == argnum_start)
1606 argnum = strtol (argnum_start, &endp, 10);
1607 if (endp != argnum_end)
1613 /* Analyze the flag part. */
1618 if (strlen (flag) >= 5 && memcmp (flag, "pass-", 5) == 0)
1624 /* Unlike po_parse_comment_special(), we don't accept "fuzzy" or "wrap"
1625 here - it has no sense. */
1626 if (strlen (flag) >= 7
1627 && memcmp (flag + strlen (flag) - 7, "-format", 7) == 0)
1631 enum is_format value;
1635 n = strlen (flag) - 7;
1637 if (n >= 3 && memcmp (p, "no-", 3) == 0)
1643 else if (n >= 9 && memcmp (p, "possible-", 9) == 0)
1649 else if (n >= 11 && memcmp (p, "impossible-", 11) == 0)
1656 value = yes_according_to_context;
1658 for (type = 0; type < NFORMATS; type++)
1659 if (strlen (format_language[type]) == n
1660 && memcmp (format_language[type], p, n) == 0)
1665 flag_context_list_table_insert (&flag_table_c, 0,
1666 name_start, name_end,
1667 argnum, value, pass);
1668 flag_context_list_table_insert (&flag_table_cxx_qt, 0,
1669 name_start, name_end,
1670 argnum, value, pass);
1671 flag_context_list_table_insert (&flag_table_cxx_kde, 0,
1672 name_start, name_end,
1673 argnum, value, pass);
1674 flag_context_list_table_insert (&flag_table_cxx_boost, 0,
1675 name_start, name_end,
1676 argnum, value, pass);
1677 flag_context_list_table_insert (&flag_table_objc, 0,
1678 name_start, name_end,
1679 argnum, value, pass);
1682 flag_context_list_table_insert (&flag_table_objc, 1,
1683 name_start, name_end,
1684 argnum, value, pass);
1687 flag_context_list_table_insert (&flag_table_sh, 0,
1688 name_start, name_end,
1689 argnum, value, pass);
1692 flag_context_list_table_insert (&flag_table_python, 0,
1693 name_start, name_end,
1694 argnum, value, pass);
1696 case format_python_brace:
1697 flag_context_list_table_insert (&flag_table_python, 0,
1698 name_start, name_end,
1699 argnum, value, pass);
1702 flag_context_list_table_insert (&flag_table_lisp, 0,
1703 name_start, name_end,
1704 argnum, value, pass);
1707 flag_context_list_table_insert (&flag_table_elisp, 0,
1708 name_start, name_end,
1709 argnum, value, pass);
1712 flag_context_list_table_insert (&flag_table_librep, 0,
1713 name_start, name_end,
1714 argnum, value, pass);
1717 flag_context_list_table_insert (&flag_table_scheme, 0,
1718 name_start, name_end,
1719 argnum, value, pass);
1721 case format_smalltalk:
1724 flag_context_list_table_insert (&flag_table_java, 0,
1725 name_start, name_end,
1726 argnum, value, pass);
1729 flag_context_list_table_insert (&flag_table_csharp, 0,
1730 name_start, name_end,
1731 argnum, value, pass);
1734 flag_context_list_table_insert (&flag_table_awk, 0,
1735 name_start, name_end,
1736 argnum, value, pass);
1741 flag_context_list_table_insert (&flag_table_ycp, 0,
1742 name_start, name_end,
1743 argnum, value, pass);
1746 flag_context_list_table_insert (&flag_table_tcl, 0,
1747 name_start, name_end,
1748 argnum, value, pass);
1751 flag_context_list_table_insert (&flag_table_perl, 0,
1752 name_start, name_end,
1753 argnum, value, pass);
1755 case format_perl_brace:
1756 flag_context_list_table_insert (&flag_table_perl, 1,
1757 name_start, name_end,
1758 argnum, value, pass);
1761 flag_context_list_table_insert (&flag_table_php, 0,
1762 name_start, name_end,
1763 argnum, value, pass);
1765 case format_gcc_internal:
1766 flag_context_list_table_insert (&flag_table_gcc_internal, 0,
1767 name_start, name_end,
1768 argnum, value, pass);
1770 case format_gfc_internal:
1771 flag_context_list_table_insert (&flag_table_gcc_internal, 1,
1772 name_start, name_end,
1773 argnum, value, pass);
1776 flag_context_list_table_insert (&flag_table_cxx_qt, 1,
1777 name_start, name_end,
1778 argnum, value, pass);
1780 case format_qt_plural:
1781 flag_context_list_table_insert (&flag_table_cxx_qt, 2,
1782 name_start, name_end,
1783 argnum, value, pass);
1786 flag_context_list_table_insert (&flag_table_cxx_kde, 1,
1787 name_start, name_end,
1788 argnum, value, pass);
1791 flag_context_list_table_insert (&flag_table_cxx_boost, 1,
1792 name_start, name_end,
1793 argnum, value, pass);
1796 flag_context_list_table_insert (&flag_table_lua, 0,
1797 name_start, name_end,
1798 argnum, value, pass);
1800 case format_javascript:
1801 flag_context_list_table_insert (&flag_table_javascript, 0,
1802 name_start, name_end,
1803 argnum, value, pass);
1810 /* If the flag is not among the valid values, the optionstring is
1817 error (EXIT_FAILURE, 0, _("\
1818 A --flag argument doesn't have the <keyword>:<argnum>:[pass-]<flag> syntax: %s"),
1823 /* Comment handling: There is a list of automatic comments that may be appended
1824 to the next message. Used by remember_a_message(). */
1826 static string_list_ty *comment;
1829 xgettext_comment_add (const char *str)
1831 if (comment == NULL)
1832 comment = string_list_alloc ();
1833 string_list_append (comment, str);
1837 xgettext_comment (size_t n)
1839 if (comment == NULL || n >= comment->nitems)
1841 return comment->item[n];
1845 xgettext_comment_reset ()
1847 if (comment != NULL)
1849 string_list_free (comment);
1855 refcounted_string_list_ty *savable_comment;
1858 savable_comment_add (const char *str)
1860 if (savable_comment == NULL)
1862 savable_comment = XMALLOC (refcounted_string_list_ty);
1863 savable_comment->refcount = 1;
1864 string_list_init (&savable_comment->contents);
1866 else if (savable_comment->refcount > 1)
1868 /* Unshare the list by making copies. */
1869 struct string_list_ty *oldcontents;
1872 savable_comment->refcount--;
1873 oldcontents = &savable_comment->contents;
1875 savable_comment = XMALLOC (refcounted_string_list_ty);
1876 savable_comment->refcount = 1;
1877 string_list_init (&savable_comment->contents);
1878 for (i = 0; i < oldcontents->nitems; i++)
1879 string_list_append (&savable_comment->contents, oldcontents->item[i]);
1881 string_list_append (&savable_comment->contents, str);
1885 savable_comment_reset ()
1887 drop_reference (savable_comment);
1888 savable_comment = NULL;
1892 savable_comment_to_xgettext_comment (refcounted_string_list_ty *rslp)
1894 xgettext_comment_reset ();
1899 for (i = 0; i < rslp->contents.nitems; i++)
1900 xgettext_comment_add (rslp->contents.item[i]);
1907 xgettext_open (const char *fn,
1908 char **logical_file_name_p, char **real_file_name_p)
1912 char *logical_file_name;
1914 if (strcmp (fn, "-") == 0)
1916 new_name = xstrdup (_("standard input"));
1917 logical_file_name = xstrdup (new_name);
1920 else if (IS_ABSOLUTE_PATH (fn))
1922 new_name = xstrdup (fn);
1923 fp = fopen (fn, "r");
1925 error (EXIT_FAILURE, errno, _("\
1926 error while opening \"%s\" for reading"), fn);
1927 logical_file_name = xstrdup (new_name);
1935 const char *dir = dir_list_nth (j);
1938 error (EXIT_FAILURE, ENOENT, _("\
1939 error while opening \"%s\" for reading"), fn);
1941 new_name = xconcatenated_filename (dir, fn, NULL);
1943 fp = fopen (new_name, "r");
1947 if (errno != ENOENT)
1948 error (EXIT_FAILURE, errno, _("\
1949 error while opening \"%s\" for reading"), new_name);
1953 /* Note that the NEW_NAME variable contains the actual file name
1954 and the logical file name is what is reported by xgettext. In
1955 this case NEW_NAME is set to the file which was found along the
1956 directory search path, and LOGICAL_FILE_NAME is is set to the
1957 file name which was searched for. */
1958 logical_file_name = xstrdup (fn);
1961 *logical_file_name_p = logical_file_name;
1962 *real_file_name_p = new_name;
1967 /* Language dependent format string parser.
1968 NULL if the language has no notion of format strings. */
1969 static struct formatstring_parser *current_formatstring_parser1;
1970 static struct formatstring_parser *current_formatstring_parser2;
1971 static struct formatstring_parser *current_formatstring_parser3;
1975 extract_from_file (const char *file_name, extractor_ty extractor,
1976 msgdomain_list_ty *mdlp)
1978 char *logical_file_name;
1979 char *real_file_name;
1980 FILE *fp = xgettext_open (file_name, &logical_file_name, &real_file_name);
1982 /* Set the default for the source file encoding. May be overridden by
1983 the extractor function. */
1984 xgettext_current_source_encoding = xgettext_global_source_encoding;
1986 xgettext_current_source_iconv = xgettext_global_source_iconv;
1989 current_formatstring_parser1 = extractor.formatstring_parser1;
1990 current_formatstring_parser2 = extractor.formatstring_parser2;
1991 current_formatstring_parser3 = extractor.formatstring_parser3;
1992 extractor.func (fp, real_file_name, logical_file_name, extractor.flag_table,
1997 free (logical_file_name);
1998 free (real_file_name);
2003 /* Error message about non-ASCII character in a specific lexical context. */
2005 non_ascii_error_message (lexical_context_ty lcontext,
2006 const char *file_name, size_t line_number)
2011 if (line_number == (size_t)(-1))
2014 sprintf (buffer, ":%ld", (long) line_number);
2020 xasprintf (_("Non-ASCII character at %s%s."), file_name, buffer);
2024 xasprintf (_("Non-ASCII comment at or before %s%s."),
2029 xasprintf (_("Non-ASCII string at %s%s."), file_name, buffer);
2037 /* Convert the given string from xgettext_current_source_encoding to
2038 the output file encoding (i.e. ASCII or UTF-8).
2039 The resulting string is either the argument string, or freshly allocated.
2040 The file_name and line_number are only used for error message purposes. */
2042 from_current_source_encoding (const char *string,
2043 lexical_context_ty lcontext,
2044 const char *file_name, size_t line_number)
2046 if (xgettext_current_source_encoding == po_charset_ascii)
2048 if (!is_ascii_string (string))
2050 multiline_error (xstrdup (""),
2051 xasprintf ("%s\n%s\n",
2052 non_ascii_error_message (lcontext,
2056 Please specify the source encoding through --from-code.")));
2057 exit (EXIT_FAILURE);
2060 else if (xgettext_current_source_encoding != po_charset_utf8)
2063 struct conversion_context context;
2065 context.from_code = xgettext_current_source_encoding;
2066 context.to_code = po_charset_utf8;
2067 context.from_filename = file_name;
2068 context.message = NULL;
2070 string = convert_string_directly (xgettext_current_source_iconv, string,
2073 /* If we don't have iconv(), the only supported values for
2074 xgettext_global_source_encoding and thus also for
2075 xgettext_current_source_encoding are ASCII and UTF-8.
2076 convert_string_directly() should not be called in this case. */
2081 return (char *) string;
2084 #define CONVERT_STRING(string, lcontext) \
2085 string = from_current_source_encoding (string, lcontext, pos->file_name, \
2089 /* Update the is_format[] flags depending on the information given in the
2092 set_format_flags_from_context (enum is_format is_format[NFORMATS],
2093 flag_context_ty context, const char *string,
2094 lex_pos_ty *pos, const char *pretty_msgstr)
2098 if (context.is_format1 != undecided
2099 || context.is_format2 != undecided
2100 || context.is_format3 != undecided)
2101 for (i = 0; i < NFORMATS; i++)
2103 if (is_format[i] == undecided)
2105 if (formatstring_parsers[i] == current_formatstring_parser1
2106 && context.is_format1 != undecided)
2107 is_format[i] = (enum is_format) context.is_format1;
2108 if (formatstring_parsers[i] == current_formatstring_parser2
2109 && context.is_format2 != undecided)
2110 is_format[i] = (enum is_format) context.is_format2;
2111 if (formatstring_parsers[i] == current_formatstring_parser3
2112 && context.is_format3 != undecided)
2113 is_format[i] = (enum is_format) context.is_format3;
2115 if (possible_format_p (is_format[i]))
2117 struct formatstring_parser *parser = formatstring_parsers[i];
2118 char *invalid_reason = NULL;
2119 void *descr = parser->parse (string, false, NULL, &invalid_reason);
2122 parser->free (descr);
2125 /* The string is not a valid format string. */
2126 if (is_format[i] != possible)
2130 error_with_progname = false;
2131 if (pos->line_number == (size_t)(-1))
2134 sprintf (buffer, ":%ld", (long) pos->line_number);
2135 multiline_warning (xasprintf (_("%s%s: warning: "),
2136 pos->file_name, buffer),
2137 xasprintf (is_format[i] == yes_according_to_context
2138 ? _("Although being used in a format string position, the %s is not a valid %s format string. Reason: %s\n")
2139 : _("Although declared as such, the %s is not a valid %s format string. Reason: %s\n"),
2141 format_language_pretty[i],
2143 error_with_progname = true;
2146 is_format[i] = impossible;
2147 free (invalid_reason);
2155 warn_format_string (enum is_format is_format[NFORMATS], const char *string,
2156 lex_pos_ty *pos, const char *pretty_msgstr)
2158 if (possible_format_p (is_format[format_python])
2159 && get_python_format_unnamed_arg_count (string) > 1)
2163 error_with_progname = false;
2164 if (pos->line_number == (size_t)(-1))
2167 sprintf (buffer, ":%ld", (long) pos->line_number);
2168 multiline_warning (xasprintf (_("%s%s: warning: "),
2169 pos->file_name, buffer),
2171 '%s' format string with unnamed arguments cannot be properly localized:\n\
2172 The translator cannot reorder the arguments.\n\
2173 Please consider using a format string with named arguments,\n\
2174 and a mapping instead of a tuple for the arguments.\n"),
2176 error_with_progname = true;
2182 remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid,
2183 flag_context_ty context, lex_pos_ty *pos,
2184 const char *extracted_comment,
2185 refcounted_string_list_ty *comment)
2187 enum is_format is_format[NFORMATS];
2188 struct argument_range range;
2189 enum is_wrap do_wrap;
2194 /* See whether we shall exclude this message. */
2195 if (exclude != NULL && message_list_search (exclude, msgctxt, msgid) != NULL)
2197 /* Tell the lexer to reset its comment buffer, so that the next
2198 message gets the correct comments. */
2199 xgettext_comment_reset ();
2200 savable_comment_reset ();
2202 if (msgctxt != NULL)
2209 savable_comment_to_xgettext_comment (comment);
2211 for (i = 0; i < NFORMATS; i++)
2212 is_format[i] = undecided;
2215 do_wrap = undecided;
2217 if (msgctxt != NULL)
2218 CONVERT_STRING (msgctxt, lc_string);
2219 CONVERT_STRING (msgid, lc_string);
2221 if (msgctxt == NULL && msgid[0] == '\0' && !xgettext_omit_header)
2225 error_with_progname = false;
2226 if (pos->line_number == (size_t)(-1))
2229 sprintf (buffer, ":%ld", (long) pos->line_number);
2230 multiline_warning (xasprintf (_("%s%s: warning: "), pos->file_name,
2233 Empty msgid. It is reserved by GNU gettext:\n\
2234 gettext(\"\") returns the header entry with\n\
2235 meta information, not the empty string.\n")));
2236 error_with_progname = true;
2239 /* See if we have seen this message before. */
2240 mp = message_list_search (mlp, msgctxt, msgid);
2243 if (msgctxt != NULL)
2246 for (i = 0; i < NFORMATS; i++)
2247 is_format[i] = mp->is_format[i];
2248 do_wrap = mp->do_wrap;
2252 /* Construct the msgstr from the prefix and suffix, otherwise use the
2255 msgstr = xasprintf ("%s%s%s", msgstr_prefix, msgid, msgstr_suffix);
2259 /* Allocate a new message and append the message to the list. */
2260 mp = message_alloc (msgctxt, msgid, NULL, msgstr, strlen (msgstr) + 1,
2262 /* Do not free msgctxt and msgid. */
2263 message_list_append (mlp, mp);
2266 /* Determine whether the context specifies that the msgid is a format
2268 set_format_flags_from_context (is_format, context, mp->msgid, pos, "msgid");
2270 /* Ask the lexer for the comments it has seen. */
2272 size_t nitems_before;
2273 size_t nitems_after;
2275 bool add_all_remaining_comments;
2277 nitems_before = (mp->comment_dot != NULL ? mp->comment_dot->nitems : 0);
2279 if (extracted_comment != NULL)
2281 char *copy = xstrdup (extracted_comment);
2285 while (*rest != '\0')
2287 char *newline = strchr (rest, '\n');
2289 if (newline != NULL)
2292 message_comment_dot_append (mp, rest);
2297 message_comment_dot_append (mp, rest);
2304 add_all_remaining_comments = add_all_comments;
2307 const char *s = xgettext_comment (j);
2312 CONVERT_STRING (s, lc_comment);
2314 /* To reduce the possibility of unwanted matches we do a two
2315 step match: the line must contain 'xgettext:' and one of
2316 the possible format description strings. */
2317 if ((t = c_strstr (s, "xgettext:")) != NULL)
2320 enum is_format tmp_format[NFORMATS];
2321 struct argument_range tmp_range;
2322 enum is_wrap tmp_wrap;
2325 t += strlen ("xgettext:");
2327 po_parse_comment_special (t, &tmp_fuzzy, tmp_format, &tmp_range,
2330 interesting = false;
2331 for (i = 0; i < NFORMATS; i++)
2332 if (tmp_format[i] != undecided)
2334 is_format[i] = tmp_format[i];
2337 if (has_range_p (tmp_range))
2342 if (tmp_wrap != undecided)
2348 /* If the "xgettext:" marker was followed by an interesting
2349 keyword, and we updated our is_format/do_wrap variables,
2350 we don't print the comment as a #. comment. */
2354 /* When the comment tag is seen, it drags in not only the line
2355 which it starts, but all remaining comment lines. */
2356 if (add_all_remaining_comments
2357 || (add_all_remaining_comments =
2358 (comment_tag != NULL
2359 && strncmp (s, comment_tag, strlen (comment_tag)) == 0)))
2360 message_comment_dot_append (mp, s);
2363 nitems_after = (mp->comment_dot != NULL ? mp->comment_dot->nitems : 0);
2365 /* Don't add the comments if they are a repetition of the tail of the
2366 already present comments. This avoids unneeded duplication if the
2367 same message appears several times, each time with the same comment. */
2368 if (nitems_before < nitems_after)
2370 size_t added = nitems_after - nitems_before;
2372 if (added <= nitems_before)
2374 bool repeated = true;
2376 for (i = 0; i < added; i++)
2377 if (strcmp (mp->comment_dot->item[nitems_before - added + i],
2378 mp->comment_dot->item[nitems_before + i]) != 0)
2386 for (i = 0; i < added; i++)
2387 free ((char *) mp->comment_dot->item[nitems_before + i]);
2388 mp->comment_dot->nitems = nitems_before;
2394 /* If it is not already decided, through programmer comments, whether the
2395 msgid is a format string, examine the msgid. This is a heuristic. */
2396 for (i = 0; i < NFORMATS; i++)
2398 if (is_format[i] == undecided
2399 && (formatstring_parsers[i] == current_formatstring_parser1
2400 || formatstring_parsers[i] == current_formatstring_parser2
2401 || formatstring_parsers[i] == current_formatstring_parser3)
2402 /* But avoid redundancy: objc-format is stronger than c-format. */
2403 && !(i == format_c && possible_format_p (is_format[format_objc]))
2404 && !(i == format_objc && possible_format_p (is_format[format_c]))
2405 /* Avoid flagging a string as c-format when it's known to be a
2406 qt-format or qt-plural-format or kde-format or boost-format
2409 && (possible_format_p (is_format[format_qt])
2410 || possible_format_p (is_format[format_qt_plural])
2411 || possible_format_p (is_format[format_kde])
2412 || possible_format_p (is_format[format_boost]))))
2414 struct formatstring_parser *parser = formatstring_parsers[i];
2415 char *invalid_reason = NULL;
2416 void *descr = parser->parse (mp->msgid, false, NULL, &invalid_reason);
2420 /* msgid is a valid format string. We mark only those msgids
2421 as format strings which contain at least one format directive
2422 and thus are format strings with a high probability. We
2423 don't mark strings without directives as format strings,
2424 because that would force the programmer to add
2425 "xgettext: no-c-format" anywhere where a translator wishes
2426 to use a percent sign. So, the msgfmt checking will not be
2427 perfect. Oh well. */
2428 if (parser->get_number_of_directives (descr) > 0
2429 && !(parser->is_unlikely_intentional != NULL
2430 && parser->is_unlikely_intentional (descr)))
2431 is_format[i] = possible;
2433 parser->free (descr);
2437 /* msgid is not a valid format string. */
2438 is_format[i] = impossible;
2439 free (invalid_reason);
2442 mp->is_format[i] = is_format[i];
2445 if (has_range_p (range))
2447 if (has_range_p (mp->range))
2449 if (range.min < mp->range.min)
2450 mp->range.min = range.min;
2451 if (range.max > mp->range.max)
2452 mp->range.max = range.max;
2458 mp->do_wrap = do_wrap == no ? no : yes; /* By default we wrap. */
2460 /* Warn about the use of non-reorderable format strings when the programming
2461 language also provides reorderable format strings. */
2462 warn_format_string (is_format, mp->msgid, pos, "msgid");
2464 /* Remember where we saw this msgid. */
2466 message_comment_filepos (mp, pos->file_name, pos->line_number);
2468 /* Tell the lexer to reset its comment buffer, so that the next
2469 message gets the correct comments. */
2470 xgettext_comment_reset ();
2471 savable_comment_reset ();
2478 remember_a_message_plural (message_ty *mp, char *string,
2479 flag_context_ty context, lex_pos_ty *pos,
2480 refcounted_string_list_ty *comment)
2488 msgid_plural = string;
2490 savable_comment_to_xgettext_comment (comment);
2492 CONVERT_STRING (msgid_plural, lc_string);
2494 /* See if the message is already a plural message. */
2495 if (mp->msgid_plural == NULL)
2497 mp->msgid_plural = msgid_plural;
2499 /* Construct the first plural form from the prefix and suffix,
2500 otherwise use the empty string. The translator will have to
2501 provide additional plural forms. */
2504 xasprintf ("%s%s%s", msgstr_prefix, msgid_plural, msgstr_suffix);
2507 msgstr1_len = strlen (msgstr1) + 1;
2508 msgstr = XNMALLOC (mp->msgstr_len + msgstr1_len, char);
2509 memcpy (msgstr, mp->msgstr, mp->msgstr_len);
2510 memcpy (msgstr + mp->msgstr_len, msgstr1, msgstr1_len);
2511 mp->msgstr = msgstr;
2512 mp->msgstr_len = mp->msgstr_len + msgstr1_len;
2516 /* Determine whether the context specifies that the msgid_plural is a
2518 set_format_flags_from_context (mp->is_format, context, mp->msgid_plural,
2519 pos, "msgid_plural");
2521 /* If it is not already decided, through programmer comments or
2522 the msgid, whether the msgid is a format string, examine the
2523 msgid_plural. This is a heuristic. */
2524 for (i = 0; i < NFORMATS; i++)
2525 if ((formatstring_parsers[i] == current_formatstring_parser1
2526 || formatstring_parsers[i] == current_formatstring_parser2
2527 || formatstring_parsers[i] == current_formatstring_parser3)
2528 && (mp->is_format[i] == undecided || mp->is_format[i] == possible)
2529 /* But avoid redundancy: objc-format is stronger than c-format. */
2531 && possible_format_p (mp->is_format[format_objc]))
2532 && !(i == format_objc
2533 && possible_format_p (mp->is_format[format_c]))
2534 /* Avoid flagging a string as c-format when it's known to be a
2535 qt-format or qt-plural-format or boost-format string. */
2537 && (possible_format_p (mp->is_format[format_qt])
2538 || possible_format_p (mp->is_format[format_qt_plural])
2539 || possible_format_p (mp->is_format[format_kde])
2540 || possible_format_p (mp->is_format[format_boost]))))
2542 struct formatstring_parser *parser = formatstring_parsers[i];
2543 char *invalid_reason = NULL;
2545 parser->parse (mp->msgid_plural, false, NULL, &invalid_reason);
2549 /* Same heuristic as in remember_a_message. */
2550 if (parser->get_number_of_directives (descr) > 0
2551 && !(parser->is_unlikely_intentional != NULL
2552 && parser->is_unlikely_intentional (descr)))
2553 mp->is_format[i] = possible;
2555 parser->free (descr);
2559 /* msgid_plural is not a valid format string. */
2560 mp->is_format[i] = impossible;
2561 free (invalid_reason);
2565 /* Warn about the use of non-reorderable format strings when the programming
2566 language also provides reorderable format strings. */
2567 warn_format_string (mp->is_format, mp->msgid_plural, pos, "msgid_plural");
2570 free (msgid_plural);
2572 /* Tell the lexer to reset its comment buffer, so that the next
2573 message gets the correct comments. */
2574 xgettext_comment_reset ();
2575 savable_comment_reset ();
2579 struct arglist_parser *
2580 arglist_parser_alloc (message_list_ty *mlp, const struct callshapes *shapes)
2582 if (shapes == NULL || shapes->nshapes == 0)
2584 struct arglist_parser *ap =
2585 (struct arglist_parser *)
2586 xmalloc (offsetof (struct arglist_parser, alternative[0]));
2590 ap->keyword_len = 0;
2591 ap->nalternatives = 0;
2597 struct arglist_parser *ap =
2598 (struct arglist_parser *)
2599 xmalloc (xsum (sizeof (struct arglist_parser),
2600 xtimes (shapes->nshapes - 1,
2601 sizeof (struct partial_call))));
2605 ap->keyword = shapes->keyword;
2606 ap->keyword_len = shapes->keyword_len;
2607 ap->nalternatives = shapes->nshapes;
2608 for (i = 0; i < shapes->nshapes; i++)
2610 ap->alternative[i].argnumc = shapes->shapes[i].argnumc;
2611 ap->alternative[i].argnum1 = shapes->shapes[i].argnum1;
2612 ap->alternative[i].argnum2 = shapes->shapes[i].argnum2;
2613 ap->alternative[i].argnum1_glib_context =
2614 shapes->shapes[i].argnum1_glib_context;
2615 ap->alternative[i].argnum2_glib_context =
2616 shapes->shapes[i].argnum2_glib_context;
2617 ap->alternative[i].argtotal = shapes->shapes[i].argtotal;
2618 ap->alternative[i].xcomments = shapes->shapes[i].xcomments;
2619 ap->alternative[i].msgctxt = NULL;
2620 ap->alternative[i].msgctxt_pos.file_name = NULL;
2621 ap->alternative[i].msgctxt_pos.line_number = (size_t)(-1);
2622 ap->alternative[i].msgid = NULL;
2623 ap->alternative[i].msgid_context = null_context;
2624 ap->alternative[i].msgid_pos.file_name = NULL;
2625 ap->alternative[i].msgid_pos.line_number = (size_t)(-1);
2626 ap->alternative[i].msgid_comment = NULL;
2627 ap->alternative[i].msgid_plural = NULL;
2628 ap->alternative[i].msgid_plural_context = null_context;
2629 ap->alternative[i].msgid_plural_pos.file_name = NULL;
2630 ap->alternative[i].msgid_plural_pos.line_number = (size_t)(-1);
2638 struct arglist_parser *
2639 arglist_parser_clone (struct arglist_parser *ap)
2641 struct arglist_parser *copy =
2642 (struct arglist_parser *)
2643 xmalloc (xsum (sizeof (struct arglist_parser) - sizeof (struct partial_call),
2644 xtimes (ap->nalternatives, sizeof (struct partial_call))));
2647 copy->mlp = ap->mlp;
2648 copy->keyword = ap->keyword;
2649 copy->keyword_len = ap->keyword_len;
2650 copy->nalternatives = ap->nalternatives;
2651 for (i = 0; i < ap->nalternatives; i++)
2653 const struct partial_call *cp = &ap->alternative[i];
2654 struct partial_call *ccp = ©->alternative[i];
2656 ccp->argnumc = cp->argnumc;
2657 ccp->argnum1 = cp->argnum1;
2658 ccp->argnum2 = cp->argnum2;
2659 ccp->argnum1_glib_context = cp->argnum1_glib_context;
2660 ccp->argnum2_glib_context = cp->argnum2_glib_context;
2661 ccp->argtotal = cp->argtotal;
2662 ccp->xcomments = cp->xcomments;
2663 ccp->msgctxt = (cp->msgctxt != NULL ? xstrdup (cp->msgctxt) : NULL);
2664 ccp->msgctxt_pos = cp->msgctxt_pos;
2665 ccp->msgid = (cp->msgid != NULL ? xstrdup (cp->msgid) : NULL);
2666 ccp->msgid_context = cp->msgid_context;
2667 ccp->msgid_pos = cp->msgctxt_pos;
2668 ccp->msgid_comment = add_reference (cp->msgid_comment);
2670 (cp->msgid_plural != NULL ? xstrdup (cp->msgid_plural) : NULL);
2671 ccp->msgid_plural_context = cp->msgid_plural_context;
2672 ccp->msgid_plural_pos = cp->msgid_plural_pos;
2680 arglist_parser_remember (struct arglist_parser *ap,
2681 int argnum, char *string,
2682 flag_context_ty context,
2683 char *file_name, size_t line_number,
2684 refcounted_string_list_ty *comment)
2686 bool stored_string = false;
2687 size_t nalternatives = ap->nalternatives;
2692 for (i = 0; i < nalternatives; i++)
2694 struct partial_call *cp = &ap->alternative[i];
2696 if (argnum == cp->argnumc)
2698 cp->msgctxt = string;
2699 cp->msgctxt_pos.file_name = file_name;
2700 cp->msgctxt_pos.line_number = line_number;
2701 stored_string = true;
2702 /* Mark msgctxt as done. */
2707 if (argnum == cp->argnum1)
2710 cp->msgid_context = context;
2711 cp->msgid_pos.file_name = file_name;
2712 cp->msgid_pos.line_number = line_number;
2713 cp->msgid_comment = add_reference (comment);
2714 stored_string = true;
2715 /* Mark msgid as done. */
2718 if (argnum == cp->argnum2)
2720 cp->msgid_plural = string;
2721 cp->msgid_plural_context = context;
2722 cp->msgid_plural_pos.file_name = file_name;
2723 cp->msgid_plural_pos.line_number = line_number;
2724 stored_string = true;
2725 /* Mark msgid_plural as done. */
2730 /* Note: There is a memory leak here: When string was stored but is later
2731 not used by arglist_parser_done, we don't free it. */
2738 arglist_parser_decidedp (struct arglist_parser *ap, int argnum)
2742 /* Test whether all alternatives are decided.
2743 Note: A decided alternative can be complete
2744 cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2745 && cp->argtotal == 0
2746 or it can be failed if no literal strings were found at the specified
2748 cp->argnumc <= argnum && cp->argnum1 <= argnum && cp->argnum2 <= argnum
2749 or it can be failed if the number of arguments is exceeded:
2750 cp->argtotal > 0 && cp->argtotal < argnum
2752 for (i = 0; i < ap->nalternatives; i++)
2754 struct partial_call *cp = &ap->alternative[i];
2756 if (!((cp->argnumc <= argnum
2757 && cp->argnum1 <= argnum
2758 && cp->argnum2 <= argnum)
2759 || (cp->argtotal > 0 && cp->argtotal < argnum)))
2760 /* cp is still undecided. */
2768 arglist_parser_done (struct arglist_parser *ap, int argnum)
2773 /* Determine the number of complete calls. */
2775 for (i = 0; i < ap->nalternatives; i++)
2777 struct partial_call *cp = &ap->alternative[i];
2779 if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2780 && (cp->argtotal == 0 || cp->argtotal == argnum))
2786 struct partial_call *best_cp = NULL;
2787 bool ambiguous = false;
2789 /* Find complete calls where msgctxt, msgid, msgid_plural are all
2791 for (i = 0; i < ap->nalternatives; i++)
2793 struct partial_call *cp = &ap->alternative[i];
2795 if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2796 && (cp->argtotal == 0 || cp->argtotal == argnum)
2797 && cp->msgctxt != NULL
2798 && cp->msgid != NULL
2799 && cp->msgid_plural != NULL)
2801 if (best_cp != NULL)
2810 if (best_cp == NULL)
2812 struct partial_call *best_cp1 = NULL;
2813 struct partial_call *best_cp2 = NULL;
2815 /* Find complete calls where msgctxt, msgid are provided. */
2816 for (i = 0; i < ap->nalternatives; i++)
2818 struct partial_call *cp = &ap->alternative[i];
2820 if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2821 && (cp->argtotal == 0 || cp->argtotal == argnum)
2822 && cp->msgctxt != NULL
2823 && cp->msgid != NULL)
2825 if (best_cp1 != NULL)
2834 /* Find complete calls where msgid, msgid_plural are provided. */
2835 for (i = 0; i < ap->nalternatives; i++)
2837 struct partial_call *cp = &ap->alternative[i];
2839 if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2840 && (cp->argtotal == 0 || cp->argtotal == argnum)
2841 && cp->msgid != NULL
2842 && cp->msgid_plural != NULL)
2844 if (best_cp2 != NULL)
2853 if (best_cp1 != NULL)
2855 if (best_cp2 != NULL)
2857 if (best_cp != NULL)
2864 if (best_cp == NULL)
2866 /* Find complete calls where msgid is provided. */
2867 for (i = 0; i < ap->nalternatives; i++)
2869 struct partial_call *cp = &ap->alternative[i];
2871 if (cp->argnumc == 0 && cp->argnum1 == 0 && cp->argnum2 == 0
2872 && (cp->argtotal == 0 || cp->argtotal == argnum)
2873 && cp->msgid != NULL)
2875 if (best_cp != NULL)
2887 error_with_progname = false;
2888 error_at_line (0, 0,
2889 best_cp->msgid_pos.file_name,
2890 best_cp->msgid_pos.line_number,
2891 _("ambiguous argument specification for keyword '%.*s'"),
2892 (int) ap->keyword_len, ap->keyword);
2893 error_with_progname = true;
2896 if (best_cp != NULL)
2898 /* best_cp indicates the best found complete call.
2899 Now call remember_a_message. */
2902 /* Split strings in the GNOME glib syntax "msgctxt|msgid". */
2903 if (best_cp->argnum1_glib_context || best_cp->argnum2_glib_context)
2904 /* split_keywordspec should not allow the context to be specified
2905 in two different ways. */
2906 if (best_cp->msgctxt != NULL)
2908 if (best_cp->argnum1_glib_context)
2910 const char *separator = strchr (best_cp->msgid, '|');
2912 if (separator == NULL)
2914 error_with_progname = false;
2915 error_at_line (0, 0,
2916 best_cp->msgid_pos.file_name,
2917 best_cp->msgid_pos.line_number,
2918 _("warning: missing context for keyword '%.*s'"),
2919 (int) ap->keyword_len, ap->keyword);
2920 error_with_progname = true;
2924 size_t ctxt_len = separator - best_cp->msgid;
2925 char *ctxt = XNMALLOC (ctxt_len + 1, char);
2927 memcpy (ctxt, best_cp->msgid, ctxt_len);
2928 ctxt[ctxt_len] = '\0';
2929 best_cp->msgctxt = ctxt;
2930 best_cp->msgid = xstrdup (separator + 1);
2933 if (best_cp->msgid_plural != NULL && best_cp->argnum2_glib_context)
2935 const char *separator = strchr (best_cp->msgid_plural, '|');
2937 if (separator == NULL)
2939 error_with_progname = false;
2940 error_at_line (0, 0,
2941 best_cp->msgid_plural_pos.file_name,
2942 best_cp->msgid_plural_pos.line_number,
2943 _("warning: missing context for plural argument of keyword '%.*s'"),
2944 (int) ap->keyword_len, ap->keyword);
2945 error_with_progname = true;
2949 size_t ctxt_len = separator - best_cp->msgid_plural;
2950 char *ctxt = XNMALLOC (ctxt_len + 1, char);
2952 memcpy (ctxt, best_cp->msgid_plural, ctxt_len);
2953 ctxt[ctxt_len] = '\0';
2954 if (best_cp->msgctxt == NULL)
2955 best_cp->msgctxt = ctxt;
2958 if (strcmp (ctxt, best_cp->msgctxt) != 0)
2960 error_with_progname = false;
2961 error_at_line (0, 0,
2962 best_cp->msgid_plural_pos.file_name,
2963 best_cp->msgid_plural_pos.line_number,
2964 _("context mismatch between singular and plural form"));
2965 error_with_progname = true;
2969 best_cp->msgid_plural = xstrdup (separator + 1);
2974 flag_context_ty msgid_context = best_cp->msgid_context;
2975 flag_context_ty msgid_plural_context = best_cp->msgid_plural_context;
2977 /* Special support for the 3-argument tr operator in Qt:
2978 When --qt and --keyword=tr:1,1,2c,3t are specified, add to the
2979 context the information that the argument is expeected to be a
2980 qt-plural-format. */
2981 if (recognize_format_qt
2982 && current_formatstring_parser3 == &formatstring_qt_plural
2983 && best_cp->msgid_plural == best_cp->msgid)
2985 msgid_context.is_format3 = yes_according_to_context;
2986 msgid_plural_context.is_format3 = yes_according_to_context;
2989 mp = remember_a_message (ap->mlp, best_cp->msgctxt, best_cp->msgid,
2991 &best_cp->msgid_pos,
2992 NULL, best_cp->msgid_comment);
2993 if (mp != NULL && best_cp->msgid_plural != NULL)
2994 remember_a_message_plural (mp, best_cp->msgid_plural,
2995 msgid_plural_context,
2996 &best_cp->msgid_plural_pos,
3000 if (best_cp->xcomments.nitems > 0)
3002 /* Add best_cp->xcomments to mp->comment_dot, unless already
3006 for (i = 0; i < best_cp->xcomments.nitems; i++)
3008 const char *xcomment = best_cp->xcomments.item[i];
3011 if (mp->comment_dot != NULL)
3015 for (j = 0; j < mp->comment_dot->nitems; j++)
3016 if (strcmp (xcomment, mp->comment_dot->item[j]) == 0)
3023 message_comment_dot_append (mp, xcomment);
3030 /* No complete call was parsed. */
3031 /* Note: There is a memory leak here: When there is more than one
3032 alternative, the same string can be stored in multiple alternatives,
3033 and it's not easy to free all strings reliably. */
3034 if (ap->nalternatives == 1)
3036 if (ap->alternative[0].msgctxt != NULL)
3037 free (ap->alternative[0].msgctxt);
3038 if (ap->alternative[0].msgid != NULL)
3039 free (ap->alternative[0].msgid);
3040 if (ap->alternative[0].msgid_plural != NULL)
3041 free (ap->alternative[0].msgid_plural);
3045 for (i = 0; i < ap->nalternatives; i++)
3046 drop_reference (ap->alternative[i].msgid_comment);
3054 char *project_id_version;
3060 static lex_pos_ty pos = { __FILE__, __LINE__ };
3062 if (package_name != NULL)
3064 if (package_version != NULL)
3065 project_id_version = xasprintf ("%s %s", package_name, package_version);
3067 project_id_version = xasprintf ("%s", package_name);
3070 project_id_version = xstrdup ("PACKAGE VERSION");
3072 if (msgid_bugs_address != NULL && msgid_bugs_address[0] == '\0')
3073 multiline_warning (xasprintf (_("warning: ")),
3075 The option --msgid-bugs-address was not specified.\n\
3076 If you are using a 'Makevars' file, please specify\n\
3077 the MSGID_BUGS_ADDRESS variable there; otherwise please\n\
3078 specify an --msgid-bugs-address command line option.\n\
3082 timestring = po_strftime (&now);
3084 msgstr = xasprintf ("\
3085 Project-Id-Version: %s\n\
3086 Report-Msgid-Bugs-To: %s\n\
3087 POT-Creation-Date: %s\n\
3088 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n\
3089 Last-Translator: FULL NAME <EMAIL@ADDRESS>\n\
3090 Language-Team: LANGUAGE <LL@li.org>\n\
3092 MIME-Version: 1.0\n\
3093 Content-Type: text/plain; charset=CHARSET\n\
3094 Content-Transfer-Encoding: 8bit\n",
3096 msgid_bugs_address != NULL ? msgid_bugs_address : "",
3099 free (project_id_version);
3101 mp = message_alloc (NULL, "", NULL, msgstr, strlen (msgstr) + 1, &pos);
3103 if (copyright_holder[0] != '\0')
3104 comment = xasprintf ("\
3105 SOME DESCRIPTIVE TITLE.\n\
3106 Copyright (C) YEAR %s\n\
3107 This file is distributed under the same license as the PACKAGE package.\n\
3108 FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n",
3111 comment = xstrdup ("\
3112 SOME DESCRIPTIVE TITLE.\n\
3113 This file is put in the public domain.\n\
3114 FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n");
3115 message_comment_append (mp, comment);
3118 mp->is_fuzzy = true;
3124 finalize_header (msgdomain_list_ty *mdlp)
3126 /* If the generated PO file has plural forms, add a Plural-Forms template
3127 to the constructed header. */
3133 for (i = 0; i < mdlp->nitems; i++)
3135 message_list_ty *mlp = mdlp->item[i]->messages;
3137 for (j = 0; j < mlp->nitems; j++)
3139 message_ty *mp = mlp->item[j];
3141 if (mp->msgid_plural != NULL)
3153 message_ty *header =
3154 message_list_search (mdlp->item[0]->messages, NULL, "");
3156 && c_strstr (header->msgstr, "Plural-Forms:") == NULL)
3158 size_t insertpos = strlen (header->msgstr);
3163 suffix = "\nPlural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n";
3164 if (insertpos == 0 || header->msgstr[insertpos-1] == '\n')
3166 suffix_len = strlen (suffix);
3167 new_msgstr = XNMALLOC (header->msgstr_len + suffix_len, char);
3168 memcpy (new_msgstr, header->msgstr, insertpos);
3169 memcpy (new_msgstr + insertpos, suffix, suffix_len);
3170 memcpy (new_msgstr + insertpos + suffix_len,
3171 header->msgstr + insertpos,
3172 header->msgstr_len - insertpos);
3173 header->msgstr = new_msgstr;
3174 header->msgstr_len = header->msgstr_len + suffix_len;
3179 /* If not all the strings were plain ASCII, or if the output syntax
3180 requires a charset conversion, set the charset in the header to UTF-8.
3181 All messages have already been converted to UTF-8 in remember_a_message
3182 and remember_a_message_plural. */
3184 bool has_nonascii = false;
3187 for (i = 0; i < mdlp->nitems; i++)
3189 message_list_ty *mlp = mdlp->item[i]->messages;
3191 if (!is_ascii_message_list (mlp))
3192 has_nonascii = true;
3195 if (has_nonascii || output_syntax->requires_utf8)
3197 message_list_ty *mlp = mdlp->item[0]->messages;
3199 iconv_message_list (mlp, po_charset_utf8, po_charset_utf8, NULL);
3205 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
3206 #define ENDOF(a) ((a) + SIZEOF(a))
3210 language_to_extractor (const char *name)
3215 extractor_func func;
3216 flag_context_list_table_ty *flag_table;
3217 struct formatstring_parser *formatstring_parser1;
3218 struct formatstring_parser *formatstring_parser2;
3220 typedef struct table_ty table_ty;
3222 static table_ty table[] =
3241 SCANNERS_STRINGTABLE
3247 /* Here may follow more languages and their scanners: pike, etc...
3248 Make sure new scanners honor the --exclude-file option. */
3253 for (tp = table; tp < ENDOF(table); ++tp)
3254 if (c_strcasecmp (name, tp->name) == 0)
3256 extractor_ty result;
3258 result.func = tp->func;
3259 result.flag_table = tp->flag_table;
3260 result.formatstring_parser1 = tp->formatstring_parser1;
3261 result.formatstring_parser2 = tp->formatstring_parser2;
3262 result.formatstring_parser3 = NULL;
3264 /* Handle --qt. It's preferrable to handle this facility here rather
3265 than through an option --language=C++/Qt because the latter would
3266 conflict with the language "C++" regarding the file extensions. */
3267 if (recognize_format_qt && strcmp (tp->name, "C++") == 0)
3269 result.flag_table = &flag_table_cxx_qt;
3270 result.formatstring_parser2 = &formatstring_qt;
3271 result.formatstring_parser3 = &formatstring_qt_plural;
3273 /* Likewise for --kde. */
3274 if (recognize_format_kde && strcmp (tp->name, "C++") == 0)
3276 result.flag_table = &flag_table_cxx_kde;
3277 result.formatstring_parser2 = &formatstring_kde;
3279 /* Likewise for --boost. */
3280 if (recognize_format_boost && strcmp (tp->name, "C++") == 0)
3282 result.flag_table = &flag_table_cxx_boost;
3283 result.formatstring_parser2 = &formatstring_boost;
3289 error (EXIT_FAILURE, 0, _("language '%s' unknown"), name);
3292 extractor_ty result = { NULL, NULL, NULL, NULL };
3299 extension_to_language (const char *extension)
3303 const char *extension;
3304 const char *language;
3306 typedef struct table_ty table_ty;
3308 static table_ty table[] =
3318 EXTENSIONS_SMALLTALK
3320 EXTENSIONS_PROPERTIES
3327 EXTENSIONS_STRINGTABLE
3331 EXTENSIONS_JAVASCRIPT
3333 /* Here may follow more file extensions... */
3338 for (tp = table; tp < ENDOF(table); ++tp)
3339 if (strcmp (extension, tp->extension) == 0)
3340 return tp->language;