1 /* xgettext PO and JavaProperties backends.
2 Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
3
4 This file was written by Peter Miller <millerp@canb.auug.org.au>
5
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 2, or (at your option)
9 any later version.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdbool.h>
27 #include <string.h>
28
29 #include "message.h"
30 #include "xgettext.h"
31 #include "x-po.h"
32 #include "x-properties.h"
33 #include "x-stringtable.h"
34 #include "xalloc.h"
35 #include "read-catalog.h"
36 #include "read-po.h"
37 #include "read-properties.h"
38 #include "read-stringtable.h"
39 #include "po-lex.h"
40 #include "gettext.h"
41
42 /* A convenience macro. I don't like writing gettext() every time. */
43 #define _(str) gettext (str)
44
45
46 /* The charset found in the header entry. */
47 static char *header_charset;
48
49 /* Define a subclass extract_catalog_reader_ty of default_catalog_reader_ty. */
50
51 static void
extract_add_message(default_catalog_reader_ty * this,char * msgctxt,char * msgid,lex_pos_ty * msgid_pos,char * msgid_plural,char * msgstr,size_t msgstr_len,lex_pos_ty * msgstr_pos,char * prev_msgctxt,char * prev_msgid,char * prev_msgid_plural,bool force_fuzzy,bool obsolete)52 extract_add_message (default_catalog_reader_ty *this,
53 char *msgctxt,
54 char *msgid,
55 lex_pos_ty *msgid_pos,
56 char *msgid_plural,
57 char *msgstr, size_t msgstr_len,
58 lex_pos_ty *msgstr_pos,
59 char *prev_msgctxt,
60 char *prev_msgid,
61 char *prev_msgid_plural,
62 bool force_fuzzy, bool obsolete)
63 {
64 /* See whether we shall exclude this message. */
65 if (exclude != NULL && message_list_search (exclude, msgctxt, msgid) != NULL)
66 goto discard;
67
68 /* If the msgid is the empty string, it is the old header. Throw it
69 away, we have constructed a new one. Only remember its charset.
70 But if no new one was constructed, keep the old header. This is useful
71 because the old header may contain a charset= directive. */
72 if (msgctxt == NULL && *msgid == '\0' && !xgettext_omit_header)
73 {
74 const char *charsetstr = strstr (msgstr, "charset=");
75
76 if (charsetstr != NULL)
77 {
78 size_t len;
79 char *charset;
80
81 charsetstr += strlen ("charset=");
82 len = strcspn (charsetstr, " \t\n");
83 charset = (char *) xmalloc (len + 1);
84 memcpy (charset, charsetstr, len);
85 charset[len] = '\0';
86
87 if (header_charset != NULL)
88 free (header_charset);
89 header_charset = charset;
90 }
91
92 discard:
93 if (msgctxt != NULL)
94 free (msgctxt);
95 free (msgid);
96 if (msgid_plural != NULL)
97 free (msgid_plural);
98 free (msgstr);
99 if (prev_msgctxt != NULL)
100 free (prev_msgctxt);
101 if (prev_msgid != NULL)
102 free (prev_msgid);
103 if (prev_msgid_plural != NULL)
104 free (prev_msgid_plural);
105 return;
106 }
107
108 /* Invoke superclass method. */
109 default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural,
110 msgstr, msgstr_len, msgstr_pos,
111 prev_msgctxt, prev_msgid, prev_msgid_plural,
112 force_fuzzy, obsolete);
113 }
114
115
116 /* So that the one parser can be used for multiple programs, and also
117 use good data hiding and encapsulation practices, an object
118 oriented approach has been taken. An object instance is allocated,
119 and all actions resulting from the parse will be through
120 invocations of method functions of that object. */
121
122 static default_catalog_reader_class_ty extract_methods =
123 {
124 {
125 sizeof (default_catalog_reader_ty),
126 default_constructor,
127 default_destructor,
128 default_parse_brief,
129 default_parse_debrief,
130 default_directive_domain,
131 default_directive_message,
132 default_comment,
133 default_comment_dot,
134 default_comment_filepos,
135 default_comment_special
136 },
137 default_set_domain, /* set_domain */
138 extract_add_message, /* add_message */
139 NULL /* frob_new_message */
140 };
141
142
143 static void
extract(FILE * fp,const char * real_filename,const char * logical_filename,catalog_input_format_ty input_syntax,msgdomain_list_ty * mdlp)144 extract (FILE *fp,
145 const char *real_filename, const char *logical_filename,
146 catalog_input_format_ty input_syntax,
147 msgdomain_list_ty *mdlp)
148 {
149 default_catalog_reader_ty *pop;
150
151 header_charset = NULL;
152
153 pop = default_catalog_reader_alloc (&extract_methods);
154 pop->handle_comments = true;
155 pop->handle_filepos_comments = (line_comment != 0);
156 pop->allow_domain_directives = false;
157 pop->allow_duplicates = false;
158 pop->allow_duplicates_if_same_msgstr = true;
159 pop->mdlp = NULL;
160 pop->mlp = mdlp->item[0]->messages;
161 catalog_reader_parse ((abstract_catalog_reader_ty *) pop, fp, real_filename,
162 logical_filename, input_syntax);
163 catalog_reader_free ((abstract_catalog_reader_ty *) pop);
164
165 if (header_charset != NULL)
166 {
167 if (!xgettext_omit_header)
168 {
169 /* Put the old charset into the freshly constructed header entry. */
170 message_ty *mp =
171 message_list_search (mdlp->item[0]->messages, NULL, "");
172
173 if (mp != NULL && !mp->obsolete)
174 {
175 const char *header = mp->msgstr;
176
177 if (header != NULL)
178 {
179 const char *charsetstr = strstr (header, "charset=");
180
181 if (charsetstr != NULL)
182 {
183 size_t len, len1, len2, len3;
184 char *new_header;
185
186 charsetstr += strlen ("charset=");
187 len = strcspn (charsetstr, " \t\n");
188
189 len1 = charsetstr - header;
190 len2 = strlen (header_charset);
191 len3 = (header + strlen (header)) - (charsetstr + len);
192 new_header = (char *) xmalloc (len1 + len2 + len3 + 1);
193 memcpy (new_header, header, len1);
194 memcpy (new_header + len1, header_charset, len2);
195 memcpy (new_header + len1 + len2, charsetstr + len, len3 + 1);
196 mp->msgstr = new_header;
197 mp->msgstr_len = len1 + len2 + len3 + 1;
198 }
199 }
200 }
201 }
202
203 free (header_charset);
204 }
205 }
206
207
208 void
extract_po(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)209 extract_po (FILE *fp,
210 const char *real_filename, const char *logical_filename,
211 flag_context_list_table_ty *flag_table,
212 msgdomain_list_ty *mdlp)
213 {
214 extract (fp, real_filename, logical_filename, &input_format_po, mdlp);
215 }
216
217
218 void
extract_properties(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)219 extract_properties (FILE *fp,
220 const char *real_filename, const char *logical_filename,
221 flag_context_list_table_ty *flag_table,
222 msgdomain_list_ty *mdlp)
223 {
224 extract (fp, real_filename, logical_filename, &input_format_properties,
225 mdlp);
226 }
227
228
229 void
extract_stringtable(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)230 extract_stringtable (FILE *fp,
231 const char *real_filename, const char *logical_filename,
232 flag_context_list_table_ty *flag_table,
233 msgdomain_list_ty *mdlp)
234 {
235 extract (fp, real_filename, logical_filename, &input_format_stringtable,
236 mdlp);
237 }
238