1/* Writing C# .resources files. 2 Copyright (C) 2003, 2005, 2007 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2003. 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 22/* Specification. */ 23#include "write-resources.h" 24 25#include <errno.h> 26#include <stdbool.h> 27#include <stdlib.h> 28#include <stdio.h> 29#include <string.h> 30 31#include "error.h" 32#include "xerror.h" 33#include "relocatable.h" 34#include "csharpexec.h" 35#include "pipe.h" 36#include "wait-process.h" 37#include "message.h" 38#include "msgfmt.h" 39#include "msgl-iconv.h" 40#include "po-charset.h" 41#include "xalloc.h" 42#include "filename.h" 43#include "fwriteerror.h" 44#include "gettext.h" 45 46#define _(str) gettext (str) 47 48 49/* A .resources file has such a complex format that it's most easily generated 50 through the C# class ResourceWriter. So we start a C# process to execute 51 the WriteResource program, sending it the msgid/msgstr pairs as 52 NUL-terminated UTF-8 encoded strings. */ 53 54struct locals 55{ 56 /* IN */ 57 message_list_ty *mlp; 58}; 59 60static bool 61execute_writing_input (const char *progname, 62 const char *prog_path, char **prog_argv, 63 void *private_data) 64{ 65 struct locals *l = (struct locals *) private_data; 66 pid_t child; 67 int fd[1]; 68 FILE *fp; 69 int exitstatus; 70 71 /* Open a pipe to the C# execution engine. */ 72 child = create_pipe_out (progname, prog_path, prog_argv, NULL, false, 73 true, true, fd); 74 75 fp = fdopen (fd[0], "wb"); 76 if (fp == NULL) 77 error (EXIT_FAILURE, errno, _("fdopen() failed")); 78 79 /* Write the message list. */ 80 { 81 message_list_ty *mlp = l->mlp; 82 size_t j; 83 84 for (j = 0; j < mlp->nitems; j++) 85 { 86 message_ty *mp = mlp->item[j]; 87 88 fwrite (mp->msgid, 1, strlen (mp->msgid) + 1, fp); 89 fwrite (mp->msgstr, 1, strlen (mp->msgstr) + 1, fp); 90 } 91 } 92 93 if (fwriteerror (fp)) 94 error (EXIT_FAILURE, 0, _("error while writing to %s subprocess"), 95 progname); 96 97 /* Remove zombie process from process list, and retrieve exit status. */ 98 /* He we can ignore SIGPIPE because WriteResource either writes to a file 99 - then it never gets SIGPIPE - or to standard output, and in the latter 100 case it has no side effects other than writing to standard output. */ 101 exitstatus = wait_subprocess (child, progname, true, false, true, true); 102 if (exitstatus != 0) 103 error (EXIT_FAILURE, 0, _("%s subprocess failed with exit code %d"), 104 progname, exitstatus); 105 106 return false; 107} 108 109int 110msgdomain_write_csharp_resources (message_list_ty *mlp, 111 const char *canon_encoding, 112 const char *domain_name, 113 const char *file_name) 114{ 115 /* If no entry for this domain don't even create the file. */ 116 if (mlp->nitems != 0) 117 { 118 /* Determine whether mlp has entries with context. */ 119 { 120 bool has_context; 121 size_t j; 122 123 has_context = false; 124 for (j = 0; j < mlp->nitems; j++) 125 if (mlp->item[j]->msgctxt != NULL) 126 has_context = true; 127 if (has_context) 128 { 129 multiline_error (xstrdup (""), 130 xstrdup (_("\ 131message catalog has context dependent translations\n\ 132but the C# .resources format doesn't support contexts\n"))); 133 return 1; 134 } 135 } 136 137 /* Determine whether mlp has plural entries. */ 138 { 139 bool has_plural; 140 size_t j; 141 142 has_plural = false; 143 for (j = 0; j < mlp->nitems; j++) 144 if (mlp->item[j]->msgid_plural != NULL) 145 has_plural = true; 146 if (has_plural) 147 { 148 multiline_error (xstrdup (""), 149 xstrdup (_("\ 150message catalog has plural form translations\n\ 151but the C# .resources format doesn't support plural handling\n"))); 152 return 1; 153 } 154 } 155 156 /* Convert the messages to Unicode. */ 157 iconv_message_list (mlp, canon_encoding, po_charset_utf8, NULL); 158 159 /* Execute the WriteResource program. */ 160 { 161 const char *args[2]; 162 const char *gettextexedir; 163 char *assembly_path; 164 struct locals locals; 165 166 /* Prepare arguments. */ 167 args[0] = file_name; 168 args[1] = NULL; 169 170 /* Make it possible to override the .exe location. This is 171 necessary for running the testsuite before "make install". */ 172 gettextexedir = getenv ("GETTEXTCSHARPEXEDIR"); 173 if (gettextexedir == NULL || gettextexedir[0] == '\0') 174 gettextexedir = relocate (LIBDIR "/gettext"); 175 176 assembly_path = 177 concatenated_filename (gettextexedir, "msgfmt.net", ".exe"); 178 179 locals.mlp = mlp; 180 181 if (execute_csharp_program (assembly_path, NULL, 0, 182 args, 183 verbose, false, 184 execute_writing_input, &locals)) 185 /* An error message should already have been provided. */ 186 exit (EXIT_FAILURE); 187 188 free (assembly_path); 189 } 190 } 191 192 return 0; 193} 194