Imported Upstream version 0.18.3.2
[platform/upstream/gettext.git] / gettext-tools / src / read-tcl.c
1 /* Reading tcl/msgcat .msg files.
2    Copyright (C) 2002-2003, 2005-2008, 2011 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 "read-tcl.h"
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "msgunfmt.h"
31 #include "relocatable.h"
32 #include "concat-filename.h"
33 #include "sh-quote.h"
34 #include "spawn-pipe.h"
35 #include "wait-process.h"
36 #include "read-catalog.h"
37 #include "read-po.h"
38 #include "xmalloca.h"
39 #include "error.h"
40 #include "gettext.h"
41
42 #define _(str) gettext (str)
43
44
45 /* A Tcl .msg file contains Tcl commands.  It is best interpreted by Tcl
46    itself.  But we redirect the msgcat::mcset function so that it passes
47    the msgid/msgstr pair to us, instead of storing it in the hash table.  */
48
49 msgdomain_list_ty *
50 msgdomain_read_tcl (const char *locale_name, const char *directory)
51 {
52   const char *gettextdatadir;
53   char *tclscript;
54   size_t len;
55   char *frobbed_locale_name;
56   char *p;
57   char *file_name;
58   char *argv[4];
59   pid_t child;
60   int fd[1];
61   FILE *fp;
62   msgdomain_list_ty *mdlp;
63   int exitstatus;
64   size_t k;
65
66   /* Make it possible to override the msgunfmt.tcl location.  This is
67      necessary for running the testsuite before "make install".  */
68   gettextdatadir = getenv ("GETTEXTDATADIR");
69   if (gettextdatadir == NULL || gettextdatadir[0] == '\0')
70     gettextdatadir = relocate (GETTEXTDATADIR);
71
72   tclscript = xconcatenated_filename (gettextdatadir, "msgunfmt.tcl", NULL);
73
74   /* Convert the locale name to lowercase and remove any encoding.  */
75   len = strlen (locale_name);
76   frobbed_locale_name = (char *) xmalloca (len + 1);
77   memcpy (frobbed_locale_name, locale_name, len + 1);
78   for (p = frobbed_locale_name; *p != '\0'; p++)
79     if (*p >= 'A' && *p <= 'Z')
80       *p = *p - 'A' + 'a';
81     else if (*p == '.')
82       {
83         *p = '\0';
84         break;
85       }
86
87   file_name = xconcatenated_filename (directory, frobbed_locale_name, ".msg");
88
89   freea (frobbed_locale_name);
90
91   /* Prepare arguments.  */
92   argv[0] = "tclsh";
93   argv[1] = tclscript;
94   argv[2] = file_name;
95   argv[3] = NULL;
96
97   if (verbose)
98     {
99       char *command = shell_quote_argv (argv);
100       printf ("%s\n", command);
101       free (command);
102     }
103
104   /* Open a pipe to the Tcl interpreter.  */
105   child = create_pipe_in ("tclsh", "tclsh", argv, DEV_NULL, false, true, true,
106                           fd);
107
108   fp = fdopen (fd[0], "r");
109   if (fp == NULL)
110     error (EXIT_FAILURE, errno, _("fdopen() failed"));
111
112   /* Read the message list.  */
113   mdlp = read_catalog_stream (fp, "(pipe)", "(pipe)", &input_format_po);
114
115   fclose (fp);
116
117   /* Remove zombie process from process list, and retrieve exit status.  */
118   exitstatus =
119     wait_subprocess (child, "tclsh", false, false, true, true, NULL);
120   if (exitstatus != 0)
121     {
122       if (exitstatus == 2)
123         /* Special exitcode provided by msgunfmt.tcl.  */
124         error (EXIT_FAILURE, ENOENT,
125                _("error while opening \"%s\" for reading"), file_name);
126       else
127         error (EXIT_FAILURE, 0, _("%s subprocess failed with exit code %d"),
128                "tclsh", exitstatus);
129     }
130
131   free (tclscript);
132
133   /* Move the header entry to the beginning.  */
134   for (k = 0; k < mdlp->nitems; k++)
135     {
136       message_list_ty *mlp = mdlp->item[k]->messages;
137       size_t j;
138
139       for (j = 0; j < mlp->nitems; j++)
140         if (is_header (mlp->item[j]))
141           {
142             /* Found the header entry.  */
143             if (j > 0)
144               {
145                 message_ty *header = mlp->item[j];
146                 size_t i;
147
148                 for (i = j; i > 0; i--)
149                   mlp->item[i] = mlp->item[i - 1];
150                 mlp->item[0] = header;
151               }
152             break;
153           }
154     }
155
156   return mdlp;
157 }