xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/x-po.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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