• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/src/
1/* Writing tcl/msgcat .msg files.
2   Copyright (C) 2002-2003, 2005, 2007 Free Software Foundation, Inc.
3   Written by Bruno Haible <bruno@clisp.org>, 2002.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <alloca.h>
22
23/* Specification.  */
24#include "write-tcl.h"
25
26#include <errno.h>
27#include <stdbool.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "error.h"
33#include "xerror.h"
34#include "message.h"
35#include "msgl-iconv.h"
36#include "po-charset.h"
37#include "xalloc.h"
38#include "xmalloca.h"
39#include "filename.h"
40#include "fwriteerror.h"
41#include "unistr.h"
42#include "gettext.h"
43
44#define _(str) gettext (str)
45
46
47/* Write a string in Tcl Unicode notation to the given stream.
48   Tcl 8 uses Unicode for its internal string representation.
49   In tcl-8.3.3, the .msg files are read in using the locale dependent
50   encoding.  The only way to specify strings in an encoding independent
51   form is the \unnnn notation.  Newer tcl versions have this fixed:
52   they read the .msg files in UTF-8 encoding.  */
53static void
54write_tcl_string (FILE *stream, const char *str)
55{
56  static const char hexdigit[] = "0123456789abcdef";
57  const char *str_limit = str + strlen (str);
58
59  fprintf (stream, "\"");
60  while (str < str_limit)
61    {
62      unsigned int uc;
63      unsigned int count;
64      count = u8_mbtouc (&uc, (const unsigned char *) str, str_limit - str);
65      if (uc < 0x10000)
66	{
67	  /* Single UCS-2 'char'.  */
68	  if (uc == 0x000a)
69	    fprintf (stream, "\\n");
70	  else if (uc == 0x000d)
71	    fprintf (stream, "\\r");
72	  else if (uc == 0x0022)
73	    fprintf (stream, "\\\"");
74	  else if (uc == 0x0024)
75	    fprintf (stream, "\\$");
76	  else if (uc == 0x005b)
77	    fprintf (stream, "\\[");
78	  else if (uc == 0x005c)
79	    fprintf (stream, "\\\\");
80	  else if (uc == 0x005d)
81	    fprintf (stream, "\\]");
82	  /* No need to escape '{' and '}' because we don't have opening
83	     braces outside the strings.  */
84#if 0
85	  else if (uc == 0x007b)
86	    fprintf (stream, "\\{");
87	  else if (uc == 0x007d)
88	    fprintf (stream, "\\}");
89#endif
90	  else if (uc >= 0x0020 && uc < 0x007f)
91	    fprintf (stream, "%c", uc);
92	  else
93	    fprintf (stream, "\\u%c%c%c%c",
94		     hexdigit[(uc >> 12) & 0x0f], hexdigit[(uc >> 8) & 0x0f],
95		     hexdigit[(uc >> 4) & 0x0f], hexdigit[uc & 0x0f]);
96	}
97      else
98	/* The \unnnn notation doesn't support characters >= 0x10000.
99	   We output them as UTF-8 byte sequences and hope that either
100	   the Tcl version reading them will be new enough or that the
101	   user is using an UTF-8 locale.  */
102	fwrite (str, 1, count, stream);
103      str += count;
104    }
105  fprintf (stream, "\"");
106}
107
108
109static void
110write_msg (FILE *output_file, message_list_ty *mlp, const char *locale_name)
111{
112  size_t j;
113
114  /* We don't care about esthetic formattic of the output (like respecting
115     a maximum line width, or including the translator comments) because
116     the \unnnn notation is unesthetic anyway.  Translators shall edit
117     the PO file.  */
118  for (j = 0; j < mlp->nitems; j++)
119    {
120      message_ty *mp = mlp->item[j];
121
122      if (is_header (mp))
123	/* Tcl's msgcat unit ignores this, but msgunfmt needs it.  */
124	fprintf (output_file, "set ::msgcat::header ");
125      else
126	{
127	  fprintf (output_file, "::msgcat::mcset %s ", locale_name);
128	  write_tcl_string (output_file, mp->msgid);
129	  fprintf (output_file, " ");
130	}
131      write_tcl_string (output_file, mp->msgstr);
132      fprintf (output_file, "\n");
133    }
134}
135
136int
137msgdomain_write_tcl (message_list_ty *mlp, const char *canon_encoding,
138		     const char *locale_name,
139		     const char *directory)
140{
141  /* If no entry for this domain don't even create the file.  */
142  if (mlp->nitems == 0)
143    return 0;
144
145  /* Determine whether mlp has entries with context.  */
146  {
147    bool has_context;
148    size_t j;
149
150    has_context = false;
151    for (j = 0; j < mlp->nitems; j++)
152      if (mlp->item[j]->msgctxt != NULL)
153	has_context = true;
154    if (has_context)
155      {
156	multiline_error (xstrdup (""),
157			 xstrdup (_("\
158message catalog has context dependent translations\n\
159but the Tcl message catalog format doesn't support contexts\n")));
160	return 1;
161      }
162  }
163
164  /* Determine whether mlp has plural entries.  */
165  {
166    bool has_plural;
167    size_t j;
168
169    has_plural = false;
170    for (j = 0; j < mlp->nitems; j++)
171      if (mlp->item[j]->msgid_plural != NULL)
172	has_plural = true;
173    if (has_plural)
174      {
175	multiline_error (xstrdup (""),
176			 xstrdup (_("\
177message catalog has plural form translations\n\
178but the Tcl message catalog format doesn't support plural handling\n")));
179	return 1;
180      }
181  }
182
183  /* Convert the messages to Unicode.  */
184  iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL);
185
186  /* Now create the file.  */
187  {
188    size_t len;
189    char *frobbed_locale_name;
190    char *p;
191    char *file_name;
192    FILE *output_file;
193
194    /* Convert the locale name to lowercase and remove any encoding.  */
195    len = strlen (locale_name);
196    frobbed_locale_name = (char *) xmalloca (len + 1);
197    memcpy (frobbed_locale_name, locale_name, len + 1);
198    for (p = frobbed_locale_name; *p != '\0'; p++)
199      if (*p >= 'A' && *p <= 'Z')
200	*p = *p - 'A' + 'a';
201      else if (*p == '.')
202	{
203	  *p = '\0';
204	  break;
205	}
206
207    file_name = concatenated_filename (directory, frobbed_locale_name, ".msg");
208
209    output_file = fopen (file_name, "w");
210    if (output_file == NULL)
211      {
212	error (0, errno, _("error while opening \"%s\" for writing"),
213	       file_name);
214	freea (frobbed_locale_name);
215	return 1;
216      }
217
218    write_msg (output_file, mlp, frobbed_locale_name);
219
220    /* Make sure nothing went wrong.  */
221    if (fwriteerror (output_file))
222      error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
223	     file_name);
224
225    freea (frobbed_locale_name);
226  }
227
228  return 0;
229}
230