Imported Upstream version 0.18.3.2
[platform/upstream/gettext.git] / gettext-tools / src / x-po.c
1 /* xgettext PO and JavaProperties backends.
2    Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009 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 3 of the License, or
9    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 /* Specification.  */
24 #include "x-po.h"
25 #include "x-properties.h"
26 #include "x-stringtable.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdbool.h>
31 #include <string.h>
32
33 #include "message.h"
34 #include "xgettext.h"
35 #include "xalloc.h"
36 #include "read-catalog.h"
37 #include "read-po.h"
38 #include "read-properties.h"
39 #include "read-stringtable.h"
40 #include "po-lex.h"
41 #include "gettext.h"
42
43 /* A convenience macro.  I don't like writing gettext() every time.  */
44 #define _(str) gettext (str)
45
46
47 /* The charset found in the header entry.  */
48 static char *header_charset;
49
50 /* Define a subclass extract_catalog_reader_ty of default_catalog_reader_ty.  */
51
52 static void
53 extract_add_message (default_catalog_reader_ty *this,
54                      char *msgctxt,
55                      char *msgid,
56                      lex_pos_ty *msgid_pos,
57                      char *msgid_plural,
58                      char *msgstr, size_t msgstr_len,
59                      lex_pos_ty *msgstr_pos,
60                      char *prev_msgctxt,
61                      char *prev_msgid,
62                      char *prev_msgid_plural,
63                      bool force_fuzzy, bool obsolete)
64 {
65   /* See whether we shall exclude this message.  */
66   if (exclude != NULL && message_list_search (exclude, msgctxt, msgid) != NULL)
67     goto discard;
68
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)
74     {
75       {
76         const char *charsetstr = strstr (msgstr, "charset=");
77
78         if (charsetstr != NULL)
79           {
80             size_t len;
81             char *charset;
82
83             charsetstr += strlen ("charset=");
84             len = strcspn (charsetstr, " \t\n");
85             charset = XNMALLOC (len + 1, char);
86             memcpy (charset, charsetstr, len);
87             charset[len] = '\0';
88
89             if (header_charset != NULL)
90               free (header_charset);
91             header_charset = charset;
92           }
93       }
94
95      discard:
96       if (msgctxt != NULL)
97         free (msgctxt);
98       free (msgid);
99       if (msgid_plural != NULL)
100         free (msgid_plural);
101       free (msgstr);
102       if (prev_msgctxt != NULL)
103         free (prev_msgctxt);
104       if (prev_msgid != NULL)
105         free (prev_msgid);
106       if (prev_msgid_plural != NULL)
107         free (prev_msgid_plural);
108       return;
109     }
110
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);
116 }
117
118
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.  */
124
125 static default_catalog_reader_class_ty extract_methods =
126 {
127   {
128     sizeof (default_catalog_reader_ty),
129     default_constructor,
130     default_destructor,
131     default_parse_brief,
132     default_parse_debrief,
133     default_directive_domain,
134     default_directive_message,
135     default_comment,
136     default_comment_dot,
137     default_comment_filepos,
138     default_comment_special
139   },
140   default_set_domain, /* set_domain */
141   extract_add_message, /* add_message */
142   NULL /* frob_new_message */
143 };
144
145
146 static void
147 extract (FILE *fp,
148          const char *real_filename, const char *logical_filename,
149          catalog_input_format_ty input_syntax,
150          msgdomain_list_ty *mdlp)
151 {
152   default_catalog_reader_ty *pop;
153
154   header_charset = NULL;
155
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;
163   pop->mdlp = NULL;
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);
168
169   if (header_charset != NULL)
170     {
171       if (!xgettext_omit_header)
172         {
173           /* Put the old charset into the freshly constructed header entry.  */
174           message_ty *mp =
175             message_list_search (mdlp->item[0]->messages, NULL, "");
176
177           if (mp != NULL && !mp->obsolete)
178             {
179               const char *header = mp->msgstr;
180
181               if (header != NULL)
182                 {
183                   const char *charsetstr = strstr (header, "charset=");
184
185                   if (charsetstr != NULL)
186                     {
187                       size_t len, len1, len2, len3;
188                       char *new_header;
189
190                       charsetstr += strlen ("charset=");
191                       len = strcspn (charsetstr, " \t\n");
192
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;
202                     }
203                 }
204             }
205         }
206
207       free (header_charset);
208     }
209 }
210
211
212 void
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)
217 {
218   extract (fp, real_filename,  logical_filename, &input_format_po, mdlp);
219 }
220
221
222 void
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)
227 {
228   extract (fp, real_filename,  logical_filename, &input_format_properties,
229            mdlp);
230 }
231
232
233 void
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)
238 {
239   extract (fp, real_filename,  logical_filename, &input_format_stringtable,
240            mdlp);
241 }