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