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