changeset 5624:356a0afaf162

New module 'javaexec'.
author Bruno Haible <bruno@clisp.org>
date Wed, 26 Jan 2005 17:01:02 +0000
parents 597e498573cd
children 82c8ea96704e
files ChangeLog lib/ChangeLog lib/javaexec.c lib/javaexec.h lib/javaexec.sh.in m4/ChangeLog m4/javaexec.m4 modules/javaexec
diffstat 8 files changed, 683 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-01-26  Bruno Haible  <bruno@clisp.org>
+
+	* modules/javaexec: New file.
+	* MODULES.html.sh (Java): Add javaexec.
+
 2005-01-24  Sergey Poznyakoff  <gray@Mirddin.farlep.net>
 
 	* modules/lchown (Depends-on): Remove lchown.h
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,9 @@
+2005-01-26  Bruno Haible  <bruno@clisp.org>
+
+	* javaexec.sh.in: New file, from GNU gettext.
+	* javaexec.h: New file, from GNU gettext.
+	* javaexec.c: New file, from GNU gettext.
+
 2005-01-26  Simon Josefsson  <jas@extundo.com>
 
 	* gai_strerror.c: Use GPL in header.
new file mode 100644
--- /dev/null
+++ b/lib/javaexec.c
@@ -0,0 +1,432 @@
+/* Execute a Java program.
+   Copyright (C) 2001-2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <alloca.h>
+
+/* Specification.  */
+#include "javaexec.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "execute.h"
+#include "classpath.h"
+#include "xsetenv.h"
+#include "sh-quote.h"
+#include "pathname.h"
+#include "xalloc.h"
+#include "xallocsa.h"
+#include "error.h"
+#include "gettext.h"
+
+#define _(str) gettext (str)
+
+
+/* Survey of Java virtual machines.
+
+   A = does it work without CLASSPATH being set
+   B = does it work with CLASSPATH being set to empty
+   C = option to set CLASSPATH, other than setting it in the environment
+   T = test for presence
+
+   Program    from         A B  C              T
+
+   $JAVA      unknown      N Y  n/a            true
+   gij        GCC 3.0      Y Y  n/a            gij --version >/dev/null
+   java       JDK 1.1.8    Y Y  -classpath P   java -version 2>/dev/null
+   jre        JDK 1.1.8    N Y  -classpath P   jre 2>/dev/null; test $? = 1
+   java       JDK 1.3.0    Y Y  -classpath P   java -version 2>/dev/null
+   jview      MS IE        Y Y  -cp P          jview -? >nul; %errorlevel% = 1
+
+   The CLASSPATH is a colon separated list of pathnames. (On Windows: a
+   semicolon separated list of pathnames.)
+
+   We try the Java virtual machines in the following order:
+     1. getenv ("JAVA"), because the user must be able to override our
+	preferences,
+     2. "gij", because it is a completely free JVM,
+     3. "java", because it is a standard JVM,
+     4. "jre", comes last because it requires a CLASSPATH environment variable,
+     5. "jview", on Windows only, because it is frequently installed.
+
+   We unset the JAVA_HOME environment variable, because a wrong setting of
+   this variable can confuse the JDK's javac.
+ */
+
+bool
+execute_java_class (const char *class_name,
+		    const char * const *classpaths,
+		    unsigned int classpaths_count,
+		    bool use_minimal_classpath,
+		    const char *exe_dir,
+		    const char * const *args,
+		    bool verbose, bool quiet,
+		    execute_fn *executer, void *private_data)
+{
+  bool err = false;
+  unsigned int nargs;
+  char *old_JAVA_HOME;
+
+  /* Count args.  */
+  {
+    const char * const *arg;
+
+    for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++)
+     ;
+  }
+
+  /* First, try a class compiled to a native code executable.  */
+  if (exe_dir != NULL)
+    {
+      char *exe_pathname = concatenated_pathname (exe_dir, class_name, EXEEXT);
+      char *old_classpath;
+      char **argv = (char **) xallocsa ((1 + nargs + 1) * sizeof (char *));
+      unsigned int i;
+
+      /* Set CLASSPATH.  */
+      old_classpath =
+	set_classpath (classpaths, classpaths_count, use_minimal_classpath,
+		       verbose);
+
+      argv[0] = exe_pathname;
+      for (i = 0; i <= nargs; i++)
+	argv[1 + i] = (char *) args[i];
+
+      if (verbose)
+	{
+	  char *command = shell_quote_argv (argv);
+	  printf ("%s\n", command);
+	  free (command);
+	}
+
+      err = executer (class_name, exe_pathname, argv, private_data);
+
+      /* Reset CLASSPATH.  */
+      reset_classpath (old_classpath);
+
+      freesa (argv);
+
+      goto done1;
+    }
+
+  {
+    const char *java = getenv ("JAVA");
+    if (java != NULL && java[0] != '\0')
+      {
+	/* Because $JAVA may consist of a command and options, we use the
+	   shell.  Because $JAVA has been set by the user, we leave all
+	   all environment variables in place, including JAVA_HOME, and
+	   we don't erase the user's CLASSPATH.  */
+	char *old_classpath;
+	unsigned int command_length;
+	char *command;
+	char *argv[4];
+	const char * const *arg;
+	char *p;
+
+	/* Set CLASSPATH.  */
+	old_classpath =
+	  set_classpath (classpaths, classpaths_count, false,
+			 verbose);
+
+	command_length = strlen (java);
+	command_length += 1 + shell_quote_length (class_name);
+	for (arg = args; *arg != NULL; arg++)
+	  command_length += 1 + shell_quote_length (*arg);
+	command_length += 1;
+
+	command = (char *) xallocsa (command_length);
+	p = command;
+	/* Don't shell_quote $JAVA, because it may consist of a command
+	   and options.  */
+	memcpy (p, java, strlen (java));
+	p += strlen (java);
+	*p++ = ' ';
+	p = shell_quote_copy (p, class_name);
+	for (arg = args; *arg != NULL; arg++)
+	  {
+	    *p++ = ' ';
+	    p = shell_quote_copy (p, *arg);
+	  }
+	*p++ = '\0';
+	/* Ensure command_length was correctly calculated.  */
+	if (p - command > command_length)
+	  abort ();
+
+	if (verbose)
+	  printf ("%s\n", command);
+
+	argv[0] = "/bin/sh";
+	argv[1] = "-c";
+	argv[2] = command;
+	argv[3] = NULL;
+	err = executer (java, "/bin/sh", argv, private_data);
+
+	freesa (command);
+
+	/* Reset CLASSPATH.  */
+	reset_classpath (old_classpath);
+
+	goto done1;
+      }
+  }
+
+  /* Unset the JAVA_HOME environment variable.  */
+  old_JAVA_HOME = getenv ("JAVA_HOME");
+  if (old_JAVA_HOME != NULL)
+    {
+      old_JAVA_HOME = xstrdup (old_JAVA_HOME);
+      unsetenv ("JAVA_HOME");
+    }
+
+  {
+    static bool gij_tested;
+    static bool gij_present;
+
+    if (!gij_tested)
+      {
+	/* Test for presence of gij: "gij --version > /dev/null"  */
+	char *argv[3];
+	int exitstatus;
+
+	argv[0] = "gij";
+	argv[1] = "--version";
+	argv[2] = NULL;
+	exitstatus = execute ("gij", "gij", argv, false, false, true, true,
+			      true, false);
+	gij_present = (exitstatus == 0);
+	gij_tested = true;
+      }
+
+    if (gij_present)
+      {
+	char *old_classpath;
+	char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *));
+	unsigned int i;
+
+	/* Set CLASSPATH.  */
+	old_classpath =
+	  set_classpath (classpaths, classpaths_count, use_minimal_classpath,
+			 verbose);
+
+	argv[0] = "gij";
+	argv[1] = (char *) class_name;
+	for (i = 0; i <= nargs; i++)
+	  argv[2 + i] = (char *) args[i];
+
+	if (verbose)
+	  {
+	    char *command = shell_quote_argv (argv);
+	    printf ("%s\n", command);
+	    free (command);
+	  }
+
+	err = executer ("gij", "gij", argv, private_data);
+
+	/* Reset CLASSPATH.  */
+	reset_classpath (old_classpath);
+
+	freesa (argv);
+
+	goto done2;
+      }
+  }
+
+  {
+    static bool java_tested;
+    static bool java_present;
+
+    if (!java_tested)
+      {
+	/* Test for presence of java: "java -version 2> /dev/null"  */
+	char *argv[3];
+	int exitstatus;
+
+	argv[0] = "java";
+	argv[1] = "-version";
+	argv[2] = NULL;
+	exitstatus = execute ("java", "java", argv, false, false, true, true,
+			      true, false);
+	java_present = (exitstatus == 0);
+	java_tested = true;
+      }
+
+    if (java_present)
+      {
+	char *old_classpath;
+	char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *));
+	unsigned int i;
+
+	/* Set CLASSPATH.  We don't use the "-classpath ..." option because
+	   in JDK 1.1.x its argument should also contain the JDK's classes.zip,
+	   but we don't know its location.  (In JDK 1.3.0 it would work.)  */
+	old_classpath =
+	  set_classpath (classpaths, classpaths_count, use_minimal_classpath,
+			 verbose);
+
+	argv[0] = "java";
+	argv[1] = (char *) class_name;
+	for (i = 0; i <= nargs; i++)
+	  argv[2 + i] = (char *) args[i];
+
+	if (verbose)
+	  {
+	    char *command = shell_quote_argv (argv);
+	    printf ("%s\n", command);
+	    free (command);
+	  }
+
+	err = executer ("java", "java", argv, private_data);
+
+	/* Reset CLASSPATH.  */
+	reset_classpath (old_classpath);
+
+	freesa (argv);
+
+	goto done2;
+      }
+  }
+
+  {
+    static bool jre_tested;
+    static bool jre_present;
+
+    if (!jre_tested)
+      {
+	/* Test for presence of jre: "jre 2> /dev/null ; test $? = 1"  */
+	char *argv[2];
+	int exitstatus;
+
+	argv[0] = "jre";
+	argv[1] = NULL;
+	exitstatus = execute ("jre", "jre", argv, false, false, true, true,
+			      true, false);
+	jre_present = (exitstatus == 0 || exitstatus == 1);
+	jre_tested = true;
+      }
+
+    if (jre_present)
+      {
+	char *old_classpath;
+	char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *));
+	unsigned int i;
+
+	/* Set CLASSPATH.  We don't use the "-classpath ..." option because
+	   in JDK 1.1.x its argument should also contain the JDK's classes.zip,
+	   but we don't know its location.  */
+	old_classpath =
+	  set_classpath (classpaths, classpaths_count, use_minimal_classpath,
+			 verbose);
+
+	argv[0] = "jre";
+	argv[1] = (char *) class_name;
+	for (i = 0; i <= nargs; i++)
+	  argv[2 + i] = (char *) args[i];
+
+	if (verbose)
+	  {
+	    char *command = shell_quote_argv (argv);
+	    printf ("%s\n", command);
+	    free (command);
+	  }
+
+	err = executer ("jre", "jre", argv, private_data);
+
+	/* Reset CLASSPATH.  */
+	reset_classpath (old_classpath);
+
+	freesa (argv);
+
+	goto done2;
+      }
+  }
+
+#if defined _WIN32 || defined __WIN32__
+  /* Win32 */
+  {
+    static bool jview_tested;
+    static bool jview_present;
+
+    if (!jview_tested)
+      {
+	/* Test for presence of jview: "jview -? >nul ; test $? = 1"  */
+	char *argv[3];
+	int exitstatus;
+
+	argv[0] = "jview";
+	argv[1] = "-?";
+	argv[2] = NULL;
+	exitstatus = execute ("jview", "jview", argv, false, false, true, true,
+			      true, false);
+	jview_present = (exitstatus == 0 || exitstatus == 1);
+	jview_tested = true;
+      }
+
+    if (jview_present)
+      {
+	char *old_classpath;
+	char **argv = (char **) xallocsa ((2 + nargs + 1) * sizeof (char *));
+	unsigned int i;
+
+	/* Set CLASSPATH.  */
+	old_classpath =
+	  set_classpath (classpaths, classpaths_count, use_minimal_classpath,
+			 verbose);
+
+	argv[0] = "jview";
+	argv[1] = (char *) class_name;
+	for (i = 0; i <= nargs; i++)
+	  argv[2 + i] = (char *) args[i];
+
+	if (verbose)
+	  {
+	    char *command = shell_quote_argv (argv);
+	    printf ("%s\n", command);
+	    free (command);
+	  }
+
+	err = executer ("jview", "jview", argv, private_data);
+
+	/* Reset CLASSPATH.  */
+	reset_classpath (old_classpath);
+
+	freesa (argv);
+
+	goto done2;
+      }
+  }
+#endif
+
+  if (!quiet)
+    error (0, 0, _("Java virtual machine not found, try installing gij or set $JAVA"));
+  err = true;
+
+ done2:
+  if (old_JAVA_HOME != NULL)
+    {
+      xsetenv ("JAVA_HOME", old_JAVA_HOME, 1);
+      free (old_JAVA_HOME);
+    }
+
+ done1:
+  return err;
+}
new file mode 100644
--- /dev/null
+++ b/lib/javaexec.h
@@ -0,0 +1,51 @@
+/* Execute a Java program.
+   Copyright (C) 2001-2002 Free Software Foundation, Inc.
+   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _JAVAEXEC_H
+#define _JAVAEXEC_H
+
+#include <stdbool.h>
+
+typedef bool execute_fn (const char *progname,
+			 const char *prog_path, char **prog_argv,
+			 void *private_data);
+
+/* Execute a Java class.
+   class_name is the Java class name to be executed.
+   classpaths is a list of pathnames to be prepended to the CLASSPATH.
+   use_minimal_classpath = true means to ignore the user's CLASSPATH and
+   use a minimal one. This is likely to reduce possible problems if the
+   user's CLASSPATH contains garbage or a classes.zip file of the wrong
+   Java version.
+   exe_dir is a directory that may contain a native executable for the class.
+   args is a NULL terminated list of arguments to be passed to the program.
+   If verbose, the command to be executed will be printed.
+   Then the command is passed to the execute function together with the
+   private_data argument.  This function returns false if OK, true on error.
+   Return false if OK, true on error.
+   If quiet, error messages will not be printed.  */
+extern bool execute_java_class (const char *class_name,
+				const char * const *classpaths,
+				unsigned int classpaths_count,
+				bool use_minimal_classpath,
+				const char *exe_dir,
+				const char * const *args,
+				bool verbose, bool quiet,
+				execute_fn *executer, void *private_data);
+
+#endif /* _JAVAEXEC_H */
new file mode 100644
--- /dev/null
+++ b/lib/javaexec.sh.in
@@ -0,0 +1,67 @@
+#!/bin/sh
+# Execute a Java program.
+
+# Copyright (C) 2001 Free Software Foundation, Inc.
+# Written by Bruno Haible <haible@clisp.cons.org>, 2001.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+# This uses the same choices as javaexec.c, but instead of relying on the
+# environment settings at run time, it uses the environment variables
+# present at configuration time.
+#
+# This is a separate shell script, because it must be able to unset JAVA_HOME
+# in some cases, which a simple shell command cannot do.
+#
+# The extra CLASSPATH must have been set prior to calling this script.
+
+CONF_JAVA='@JAVA@'
+CONF_CLASSPATH='@CLASSPATH@'
+if test -n "$CONF_JAVA"; then
+  # Combine given CLASSPATH and configured CLASSPATH.
+  if test -n "$CLASSPATH"; then
+    CLASSPATH="$CLASSPATH${CONF_CLASSPATH:+@CLASSPATH_SEPARATOR@$CONF_CLASSPATH}"
+  else
+    CLASSPATH="$CONF_CLASSPATH"
+  fi
+  export CLASSPATH
+  test -z "$JAVA_VERBOSE" || echo "$CONF_JAVA $@"
+  exec $CONF_JAVA "$@"
+else
+  unset JAVA_HOME
+  export CLASSPATH
+  if test -n "@HAVE_GIJ@"; then
+    test -z "$JAVA_VERBOSE" || echo gij "$@"
+    exec gij "$@"
+  else
+    if test -n "@HAVE_JAVA@"; then
+      test -z "$JAVA_VERBOSE" || echo java "$@"
+      exec java "$@"
+    else
+      if test -n "@HAVE_JRE@"; then
+        test -z "$JAVA_VERBOSE" || echo jre "$@"
+        exec jre "$@"
+      else
+        if test -n "@HAVE_JVIEW@"; then
+          test -z "$JAVA_VERBOSE" || echo jview "$@"
+          exec jview "$@"
+        else
+          echo 'Java virtual machine not found, try installing gij or set $JAVA, then reconfigure' 1>&2
+          exit 1
+        fi
+      fi
+    fi
+  fi
+fi
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2005-01-26  Bruno Haible  <bruno@clisp.org>
+
+	* javaexec.m4: New file, from GNU gettext.
+
 2005-01-24  Sergey Poznyakoff  <gray@Mirddin.farlep.net>
 
 	* sysexits.m4 (gl_SYSEXITS): Reverted logic. SYSEXITS_H
new file mode 100644
--- /dev/null
+++ b/m4/javaexec.m4
@@ -0,0 +1,80 @@
+# javaexec.m4 serial 2 (gettext-0.13)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Prerequisites of javaexec.sh.
+# gt_JAVAEXEC or gt_JAVAEXEC(testclass, its-directory)
+# Sets HAVE_JAVAEXEC to nonempty if javaexec.sh will work.
+
+AC_DEFUN([gt_JAVAEXEC],
+[
+  AC_MSG_CHECKING([for Java virtual machine])
+  AC_EGREP_CPP(yes, [
+#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
+  yes
+#endif
+], CLASSPATH_SEPARATOR=';', CLASSPATH_SEPARATOR=':')
+  HAVE_JAVAEXEC=1
+  if test -n "$JAVA"; then
+    ac_result="$JAVA"
+  else
+    pushdef([AC_MSG_CHECKING],[:])dnl
+    pushdef([AC_CHECKING],[:])dnl
+    pushdef([AC_MSG_RESULT],[:])dnl
+    AC_CHECK_PROG(HAVE_GIJ_IN_PATH, gij, yes)
+    AC_CHECK_PROG(HAVE_JAVA_IN_PATH, java, yes)
+    AC_CHECK_PROG(HAVE_JRE_IN_PATH, jre, yes)
+    AC_CHECK_PROG(HAVE_JVIEW_IN_PATH, jview, yes)
+    popdef([AC_MSG_RESULT])dnl
+    popdef([AC_CHECKING])dnl
+    popdef([AC_MSG_CHECKING])dnl
+    ifelse([$1], , , [
+      save_CLASSPATH="$CLASSPATH"
+      CLASSPATH="$2"${CLASSPATH+"$CLASSPATH_SEPARATOR$CLASSPATH"}
+      ])
+    export CLASSPATH
+    if test -n "$HAVE_GIJ_IN_PATH" \
+       && gij --version >/dev/null 2>/dev/null \
+       ifelse([$1], , , [&& gij $1 >/dev/null 2>/dev/null]); then
+      HAVE_GIJ=1
+      ac_result="gij"
+    else
+      if test -n "$HAVE_JAVA_IN_PATH" \
+         && java -version >/dev/null 2>/dev/null \
+         ifelse([$1], , , [&& java $1 >/dev/null 2>/dev/null]); then
+        HAVE_JAVA=1
+        ac_result="java"
+      else
+        if test -n "$HAVE_JRE_IN_PATH" \
+           && (jre >/dev/null 2>/dev/null || test $? = 1) \
+           ifelse([$1], , , [&& jre $1 >/dev/null 2>/dev/null]); then
+          HAVE_JRE=1
+          ac_result="jre"
+        else
+          if test -n "$HAVE_JVIEW_IN_PATH" \
+             && (jview -? >/dev/null 2>/dev/null || test $? = 1) \
+             ifelse([$1], , , [&& jview $1 >/dev/null 2>/dev/null]); then
+            HAVE_JVIEW=1
+            ac_result="jview"
+          else
+            HAVE_JAVAEXEC=
+            ac_result="no"
+          fi
+        fi
+      fi
+    fi
+    ifelse([$1], , , [
+      CLASSPATH="$save_CLASSPATH"
+    ])
+  fi
+  AC_MSG_RESULT([$ac_result])
+  AC_SUBST(JAVA)
+  AC_SUBST(CLASSPATH)
+  AC_SUBST(CLASSPATH_SEPARATOR)
+  AC_SUBST(HAVE_GIJ)
+  AC_SUBST(HAVE_JAVA)
+  AC_SUBST(HAVE_JRE)
+  AC_SUBST(HAVE_JVIEW)
+])
new file mode 100644
--- /dev/null
+++ b/modules/javaexec
@@ -0,0 +1,38 @@
+Description:
+Execute a Java program.
+
+Files:
+lib/javaexec.h
+lib/javaexec.c
+lib/javaexec.sh.in
+m4/javaexec.m4
+
+Depends-on:
+stdbool
+execute
+classpath
+xsetenv
+sh-quote
+pathname
+xalloc
+xallocsa
+error
+gettext
+
+configure.ac:
+gt_JAVAEXEC
+
+Makefile.am:
+DEFS += -DEXEEXT=\"$(EXEEXT)\"
+lib_SOURCES += javaexec.h javaexec.c
+EXTRA_DIST += javaexec.sh.in
+
+Include:
+"javaexec.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible
+