604e13769ff682642689bc78233fa50697eab65f
[gnulib.git] / lib / csharpexec.c
1 /* Execute a C# program.
2    Copyright (C) 2003-2004 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., 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 "csharpexec.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "execute.h"
31 #include "sh-quote.h"
32 #include "xallocsa.h"
33 #include "error.h"
34 #include "gettext.h"
35
36 /* Handling of MONO_PATH is just like Java CLASSPATH.  */
37 #define CLASSPATHVAR "MONO_PATH"
38 #define new_classpath new_monopath
39 #define set_classpath set_monopath
40 #define reset_classpath reset_monopath
41 #include "classpath.h"
42 #include "classpath.c"
43
44 #define _(str) gettext (str)
45
46
47 /* Survey of CIL interpreters.
48
49    Program    from
50
51    ilrun      pnet
52    mono       mono
53
54    With Mono, the MONO_PATH is a colon separated list of pathnames. (On
55    Windows: semicolon separated list of pathnames.)
56
57    We try the CIL interpreters in the following order:
58      1. "ilrun", because it is a completely free system.
59      2. "mono", because it is a partially free system but doesn't integrate
60         well with Unix.
61    But the order can be changed through the --enable-csharp configuration
62    option.
63  */
64
65 static int
66 execute_csharp_using_pnet (const char *assembly_path,
67                            const char * const *libdirs,
68                            unsigned int libdirs_count,
69                            const char * const *args, unsigned int nargs,
70                            bool verbose, bool quiet,
71                            execute_fn *executer, void *private_data)
72 {
73   static bool ilrun_tested;
74   static bool ilrun_present;
75
76   if (!ilrun_tested)
77     {
78       /* Test for presence of ilrun:
79          "ilrun --version >/dev/null 2>/dev/null"  */
80       char *argv[3];
81       int exitstatus;
82
83       argv[0] = "ilrun";
84       argv[1] = "--version";
85       argv[2] = NULL;
86       exitstatus = execute ("ilrun", "ilrun", argv, false, false, true, true,
87                             true, false);
88       ilrun_present = (exitstatus == 0);
89       ilrun_tested = true;
90     }
91
92   if (ilrun_present)
93     {
94       unsigned int argc;
95       char **argv;
96       char **argp;
97       unsigned int i;
98       bool err;
99
100       argc = 1 + 2 * libdirs_count + 1 + nargs;
101       argv = (char **) xallocsa ((argc + 1) * sizeof (char *));
102
103       argp = argv;
104       *argp++ = "ilrun";
105       for (i = 0; i < libdirs_count; i++)
106         {
107           *argp++ = "-L";
108           *argp++ = (char *) libdirs[i];
109         }
110       *argp++ = (char *) assembly_path;
111       for (i = 0; i < nargs; i++)
112         *argp++ = (char *) args[i];
113       *argp = NULL;
114       /* Ensure argv length was correctly calculated.  */
115       if (argp - argv != argc)
116         abort ();
117
118       if (verbose)
119         {
120           char *command = shell_quote_argv (argv);
121           printf ("%s\n", command);
122           free (command);
123         }
124
125       err = executer ("ilrun", "ilrun", argv, private_data);
126
127       freesa (argv);
128
129       return err;
130     }
131   else
132     return -1;
133 }
134
135 static int
136 execute_csharp_using_mono (const char *assembly_path,
137                            const char * const *libdirs,
138                            unsigned int libdirs_count,
139                            const char * const *args, unsigned int nargs,
140                            bool verbose, bool quiet,
141                            execute_fn *executer, void *private_data)
142 {
143   static bool mono_tested;
144   static bool mono_present;
145
146   if (!mono_tested)
147     {
148       /* Test for presence of mono:
149          "mono --version >/dev/null 2>/dev/null"  */
150       char *argv[3];
151       int exitstatus;
152
153       argv[0] = "mono";
154       argv[1] = "--version";
155       argv[2] = NULL;
156       exitstatus = execute ("mono", "mono", argv, false, false, true, true,
157                             true, false);
158       mono_present = (exitstatus == 0);
159       mono_tested = true;
160     }
161
162   if (mono_present)
163     {
164       char *old_monopath;
165       char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *));
166       unsigned int i;
167       bool err;
168
169       /* Set MONO_PATH.  */
170       old_monopath = set_monopath (libdirs, libdirs_count, false, verbose);
171
172       argv[0] = "mono";
173       argv[1] = (char *) assembly_path;
174       for (i = 0; i <= nargs; i++)
175         argv[2 + i] = (char *) args[i];
176
177       if (verbose)
178         {
179           char *command = shell_quote_argv (argv);
180           printf ("%s\n", command);
181           free (command);
182         }
183
184       err = executer ("mono", "mono", argv, private_data);
185
186       /* Reset MONO_PATH.  */
187       reset_monopath (old_monopath);
188
189       freesa (argv);
190
191       return err;
192     }
193   else
194     return -1;
195 }
196
197 bool
198 execute_csharp_program (const char *assembly_path,
199                         const char * const *libdirs,
200                         unsigned int libdirs_count,
201                         const char * const *args,
202                         bool verbose, bool quiet,
203                         execute_fn *executer, void *private_data)
204 {
205   unsigned int nargs;
206   int result;
207
208   /* Count args.  */
209   {
210     const char * const *arg;
211
212     for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++)
213      ;
214   }
215
216   /* First try the C# implementation specified through --enable-csharp.  */
217 #if CSHARP_CHOICE_PNET
218   result = execute_csharp_using_pnet (assembly_path, libdirs, libdirs_count,
219                                       args, nargs, verbose, quiet,
220                                       executer, private_data);
221   if (result >= 0)
222     return (bool) result;
223 #endif
224
225 #if CSHARP_CHOICE_MONO
226   result = execute_csharp_using_mono (assembly_path, libdirs, libdirs_count,
227                                       args, nargs, verbose, quiet,
228                                       executer, private_data);
229   if (result >= 0)
230     return (bool) result;
231 #endif
232
233   /* Then try the remaining C# implementations in our standard order.  */
234 #if !CSHARP_CHOICE_PNET
235   result = execute_csharp_using_pnet (assembly_path, libdirs, libdirs_count,
236                                       args, nargs, verbose, quiet,
237                                       executer, private_data);
238   if (result >= 0)
239     return (bool) result;
240 #endif
241
242 #if !CSHARP_CHOICE_MONO
243   result = execute_csharp_using_mono (assembly_path, libdirs, libdirs_count,
244                                       args, nargs, verbose, quiet,
245                                       executer, private_data);
246   if (result >= 0)
247     return (bool) result;
248 #endif
249
250   if (!quiet)
251     error (0, 0, _("C# virtual machine not found, try installing pnet"));
252   return true;
253 }