• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* xgettext PO, JavaProperties, and NXStringTable backends.
2    Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008-2009, 2014, 2018, 2020 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 <https://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
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)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
extract(FILE * fp,const char * real_filename,const char * logical_filename,catalog_input_format_ty input_syntax,msgdomain_list_ty * mdlp)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->allow_domain_directives = false;
159   pop->allow_duplicates = false;
160   pop->allow_duplicates_if_same_msgstr = true;
161   pop->file_name = real_filename;
162   pop->mdlp = NULL;
163   pop->mlp = mdlp->item[0]->messages;
164   catalog_reader_parse ((abstract_catalog_reader_ty *) pop, fp, real_filename,
165                         logical_filename, input_syntax);
166   catalog_reader_free ((abstract_catalog_reader_ty *) pop);
167 
168   if (header_charset != NULL)
169     {
170       if (!xgettext_omit_header)
171         {
172           /* Put the old charset into the freshly constructed header entry.  */
173           message_ty *mp =
174             message_list_search (mdlp->item[0]->messages, NULL, "");
175 
176           if (mp != NULL && !mp->obsolete)
177             {
178               const char *header = mp->msgstr;
179 
180               if (header != NULL)
181                 {
182                   const char *charsetstr = strstr (header, "charset=");
183 
184                   if (charsetstr != NULL)
185                     {
186                       size_t len, len1, len2, len3;
187                       char *new_header;
188 
189                       charsetstr += strlen ("charset=");
190                       len = strcspn (charsetstr, " \t\n");
191 
192                       len1 = charsetstr - header;
193                       len2 = strlen (header_charset);
194                       len3 = (header + strlen (header)) - (charsetstr + len);
195                       new_header = XNMALLOC (len1 + len2 + len3 + 1, char);
196                       memcpy (new_header, header, len1);
197                       memcpy (new_header + len1, header_charset, len2);
198                       memcpy (new_header + len1 + len2, charsetstr + len, len3 + 1);
199                       mp->msgstr = new_header;
200                       mp->msgstr_len = len1 + len2 + len3 + 1;
201                     }
202                 }
203             }
204         }
205 
206       free (header_charset);
207     }
208 }
209 
210 
211 void
extract_po(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)212 extract_po (FILE *fp,
213             const char *real_filename, const char *logical_filename,
214             flag_context_list_table_ty *flag_table,
215             msgdomain_list_ty *mdlp)
216 {
217   extract (fp, real_filename,  logical_filename, &input_format_po, mdlp);
218 }
219 
220 
221 void
extract_properties(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)222 extract_properties (FILE *fp,
223                     const char *real_filename, const char *logical_filename,
224                     flag_context_list_table_ty *flag_table,
225                     msgdomain_list_ty *mdlp)
226 {
227   extract (fp, real_filename,  logical_filename, &input_format_properties,
228            mdlp);
229 }
230 
231 
232 void
extract_stringtable(FILE * fp,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)233 extract_stringtable (FILE *fp,
234                      const char *real_filename, const char *logical_filename,
235                      flag_context_list_table_ty *flag_table,
236                      msgdomain_list_ty *mdlp)
237 {
238   extract (fp, real_filename,  logical_filename, &input_format_stringtable,
239            mdlp);
240 }
241