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