src/share/tools/launcher/java.c

changeset 2327
cb2d0a362639
child 2369
aa6e219afbf1
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/tools/launcher/java.c	Thu Dec 02 05:45:54 2010 -0800
     1.3 @@ -0,0 +1,2078 @@
     1.4 +/*
     1.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +/*
    1.29 + * Gamma (Hotspot internal engineering test) launcher based on 6.0u22 JDK,
    1.30 + * search "GAMMA" for gamma specific changes.
    1.31 + *
    1.32 + * GAMMA: gamma launcher is much simpler than regular java launcher in that
    1.33 + *        JVM is either statically linked in or it is installed in the
    1.34 + *        same directory where the launcher exists, so we don't have to
    1.35 + *        worry about choosing the right JVM based on command line flag, jar
    1.36 + *        file and/or ergonomics. Intead of removing unused logic from source
    1.37 + *        they are commented out with #ifndef GAMMA, hopefully it'll be easier
    1.38 + *        to maintain this file in sync with regular JDK launcher.
    1.39 + */
    1.40 +
    1.41 +/*
    1.42 + * Shared source for 'java' command line tool.
    1.43 + *
    1.44 + * If JAVA_ARGS is defined, then acts as a launcher for applications. For
    1.45 + * instance, the JDK command line tools such as javac and javadoc (see
    1.46 + * makefiles for more details) are built with this program.  Any arguments
    1.47 + * prefixed with '-J' will be passed directly to the 'java' command.
    1.48 + */
    1.49 +
    1.50 +#ifdef GAMMA
    1.51 +#  ifdef JAVA_ARGS
    1.52 +#    error Do NOT define JAVA_ARGS when building gamma launcher
    1.53 +#  endif
    1.54 +#  if !defined(LINK_INTO_AOUT) && !defined(LINK_INTO_LIBJVM)
    1.55 +#    error Either LINK_INTO_AOUT or LINK_INTO_LIBJVM must be defined
    1.56 +#  endif
    1.57 +#endif
    1.58 +
    1.59 +/*
    1.60 + * One job of the launcher is to remove command line options which the
    1.61 + * vm does not understand and will not process.  These options include
    1.62 + * options which select which style of vm is run (e.g. -client and
    1.63 + * -server) as well as options which select the data model to use.
    1.64 + * Additionally, for tools which invoke an underlying vm "-J-foo"
    1.65 + * options are turned into "-foo" options to the vm.  This option
    1.66 + * filtering is handled in a number of places in the launcher, some of
    1.67 + * it in machine-dependent code.  In this file, the function
    1.68 + * CheckJVMType removes vm style options and TranslateApplicationArgs
    1.69 + * removes "-J" prefixes.  On unix platforms, the
    1.70 + * CreateExecutionEnvironment function from the unix java_md.c file
    1.71 + * processes and removes -d<n> options.  However, in case
    1.72 + * CreateExecutionEnvironment does not need to exec because
    1.73 + * LD_LIBRARY_PATH is set acceptably and the data model does not need
    1.74 + * to be changed, ParseArguments will screen out the redundant -d<n>
    1.75 + * options and prevent them from being passed to the vm; this is done
    1.76 + * by using the machine-dependent call
    1.77 + * RemovableMachineDependentOption.
    1.78 + */
    1.79 +
    1.80 +#include <stdio.h>
    1.81 +#include <stdlib.h>
    1.82 +#include <string.h>
    1.83 +
    1.84 +#include <jni.h>
    1.85 +#include <jvm.h>
    1.86 +#include "java.h"
    1.87 +#ifndef GAMMA
    1.88 +#include "manifest_info.h"
    1.89 +#include "version_comp.h"
    1.90 +#include "splashscreen.h"
    1.91 +#endif
    1.92 +#include "wildcard.h"
    1.93 +
    1.94 +#ifndef FULL_VERSION
    1.95 +#define FULL_VERSION JDK_MAJOR_VERSION "." JDK_MINOR_VERSION
    1.96 +#endif
    1.97 +
    1.98 +/*
    1.99 + * The following environment variable is used to influence the behavior
   1.100 + * of the jre exec'd through the SelectVersion routine.  The command line
   1.101 + * options which specify the version are not passed to the exec'd version,
   1.102 + * because that jre may be an older version which wouldn't recognize them.
   1.103 + * This environment variable is known to this (and later) version and serves
   1.104 + * to suppress the version selection code.  This is not only for efficiency,
   1.105 + * but also for correctness, since any command line options have been
   1.106 + * removed which would cause any value found in the manifest to be used.
   1.107 + * This would be incorrect because the command line options are defined
   1.108 + * to take precedence.
   1.109 + *
   1.110 + * The value associated with this environment variable is the MainClass
   1.111 + * name from within the executable jar file (if any). This is strictly a
   1.112 + * performance enhancement to avoid re-reading the jar file manifest.
   1.113 + *
   1.114 + * A NOTE TO DEVELOPERS: For performance reasons it is important that
   1.115 + * the program image remain relatively small until after SelectVersion
   1.116 + * CreateExecutionEnvironment have finished their possibly recursive
   1.117 + * processing. Watch everything, but resist all temptations to use Java
   1.118 + * interfaces.
   1.119 + */
   1.120 +#define ENV_ENTRY "_JAVA_VERSION_SET"
   1.121 +
   1.122 +#ifndef GAMMA
   1.123 +#define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE"
   1.124 +#define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR"
   1.125 +#endif
   1.126 +
   1.127 +static jboolean printVersion = JNI_FALSE; /* print and exit */
   1.128 +static jboolean showVersion = JNI_FALSE;  /* print but continue */
   1.129 +static char *progname;
   1.130 +jboolean _launcher_debug = JNI_FALSE;
   1.131 +
   1.132 +#ifndef GAMMA
   1.133 +/*
   1.134 + * Entries for splash screen environment variables.
   1.135 + * putenv is performed in SelectVersion. We need
   1.136 + * them in memory until UnsetEnv, so they are made static
   1.137 + * global instead of auto local.
   1.138 + */
   1.139 +static char* splash_file_entry = NULL;
   1.140 +static char* splash_jar_entry = NULL;
   1.141 +#endif
   1.142 +
   1.143 +/*
   1.144 + * List of VM options to be specified when the VM is created.
   1.145 + */
   1.146 +static JavaVMOption *options;
   1.147 +static int numOptions, maxOptions;
   1.148 +
   1.149 +/*
   1.150 + * Prototypes for functions internal to launcher.
   1.151 + */
   1.152 +static void SetClassPath(const char *s);
   1.153 +static void SelectVersion(int argc, char **argv, char **main_class);
   1.154 +static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile,
   1.155 +                               char **pclassname, int *pret, const char *jvmpath);
   1.156 +static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
   1.157 +                              InvocationFunctions *ifn);
   1.158 +static jstring NewPlatformString(JNIEnv *env, char *s);
   1.159 +static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc);
   1.160 +static jclass LoadClass(JNIEnv *env, char *name);
   1.161 +static jstring GetMainClassName(JNIEnv *env, char *jarname);
   1.162 +static void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv);
   1.163 +static void SetJavaLauncherProp(void);
   1.164 +
   1.165 +#ifdef JAVA_ARGS
   1.166 +static void TranslateApplicationArgs(int *pargc, char ***pargv);
   1.167 +static jboolean AddApplicationOptions(void);
   1.168 +#endif
   1.169 +
   1.170 +static void PrintJavaVersion(JNIEnv *env);
   1.171 +static void PrintUsage(void);
   1.172 +static jint PrintXUsage(const char *jvmpath);
   1.173 +
   1.174 +static void SetPaths(int argc, char **argv);
   1.175 +
   1.176 +#ifndef GAMMA
   1.177 +
   1.178 +/* Maximum supported entries from jvm.cfg. */
   1.179 +#define INIT_MAX_KNOWN_VMS      10
   1.180 +/* Values for vmdesc.flag */
   1.181 +#define VM_UNKNOWN              -1
   1.182 +#define VM_KNOWN                 0
   1.183 +#define VM_ALIASED_TO            1
   1.184 +#define VM_WARN                  2
   1.185 +#define VM_ERROR                 3
   1.186 +#define VM_IF_SERVER_CLASS       4
   1.187 +#define VM_IGNORE                5
   1.188 +struct vmdesc {
   1.189 +    char *name;
   1.190 +    int flag;
   1.191 +    char *alias;
   1.192 +    char *server_class;
   1.193 +};
   1.194 +static struct vmdesc *knownVMs = NULL;
   1.195 +static int knownVMsCount = 0;
   1.196 +static int knownVMsLimit = 0;
   1.197 +
   1.198 +static void GrowKnownVMs();
   1.199 +static int  KnownVMIndex(const char* name);
   1.200 +static void FreeKnownVMs();
   1.201 +static void ShowSplashScreen();
   1.202 +
   1.203 +#endif /* ifndef GAMMA */
   1.204 +
   1.205 +jboolean ServerClassMachine();
   1.206 +
   1.207 +/* flag which if set suppresses error messages from the launcher */
   1.208 +static int noExitErrorMessage = 0;
   1.209 +
   1.210 +/*
   1.211 + * Running Java code in primordial thread caused many problems. We will
   1.212 + * create a new thread to invoke JVM. See 6316197 for more information.
   1.213 + */
   1.214 +static jlong threadStackSize = 0;  /* stack size of the new thread */
   1.215 +
   1.216 +int JNICALL JavaMain(void * args); /* entry point                  */
   1.217 +
   1.218 +struct JavaMainArgs {
   1.219 +  int     argc;
   1.220 +  char ** argv;
   1.221 +  char *  jarfile;
   1.222 +  char *  classname;
   1.223 +  InvocationFunctions ifn;
   1.224 +};
   1.225 +
   1.226 +/*
   1.227 + * Entry point.
   1.228 + */
   1.229 +int
   1.230 +main(int argc, char ** argv)
   1.231 +{
   1.232 +    char *jarfile = 0;
   1.233 +    char *classname = 0;
   1.234 +    char *s = 0;
   1.235 +    char *main_class = NULL;
   1.236 +    int ret;
   1.237 +    InvocationFunctions ifn;
   1.238 +    jlong start, end;
   1.239 +    char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN];
   1.240 +    char ** original_argv = argv;
   1.241 +
   1.242 +    if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) {
   1.243 +        _launcher_debug = JNI_TRUE;
   1.244 +        printf("----_JAVA_LAUNCHER_DEBUG----\n");
   1.245 +    }
   1.246 +
   1.247 +#ifndef GAMMA
   1.248 +    /*
   1.249 +     * Make sure the specified version of the JRE is running.
   1.250 +     *
   1.251 +     * There are three things to note about the SelectVersion() routine:
   1.252 +     *  1) If the version running isn't correct, this routine doesn't
   1.253 +     *     return (either the correct version has been exec'd or an error
   1.254 +     *     was issued).
   1.255 +     *  2) Argc and Argv in this scope are *not* altered by this routine.
   1.256 +     *     It is the responsibility of subsequent code to ignore the
   1.257 +     *     arguments handled by this routine.
   1.258 +     *  3) As a side-effect, the variable "main_class" is guaranteed to
   1.259 +     *     be set (if it should ever be set).  This isn't exactly the
   1.260 +     *     poster child for structured programming, but it is a small
   1.261 +     *     price to pay for not processing a jar file operand twice.
   1.262 +     *     (Note: This side effect has been disabled.  See comment on
   1.263 +     *     bugid 5030265 below.)
   1.264 +     */
   1.265 +    SelectVersion(argc, argv, &main_class);
   1.266 +#endif /* ifndef GAMMA */
   1.267 +
   1.268 +    /* copy original argv */
   1.269 +    {
   1.270 +      int i;
   1.271 +      original_argv = (char**)JLI_MemAlloc(sizeof(char*)*(argc+1));
   1.272 +      for(i = 0; i < argc+1; i++)
   1.273 +        original_argv[i] = argv[i];
   1.274 +    }
   1.275 +
   1.276 +    CreateExecutionEnvironment(&argc, &argv,
   1.277 +                               jrepath, sizeof(jrepath),
   1.278 +                               jvmpath, sizeof(jvmpath),
   1.279 +                               original_argv);
   1.280 +
   1.281 +    ifn.CreateJavaVM = 0;
   1.282 +    ifn.GetDefaultJavaVMInitArgs = 0;
   1.283 +
   1.284 +    if (_launcher_debug)
   1.285 +      start = CounterGet();
   1.286 +    if (!LoadJavaVM(jvmpath, &ifn)) {
   1.287 +      exit(6);
   1.288 +    }
   1.289 +    if (_launcher_debug) {
   1.290 +      end   = CounterGet();
   1.291 +      printf("%ld micro seconds to LoadJavaVM\n",
   1.292 +             (long)(jint)Counter2Micros(end-start));
   1.293 +    }
   1.294 +
   1.295 +#ifdef JAVA_ARGS  /* javac, jar and friends. */
   1.296 +    progname = "java";
   1.297 +#else             /* java, oldjava, javaw and friends */
   1.298 +#ifdef PROGNAME
   1.299 +    progname = PROGNAME;
   1.300 +#else
   1.301 +    progname = *argv;
   1.302 +    if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {
   1.303 +        progname = s + 1;
   1.304 +    }
   1.305 +#endif /* PROGNAME */
   1.306 +#endif /* JAVA_ARGS */
   1.307 +    ++argv;
   1.308 +    --argc;
   1.309 +
   1.310 +#ifdef JAVA_ARGS
   1.311 +    /* Preprocess wrapper arguments */
   1.312 +    TranslateApplicationArgs(&argc, &argv);
   1.313 +    if (!AddApplicationOptions()) {
   1.314 +        exit(1);
   1.315 +    }
   1.316 +#endif
   1.317 +
   1.318 +    /* Set default CLASSPATH */
   1.319 +    if ((s = getenv("CLASSPATH")) == 0) {
   1.320 +        s = ".";
   1.321 +    }
   1.322 +#ifndef JAVA_ARGS
   1.323 +    SetClassPath(s);
   1.324 +#endif
   1.325 +
   1.326 +    /*
   1.327 +     *  Parse command line options; if the return value of
   1.328 +     *  ParseArguments is false, the program should exit.
   1.329 +     */
   1.330 +    if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) {
   1.331 +      exit(ret);
   1.332 +    }
   1.333 +
   1.334 +    /* Override class path if -jar flag was specified */
   1.335 +    if (jarfile != 0) {
   1.336 +        SetClassPath(jarfile);
   1.337 +    }
   1.338 +
   1.339 +    /* set the -Dsun.java.command pseudo property */
   1.340 +    SetJavaCommandLineProp(classname, jarfile, argc, argv);
   1.341 +
   1.342 +    /* Set the -Dsun.java.launcher pseudo property */
   1.343 +    SetJavaLauncherProp();
   1.344 +
   1.345 +    /* set the -Dsun.java.launcher.* platform properties */
   1.346 +    SetJavaLauncherPlatformProps();
   1.347 +
   1.348 +#ifndef GAMMA
   1.349 +    /* Show the splash screen if needed */
   1.350 +    ShowSplashScreen();
   1.351 +#endif
   1.352 +
   1.353 +    /*
   1.354 +     * Done with all command line processing and potential re-execs so
   1.355 +     * clean up the environment.
   1.356 +     */
   1.357 +    (void)UnsetEnv(ENV_ENTRY);
   1.358 +#ifndef GAMMA
   1.359 +    (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY);
   1.360 +    (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY);
   1.361 +
   1.362 +    JLI_MemFree(splash_jar_entry);
   1.363 +    JLI_MemFree(splash_file_entry);
   1.364 +#endif
   1.365 +
   1.366 +    /*
   1.367 +     * If user doesn't specify stack size, check if VM has a preference.
   1.368 +     * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will
   1.369 +     * return its default stack size through the init args structure.
   1.370 +     */
   1.371 +    if (threadStackSize == 0) {
   1.372 +      struct JDK1_1InitArgs args1_1;
   1.373 +      memset((void*)&args1_1, 0, sizeof(args1_1));
   1.374 +      args1_1.version = JNI_VERSION_1_1;
   1.375 +      ifn.GetDefaultJavaVMInitArgs(&args1_1);  /* ignore return value */
   1.376 +      if (args1_1.javaStackSize > 0) {
   1.377 +         threadStackSize = args1_1.javaStackSize;
   1.378 +      }
   1.379 +    }
   1.380 +
   1.381 +    { /* Create a new thread to create JVM and invoke main method */
   1.382 +      struct JavaMainArgs args;
   1.383 +
   1.384 +      args.argc = argc;
   1.385 +      args.argv = argv;
   1.386 +      args.jarfile = jarfile;
   1.387 +      args.classname = classname;
   1.388 +      args.ifn = ifn;
   1.389 +
   1.390 +      return ContinueInNewThread(JavaMain, threadStackSize, (void*)&args);
   1.391 +    }
   1.392 +}
   1.393 +
   1.394 +int JNICALL
   1.395 +JavaMain(void * _args)
   1.396 +{
   1.397 +    struct JavaMainArgs *args = (struct JavaMainArgs *)_args;
   1.398 +    int argc = args->argc;
   1.399 +    char **argv = args->argv;
   1.400 +    char *jarfile = args->jarfile;
   1.401 +    char *classname = args->classname;
   1.402 +    InvocationFunctions ifn = args->ifn;
   1.403 +
   1.404 +    JavaVM *vm = 0;
   1.405 +    JNIEnv *env = 0;
   1.406 +    jstring mainClassName;
   1.407 +    jclass mainClass;
   1.408 +    jmethodID mainID;
   1.409 +    jobjectArray mainArgs;
   1.410 +    int ret = 0;
   1.411 +    jlong start, end;
   1.412 +
   1.413 +    /*
   1.414 +     * Error message to print or display; by default the message will
   1.415 +     * only be displayed in a window.
   1.416 +     */
   1.417 +    char * message = "Fatal exception occurred.  Program will exit.";
   1.418 +    jboolean messageDest = JNI_FALSE;
   1.419 +
   1.420 +    /* Initialize the virtual machine */
   1.421 +
   1.422 +    if (_launcher_debug)
   1.423 +        start = CounterGet();
   1.424 +    if (!InitializeJVM(&vm, &env, &ifn)) {
   1.425 +        ReportErrorMessage("Could not create the Java virtual machine.",
   1.426 +                           JNI_TRUE);
   1.427 +        exit(1);
   1.428 +    }
   1.429 +
   1.430 +    if (printVersion || showVersion) {
   1.431 +        PrintJavaVersion(env);
   1.432 +        if ((*env)->ExceptionOccurred(env)) {
   1.433 +            ReportExceptionDescription(env);
   1.434 +            goto leave;
   1.435 +        }
   1.436 +        if (printVersion) {
   1.437 +            ret = 0;
   1.438 +            message = NULL;
   1.439 +            goto leave;
   1.440 +        }
   1.441 +        if (showVersion) {
   1.442 +            fprintf(stderr, "\n");
   1.443 +        }
   1.444 +    }
   1.445 +
   1.446 +    /* If the user specified neither a class name nor a JAR file */
   1.447 +    if (jarfile == 0 && classname == 0) {
   1.448 +        PrintUsage();
   1.449 +        message = NULL;
   1.450 +        goto leave;
   1.451 +    }
   1.452 +
   1.453 +#ifndef GAMMA
   1.454 +    FreeKnownVMs();  /* after last possible PrintUsage() */
   1.455 +#endif
   1.456 +
   1.457 +    if (_launcher_debug) {
   1.458 +        end   = CounterGet();
   1.459 +        printf("%ld micro seconds to InitializeJVM\n",
   1.460 +               (long)(jint)Counter2Micros(end-start));
   1.461 +    }
   1.462 +
   1.463 +    /* At this stage, argc/argv have the applications' arguments */
   1.464 +    if (_launcher_debug) {
   1.465 +        int i = 0;
   1.466 +        printf("Main-Class is '%s'\n", classname ? classname : "");
   1.467 +        printf("Apps' argc is %d\n", argc);
   1.468 +        for (; i < argc; i++) {
   1.469 +            printf("    argv[%2d] = '%s'\n", i, argv[i]);
   1.470 +        }
   1.471 +    }
   1.472 +
   1.473 +    ret = 1;
   1.474 +
   1.475 +    /*
   1.476 +     * Get the application's main class.
   1.477 +     *
   1.478 +     * See bugid 5030265.  The Main-Class name has already been parsed
   1.479 +     * from the manifest, but not parsed properly for UTF-8 support.
   1.480 +     * Hence the code here ignores the value previously extracted and
   1.481 +     * uses the pre-existing code to reextract the value.  This is
   1.482 +     * possibly an end of release cycle expedient.  However, it has
   1.483 +     * also been discovered that passing some character sets through
   1.484 +     * the environment has "strange" behavior on some variants of
   1.485 +     * Windows.  Hence, maybe the manifest parsing code local to the
   1.486 +     * launcher should never be enhanced.
   1.487 +     *
   1.488 +     * Hence, future work should either:
   1.489 +     *     1)   Correct the local parsing code and verify that the
   1.490 +     *          Main-Class attribute gets properly passed through
   1.491 +     *          all environments,
   1.492 +     *     2)   Remove the vestages of maintaining main_class through
   1.493 +     *          the environment (and remove these comments).
   1.494 +     */
   1.495 +    if (jarfile != 0) {
   1.496 +        mainClassName = GetMainClassName(env, jarfile);
   1.497 +        if ((*env)->ExceptionOccurred(env)) {
   1.498 +            ReportExceptionDescription(env);
   1.499 +            goto leave;
   1.500 +        }
   1.501 +        if (mainClassName == NULL) {
   1.502 +          const char * format = "Failed to load Main-Class manifest "
   1.503 +                                "attribute from\n%s";
   1.504 +          message = (char*)JLI_MemAlloc((strlen(format) + strlen(jarfile)) *
   1.505 +                                    sizeof(char));
   1.506 +          sprintf(message, format, jarfile);
   1.507 +          messageDest = JNI_TRUE;
   1.508 +          goto leave;
   1.509 +        }
   1.510 +        classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
   1.511 +        if (classname == NULL) {
   1.512 +            ReportExceptionDescription(env);
   1.513 +            goto leave;
   1.514 +        }
   1.515 +        mainClass = LoadClass(env, classname);
   1.516 +        if(mainClass == NULL) { /* exception occured */
   1.517 +            const char * format = "Could not find the main class: %s. Program will exit.";
   1.518 +            ReportExceptionDescription(env);
   1.519 +            message = (char *)JLI_MemAlloc((strlen(format) +
   1.520 +                                            strlen(classname)) * sizeof(char) );
   1.521 +            messageDest = JNI_TRUE;
   1.522 +            sprintf(message, format, classname);
   1.523 +            goto leave;
   1.524 +        }
   1.525 +        (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
   1.526 +    } else {
   1.527 +      mainClassName = NewPlatformString(env, classname);
   1.528 +      if (mainClassName == NULL) {
   1.529 +        const char * format = "Failed to load Main Class: %s";
   1.530 +        message = (char *)JLI_MemAlloc((strlen(format) + strlen(classname)) *
   1.531 +                                   sizeof(char) );
   1.532 +        sprintf(message, format, classname);
   1.533 +        messageDest = JNI_TRUE;
   1.534 +        goto leave;
   1.535 +      }
   1.536 +      classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
   1.537 +      if (classname == NULL) {
   1.538 +        ReportExceptionDescription(env);
   1.539 +        goto leave;
   1.540 +      }
   1.541 +      mainClass = LoadClass(env, classname);
   1.542 +      if(mainClass == NULL) { /* exception occured */
   1.543 +        const char * format = "Could not find the main class: %s.  Program will exit.";
   1.544 +        ReportExceptionDescription(env);
   1.545 +        message = (char *)JLI_MemAlloc((strlen(format) +
   1.546 +                                        strlen(classname)) * sizeof(char) );
   1.547 +        messageDest = JNI_TRUE;
   1.548 +        sprintf(message, format, classname);
   1.549 +        goto leave;
   1.550 +      }
   1.551 +      (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
   1.552 +    }
   1.553 +
   1.554 +    /* Get the application's main method */
   1.555 +    mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
   1.556 +                                       "([Ljava/lang/String;)V");
   1.557 +    if (mainID == NULL) {
   1.558 +        if ((*env)->ExceptionOccurred(env)) {
   1.559 +            ReportExceptionDescription(env);
   1.560 +        } else {
   1.561 +          message = "No main method found in specified class.";
   1.562 +          messageDest = JNI_TRUE;
   1.563 +        }
   1.564 +        goto leave;
   1.565 +    }
   1.566 +
   1.567 +    {    /* Make sure the main method is public */
   1.568 +        jint mods;
   1.569 +        jmethodID mid;
   1.570 +        jobject obj = (*env)->ToReflectedMethod(env, mainClass,
   1.571 +                                                mainID, JNI_TRUE);
   1.572 +
   1.573 +        if( obj == NULL) { /* exception occurred */
   1.574 +            ReportExceptionDescription(env);
   1.575 +            goto leave;
   1.576 +        }
   1.577 +
   1.578 +        mid =
   1.579 +          (*env)->GetMethodID(env,
   1.580 +                              (*env)->GetObjectClass(env, obj),
   1.581 +                              "getModifiers", "()I");
   1.582 +        if ((*env)->ExceptionOccurred(env)) {
   1.583 +            ReportExceptionDescription(env);
   1.584 +            goto leave;
   1.585 +        }
   1.586 +
   1.587 +        mods = (*env)->CallIntMethod(env, obj, mid);
   1.588 +        if ((mods & 1) == 0) { /* if (!Modifier.isPublic(mods)) ... */
   1.589 +            message = "Main method not public.";
   1.590 +            messageDest = JNI_TRUE;
   1.591 +            goto leave;
   1.592 +        }
   1.593 +    }
   1.594 +
   1.595 +    /* Build argument array */
   1.596 +    mainArgs = NewPlatformStringArray(env, argv, argc);
   1.597 +    if (mainArgs == NULL) {
   1.598 +        ReportExceptionDescription(env);
   1.599 +        goto leave;
   1.600 +    }
   1.601 +
   1.602 +    /* Invoke main method. */
   1.603 +    (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
   1.604 +
   1.605 +    /*
   1.606 +     * The launcher's exit code (in the absence of calls to
   1.607 +     * System.exit) will be non-zero if main threw an exception.
   1.608 +     */
   1.609 +    ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1;
   1.610 +
   1.611 +    /*
   1.612 +     * Detach the main thread so that it appears to have ended when
   1.613 +     * the application's main method exits.  This will invoke the
   1.614 +     * uncaught exception handler machinery if main threw an
   1.615 +     * exception.  An uncaught exception handler cannot change the
   1.616 +     * launcher's return code except by calling System.exit.
   1.617 +     */
   1.618 +    if ((*vm)->DetachCurrentThread(vm) != 0) {
   1.619 +        message = "Could not detach main thread.";
   1.620 +        messageDest = JNI_TRUE;
   1.621 +        ret = 1;
   1.622 +        goto leave;
   1.623 +    }
   1.624 +
   1.625 +    message = NULL;
   1.626 +
   1.627 + leave:
   1.628 +    /*
   1.629 +     * Wait for all non-daemon threads to end, then destroy the VM.
   1.630 +     * This will actually create a trivial new Java waiter thread
   1.631 +     * named "DestroyJavaVM", but this will be seen as a different
   1.632 +     * thread from the one that executed main, even though they are
   1.633 +     * the same C thread.  This allows mainThread.join() and
   1.634 +     * mainThread.isAlive() to work as expected.
   1.635 +     */
   1.636 +    (*vm)->DestroyJavaVM(vm);
   1.637 +
   1.638 +    if(message != NULL && !noExitErrorMessage)
   1.639 +      ReportErrorMessage(message, messageDest);
   1.640 +    return ret;
   1.641 +}
   1.642 +
   1.643 +#ifndef GAMMA
   1.644 +/*
   1.645 + * Checks the command line options to find which JVM type was
   1.646 + * specified.  If no command line option was given for the JVM type,
   1.647 + * the default type is used.  The environment variable
   1.648 + * JDK_ALTERNATE_VM and the command line option -XXaltjvm= are also
   1.649 + * checked as ways of specifying which JVM type to invoke.
   1.650 + */
   1.651 +char *
   1.652 +CheckJvmType(int *pargc, char ***argv, jboolean speculative) {
   1.653 +    int i, argi;
   1.654 +    int argc;
   1.655 +    char **newArgv;
   1.656 +    int newArgvIdx = 0;
   1.657 +    int isVMType;
   1.658 +    int jvmidx = -1;
   1.659 +    char *jvmtype = getenv("JDK_ALTERNATE_VM");
   1.660 +
   1.661 +    argc = *pargc;
   1.662 +
   1.663 +    /* To make things simpler we always copy the argv array */
   1.664 +    newArgv = JLI_MemAlloc((argc + 1) * sizeof(char *));
   1.665 +
   1.666 +    /* The program name is always present */
   1.667 +    newArgv[newArgvIdx++] = (*argv)[0];
   1.668 +
   1.669 +    for (argi = 1; argi < argc; argi++) {
   1.670 +        char *arg = (*argv)[argi];
   1.671 +        isVMType = 0;
   1.672 +
   1.673 +#ifdef JAVA_ARGS
   1.674 +        if (arg[0] != '-') {
   1.675 +            newArgv[newArgvIdx++] = arg;
   1.676 +            continue;
   1.677 +        }
   1.678 +#else
   1.679 +        if (strcmp(arg, "-classpath") == 0 ||
   1.680 +            strcmp(arg, "-cp") == 0) {
   1.681 +            newArgv[newArgvIdx++] = arg;
   1.682 +            argi++;
   1.683 +            if (argi < argc) {
   1.684 +                newArgv[newArgvIdx++] = (*argv)[argi];
   1.685 +            }
   1.686 +            continue;
   1.687 +        }
   1.688 +        if (arg[0] != '-') break;
   1.689 +#endif
   1.690 +
   1.691 +        /* Did the user pass an explicit VM type? */
   1.692 +        i = KnownVMIndex(arg);
   1.693 +        if (i >= 0) {
   1.694 +            jvmtype = knownVMs[jvmidx = i].name + 1; /* skip the - */
   1.695 +            isVMType = 1;
   1.696 +            *pargc = *pargc - 1;
   1.697 +        }
   1.698 +
   1.699 +        /* Did the user specify an "alternate" VM? */
   1.700 +        else if (strncmp(arg, "-XXaltjvm=", 10) == 0 || strncmp(arg, "-J-XXaltjvm=", 12) == 0) {
   1.701 +            isVMType = 1;
   1.702 +            jvmtype = arg+((arg[1]=='X')? 10 : 12);
   1.703 +            jvmidx = -1;
   1.704 +        }
   1.705 +
   1.706 +        if (!isVMType) {
   1.707 +            newArgv[newArgvIdx++] = arg;
   1.708 +        }
   1.709 +    }
   1.710 +
   1.711 +    /*
   1.712 +     * Finish copying the arguments if we aborted the above loop.
   1.713 +     * NOTE that if we aborted via "break" then we did NOT copy the
   1.714 +     * last argument above, and in addition argi will be less than
   1.715 +     * argc.
   1.716 +     */
   1.717 +    while (argi < argc) {
   1.718 +        newArgv[newArgvIdx++] = (*argv)[argi];
   1.719 +        argi++;
   1.720 +    }
   1.721 +
   1.722 +    /* argv is null-terminated */
   1.723 +    newArgv[newArgvIdx] = 0;
   1.724 +
   1.725 +    /* Copy back argv */
   1.726 +    *argv = newArgv;
   1.727 +    *pargc = newArgvIdx;
   1.728 +
   1.729 +    /* use the default VM type if not specified (no alias processing) */
   1.730 +    if (jvmtype == NULL) {
   1.731 +      char* result = knownVMs[0].name+1;
   1.732 +      /* Use a different VM type if we are on a server class machine? */
   1.733 +      if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) &&
   1.734 +          (ServerClassMachine() == JNI_TRUE)) {
   1.735 +        result = knownVMs[0].server_class+1;
   1.736 +      }
   1.737 +      if (_launcher_debug) {
   1.738 +        printf("Default VM: %s\n", result);
   1.739 +      }
   1.740 +      return result;
   1.741 +    }
   1.742 +
   1.743 +    /* if using an alternate VM, no alias processing */
   1.744 +    if (jvmidx < 0)
   1.745 +      return jvmtype;
   1.746 +
   1.747 +    /* Resolve aliases first */
   1.748 +    {
   1.749 +      int loopCount = 0;
   1.750 +      while (knownVMs[jvmidx].flag == VM_ALIASED_TO) {
   1.751 +        int nextIdx = KnownVMIndex(knownVMs[jvmidx].alias);
   1.752 +
   1.753 +        if (loopCount > knownVMsCount) {
   1.754 +          if (!speculative) {
   1.755 +            ReportErrorMessage("Error: Corrupt jvm.cfg file; cycle in alias list.",
   1.756 +                               JNI_TRUE);
   1.757 +            exit(1);
   1.758 +          } else {
   1.759 +            return "ERROR";
   1.760 +            /* break; */
   1.761 +          }
   1.762 +        }
   1.763 +
   1.764 +        if (nextIdx < 0) {
   1.765 +          if (!speculative) {
   1.766 +            ReportErrorMessage2("Error: Unable to resolve VM alias %s",
   1.767 +                                knownVMs[jvmidx].alias, JNI_TRUE);
   1.768 +            exit(1);
   1.769 +          } else {
   1.770 +            return "ERROR";
   1.771 +          }
   1.772 +        }
   1.773 +        jvmidx = nextIdx;
   1.774 +        jvmtype = knownVMs[jvmidx].name+1;
   1.775 +        loopCount++;
   1.776 +      }
   1.777 +    }
   1.778 +
   1.779 +    switch (knownVMs[jvmidx].flag) {
   1.780 +    case VM_WARN:
   1.781 +        if (!speculative) {
   1.782 +            fprintf(stderr, "Warning: %s VM not supported; %s VM will be used\n",
   1.783 +                    jvmtype, knownVMs[0].name + 1);
   1.784 +        }
   1.785 +        /* fall through */
   1.786 +    case VM_IGNORE:
   1.787 +        jvmtype = knownVMs[jvmidx=0].name + 1;
   1.788 +        /* fall through */
   1.789 +    case VM_KNOWN:
   1.790 +        break;
   1.791 +    case VM_ERROR:
   1.792 +        if (!speculative) {
   1.793 +            ReportErrorMessage2("Error: %s VM not supported", jvmtype, JNI_TRUE);
   1.794 +            exit(1);
   1.795 +        } else {
   1.796 +            return "ERROR";
   1.797 +        }
   1.798 +    }
   1.799 +
   1.800 +    return jvmtype;
   1.801 +}
   1.802 +#endif /* ifndef GAMMA */
   1.803 +
   1.804 +# define KB (1024UL)
   1.805 +# define MB (1024UL * KB)
   1.806 +# define GB (1024UL * MB)
   1.807 +
   1.808 +/* copied from HotSpot function "atomll()" */
   1.809 +static int
   1.810 +parse_stack_size(const char *s, jlong *result) {
   1.811 +  jlong n = 0;
   1.812 +  int args_read = sscanf(s, jlong_format_specifier(), &n);
   1.813 +  if (args_read != 1) {
   1.814 +    return 0;
   1.815 +  }
   1.816 +  while (*s != '\0' && *s >= '0' && *s <= '9') {
   1.817 +    s++;
   1.818 +  }
   1.819 +  // 4705540: illegal if more characters are found after the first non-digit
   1.820 +  if (strlen(s) > 1) {
   1.821 +    return 0;
   1.822 +  }
   1.823 +  switch (*s) {
   1.824 +    case 'T': case 't':
   1.825 +      *result = n * GB * KB;
   1.826 +      return 1;
   1.827 +    case 'G': case 'g':
   1.828 +      *result = n * GB;
   1.829 +      return 1;
   1.830 +    case 'M': case 'm':
   1.831 +      *result = n * MB;
   1.832 +      return 1;
   1.833 +    case 'K': case 'k':
   1.834 +      *result = n * KB;
   1.835 +      return 1;
   1.836 +    case '\0':
   1.837 +      *result = n;
   1.838 +      return 1;
   1.839 +    default:
   1.840 +      /* Create JVM with default stack and let VM handle malformed -Xss string*/
   1.841 +      return 0;
   1.842 +  }
   1.843 +}
   1.844 +
   1.845 +/*
   1.846 + * Adds a new VM option with the given given name and value.
   1.847 + */
   1.848 +void
   1.849 +AddOption(char *str, void *info)
   1.850 +{
   1.851 +    /*
   1.852 +     * Expand options array if needed to accommodate at least one more
   1.853 +     * VM option.
   1.854 +     */
   1.855 +    if (numOptions >= maxOptions) {
   1.856 +        if (options == 0) {
   1.857 +            maxOptions = 4;
   1.858 +            options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
   1.859 +        } else {
   1.860 +            JavaVMOption *tmp;
   1.861 +            maxOptions *= 2;
   1.862 +            tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));
   1.863 +            memcpy(tmp, options, numOptions * sizeof(JavaVMOption));
   1.864 +            JLI_MemFree(options);
   1.865 +            options = tmp;
   1.866 +        }
   1.867 +    }
   1.868 +    options[numOptions].optionString = str;
   1.869 +    options[numOptions++].extraInfo = info;
   1.870 +
   1.871 +    if (strncmp(str, "-Xss", 4) == 0) {
   1.872 +      jlong tmp;
   1.873 +      if (parse_stack_size(str + 4, &tmp)) {
   1.874 +        threadStackSize = tmp;
   1.875 +      }
   1.876 +    }
   1.877 +}
   1.878 +
   1.879 +static void
   1.880 +SetClassPath(const char *s)
   1.881 +{
   1.882 +    char *def;
   1.883 +    s = JLI_WildcardExpandClasspath(s);
   1.884 +    def = JLI_MemAlloc(strlen(s) + 40);
   1.885 +    sprintf(def, "-Djava.class.path=%s", s);
   1.886 +    AddOption(def, NULL);
   1.887 +}
   1.888 +
   1.889 +#ifndef GAMMA
   1.890 +/*
   1.891 + * The SelectVersion() routine ensures that an appropriate version of
   1.892 + * the JRE is running.  The specification for the appropriate version
   1.893 + * is obtained from either the manifest of a jar file (preferred) or
   1.894 + * from command line options.
   1.895 + * The routine also parses splash screen command line options and
   1.896 + * passes on their values in private environment variables.
   1.897 + */
   1.898 +static void
   1.899 +SelectVersion(int argc, char **argv, char **main_class)
   1.900 +{
   1.901 +    char    *arg;
   1.902 +    char    **new_argv;
   1.903 +    char    **new_argp;
   1.904 +    char    *operand;
   1.905 +    char    *version = NULL;
   1.906 +    char    *jre = NULL;
   1.907 +    int     jarflag = 0;
   1.908 +    int     headlessflag = 0;
   1.909 +    int     restrict_search = -1;               /* -1 implies not known */
   1.910 +    manifest_info info;
   1.911 +    char    env_entry[MAXNAMELEN + 24] = ENV_ENTRY "=";
   1.912 +    char    *splash_file_name = NULL;
   1.913 +    char    *splash_jar_name = NULL;
   1.914 +    char    *env_in;
   1.915 +    int     res;
   1.916 +
   1.917 +    /*
   1.918 +     * If the version has already been selected, set *main_class
   1.919 +     * with the value passed through the environment (if any) and
   1.920 +     * simply return.
   1.921 +     */
   1.922 +    if ((env_in = getenv(ENV_ENTRY)) != NULL) {
   1.923 +        if (*env_in != '\0')
   1.924 +            *main_class = JLI_StringDup(env_in);
   1.925 +        return;
   1.926 +    }
   1.927 +
   1.928 +    /*
   1.929 +     * Scan through the arguments for options relevant to multiple JRE
   1.930 +     * support.  For reference, the command line syntax is defined as:
   1.931 +     *
   1.932 +     * SYNOPSIS
   1.933 +     *      java [options] class [argument...]
   1.934 +     *
   1.935 +     *      java [options] -jar file.jar [argument...]
   1.936 +     *
   1.937 +     * As the scan is performed, make a copy of the argument list with
   1.938 +     * the version specification options (new to 1.5) removed, so that
   1.939 +     * a version less than 1.5 can be exec'd.
   1.940 +     *
   1.941 +     * Note that due to the syntax of the native Windows interface
   1.942 +     * CreateProcess(), processing similar to the following exists in
   1.943 +     * the Windows platform specific routine ExecJRE (in java_md.c).
   1.944 +     * Changes here should be reproduced there.
   1.945 +     */
   1.946 +    new_argv = JLI_MemAlloc((argc + 1) * sizeof(char*));
   1.947 +    new_argv[0] = argv[0];
   1.948 +    new_argp = &new_argv[1];
   1.949 +    argc--;
   1.950 +    argv++;
   1.951 +    while ((arg = *argv) != 0 && *arg == '-') {
   1.952 +        if (strncmp(arg, "-version:", 9) == 0) {
   1.953 +            version = arg + 9;
   1.954 +        } else if (strcmp(arg, "-jre-restrict-search") == 0) {
   1.955 +            restrict_search = 1;
   1.956 +        } else if (strcmp(arg, "-no-jre-restrict-search") == 0) {
   1.957 +            restrict_search = 0;
   1.958 +        } else {
   1.959 +            if (strcmp(arg, "-jar") == 0)
   1.960 +                jarflag = 1;
   1.961 +            /* deal with "unfortunate" classpath syntax */
   1.962 +            if ((strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) &&
   1.963 +              (argc >= 2)) {
   1.964 +                *new_argp++ = arg;
   1.965 +                argc--;
   1.966 +                argv++;
   1.967 +                arg = *argv;
   1.968 +            }
   1.969 +
   1.970 +            /*
   1.971 +             * Checking for headless toolkit option in the some way as AWT does:
   1.972 +             * "true" means true and any other value means false
   1.973 +             */
   1.974 +            if (strcmp(arg, "-Djava.awt.headless=true") == 0) {
   1.975 +                headlessflag = 1;
   1.976 +            } else if (strncmp(arg, "-Djava.awt.headless=", 20) == 0) {
   1.977 +                headlessflag = 0;
   1.978 +            } else if (strncmp(arg, "-splash:", 8) == 0) {
   1.979 +                splash_file_name = arg+8;
   1.980 +            }
   1.981 +            *new_argp++ = arg;
   1.982 +        }
   1.983 +        argc--;
   1.984 +        argv++;
   1.985 +    }
   1.986 +    if (argc <= 0) {    /* No operand? Possibly legit with -[full]version */
   1.987 +        operand = NULL;
   1.988 +    } else {
   1.989 +        argc--;
   1.990 +        *new_argp++ = operand = *argv++;
   1.991 +    }
   1.992 +    while (argc-- > 0)  /* Copy over [argument...] */
   1.993 +        *new_argp++ = *argv++;
   1.994 +    *new_argp = NULL;
   1.995 +
   1.996 +    /*
   1.997 +     * If there is a jar file, read the manifest. If the jarfile can't be
   1.998 +     * read, the manifest can't be read from the jar file, or the manifest
   1.999 +     * is corrupt, issue the appropriate error messages and exit.
  1.1000 +     *
  1.1001 +     * Even if there isn't a jar file, construct a manifest_info structure
  1.1002 +     * containing the command line information.  It's a convenient way to carry
  1.1003 +     * this data around.
  1.1004 +     */
  1.1005 +    if (jarflag && operand) {
  1.1006 +        if ((res = JLI_ParseManifest(operand, &info)) != 0) {
  1.1007 +            if (res == -1)
  1.1008 +                ReportErrorMessage2("Unable to access jarfile %s",
  1.1009 +                  operand, JNI_TRUE);
  1.1010 +            else
  1.1011 +                ReportErrorMessage2("Invalid or corrupt jarfile %s",
  1.1012 +                  operand, JNI_TRUE);
  1.1013 +            exit(1);
  1.1014 +        }
  1.1015 +
  1.1016 +        /*
  1.1017 +         * Command line splash screen option should have precedence
  1.1018 +         * over the manifest, so the manifest data is used only if
  1.1019 +         * splash_file_name has not been initialized above during command
  1.1020 +         * line parsing
  1.1021 +         */
  1.1022 +        if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) {
  1.1023 +            splash_file_name = info.splashscreen_image_file_name;
  1.1024 +            splash_jar_name = operand;
  1.1025 +        }
  1.1026 +    } else {
  1.1027 +        info.manifest_version = NULL;
  1.1028 +        info.main_class = NULL;
  1.1029 +        info.jre_version = NULL;
  1.1030 +        info.jre_restrict_search = 0;
  1.1031 +    }
  1.1032 +
  1.1033 +    /*
  1.1034 +     * Passing on splash screen info in environment variables
  1.1035 +     */
  1.1036 +    if (splash_file_name && !headlessflag) {
  1.1037 +        char* splash_file_entry = JLI_MemAlloc(strlen(SPLASH_FILE_ENV_ENTRY "=")+strlen(splash_file_name)+1);
  1.1038 +        strcpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "=");
  1.1039 +        strcat(splash_file_entry, splash_file_name);
  1.1040 +        putenv(splash_file_entry);
  1.1041 +    }
  1.1042 +    if (splash_jar_name && !headlessflag) {
  1.1043 +        char* splash_jar_entry = JLI_MemAlloc(strlen(SPLASH_JAR_ENV_ENTRY "=")+strlen(splash_jar_name)+1);
  1.1044 +        strcpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "=");
  1.1045 +        strcat(splash_jar_entry, splash_jar_name);
  1.1046 +        putenv(splash_jar_entry);
  1.1047 +    }
  1.1048 +
  1.1049 +    /*
  1.1050 +     * The JRE-Version and JRE-Restrict-Search values (if any) from the
  1.1051 +     * manifest are overwritten by any specified on the command line.
  1.1052 +     */
  1.1053 +    if (version != NULL)
  1.1054 +        info.jre_version = version;
  1.1055 +    if (restrict_search != -1)
  1.1056 +        info.jre_restrict_search = restrict_search;
  1.1057 +
  1.1058 +    /*
  1.1059 +     * "Valid" returns (other than unrecoverable errors) follow.  Set
  1.1060 +     * main_class as a side-effect of this routine.
  1.1061 +     */
  1.1062 +    if (info.main_class != NULL)
  1.1063 +        *main_class = JLI_StringDup(info.main_class);
  1.1064 +
  1.1065 +    /*
  1.1066 +     * If no version selection information is found either on the command
  1.1067 +     * line or in the manifest, simply return.
  1.1068 +     */
  1.1069 +    if (info.jre_version == NULL) {
  1.1070 +        JLI_FreeManifest();
  1.1071 +        JLI_MemFree(new_argv);
  1.1072 +        return;
  1.1073 +    }
  1.1074 +
  1.1075 +    /*
  1.1076 +     * Check for correct syntax of the version specification (JSR 56).
  1.1077 +     */
  1.1078 +    if (!JLI_ValidVersionString(info.jre_version)) {
  1.1079 +        ReportErrorMessage2("Syntax error in version specification \"%s\"",
  1.1080 +          info.jre_version, JNI_TRUE);
  1.1081 +        exit(1);
  1.1082 +    }
  1.1083 +
  1.1084 +    /*
  1.1085 +     * Find the appropriate JVM on the system. Just to be as forgiving as
  1.1086 +     * possible, if the standard algorithms don't locate an appropriate
  1.1087 +     * jre, check to see if the one running will satisfy the requirements.
  1.1088 +     * This can happen on systems which haven't been set-up for multiple
  1.1089 +     * JRE support.
  1.1090 +     */
  1.1091 +    jre = LocateJRE(&info);
  1.1092 +    if (_launcher_debug)
  1.1093 +        printf("JRE-Version = %s, JRE-Restrict-Search = %s Selected = %s\n",
  1.1094 +          (info.jre_version?info.jre_version:"null"),
  1.1095 +          (info.jre_restrict_search?"true":"false"), (jre?jre:"null"));
  1.1096 +    if (jre == NULL) {
  1.1097 +        if (JLI_AcceptableRelease(FULL_VERSION, info.jre_version)) {
  1.1098 +            JLI_FreeManifest();
  1.1099 +            JLI_MemFree(new_argv);
  1.1100 +            return;
  1.1101 +        } else {
  1.1102 +            ReportErrorMessage2(
  1.1103 +              "Unable to locate JRE meeting specification \"%s\"",
  1.1104 +              info.jre_version, JNI_TRUE);
  1.1105 +            exit(1);
  1.1106 +        }
  1.1107 +    }
  1.1108 +
  1.1109 +    /*
  1.1110 +     * If I'm not the chosen one, exec the chosen one.  Returning from
  1.1111 +     * ExecJRE indicates that I am indeed the chosen one.
  1.1112 +     *
  1.1113 +     * The private environment variable _JAVA_VERSION_SET is used to
  1.1114 +     * prevent the chosen one from re-reading the manifest file and
  1.1115 +     * using the values found within to override the (potential) command
  1.1116 +     * line flags stripped from argv (because the target may not
  1.1117 +     * understand them).  Passing the MainClass value is an optimization
  1.1118 +     * to avoid locating, expanding and parsing the manifest extra
  1.1119 +     * times.
  1.1120 +     */
  1.1121 +    if (info.main_class != NULL) {
  1.1122 +        if (strlen(info.main_class) <= MAXNAMELEN) {
  1.1123 +            (void)strcat(env_entry, info.main_class);
  1.1124 +        } else {
  1.1125 +            ReportErrorMessage("Error: main-class: attribute exceeds system limits\n", JNI_TRUE);
  1.1126 +            exit(1);
  1.1127 +        }
  1.1128 +    }
  1.1129 +    (void)putenv(env_entry);
  1.1130 +    ExecJRE(jre, new_argv);
  1.1131 +    JLI_FreeManifest();
  1.1132 +    JLI_MemFree(new_argv);
  1.1133 +    return;
  1.1134 +}
  1.1135 +#endif /* ifndef GAMMA */
  1.1136 +
  1.1137 +/*
  1.1138 + * Parses command line arguments.  Returns JNI_FALSE if launcher
  1.1139 + * should exit without starting vm (e.g. certain version and usage
  1.1140 + * options); returns JNI_TRUE if vm needs to be started to process
  1.1141 + * given options.  *pret (the launcher process return value) is set to
  1.1142 + * 0 for a normal exit.
  1.1143 + */
  1.1144 +static jboolean
  1.1145 +ParseArguments(int *pargc, char ***pargv, char **pjarfile,
  1.1146 +                       char **pclassname, int *pret, const char *jvmpath)
  1.1147 +{
  1.1148 +    int argc = *pargc;
  1.1149 +    char **argv = *pargv;
  1.1150 +    jboolean jarflag = JNI_FALSE;
  1.1151 +    char *arg;
  1.1152 +
  1.1153 +    *pret = 1;
  1.1154 +    while ((arg = *argv) != 0 && *arg == '-') {
  1.1155 +        argv++; --argc;
  1.1156 +        if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) {
  1.1157 +            if (argc < 1) {
  1.1158 +                ReportErrorMessage2("%s requires class path specification",
  1.1159 +                                    arg, JNI_TRUE);
  1.1160 +                PrintUsage();
  1.1161 +                return JNI_FALSE;
  1.1162 +            }
  1.1163 +            SetClassPath(*argv);
  1.1164 +            argv++; --argc;
  1.1165 +        } else if (strcmp(arg, "-jar") == 0) {
  1.1166 +            jarflag = JNI_TRUE;
  1.1167 +        } else if (strcmp(arg, "-help") == 0 ||
  1.1168 +                   strcmp(arg, "-h") == 0 ||
  1.1169 +                   strcmp(arg, "-?") == 0) {
  1.1170 +            PrintUsage();
  1.1171 +            *pret = 0;
  1.1172 +            return JNI_FALSE;
  1.1173 +        } else if (strcmp(arg, "-version") == 0) {
  1.1174 +            printVersion = JNI_TRUE;
  1.1175 +            return JNI_TRUE;
  1.1176 +        } else if (strcmp(arg, "-showversion") == 0) {
  1.1177 +            showVersion = JNI_TRUE;
  1.1178 +        } else if (strcmp(arg, "-X") == 0) {
  1.1179 +            *pret = PrintXUsage(jvmpath);
  1.1180 +            return JNI_FALSE;
  1.1181 +/*
  1.1182 + * The following case provide backward compatibility with old-style
  1.1183 + * command line options.
  1.1184 + */
  1.1185 +        } else if (strcmp(arg, "-fullversion") == 0) {
  1.1186 +            fprintf(stderr, "%s full version \"%s\"\n", progname,
  1.1187 +                    FULL_VERSION);
  1.1188 +            *pret = 0;
  1.1189 +            return JNI_FALSE;
  1.1190 +        } else if (strcmp(arg, "-verbosegc") == 0) {
  1.1191 +            AddOption("-verbose:gc", NULL);
  1.1192 +        } else if (strcmp(arg, "-t") == 0) {
  1.1193 +            AddOption("-Xt", NULL);
  1.1194 +        } else if (strcmp(arg, "-tm") == 0) {
  1.1195 +            AddOption("-Xtm", NULL);
  1.1196 +        } else if (strcmp(arg, "-debug") == 0) {
  1.1197 +            AddOption("-Xdebug", NULL);
  1.1198 +        } else if (strcmp(arg, "-noclassgc") == 0) {
  1.1199 +            AddOption("-Xnoclassgc", NULL);
  1.1200 +        } else if (strcmp(arg, "-Xfuture") == 0) {
  1.1201 +            AddOption("-Xverify:all", NULL);
  1.1202 +        } else if (strcmp(arg, "-verify") == 0) {
  1.1203 +            AddOption("-Xverify:all", NULL);
  1.1204 +        } else if (strcmp(arg, "-verifyremote") == 0) {
  1.1205 +            AddOption("-Xverify:remote", NULL);
  1.1206 +        } else if (strcmp(arg, "-noverify") == 0) {
  1.1207 +            AddOption("-Xverify:none", NULL);
  1.1208 +        } else if (strcmp(arg, "-XXsuppressExitMessage") == 0) {
  1.1209 +            noExitErrorMessage = 1;
  1.1210 +        } else if (strncmp(arg, "-prof", 5) == 0) {
  1.1211 +            char *p = arg + 5;
  1.1212 +            char *tmp = JLI_MemAlloc(strlen(arg) + 50);
  1.1213 +            if (*p) {
  1.1214 +                sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);
  1.1215 +            } else {
  1.1216 +                sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");
  1.1217 +            }
  1.1218 +            AddOption(tmp, NULL);
  1.1219 +        } else if (strncmp(arg, "-ss", 3) == 0 ||
  1.1220 +                   strncmp(arg, "-oss", 4) == 0 ||
  1.1221 +                   strncmp(arg, "-ms", 3) == 0 ||
  1.1222 +                   strncmp(arg, "-mx", 3) == 0) {
  1.1223 +            char *tmp = JLI_MemAlloc(strlen(arg) + 6);
  1.1224 +            sprintf(tmp, "-X%s", arg + 1); /* skip '-' */
  1.1225 +            AddOption(tmp, NULL);
  1.1226 +        } else if (strcmp(arg, "-checksource") == 0 ||
  1.1227 +                   strcmp(arg, "-cs") == 0 ||
  1.1228 +                   strcmp(arg, "-noasyncgc") == 0) {
  1.1229 +            /* No longer supported */
  1.1230 +            fprintf(stderr,
  1.1231 +                    "Warning: %s option is no longer supported.\n",
  1.1232 +                    arg);
  1.1233 +        } else if (strncmp(arg, "-version:", 9) == 0 ||
  1.1234 +                   strcmp(arg, "-no-jre-restrict-search") == 0 ||
  1.1235 +                   strcmp(arg, "-jre-restrict-search") == 0 ||
  1.1236 +                   strncmp(arg, "-splash:", 8) == 0) {
  1.1237 +            ; /* Ignore machine independent options already handled */
  1.1238 +        } else if (RemovableMachineDependentOption(arg) ) {
  1.1239 +            ; /* Do not pass option to vm. */
  1.1240 +        }
  1.1241 +        else {
  1.1242 +            AddOption(arg, NULL);
  1.1243 +        }
  1.1244 +    }
  1.1245 +
  1.1246 +    if (--argc >= 0) {
  1.1247 +        if (jarflag) {
  1.1248 +            *pjarfile = *argv++;
  1.1249 +            *pclassname = 0;
  1.1250 +        } else {
  1.1251 +            *pjarfile = 0;
  1.1252 +            *pclassname = *argv++;
  1.1253 +        }
  1.1254 +        *pargc = argc;
  1.1255 +        *pargv = argv;
  1.1256 +    }
  1.1257 +
  1.1258 +    return JNI_TRUE;
  1.1259 +}
  1.1260 +
  1.1261 +/*
  1.1262 + * Initializes the Java Virtual Machine. Also frees options array when
  1.1263 + * finished.
  1.1264 + */
  1.1265 +static jboolean
  1.1266 +InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
  1.1267 +{
  1.1268 +    JavaVMInitArgs args;
  1.1269 +    jint r;
  1.1270 +
  1.1271 +    memset(&args, 0, sizeof(args));
  1.1272 +    args.version  = JNI_VERSION_1_2;
  1.1273 +    args.nOptions = numOptions;
  1.1274 +    args.options  = options;
  1.1275 +    args.ignoreUnrecognized = JNI_FALSE;
  1.1276 +
  1.1277 +    if (_launcher_debug) {
  1.1278 +        int i = 0;
  1.1279 +        printf("JavaVM args:\n    ");
  1.1280 +        printf("version 0x%08lx, ", (long)args.version);
  1.1281 +        printf("ignoreUnrecognized is %s, ",
  1.1282 +               args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
  1.1283 +        printf("nOptions is %ld\n", (long)args.nOptions);
  1.1284 +        for (i = 0; i < numOptions; i++)
  1.1285 +            printf("    option[%2d] = '%s'\n",
  1.1286 +                   i, args.options[i].optionString);
  1.1287 +    }
  1.1288 +
  1.1289 +    r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
  1.1290 +    JLI_MemFree(options);
  1.1291 +    return r == JNI_OK;
  1.1292 +}
  1.1293 +
  1.1294 +
  1.1295 +#define NULL_CHECK0(e) if ((e) == 0) return 0
  1.1296 +#define NULL_CHECK(e) if ((e) == 0) return
  1.1297 +
  1.1298 +static jstring platformEncoding = NULL;
  1.1299 +static jstring getPlatformEncoding(JNIEnv *env) {
  1.1300 +    if (platformEncoding == NULL) {
  1.1301 +        jstring propname = (*env)->NewStringUTF(env, "sun.jnu.encoding");
  1.1302 +        if (propname) {
  1.1303 +            jclass cls;
  1.1304 +            jmethodID mid;
  1.1305 +            NULL_CHECK0 (cls = (*env)->FindClass(env, "java/lang/System"));
  1.1306 +            NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
  1.1307 +                                   env, cls,
  1.1308 +                                   "getProperty",
  1.1309 +                                   "(Ljava/lang/String;)Ljava/lang/String;"));
  1.1310 +            platformEncoding = (*env)->CallStaticObjectMethod (
  1.1311 +                                    env, cls, mid, propname);
  1.1312 +        }
  1.1313 +    }
  1.1314 +    return platformEncoding;
  1.1315 +}
  1.1316 +
  1.1317 +static jboolean isEncodingSupported(JNIEnv *env, jstring enc) {
  1.1318 +    jclass cls;
  1.1319 +    jmethodID mid;
  1.1320 +    NULL_CHECK0 (cls = (*env)->FindClass(env, "java/nio/charset/Charset"));
  1.1321 +    NULL_CHECK0 (mid = (*env)->GetStaticMethodID(
  1.1322 +                           env, cls,
  1.1323 +                           "isSupported",
  1.1324 +                           "(Ljava/lang/String;)Z"));
  1.1325 +    return (*env)->CallStaticBooleanMethod(env, cls, mid, enc);
  1.1326 +}
  1.1327 +
  1.1328 +/*
  1.1329 + * Returns a new Java string object for the specified platform string.
  1.1330 + */
  1.1331 +static jstring
  1.1332 +NewPlatformString(JNIEnv *env, char *s)
  1.1333 +{
  1.1334 +    int len = (int)strlen(s);
  1.1335 +    jclass cls;
  1.1336 +    jmethodID mid;
  1.1337 +    jbyteArray ary;
  1.1338 +    jstring enc;
  1.1339 +
  1.1340 +    if (s == NULL)
  1.1341 +        return 0;
  1.1342 +    enc = getPlatformEncoding(env);
  1.1343 +
  1.1344 +    ary = (*env)->NewByteArray(env, len);
  1.1345 +    if (ary != 0) {
  1.1346 +        jstring str = 0;
  1.1347 +        (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
  1.1348 +        if (!(*env)->ExceptionOccurred(env)) {
  1.1349 +            if (isEncodingSupported(env, enc) == JNI_TRUE) {
  1.1350 +                NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  1.1351 +                NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
  1.1352 +                                          "([BLjava/lang/String;)V"));
  1.1353 +                str = (*env)->NewObject(env, cls, mid, ary, enc);
  1.1354 +            } else {
  1.1355 +                /*If the encoding specified in sun.jnu.encoding is not
  1.1356 +                  endorsed by "Charset.isSupported" we have to fall back
  1.1357 +                  to use String(byte[]) explicitly here without specifying
  1.1358 +                  the encoding name, in which the StringCoding class will
  1.1359 +                  pickup the iso-8859-1 as the fallback converter for us.
  1.1360 +                */
  1.1361 +                NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  1.1362 +                NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
  1.1363 +                                          "([B)V"));
  1.1364 +                str = (*env)->NewObject(env, cls, mid, ary);
  1.1365 +            }
  1.1366 +            (*env)->DeleteLocalRef(env, ary);
  1.1367 +            return str;
  1.1368 +        }
  1.1369 +    }
  1.1370 +    return 0;
  1.1371 +}
  1.1372 +
  1.1373 +/*
  1.1374 + * Returns a new array of Java string objects for the specified
  1.1375 + * array of platform strings.
  1.1376 + */
  1.1377 +static jobjectArray
  1.1378 +NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
  1.1379 +{
  1.1380 +    jarray cls;
  1.1381 +    jarray ary;
  1.1382 +    int i;
  1.1383 +
  1.1384 +    NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  1.1385 +    NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
  1.1386 +    for (i = 0; i < strc; i++) {
  1.1387 +        jstring str = NewPlatformString(env, *strv++);
  1.1388 +        NULL_CHECK0(str);
  1.1389 +        (*env)->SetObjectArrayElement(env, ary, i, str);
  1.1390 +        (*env)->DeleteLocalRef(env, str);
  1.1391 +    }
  1.1392 +    return ary;
  1.1393 +}
  1.1394 +
  1.1395 +/*
  1.1396 + * Loads a class, convert the '.' to '/'.
  1.1397 + */
  1.1398 +static jclass
  1.1399 +LoadClass(JNIEnv *env, char *name)
  1.1400 +{
  1.1401 +    char *buf = JLI_MemAlloc(strlen(name) + 1);
  1.1402 +    char *s = buf, *t = name, c;
  1.1403 +    jclass cls;
  1.1404 +    jlong start, end;
  1.1405 +
  1.1406 +    if (_launcher_debug)
  1.1407 +        start = CounterGet();
  1.1408 +
  1.1409 +    do {
  1.1410 +        c = *t++;
  1.1411 +        *s++ = (c == '.') ? '/' : c;
  1.1412 +    } while (c != '\0');
  1.1413 +    cls = (*env)->FindClass(env, buf);
  1.1414 +    JLI_MemFree(buf);
  1.1415 +
  1.1416 +    if (_launcher_debug) {
  1.1417 +        end   = CounterGet();
  1.1418 +        printf("%ld micro seconds to load main class\n",
  1.1419 +               (long)(jint)Counter2Micros(end-start));
  1.1420 +        printf("----_JAVA_LAUNCHER_DEBUG----\n");
  1.1421 +    }
  1.1422 +
  1.1423 +    return cls;
  1.1424 +}
  1.1425 +
  1.1426 +
  1.1427 +/*
  1.1428 + * Returns the main class name for the specified jar file.
  1.1429 + */
  1.1430 +static jstring
  1.1431 +GetMainClassName(JNIEnv *env, char *jarname)
  1.1432 +{
  1.1433 +#define MAIN_CLASS "Main-Class"
  1.1434 +    jclass cls;
  1.1435 +    jmethodID mid;
  1.1436 +    jobject jar, man, attr;
  1.1437 +    jstring str, result = 0;
  1.1438 +
  1.1439 +    NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile"));
  1.1440 +    NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
  1.1441 +                                          "(Ljava/lang/String;)V"));
  1.1442 +    NULL_CHECK0(str = NewPlatformString(env, jarname));
  1.1443 +    NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str));
  1.1444 +    NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest",
  1.1445 +                                          "()Ljava/util/jar/Manifest;"));
  1.1446 +    man = (*env)->CallObjectMethod(env, jar, mid);
  1.1447 +    if (man != 0) {
  1.1448 +        NULL_CHECK0(mid = (*env)->GetMethodID(env,
  1.1449 +                                    (*env)->GetObjectClass(env, man),
  1.1450 +                                    "getMainAttributes",
  1.1451 +                                    "()Ljava/util/jar/Attributes;"));
  1.1452 +        attr = (*env)->CallObjectMethod(env, man, mid);
  1.1453 +        if (attr != 0) {
  1.1454 +            NULL_CHECK0(mid = (*env)->GetMethodID(env,
  1.1455 +                                    (*env)->GetObjectClass(env, attr),
  1.1456 +                                    "getValue",
  1.1457 +                                    "(Ljava/lang/String;)Ljava/lang/String;"));
  1.1458 +            NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS));
  1.1459 +            result = (*env)->CallObjectMethod(env, attr, mid, str);
  1.1460 +        }
  1.1461 +    }
  1.1462 +    return result;
  1.1463 +}
  1.1464 +
  1.1465 +#ifdef JAVA_ARGS
  1.1466 +static char *java_args[] = JAVA_ARGS;
  1.1467 +static char *app_classpath[] = APP_CLASSPATH;
  1.1468 +
  1.1469 +/*
  1.1470 + * For tools, convert command line args thus:
  1.1471 + *   javac -cp foo:foo/"*" -J-ms32m ...
  1.1472 + *   java -ms32m -cp JLI_WildcardExpandClasspath(foo:foo/"*") ...
  1.1473 + */
  1.1474 +static void
  1.1475 +TranslateApplicationArgs(int *pargc, char ***pargv)
  1.1476 +{
  1.1477 +    const int NUM_ARGS = (sizeof(java_args) / sizeof(char *));
  1.1478 +    int argc = *pargc;
  1.1479 +    char **argv = *pargv;
  1.1480 +    int nargc = argc + NUM_ARGS;
  1.1481 +    char **nargv = JLI_MemAlloc((nargc + 1) * sizeof(char *));
  1.1482 +    int i;
  1.1483 +
  1.1484 +    *pargc = nargc;
  1.1485 +    *pargv = nargv;
  1.1486 +
  1.1487 +    /* Copy the VM arguments (i.e. prefixed with -J) */
  1.1488 +    for (i = 0; i < NUM_ARGS; i++) {
  1.1489 +        char *arg = java_args[i];
  1.1490 +        if (arg[0] == '-' && arg[1] == 'J') {
  1.1491 +            *nargv++ = arg + 2;
  1.1492 +        }
  1.1493 +    }
  1.1494 +
  1.1495 +    for (i = 0; i < argc; i++) {
  1.1496 +        char *arg = argv[i];
  1.1497 +        if (arg[0] == '-' && arg[1] == 'J') {
  1.1498 +            if (arg[2] == '\0') {
  1.1499 +                ReportErrorMessage("Error: the -J option should not be "
  1.1500 +                                   "followed by a space.", JNI_TRUE);
  1.1501 +                exit(1);
  1.1502 +            }
  1.1503 +            *nargv++ = arg + 2;
  1.1504 +        }
  1.1505 +    }
  1.1506 +
  1.1507 +    /* Copy the rest of the arguments */
  1.1508 +    for (i = 0; i < NUM_ARGS; i++) {
  1.1509 +        char *arg = java_args[i];
  1.1510 +        if (arg[0] != '-' || arg[1] != 'J') {
  1.1511 +            *nargv++ = arg;
  1.1512 +        }
  1.1513 +    }
  1.1514 +    for (i = 0; i < argc; i++) {
  1.1515 +        char *arg = argv[i];
  1.1516 +        if (arg[0] == '-') {
  1.1517 +            if (arg[1] == 'J')
  1.1518 +                continue;
  1.1519 +#ifdef EXPAND_CLASSPATH_WILDCARDS
  1.1520 +            if (arg[1] == 'c'
  1.1521 +                && (strcmp(arg, "-cp") == 0 ||
  1.1522 +                    strcmp(arg, "-classpath") == 0)
  1.1523 +                && i < argc - 1) {
  1.1524 +                *nargv++ = arg;
  1.1525 +                *nargv++ = (char *) JLI_WildcardExpandClasspath(argv[i+1]);
  1.1526 +                i++;
  1.1527 +                continue;
  1.1528 +            }
  1.1529 +#endif
  1.1530 +        }
  1.1531 +        *nargv++ = arg;
  1.1532 +    }
  1.1533 +    *nargv = 0;
  1.1534 +}
  1.1535 +
  1.1536 +/*
  1.1537 + * For our tools, we try to add 3 VM options:
  1.1538 + *      -Denv.class.path=<envcp>
  1.1539 + *      -Dapplication.home=<apphome>
  1.1540 + *      -Djava.class.path=<appcp>
  1.1541 + * <envcp>   is the user's setting of CLASSPATH -- for instance the user
  1.1542 + *           tells javac where to find binary classes through this environment
  1.1543 + *           variable.  Notice that users will be able to compile against our
  1.1544 + *           tools classes (sun.tools.javac.Main) only if they explicitly add
  1.1545 + *           tools.jar to CLASSPATH.
  1.1546 + * <apphome> is the directory where the application is installed.
  1.1547 + * <appcp>   is the classpath to where our apps' classfiles are.
  1.1548 + */
  1.1549 +static jboolean
  1.1550 +AddApplicationOptions()
  1.1551 +{
  1.1552 +    const int NUM_APP_CLASSPATH = (sizeof(app_classpath) / sizeof(char *));
  1.1553 +    char *envcp, *appcp, *apphome;
  1.1554 +    char home[MAXPATHLEN]; /* application home */
  1.1555 +    char separator[] = { PATH_SEPARATOR, '\0' };
  1.1556 +    int size, i;
  1.1557 +    int strlenHome;
  1.1558 +
  1.1559 +    {
  1.1560 +        const char *s = getenv("CLASSPATH");
  1.1561 +        if (s) {
  1.1562 +            s = (char *) JLI_WildcardExpandClasspath(s);
  1.1563 +            /* 40 for -Denv.class.path= */
  1.1564 +            envcp = (char *)JLI_MemAlloc(strlen(s) + 40);
  1.1565 +            sprintf(envcp, "-Denv.class.path=%s", s);
  1.1566 +            AddOption(envcp, NULL);
  1.1567 +        }
  1.1568 +    }
  1.1569 +
  1.1570 +    if (!GetApplicationHome(home, sizeof(home))) {
  1.1571 +        ReportErrorMessage("Can't determine application home", JNI_TRUE);
  1.1572 +        return JNI_FALSE;
  1.1573 +    }
  1.1574 +
  1.1575 +    /* 40 for '-Dapplication.home=' */
  1.1576 +    apphome = (char *)JLI_MemAlloc(strlen(home) + 40);
  1.1577 +    sprintf(apphome, "-Dapplication.home=%s", home);
  1.1578 +    AddOption(apphome, NULL);
  1.1579 +
  1.1580 +    /* How big is the application's classpath? */
  1.1581 +    size = 40;                                 /* 40: "-Djava.class.path=" */
  1.1582 +    strlenHome = (int)strlen(home);
  1.1583 +    for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  1.1584 +        size += strlenHome + (int)strlen(app_classpath[i]) + 1; /* 1: separator */
  1.1585 +    }
  1.1586 +    appcp = (char *)JLI_MemAlloc(size + 1);
  1.1587 +    strcpy(appcp, "-Djava.class.path=");
  1.1588 +    for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  1.1589 +        strcat(appcp, home);                    /* c:\program files\myapp */
  1.1590 +        strcat(appcp, app_classpath[i]);        /* \lib\myapp.jar         */
  1.1591 +        strcat(appcp, separator);               /* ;                      */
  1.1592 +    }
  1.1593 +    appcp[strlen(appcp)-1] = '\0';  /* remove trailing path separator */
  1.1594 +    AddOption(appcp, NULL);
  1.1595 +    return JNI_TRUE;
  1.1596 +}
  1.1597 +#endif /* JAVA_ARGS */
  1.1598 +
  1.1599 +/*
  1.1600 + * inject the -Dsun.java.command pseudo property into the args structure
  1.1601 + * this pseudo property is used in the HotSpot VM to expose the
  1.1602 + * Java class name and arguments to the main method to the VM. The
  1.1603 + * HotSpot VM uses this pseudo property to store the Java class name
  1.1604 + * (or jar file name) and the arguments to the class's main method
  1.1605 + * to the instrumentation memory region. The sun.java.command pseudo
  1.1606 + * property is not exported by HotSpot to the Java layer.
  1.1607 + */
  1.1608 +void
  1.1609 +SetJavaCommandLineProp(char *classname, char *jarfile,
  1.1610 +                       int argc, char **argv)
  1.1611 +{
  1.1612 +
  1.1613 +    int i = 0;
  1.1614 +    size_t len = 0;
  1.1615 +    char* javaCommand = NULL;
  1.1616 +    char* dashDstr = "-Dsun.java.command=";
  1.1617 +
  1.1618 +    if (classname == NULL && jarfile == NULL) {
  1.1619 +        /* unexpected, one of these should be set. just return without
  1.1620 +         * setting the property
  1.1621 +         */
  1.1622 +        return;
  1.1623 +    }
  1.1624 +
  1.1625 +    /* if the class name is not set, then use the jarfile name */
  1.1626 +    if (classname == NULL) {
  1.1627 +        classname = jarfile;
  1.1628 +    }
  1.1629 +
  1.1630 +    /* determine the amount of memory to allocate assuming
  1.1631 +     * the individual components will be space separated
  1.1632 +     */
  1.1633 +    len = strlen(classname);
  1.1634 +    for (i = 0; i < argc; i++) {
  1.1635 +        len += strlen(argv[i]) + 1;
  1.1636 +    }
  1.1637 +
  1.1638 +    /* allocate the memory */
  1.1639 +    javaCommand = (char*) JLI_MemAlloc(len + strlen(dashDstr) + 1);
  1.1640 +
  1.1641 +    /* build the -D string */
  1.1642 +    *javaCommand = '\0';
  1.1643 +    strcat(javaCommand, dashDstr);
  1.1644 +    strcat(javaCommand, classname);
  1.1645 +
  1.1646 +    for (i = 0; i < argc; i++) {
  1.1647 +        /* the components of the string are space separated. In
  1.1648 +         * the case of embedded white space, the relationship of
  1.1649 +         * the white space separated components to their true
  1.1650 +         * positional arguments will be ambiguous. This issue may
  1.1651 +         * be addressed in a future release.
  1.1652 +         */
  1.1653 +        strcat(javaCommand, " ");
  1.1654 +        strcat(javaCommand, argv[i]);
  1.1655 +    }
  1.1656 +
  1.1657 +    AddOption(javaCommand, NULL);
  1.1658 +}
  1.1659 +
  1.1660 +/*
  1.1661 + * JVM would like to know if it's created by a standard Sun launcher, or by
  1.1662 + * user native application, the following property indicates the former.
  1.1663 + */
  1.1664 +void SetJavaLauncherProp() {
  1.1665 +  AddOption("-Dsun.java.launcher=" LAUNCHER_TYPE, NULL);
  1.1666 +}
  1.1667 +
  1.1668 +/*
  1.1669 + * Prints the version information from the java.version and other properties.
  1.1670 + */
  1.1671 +static void
  1.1672 +PrintJavaVersion(JNIEnv *env)
  1.1673 +{
  1.1674 +    jclass ver;
  1.1675 +    jmethodID print;
  1.1676 +
  1.1677 +    NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version"));
  1.1678 +    NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V"));
  1.1679 +
  1.1680 +    (*env)->CallStaticVoidMethod(env, ver, print);
  1.1681 +}
  1.1682 +
  1.1683 +/*
  1.1684 + * Prints default usage message.
  1.1685 + */
  1.1686 +static void
  1.1687 +PrintUsage(void)
  1.1688 +{
  1.1689 +#ifndef GAMMA
  1.1690 +    int i;
  1.1691 +#endif
  1.1692 +
  1.1693 +    fprintf(stdout,
  1.1694 +        "Usage: %s [-options] class [args...]\n"
  1.1695 +        "           (to execute a class)\n"
  1.1696 +        "   or  %s [-options] -jar jarfile [args...]\n"
  1.1697 +        "           (to execute a jar file)\n"
  1.1698 +        "\n"
  1.1699 +        "where options include:\n",
  1.1700 +        progname,
  1.1701 +        progname);
  1.1702 +
  1.1703 +#ifndef GAMMA
  1.1704 +    PrintMachineDependentOptions();
  1.1705 +
  1.1706 +    if ((knownVMs[0].flag == VM_KNOWN) ||
  1.1707 +        (knownVMs[0].flag == VM_IF_SERVER_CLASS)) {
  1.1708 +      fprintf(stdout, "    %s\t  to select the \"%s\" VM\n",
  1.1709 +              knownVMs[0].name, knownVMs[0].name+1);
  1.1710 +    }
  1.1711 +    for (i=1; i<knownVMsCount; i++) {
  1.1712 +        if (knownVMs[i].flag == VM_KNOWN)
  1.1713 +            fprintf(stdout, "    %s\t  to select the \"%s\" VM\n",
  1.1714 +                    knownVMs[i].name, knownVMs[i].name+1);
  1.1715 +    }
  1.1716 +    for (i=1; i<knownVMsCount; i++) {
  1.1717 +        if (knownVMs[i].flag == VM_ALIASED_TO)
  1.1718 +            fprintf(stdout, "    %s\t  is a synonym for "
  1.1719 +                    "the \"%s\" VM  [deprecated]\n",
  1.1720 +                    knownVMs[i].name, knownVMs[i].alias+1);
  1.1721 +    }
  1.1722 +    /* The first known VM is the default */
  1.1723 +    {
  1.1724 +      const char* defaultVM   = knownVMs[0].name+1;
  1.1725 +      const char* punctuation = ".";
  1.1726 +      const char* reason      = "";
  1.1727 +      if ((knownVMs[0].flag == VM_IF_SERVER_CLASS) &&
  1.1728 +          (ServerClassMachine() == JNI_TRUE)) {
  1.1729 +        defaultVM = knownVMs[0].server_class+1;
  1.1730 +        punctuation = ", ";
  1.1731 +        reason = "because you are running on a server-class machine.\n";
  1.1732 +      }
  1.1733 +      fprintf(stdout, "                  The default VM is %s%s\n",
  1.1734 +              defaultVM, punctuation);
  1.1735 +      fprintf(stdout, "                  %s\n",
  1.1736 +              reason);
  1.1737 +    }
  1.1738 +#endif /* ifndef GAMMA */
  1.1739 +
  1.1740 +    fprintf(stdout,
  1.1741 +"    -cp <class search path of directories and zip/jar files>\n"
  1.1742 +"    -classpath <class search path of directories and zip/jar files>\n"
  1.1743 +"                  A %c separated list of directories, JAR archives,\n"
  1.1744 +"                  and ZIP archives to search for class files.\n"
  1.1745 +"    -D<name>=<value>\n"
  1.1746 +"                  set a system property\n"
  1.1747 +"    -verbose[:class|gc|jni]\n"
  1.1748 +"                  enable verbose output\n"
  1.1749 +"    -version      print product version and exit\n"
  1.1750 +"    -version:<value>\n"
  1.1751 +"                  require the specified version to run\n"
  1.1752 +"    -showversion  print product version and continue\n"
  1.1753 +"    -jre-restrict-search | -jre-no-restrict-search\n"
  1.1754 +"                  include/exclude user private JREs in the version search\n"
  1.1755 +"    -? -help      print this help message\n"
  1.1756 +"    -X            print help on non-standard options\n"
  1.1757 +"    -ea[:<packagename>...|:<classname>]\n"
  1.1758 +"    -enableassertions[:<packagename>...|:<classname>]\n"
  1.1759 +"                  enable assertions\n"
  1.1760 +"    -da[:<packagename>...|:<classname>]\n"
  1.1761 +"    -disableassertions[:<packagename>...|:<classname>]\n"
  1.1762 +"                  disable assertions\n"
  1.1763 +"    -esa | -enablesystemassertions\n"
  1.1764 +"                  enable system assertions\n"
  1.1765 +"    -dsa | -disablesystemassertions\n"
  1.1766 +"                  disable system assertions\n"
  1.1767 +"    -agentlib:<libname>[=<options>]\n"
  1.1768 +"                  load native agent library <libname>, e.g. -agentlib:hprof\n"
  1.1769 +"                    see also, -agentlib:jdwp=help and -agentlib:hprof=help\n"
  1.1770 +"    -agentpath:<pathname>[=<options>]\n"
  1.1771 +"                  load native agent library by full pathname\n"
  1.1772 +"    -javaagent:<jarpath>[=<options>]\n"
  1.1773 +"                  load Java programming language agent, see java.lang.instrument\n"
  1.1774 +"    -splash:<imagepath>\n"
  1.1775 +"                  show splash screen with specified image\n"
  1.1776 +
  1.1777 +            ,PATH_SEPARATOR);
  1.1778 +}
  1.1779 +
  1.1780 +/*
  1.1781 + * Print usage message for -X options.
  1.1782 + */
  1.1783 +static jint
  1.1784 +PrintXUsage(const char *jvmpath)
  1.1785 +{
  1.1786 +    /*
  1.1787 +       A 32 bit cushion to prevent buffer overrun, noting that
  1.1788 +       fopen(3C) may fail if the buffer exceeds MAXPATHLEN.
  1.1789 +    */
  1.1790 +    char path[MAXPATHLEN+32];
  1.1791 +    char buf[128];
  1.1792 +    size_t n;
  1.1793 +    FILE *fp;
  1.1794 +    static const char Xusage_txt[] = "/Xusage.txt";
  1.1795 +
  1.1796 +    strcpy(path, jvmpath);
  1.1797 +    /* Note the FILE_SEPARATOR is platform dependent */
  1.1798 +    strcpy(strrchr(path, FILE_SEPARATOR), Xusage_txt);
  1.1799 +    fp = fopen(path, "r");
  1.1800 +    if (fp == 0) {
  1.1801 +        fprintf(stderr, "Can't open %s\n", path);
  1.1802 +        return 1;
  1.1803 +    }
  1.1804 +    while ((n = fread(buf, 1, sizeof(buf), fp)) != 0) {
  1.1805 +        fwrite(buf, 1, n, stdout);
  1.1806 +    }
  1.1807 +    fclose(fp);
  1.1808 +    return 0;
  1.1809 +}
  1.1810 +
  1.1811 +#ifndef GAMMA
  1.1812 +/*
  1.1813 + * Read the jvm.cfg file and fill the knownJVMs[] array.
  1.1814 + *
  1.1815 + * The functionality of the jvm.cfg file is subject to change without
  1.1816 + * notice and the mechanism will be removed in the future.
  1.1817 + *
  1.1818 + * The lexical structure of the jvm.cfg file is as follows:
  1.1819 + *
  1.1820 + *     jvmcfg         :=  { vmLine }
  1.1821 + *     vmLine         :=  knownLine
  1.1822 + *                    |   aliasLine
  1.1823 + *                    |   warnLine
  1.1824 + *                    |   ignoreLine
  1.1825 + *                    |   errorLine
  1.1826 + *                    |   predicateLine
  1.1827 + *                    |   commentLine
  1.1828 + *     knownLine      :=  flag  "KNOWN"                  EOL
  1.1829 + *     warnLine       :=  flag  "WARN"                   EOL
  1.1830 + *     ignoreLine     :=  flag  "IGNORE"                 EOL
  1.1831 + *     errorLine      :=  flag  "ERROR"                  EOL
  1.1832 + *     aliasLine      :=  flag  "ALIASED_TO"       flag  EOL
  1.1833 + *     predicateLine  :=  flag  "IF_SERVER_CLASS"  flag  EOL
  1.1834 + *     commentLine    :=  "#" text                       EOL
  1.1835 + *     flag           :=  "-" identifier
  1.1836 + *
  1.1837 + * The semantics are that when someone specifies a flag on the command line:
  1.1838 + * - if the flag appears on a knownLine, then the identifier is used as
  1.1839 + *   the name of the directory holding the JVM library (the name of the JVM).
  1.1840 + * - if the flag appears as the first flag on an aliasLine, the identifier
  1.1841 + *   of the second flag is used as the name of the JVM.
  1.1842 + * - if the flag appears on a warnLine, the identifier is used as the
  1.1843 + *   name of the JVM, but a warning is generated.
  1.1844 + * - if the flag appears on an ignoreLine, the identifier is recognized as the
  1.1845 + *   name of a JVM, but the identifier is ignored and the default vm used
  1.1846 + * - if the flag appears on an errorLine, an error is generated.
  1.1847 + * - if the flag appears as the first flag on a predicateLine, and
  1.1848 + *   the machine on which you are running passes the predicate indicated,
  1.1849 + *   then the identifier of the second flag is used as the name of the JVM,
  1.1850 + *   otherwise the identifier of the first flag is used as the name of the JVM.
  1.1851 + * If no flag is given on the command line, the first vmLine of the jvm.cfg
  1.1852 + * file determines the name of the JVM.
  1.1853 + * PredicateLines are only interpreted on first vmLine of a jvm.cfg file,
  1.1854 + * since they only make sense if someone hasn't specified the name of the
  1.1855 + * JVM on the command line.
  1.1856 + *
  1.1857 + * The intent of the jvm.cfg file is to allow several JVM libraries to
  1.1858 + * be installed in different subdirectories of a single JRE installation,
  1.1859 + * for space-savings and convenience in testing.
  1.1860 + * The intent is explicitly not to provide a full aliasing or predicate
  1.1861 + * mechanism.
  1.1862 + */
  1.1863 +jint
  1.1864 +ReadKnownVMs(const char *jrepath, char * arch, jboolean speculative)
  1.1865 +{
  1.1866 +    FILE *jvmCfg;
  1.1867 +    char jvmCfgName[MAXPATHLEN+20];
  1.1868 +    char line[MAXPATHLEN+20];
  1.1869 +    int cnt = 0;
  1.1870 +    int lineno = 0;
  1.1871 +    jlong start, end;
  1.1872 +    int vmType;
  1.1873 +    char *tmpPtr;
  1.1874 +    char *altVMName = NULL;
  1.1875 +    char *serverClassVMName = NULL;
  1.1876 +    static char *whiteSpace = " \t";
  1.1877 +    if (_launcher_debug) {
  1.1878 +        start = CounterGet();
  1.1879 +    }
  1.1880 +
  1.1881 +    strcpy(jvmCfgName, jrepath);
  1.1882 +    strcat(jvmCfgName, FILESEP "lib" FILESEP);
  1.1883 +    strcat(jvmCfgName, arch);
  1.1884 +    strcat(jvmCfgName, FILESEP "jvm.cfg");
  1.1885 +
  1.1886 +    jvmCfg = fopen(jvmCfgName, "r");
  1.1887 +    if (jvmCfg == NULL) {
  1.1888 +      if (!speculative) {
  1.1889 +        ReportErrorMessage2("Error: could not open `%s'", jvmCfgName,
  1.1890 +                            JNI_TRUE);
  1.1891 +        exit(1);
  1.1892 +      } else {
  1.1893 +        return -1;
  1.1894 +      }
  1.1895 +    }
  1.1896 +    while (fgets(line, sizeof(line), jvmCfg) != NULL) {
  1.1897 +        vmType = VM_UNKNOWN;
  1.1898 +        lineno++;
  1.1899 +        if (line[0] == '#')
  1.1900 +            continue;
  1.1901 +        if (line[0] != '-') {
  1.1902 +            fprintf(stderr, "Warning: no leading - on line %d of `%s'\n",
  1.1903 +                    lineno, jvmCfgName);
  1.1904 +        }
  1.1905 +        if (cnt >= knownVMsLimit) {
  1.1906 +            GrowKnownVMs(cnt);
  1.1907 +        }
  1.1908 +        line[strlen(line)-1] = '\0'; /* remove trailing newline */
  1.1909 +        tmpPtr = line + strcspn(line, whiteSpace);
  1.1910 +        if (*tmpPtr == 0) {
  1.1911 +            fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n",
  1.1912 +                    lineno, jvmCfgName);
  1.1913 +        } else {
  1.1914 +            /* Null-terminate this string for JLI_StringDup below */
  1.1915 +            *tmpPtr++ = 0;
  1.1916 +            tmpPtr += strspn(tmpPtr, whiteSpace);
  1.1917 +            if (*tmpPtr == 0) {
  1.1918 +                fprintf(stderr, "Warning: missing VM type on line %d of `%s'\n",
  1.1919 +                        lineno, jvmCfgName);
  1.1920 +            } else {
  1.1921 +                if (!strncmp(tmpPtr, "KNOWN", strlen("KNOWN"))) {
  1.1922 +                    vmType = VM_KNOWN;
  1.1923 +                } else if (!strncmp(tmpPtr, "ALIASED_TO", strlen("ALIASED_TO"))) {
  1.1924 +                    tmpPtr += strcspn(tmpPtr, whiteSpace);
  1.1925 +                    if (*tmpPtr != 0) {
  1.1926 +                        tmpPtr += strspn(tmpPtr, whiteSpace);
  1.1927 +                    }
  1.1928 +                    if (*tmpPtr == 0) {
  1.1929 +                        fprintf(stderr, "Warning: missing VM alias on line %d of `%s'\n",
  1.1930 +                                lineno, jvmCfgName);
  1.1931 +                    } else {
  1.1932 +                        /* Null terminate altVMName */
  1.1933 +                        altVMName = tmpPtr;
  1.1934 +                        tmpPtr += strcspn(tmpPtr, whiteSpace);
  1.1935 +                        *tmpPtr = 0;
  1.1936 +                        vmType = VM_ALIASED_TO;
  1.1937 +                    }
  1.1938 +                } else if (!strncmp(tmpPtr, "WARN", strlen("WARN"))) {
  1.1939 +                    vmType = VM_WARN;
  1.1940 +                } else if (!strncmp(tmpPtr, "IGNORE", strlen("IGNORE"))) {
  1.1941 +                    vmType = VM_IGNORE;
  1.1942 +                } else if (!strncmp(tmpPtr, "ERROR", strlen("ERROR"))) {
  1.1943 +                    vmType = VM_ERROR;
  1.1944 +                } else if (!strncmp(tmpPtr,
  1.1945 +                                    "IF_SERVER_CLASS",
  1.1946 +                                    strlen("IF_SERVER_CLASS"))) {
  1.1947 +                    tmpPtr += strcspn(tmpPtr, whiteSpace);
  1.1948 +                    if (*tmpPtr != 0) {
  1.1949 +                        tmpPtr += strspn(tmpPtr, whiteSpace);
  1.1950 +                    }
  1.1951 +                    if (*tmpPtr == 0) {
  1.1952 +                        fprintf(stderr, "Warning: missing server class VM on line %d of `%s'\n",
  1.1953 +                                lineno, jvmCfgName);
  1.1954 +                    } else {
  1.1955 +                        /* Null terminate server class VM name */
  1.1956 +                        serverClassVMName = tmpPtr;
  1.1957 +                        tmpPtr += strcspn(tmpPtr, whiteSpace);
  1.1958 +                        *tmpPtr = 0;
  1.1959 +                        vmType = VM_IF_SERVER_CLASS;
  1.1960 +                    }
  1.1961 +                } else {
  1.1962 +                    fprintf(stderr, "Warning: unknown VM type on line %d of `%s'\n",
  1.1963 +                            lineno, &jvmCfgName[0]);
  1.1964 +                    vmType = VM_KNOWN;
  1.1965 +                }
  1.1966 +            }
  1.1967 +        }
  1.1968 +
  1.1969 +        if (_launcher_debug)
  1.1970 +            printf("jvm.cfg[%d] = ->%s<-\n", cnt, line);
  1.1971 +        if (vmType != VM_UNKNOWN) {
  1.1972 +            knownVMs[cnt].name = JLI_StringDup(line);
  1.1973 +            knownVMs[cnt].flag = vmType;
  1.1974 +            switch (vmType) {
  1.1975 +            default:
  1.1976 +                break;
  1.1977 +            case VM_ALIASED_TO:
  1.1978 +                knownVMs[cnt].alias = JLI_StringDup(altVMName);
  1.1979 +                if (_launcher_debug) {
  1.1980 +                    printf("    name: %s  vmType: %s  alias: %s\n",
  1.1981 +                           knownVMs[cnt].name, "VM_ALIASED_TO", knownVMs[cnt].alias);
  1.1982 +                }
  1.1983 +                break;
  1.1984 +            case VM_IF_SERVER_CLASS:
  1.1985 +                knownVMs[cnt].server_class = JLI_StringDup(serverClassVMName);
  1.1986 +                if (_launcher_debug) {
  1.1987 +                    printf("    name: %s  vmType: %s  server_class: %s\n",
  1.1988 +                           knownVMs[cnt].name, "VM_IF_SERVER_CLASS", knownVMs[cnt].server_class);
  1.1989 +                }
  1.1990 +                break;
  1.1991 +            }
  1.1992 +            cnt++;
  1.1993 +        }
  1.1994 +    }
  1.1995 +    fclose(jvmCfg);
  1.1996 +    knownVMsCount = cnt;
  1.1997 +
  1.1998 +    if (_launcher_debug) {
  1.1999 +        end   = CounterGet();
  1.2000 +        printf("%ld micro seconds to parse jvm.cfg\n",
  1.2001 +               (long)(jint)Counter2Micros(end-start));
  1.2002 +    }
  1.2003 +
  1.2004 +    return cnt;
  1.2005 +}
  1.2006 +
  1.2007 +
  1.2008 +static void
  1.2009 +GrowKnownVMs(int minimum)
  1.2010 +{
  1.2011 +    struct vmdesc* newKnownVMs;
  1.2012 +    int newMax;
  1.2013 +
  1.2014 +    newMax = (knownVMsLimit == 0 ? INIT_MAX_KNOWN_VMS : (2 * knownVMsLimit));
  1.2015 +    if (newMax <= minimum) {
  1.2016 +        newMax = minimum;
  1.2017 +    }
  1.2018 +    newKnownVMs = (struct vmdesc*) JLI_MemAlloc(newMax * sizeof(struct vmdesc));
  1.2019 +    if (knownVMs != NULL) {
  1.2020 +        memcpy(newKnownVMs, knownVMs, knownVMsLimit * sizeof(struct vmdesc));
  1.2021 +    }
  1.2022 +    JLI_MemFree(knownVMs);
  1.2023 +    knownVMs = newKnownVMs;
  1.2024 +    knownVMsLimit = newMax;
  1.2025 +}
  1.2026 +
  1.2027 +
  1.2028 +/* Returns index of VM or -1 if not found */
  1.2029 +static int
  1.2030 +KnownVMIndex(const char* name)
  1.2031 +{
  1.2032 +    int i;
  1.2033 +    if (strncmp(name, "-J", 2) == 0) name += 2;
  1.2034 +    for (i = 0; i < knownVMsCount; i++) {
  1.2035 +        if (!strcmp(name, knownVMs[i].name)) {
  1.2036 +            return i;
  1.2037 +        }
  1.2038 +    }
  1.2039 +    return -1;
  1.2040 +}
  1.2041 +
  1.2042 +static void
  1.2043 +FreeKnownVMs()
  1.2044 +{
  1.2045 +    int i;
  1.2046 +    for (i = 0; i < knownVMsCount; i++) {
  1.2047 +        JLI_MemFree(knownVMs[i].name);
  1.2048 +        knownVMs[i].name = NULL;
  1.2049 +    }
  1.2050 +    JLI_MemFree(knownVMs);
  1.2051 +}
  1.2052 +
  1.2053 +
  1.2054 +/*
  1.2055 + * Displays the splash screen according to the jar file name
  1.2056 + * and image file names stored in environment variables
  1.2057 + */
  1.2058 +static void
  1.2059 +ShowSplashScreen()
  1.2060 +{
  1.2061 +    const char *jar_name = getenv(SPLASH_JAR_ENV_ENTRY);
  1.2062 +    const char *file_name = getenv(SPLASH_FILE_ENV_ENTRY);
  1.2063 +    int data_size;
  1.2064 +    void *image_data;
  1.2065 +    if (jar_name) {
  1.2066 +        image_data = JLI_JarUnpackFile(jar_name, file_name, &data_size);
  1.2067 +        if (image_data) {
  1.2068 +            DoSplashInit();
  1.2069 +            DoSplashLoadMemory(image_data, data_size);
  1.2070 +            JLI_MemFree(image_data);
  1.2071 +        }
  1.2072 +    } else if (file_name) {
  1.2073 +        DoSplashInit();
  1.2074 +        DoSplashLoadFile(file_name);
  1.2075 +    } else {
  1.2076 +        return;
  1.2077 +    }
  1.2078 +    DoSplashSetFileJarName(file_name, jar_name);
  1.2079 +}
  1.2080 +
  1.2081 +#endif /* ifndef GAMMA */

mercurial