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