1/* Reading tcl/msgcat .msg files.
2   Copyright (C) 2002-2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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-po.h"
38#include "xallocsa.h"
39#include "error.h"
40#include "exit.h"
41#include "gettext.h"
42
43#define _(str) gettext (str)
44
45
46/* A Tcl .msg file contains Tcl commands.  It is best interpreted by Tcl
47   itself.  But we redirect the msgcat::mcset function so that it passes
48   the msgid/msgstr pair to us, instead of storing it in the hash table.  */
49
50msgdomain_list_ty *
51msgdomain_read_tcl (const char *locale_name, const char *directory)
52{
53  const char *gettextdatadir;
54  char *tclscript;
55  size_t len;
56  char *frobbed_locale_name;
57  char *p;
58  char *file_name;
59  char *argv[4];
60  pid_t child;
61  int fd[1];
62  FILE *fp;
63  msgdomain_list_ty *mdlp;
64  int exitstatus;
65  size_t k;
66
67  /* Make it possible to override the msgunfmt.tcl location.  This is
68     necessary for running the testsuite before "make install".  */
69  gettextdatadir = getenv ("GETTEXTDATADIR");
70  if (gettextdatadir == NULL || gettextdatadir[0] == '\0')
71    gettextdatadir = relocate (GETTEXTDATADIR);
72
73  tclscript = concatenated_pathname (gettextdatadir, "msgunfmt.tcl", NULL);
74
75  /* Convert the locale name to lowercase and remove any encoding.  */
76  len = strlen (locale_name);
77  frobbed_locale_name = (char *) xallocsa (len + 1);
78  memcpy (frobbed_locale_name, locale_name, len + 1);
79  for (p = frobbed_locale_name; *p != '\0'; p++)
80    if (*p >= 'A' && *p <= 'Z')
81      *p = *p - 'A' + 'a';
82    else if (*p == '.')
83      {
84	*p = '\0';
85	break;
86      }
87
88  file_name = concatenated_pathname (directory, frobbed_locale_name, ".msg");
89
90  freesa (frobbed_locale_name);
91
92  /* Prepare arguments.  */
93  argv[0] = "tclsh";
94  argv[1] = tclscript;
95  argv[2] = file_name;
96  argv[3] = NULL;
97
98  if (verbose)
99    {
100      char *command = shell_quote_argv (argv);
101      printf ("%s\n", command);
102      free (command);
103    }
104
105  /* Open a pipe to the Tcl interpreter.  */
106  child = create_pipe_in ("tclsh", "tclsh", argv, DEV_NULL, false, true, true,
107			  fd);
108
109  fp = fdopen (fd[0], "r");
110  if (fp == NULL)
111    error (EXIT_FAILURE, errno, _("fdopen() failed"));
112
113  /* Read the message list.  */
114  mdlp = read_po (fp, "(pipe)", "(pipe)");
115
116  fclose (fp);
117
118  /* Remove zombie process from process list, and retrieve exit status.  */
119  exitstatus = wait_subprocess (child, "tclsh", false, false, true, true);
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 (mlp->item[j]->msgid[0] == '\0')
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}
158