1 /* xgettext PO and JavaProperties backends.
2 Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009 Free Software Foundation, Inc.
4 This file was written by Peter Miller <millerp@canb.auug.org.au>
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include "x-properties.h"
26 #include "x-stringtable.h"
36 #include "read-catalog.h"
38 #include "read-properties.h"
39 #include "read-stringtable.h"
43 /* A convenience macro. I don't like writing gettext() every time. */
44 #define _(str) gettext (str)
47 /* The charset found in the header entry. */
48 static char *header_charset;
50 /* Define a subclass extract_catalog_reader_ty of default_catalog_reader_ty. */
53 extract_add_message (default_catalog_reader_ty *this,
56 lex_pos_ty *msgid_pos,
58 char *msgstr, size_t msgstr_len,
59 lex_pos_ty *msgstr_pos,
62 char *prev_msgid_plural,
63 bool force_fuzzy, bool obsolete)
65 /* See whether we shall exclude this message. */
66 if (exclude != NULL && message_list_search (exclude, msgctxt, msgid) != NULL)
69 /* If the msgid is the empty string, it is the old header. Throw it
70 away, we have constructed a new one. Only remember its charset.
71 But if no new one was constructed, keep the old header. This is useful
72 because the old header may contain a charset= directive. */
73 if (msgctxt == NULL && *msgid == '\0' && !xgettext_omit_header)
76 const char *charsetstr = strstr (msgstr, "charset=");
78 if (charsetstr != NULL)
83 charsetstr += strlen ("charset=");
84 len = strcspn (charsetstr, " \t\n");
85 charset = XNMALLOC (len + 1, char);
86 memcpy (charset, charsetstr, len);
89 if (header_charset != NULL)
90 free (header_charset);
91 header_charset = charset;
99 if (msgid_plural != NULL)
102 if (prev_msgctxt != NULL)
104 if (prev_msgid != NULL)
106 if (prev_msgid_plural != NULL)
107 free (prev_msgid_plural);
111 /* Invoke superclass method. */
112 default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural,
113 msgstr, msgstr_len, msgstr_pos,
114 prev_msgctxt, prev_msgid, prev_msgid_plural,
115 force_fuzzy, obsolete);
119 /* So that the one parser can be used for multiple programs, and also
120 use good data hiding and encapsulation practices, an object
121 oriented approach has been taken. An object instance is allocated,
122 and all actions resulting from the parse will be through
123 invocations of method functions of that object. */
125 static default_catalog_reader_class_ty extract_methods =
128 sizeof (default_catalog_reader_ty),
132 default_parse_debrief,
133 default_directive_domain,
134 default_directive_message,
137 default_comment_filepos,
138 default_comment_special
140 default_set_domain, /* set_domain */
141 extract_add_message, /* add_message */
142 NULL /* frob_new_message */
148 const char *real_filename, const char *logical_filename,
149 catalog_input_format_ty input_syntax,
150 msgdomain_list_ty *mdlp)
152 default_catalog_reader_ty *pop;
154 header_charset = NULL;
156 pop = default_catalog_reader_alloc (&extract_methods);
157 pop->handle_comments = true;
158 pop->handle_filepos_comments = (line_comment != 0);
159 pop->allow_domain_directives = false;
160 pop->allow_duplicates = false;
161 pop->allow_duplicates_if_same_msgstr = true;
162 pop->file_name = real_filename;
164 pop->mlp = mdlp->item[0]->messages;
165 catalog_reader_parse ((abstract_catalog_reader_ty *) pop, fp, real_filename,
166 logical_filename, input_syntax);
167 catalog_reader_free ((abstract_catalog_reader_ty *) pop);
169 if (header_charset != NULL)
171 if (!xgettext_omit_header)
173 /* Put the old charset into the freshly constructed header entry. */
175 message_list_search (mdlp->item[0]->messages, NULL, "");
177 if (mp != NULL && !mp->obsolete)
179 const char *header = mp->msgstr;
183 const char *charsetstr = strstr (header, "charset=");
185 if (charsetstr != NULL)
187 size_t len, len1, len2, len3;
190 charsetstr += strlen ("charset=");
191 len = strcspn (charsetstr, " \t\n");
193 len1 = charsetstr - header;
194 len2 = strlen (header_charset);
195 len3 = (header + strlen (header)) - (charsetstr + len);
196 new_header = XNMALLOC (len1 + len2 + len3 + 1, char);
197 memcpy (new_header, header, len1);
198 memcpy (new_header + len1, header_charset, len2);
199 memcpy (new_header + len1 + len2, charsetstr + len, len3 + 1);
200 mp->msgstr = new_header;
201 mp->msgstr_len = len1 + len2 + len3 + 1;
207 free (header_charset);
213 extract_po (FILE *fp,
214 const char *real_filename, const char *logical_filename,
215 flag_context_list_table_ty *flag_table,
216 msgdomain_list_ty *mdlp)
218 extract (fp, real_filename, logical_filename, &input_format_po, mdlp);
223 extract_properties (FILE *fp,
224 const char *real_filename, const char *logical_filename,
225 flag_context_list_table_ty *flag_table,
226 msgdomain_list_ty *mdlp)
228 extract (fp, real_filename, logical_filename, &input_format_properties,
234 extract_stringtable (FILE *fp,
235 const char *real_filename, const char *logical_filename,
236 flag_context_list_table_ty *flag_table,
237 msgdomain_list_ty *mdlp)
239 extract (fp, real_filename, logical_filename, &input_format_stringtable,