home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.5 Applications 2002 November / SGI IRIX 6.5 Applications 2002 November.iso / dev / java2v131_02_dev.idb / usr / java2v131_02 / src.jar / src / launcher / java.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-06-12  |  26.3 KB  |  1,021 lines

  1. /*
  2.  * @(#)java.c    1.67 00/08/10
  3.  *
  4.  * Copyright 2000 Sun Microsystems, Inc. All rights reserved.
  5.  * Copyright 2000 Sun Microsystems, Inc. Tous droits rΘservΘs.
  6.  *
  7.  * This software is the proprietary information of Sun Microsystems, Inc.
  8.  * Use is subject to license terms.
  9.  */
  10.  
  11. /*
  12.  * Shared source for 'java' command line tool.
  13.  *
  14.  * If JAVA_ARGS is defined, then acts as a launcher for applications. For
  15.  * instance, the JDK command line tools such as javac and javadoc (see
  16.  * makefiles for more details) are built with this program.  Any arguments
  17.  * prefixed with '-J' will be passed directly to the 'java' command.
  18.  *
  19.  * If OLDJAVA is defined then enables old-style launcher behavior. In the
  20.  * old launcher, both application and system classes are loaded from the
  21.  * system class path.  In the new launcher, there is a separate class path
  22.  * and class loader for loading application classes.
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #include <jni.h>
  30. #include "java.h"
  31.  
  32. #ifndef FULL_VERSION
  33. #define FULL_VERSION "1.2"
  34. #endif
  35.  
  36. static jboolean printVersion = JNI_FALSE; /* print and exit */
  37. static jboolean showVersion = JNI_FALSE;  /* print but continue */
  38. static char *progname;
  39. jboolean debug = JNI_FALSE;
  40. int      status = 0;
  41.  
  42. /*
  43.  * List of VM options to be specified when the VM is created.
  44.  */
  45. static JavaVMOption *options;
  46. static int numOptions, maxOptions;
  47.  
  48. /*
  49.  * Prototypes for functions internal to launcher.
  50.  */
  51. static void AddOption(char *str, void *info);
  52. static void SetClassPath(char *s);
  53. static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile,
  54.                    char **pclassname, int *pret);
  55. static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
  56.                   InvocationFunctions *ifn);
  57. static void* MemAlloc(size_t size);
  58. static jstring NewPlatformString(JNIEnv *env, char *s);
  59. static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc);
  60. static jstring NewPlatformString(JNIEnv *env, char *s);
  61. static jclass LoadClass(JNIEnv *env, char *name);
  62. static jstring GetMainClassName(JNIEnv *env, char *jarname);
  63.  
  64. #ifdef JAVA_ARGS
  65. static void TranslateDashJArgs(int *pargc, char ***pargv);
  66. static jboolean AddApplicationOptions(void);
  67. #endif
  68.  
  69. static void PrintJavaVersion(JNIEnv *env);
  70. static void PrintUsage(void);
  71. static jint PrintXUsage(void);
  72.  
  73. /* Support for options such as -hotspot, -classic etc. */
  74. #define MAX_KNOWN_VMS 10
  75. static char *knownVMs[MAX_KNOWN_VMS];
  76. static int knownVMsCount;
  77. static jint ReadKnownVMs(const char *jrepath);
  78. static void FreeKnownVMs();
  79.  
  80. int jit_dump_only = 0;
  81. char *jit_dump_class = NULL;
  82.  
  83. /* for setting breakpoints during debugging */
  84. void stop_init() {}
  85.  
  86. /*
  87.  * Entry point.
  88.  */
  89. int
  90. main(int argc, char **argv)
  91. {
  92.     JavaVM *vm = 0;
  93.     JNIEnv *env = 0;
  94.     char *jarfile = 0;
  95.     char *classname = 0;
  96.     char *s = 0;
  97.     jclass mainClass;
  98.     jmethodID mainID;
  99.     jobjectArray mainArgs;
  100.     int ret;
  101.     InvocationFunctions ifn;
  102.     const char *jvmtype = 0;
  103.     jboolean jvmspecified_env = JNI_FALSE;
  104.     jboolean jvmspecified = JNI_FALSE;     /* Assume no option specified. */
  105.     char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN];
  106.     jlong start, end;
  107.     int i;
  108.  
  109.     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) {
  110.     debug = JNI_TRUE;
  111.     printf("----_JAVA_LAUNCHER_DEBUG----\n");
  112.     }
  113.  
  114.     /* Find out where the JRE is that we will be using. */
  115.     if (!GetJREPath(jrepath, sizeof(jrepath))) {
  116.     fprintf(stderr, "Error: could not find Java 2 Runtime Environment.\n");
  117.     return 2;
  118.     }
  119.  
  120.     knownVMsCount = ReadKnownVMs(jrepath);
  121.     if (knownVMsCount < 1) { /* Error already printed. */
  122.     return 3;
  123.     }
  124.  
  125.     s = getenv("JAVA_VMTYPE");
  126.     if (s) {
  127.       jvmtype = s;
  128.       jvmspecified_env = JNI_TRUE;
  129.     }
  130.  
  131.     /* Did the user pass an explicit VM type? */
  132.     if (argc > 1 && argv[1][0] == '-') {
  133.     for (i = 0; i < knownVMsCount; i++) {
  134.         if (strcmp(argv[1], knownVMs[i]) == 0) {
  135.         jvmtype = argv[1]+1; /* skip the - */
  136.         jvmspecified = JNI_TRUE;
  137.         break;
  138.         }
  139.     }
  140.     }
  141.     if (jvmspecified) {
  142.     jvmpath[0] = '\0';
  143.     if (!GetJVMPath(jrepath, jvmtype, jvmpath, sizeof(jvmpath))) {
  144.         fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath);
  145.         return 4;
  146.     }
  147.     } else {
  148.  
  149.       if (!jvmspecified_env) {
  150.     /* Find an installed VM in the preferred order... */
  151.     jboolean foundJVM = JNI_FALSE;
  152.     for (i = 0; i < knownVMsCount; i++) {
  153.         jvmtype = knownVMs[i] + 1; /* skip the - */
  154.         if (GetJVMPath(jrepath, jvmtype, jvmpath, sizeof(jvmpath))) {
  155.         foundJVM = JNI_TRUE;
  156.         break;
  157.         }
  158.     }
  159.     if (!foundJVM) {
  160.         fprintf(stderr, "Error: could not find a JVM.\n");
  161.         return 5;
  162.     }
  163.       }
  164.       else {
  165.     /* specified in the environment... */
  166.     jvmpath[0] = '\0';
  167.     if (!GetJVMPath(jrepath, jvmtype, jvmpath, sizeof(jvmpath))) {
  168.         fprintf(stderr, "Error: no `%s' JVM at `%s'.\n", jvmtype, jvmpath);
  169.         return 4;
  170.     }
  171.       }
  172.     }
  173.  
  174.     /* If we got here, jvmpath has been correctly initialized. */
  175.     ifn.CreateJavaVM = 0; ifn.GetDefaultJavaVMInitArgs = 0;
  176.     if (!LoadJavaVM(jvmpath, &ifn)) {
  177.         status = 1;
  178.     return 6;
  179.     }
  180.     
  181. #ifdef JAVA_ARGS  /* javac, jar and friends. */
  182.     progname = "java";
  183. #else             /* java, oldjava, javaw and friends */
  184. #ifdef PROGNAME
  185.     progname = PROGNAME;
  186. #else
  187.     progname = *argv;
  188.     if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {
  189.     progname = s + 1;
  190.     }
  191. #endif /* PROGNAME */
  192. #endif /* JAVA_ARGS */
  193.     ++argv;
  194.     --argc;
  195.  
  196.     /* Skip over a specified -classic/-hotspot/-server option */
  197.     if (jvmspecified) {
  198.     argv++;
  199.     argc--;
  200.     }
  201.  
  202. #ifdef JAVA_ARGS
  203.     /* Preprocess wrapper arguments */
  204.     TranslateDashJArgs(&argc, &argv);
  205.     if (!AddApplicationOptions()) {
  206.         status = 2;
  207.     return 1;
  208.     }
  209. #endif
  210.  
  211.     /* Set default CLASSPATH */
  212.     if ((s = getenv("CLASSPATH")) == 0) {
  213.     s = ".";
  214.     }
  215. #ifdef OLDJAVA
  216.     /* Prepend system class path to default */
  217.     {
  218.     JDK1_1InitArgs args;
  219.     char *buf;
  220.     args.version = JNI_VERSION_1_1;
  221.     if (ifn.GetDefaultJavaVMInitArgs(&args) != JNI_OK
  222.                 || args.classpath == 0) {
  223.         fprintf(stderr, "Could not get default system class path.\n");
  224.             status = 2;
  225.         return 1;
  226.     }
  227.     buf = MemAlloc(strlen(args.classpath) + strlen(s) + 2);
  228.     sprintf(buf, "%s%c%s", args.classpath, PATH_SEPARATOR, s);
  229.     s = buf;
  230.     }
  231. #endif
  232. #ifndef JAVA_ARGS
  233.     SetClassPath(s);
  234. #endif
  235.  
  236.     /* Parse command line options */
  237.     if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret)) {
  238.         status = 2;
  239.     return ret;
  240.     }
  241.  
  242.     /* Override class path if -jar flag was specified */
  243.     if (jarfile != 0) {
  244.     SetClassPath(jarfile);
  245.     }
  246.  
  247.     /* Initialize the virtual machine */
  248.  
  249.     if (debug)
  250.     start = CounterGet();
  251.     if (!InitializeJVM(&vm, &env, &ifn)) {
  252.     fprintf(stderr, "Could not create the Java virtual machine.\n");
  253.         status = 3;
  254.     return 1;
  255.     }
  256.  
  257.     if (printVersion || showVersion) {
  258.         PrintJavaVersion(env);
  259.     if ((*env)->ExceptionOccurred(env)) {
  260.         (*env)->ExceptionDescribe(env);
  261.         goto leave;
  262.     }
  263.     if (printVersion) {
  264.         ret = 0;
  265.         goto leave;
  266.     }
  267.     if (showVersion) {
  268.         fprintf(stderr, "\n");
  269.     }
  270.     }
  271.  
  272.     /* If the user specified neither a class name or a JAR file */
  273.     if (jarfile == 0 && classname == 0) {
  274.     PrintUsage();
  275.     goto leave;
  276.     }
  277.  
  278.     FreeKnownVMs();  /* after last possible PrintUsage() */
  279.  
  280.     if (debug) {
  281.     end   = CounterGet();
  282.     printf("%ld micro seconds to InitializeJVM\n",
  283.            (jint)Counter2Micros(end-start));
  284.     }
  285.  
  286.     /* At this stage, argc/argv have the applications' arguments */
  287.     if (debug) {
  288.     int i = 0;
  289.     printf("Main-Class is '%s'\n", classname ? classname : "");
  290.     printf("Apps' argc is %d\n", argc);
  291.     for (; i < argc; i++) {
  292.         printf("    argv[%2d] = '%s'\n", i, argv[i]);
  293.     }
  294.     }
  295.  
  296.     /* see description of -Xjitdump option in javai.c. */
  297.     if (jit_dump_only) {
  298.     jit_dump_class = classname;
  299.     }
  300.  
  301.     ret = 1;
  302.  
  303.     /* Get the application's main class */
  304.     if (jarfile != 0) {
  305.     jstring mainClassName = GetMainClassName(env, jarfile);
  306.     if ((*env)->ExceptionOccurred(env)) {
  307.         (*env)->ExceptionDescribe(env);
  308.         goto leave;
  309.     }
  310.     if (mainClassName == NULL) {
  311.         fprintf(stderr, "Failed to load Main-Class manifest attribute "
  312.             "from\n%s\n", jarfile);
  313.         goto leave;
  314.     }
  315.     classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
  316.     if (classname == NULL) {
  317.         (*env)->ExceptionDescribe(env);
  318.         goto leave;
  319.     }
  320.     mainClass = LoadClass(env, classname);
  321.     (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
  322.     } else {
  323.     mainClass = LoadClass(env, classname);
  324.     }
  325.     if (mainClass == NULL) {
  326.         (*env)->ExceptionDescribe(env);
  327.         status = 4;
  328.     goto leave;
  329.     }
  330.  
  331.     /* see description of -Xjitdump option in javai.c. */
  332.     if (jit_dump_only) {
  333.     goto leave;
  334.     }
  335.  
  336.     /* Get the application's main method */
  337.     mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
  338.                        "([Ljava/lang/String;)V");
  339.     if (mainID == NULL) {
  340.     if ((*env)->ExceptionOccurred(env)) {
  341.         (*env)->ExceptionDescribe(env);
  342.     } else {
  343.         fprintf(stderr, "No main method found in specified class.\n");
  344.     }
  345.         status = 5;
  346.     goto leave;
  347.     }
  348.  
  349.     /* Build argument array */
  350.     mainArgs = NewPlatformStringArray(env, argv, argc);
  351.     if (mainArgs == NULL) {
  352.     (*env)->ExceptionDescribe(env);
  353.     goto leave;
  354.     }
  355.  
  356.     stop_init();
  357.  
  358.     /* Invoke main method. */
  359.     (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  360.     if ((*env)->ExceptionOccurred(env)) {
  361.     /* Formerly, we used to call the "uncaughtException" method of the
  362.        main thread group, but this was later shown to be unnecessary
  363.        since the default definition merely printed out the same exception
  364.        stack trace as ExceptionDescribe and could never actually be
  365.        overridden by application programs. */
  366.     (*env)->ExceptionDescribe(env);
  367.     goto leave;
  368.     }
  369.  
  370.     /*
  371.      * Detach the current thread so that it appears to have exited when
  372.      * the application's main method exits.
  373.      */
  374.     if ((*vm)->DetachCurrentThread(vm) != 0) {
  375.     fprintf(stderr, "Could not detach main thread.\n");
  376.     goto leave;
  377.     }
  378.     ret = 0;
  379.  
  380. leave:
  381.     (*vm)->DestroyJavaVM(vm);
  382.     return ret;
  383. }
  384.  
  385. /*
  386.  * Adds a new VM option with the given given name and value.
  387.  */
  388. static void
  389. AddOption(char *str, void *info)
  390. {
  391.     /*
  392.      * Expand options array if needed to accomodate at least one more
  393.      * VM option.
  394.      */
  395.     if (numOptions >= maxOptions) {
  396.     if (options == 0) {
  397.         maxOptions = 4;
  398.         options = MemAlloc(maxOptions * sizeof(JavaVMOption));
  399.     } else {
  400.         JavaVMOption *tmp;
  401.         maxOptions *= 2;
  402.         tmp = MemAlloc(maxOptions * sizeof(JavaVMOption));
  403.         memcpy(tmp, options, numOptions * sizeof(JavaVMOption));
  404.         free(options);
  405.         options = tmp;
  406.     }
  407.     }
  408.     options[numOptions].optionString = str;
  409.     options[numOptions++].extraInfo = info;
  410. }
  411.  
  412. static void
  413. SetClassPath(char *s)
  414. {
  415.     char *def = MemAlloc(strlen(s) + 40);
  416. #ifdef OLDJAVA
  417.     sprintf(def, "-Xbootclasspath:%s", s);
  418. #else
  419.     sprintf(def, "-Djava.class.path=%s", s);
  420. #endif
  421.     AddOption(def, NULL);
  422. }
  423.  
  424. /*
  425.  * Parses command line arguments.
  426.  */
  427. static jboolean
  428. ParseArguments(int *pargc, char ***pargv, char **pjarfile,
  429.                char **pclassname, int *pret)
  430. {
  431.     int argc = *pargc;
  432.     char **argv = *pargv;
  433.     jboolean jarflag = JNI_FALSE;
  434.     char *arg;
  435.  
  436.     *pret = 1;
  437.     while ((arg = *argv) != 0 && *arg == '-') {
  438.     argv++; --argc;
  439.     if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) {
  440.         if (argc < 1) {
  441.         fprintf(stderr, "%s requires class path specification\n", arg);
  442.         PrintUsage();
  443.         return JNI_FALSE;
  444.         }
  445.         SetClassPath(*argv);
  446.         argv++; --argc;
  447. #ifndef OLDJAVA
  448.     } else if (strcmp(arg, "-jar") == 0) {
  449.         jarflag = JNI_TRUE;
  450. #endif
  451.     } else if (strcmp(arg, "-help") == 0 ||
  452.            strcmp(arg, "-h") == 0 ||
  453.            strcmp(arg, "-?") == 0) {
  454.         PrintUsage();
  455.         *pret = 0;
  456.         return JNI_FALSE;
  457.     } else if (strcmp(arg, "-version") == 0) {
  458.         printVersion = JNI_TRUE;
  459.         return JNI_TRUE;
  460.     } else if (strcmp(arg, "-showversion") == 0) {
  461.         showVersion = JNI_TRUE;
  462.     } else if (strcmp(arg, "-X") == 0) {
  463.         *pret = PrintXUsage();
  464.         return JNI_FALSE;
  465. /*
  466.  * The following case provide backward compatibility with old-style
  467.  * command line options.
  468.  */
  469.     } else if (strcmp(arg, "-fullversion") == 0) {
  470.         fprintf(stderr, "%s full version \"%s\"\n", progname,
  471.             FULL_VERSION);
  472.         *pret = 0;
  473.         return JNI_FALSE;
  474.     } else if (strcmp(arg, "-verbosegc") == 0) {
  475.         AddOption("-verbose:gc", NULL);
  476.     } else if (strcmp(arg, "-t") == 0) {
  477.         AddOption("-Xt", NULL);
  478.     } else if (strcmp(arg, "-tm") == 0) {
  479.         AddOption("-Xtm", NULL);
  480.     } else if (strcmp(arg, "-debug") == 0) {
  481.         AddOption("-Xdebug", NULL);
  482.     } else if (strcmp(arg, "-noclassgc") == 0) {
  483.         AddOption("-Xnoclassgc", NULL);
  484.     } else if (strcmp(arg, "-Xfuture") == 0) {
  485.         AddOption("-Xverify:all", NULL);
  486.     } else if (strcmp(arg, "-verify") == 0) {
  487.         AddOption("-Xverify:all", NULL);
  488.     } else if (strcmp(arg, "-verifyremote") == 0) {
  489.         AddOption("-Xverify:remote", NULL);
  490.     } else if (strcmp(arg, "-noverify") == 0) {
  491.         AddOption("-Xverify:none", NULL);
  492.     } else if (strncmp(arg, "-Xsgi:hpool-partition=", 22) == 0) {
  493.         double percentage = atof(&arg[22]);
  494.         if ((percentage < 0.01) || (percentage > 0.25)) {
  495.           fprintf(stderr, "-Xhpool-partition must be between 0.01 and 0.25\n");
  496.         } else {
  497.           extern void set_sgi_hpool_factor(double);
  498.           set_sgi_hpool_factor(percentage);
  499.         }
  500.     } else if (strncmp(arg, "-prof", 5) == 0) {
  501.         char *p = arg + 5;
  502.         char *tmp = MemAlloc(strlen(arg) + 50);
  503.         if (*p) {
  504.             sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);
  505.         } else {
  506.             sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");
  507.         }
  508.         AddOption(tmp, NULL);
  509.     } else if (strncmp(arg, "-ss", 3) == 0 ||
  510.            strncmp(arg, "-oss", 4) == 0 ||
  511.            strncmp(arg, "-ms", 3) == 0 ||
  512.            strncmp(arg, "-mx", 3) == 0) {
  513.         char *tmp = MemAlloc(strlen(arg) + 6);
  514.         sprintf(tmp, "-X%s", arg + 1); /* skip '-' */
  515.         AddOption(tmp, NULL);
  516.     } else if (strcmp(arg, "-checksource") == 0 ||
  517.            strcmp(arg, "-cs") == 0 ||
  518.            strcmp(arg, "-noasyncgc") == 0) {
  519.         /* No longer supported */
  520.         fprintf(stderr,
  521.             "Warning: %s option is no longer supported.\n",
  522.             arg);
  523.     } else {
  524.         AddOption(arg, NULL);
  525.     }
  526.     }
  527.  
  528.     if (--argc >= 0) {
  529.         if (jarflag) {
  530.         *pjarfile = *argv++;
  531.         *pclassname = 0;
  532.     } else {
  533.         *pjarfile = 0;
  534.         *pclassname = *argv++;
  535.     }
  536.     *pargc = argc;
  537.     *pargv = argv;
  538.     }
  539.  
  540.     return JNI_TRUE;
  541. }
  542.  
  543. /*
  544.  * Initializes the Java Virtual Machine. Also frees options array when
  545.  * finished.
  546.  */
  547. static jboolean
  548. InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
  549. {
  550.     JavaVMInitArgs args;
  551.     jint r;
  552.  
  553. #ifdef OLDJAVA
  554.     /* Indicate that we are using the old-style launcher */
  555.     AddOption("-Xoldjava", NULL);
  556. #endif
  557.  
  558.     memset(&args, 0, sizeof(args));
  559.     args.version  = JNI_VERSION_1_2;
  560.     args.nOptions = numOptions;
  561.     args.options  = options;
  562.     args.ignoreUnrecognized = JNI_FALSE;
  563.  
  564.     if (debug) {
  565.     int i = 0;
  566.     printf("JavaVM args:\n    ");
  567.     printf("version 0x%08lx, ", args.version);
  568.     printf("ignoreUnrecognized is %s, ",
  569.            args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
  570.     printf("nOptions is %ld\n", args.nOptions);
  571.     for (i = 0; i < numOptions; i++)
  572.         printf("    option[%2d] = '%s'\n",
  573.            i, args.options[i].optionString);
  574.     }
  575.  
  576.     r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
  577.     free(options);
  578.  
  579.     if (r == JNI_ERR) {
  580.     jio_fprintf(
  581.         stderr,
  582.         "Unable to initialize the Java VM.\n\n"
  583.         "Check to see that Java is installed correctly, and that your\n"
  584.         "CLASSPATH and LD_LIBRARY_PATH/LD_LIBRARYN32_PATH variables do\n"
  585.         "not point to a Java VM that is incompatible with the java you\n"
  586.         "are running.\n\n"
  587.         "Exiting.\n");
  588.     }
  589.  
  590.     return r == JNI_OK;
  591. }
  592.  
  593.  
  594. #define NULL_CHECK0(e) if ((e) == 0) return 0
  595. #define NULL_CHECK(e) if ((e) == 0) return
  596.  
  597. /*
  598.  * Returns a pointer to a block of at least 'size' bytes of memory.
  599.  * Prints error message and exits if the memory could not be allocated.
  600.  */
  601. static void *
  602. MemAlloc(size_t size)
  603. {
  604.     void *p = malloc(size);
  605.     if (p == 0) {
  606.     perror("malloc");
  607.     exit(1);
  608.     }
  609.     return p;
  610. }
  611.  
  612. /*
  613.  * Returns a new Java string object for the specified platform string.
  614.  */
  615. static jstring
  616. NewPlatformString(JNIEnv *env, char *s)
  617. {
  618.     int len = strlen(s);
  619.     jclass cls;
  620.     jmethodID mid;
  621.     jbyteArray ary;
  622.  
  623.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  624.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", "([B)V"));
  625.     ary = (*env)->NewByteArray(env, len);
  626.     if (ary != 0) {
  627.     jstring str = 0;
  628.     (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
  629.     if (!(*env)->ExceptionOccurred(env)) {
  630.         str = (*env)->NewObject(env, cls, mid, ary);
  631.     }
  632.     (*env)->DeleteLocalRef(env, ary);
  633.     return str;
  634.     }
  635.     return 0;
  636. }
  637.  
  638. /*
  639.  * Returns a new array of Java string objects for the specified
  640.  * array of platform strings.
  641.  */
  642. static jobjectArray
  643. NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
  644. {
  645.     jarray cls;
  646.     jarray ary;
  647.     int i;
  648.  
  649.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  650.     NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
  651.     for (i = 0; i < strc; i++) {
  652.     jstring str = NewPlatformString(env, *strv++);
  653.     NULL_CHECK0(str);
  654.     (*env)->SetObjectArrayElement(env, ary, i, str);
  655.     (*env)->DeleteLocalRef(env, str);
  656.     }
  657.     return ary;
  658. }
  659.  
  660. /*
  661.  * Loads a class, convert the '.' to '/'.
  662.  */
  663. static jclass
  664. LoadClass(JNIEnv *env, char *name)
  665. {
  666.     char *buf = MemAlloc(strlen(name) + 1);
  667.     char *s = buf, *t = name, c;
  668.     jclass cls;
  669.     jlong start, end;
  670.  
  671.     if (debug)
  672.     start = CounterGet();
  673.  
  674.     do {
  675.         c = *t++;
  676.     *s++ = (c == '.') ? '/' : c;
  677.     } while (c != '\0');
  678.     cls = (*env)->FindClass(env, buf);
  679.     free(buf);
  680.  
  681.     if (debug) {
  682.     end   = CounterGet();
  683.     printf("%ld micro seconds to load main class\n",
  684.            (jint)Counter2Micros(end-start));
  685.     printf("----_JAVA_LAUNCHER_DEBUG----\n");
  686.     }
  687.  
  688.     return cls;
  689. }
  690.  
  691. /*
  692.  * Returns the main class name for the specified jar file.
  693.  */
  694. static jstring
  695. GetMainClassName(JNIEnv *env, char *jarname)
  696. {
  697. #define MAIN_CLASS "Main-Class"
  698.     jclass cls;
  699.     jmethodID mid;
  700.     jobject jar, man, attr;
  701.     jstring str, result = 0;
  702.  
  703.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile"));
  704.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
  705.                       "(Ljava/lang/String;)V"));
  706.     NULL_CHECK0(str = NewPlatformString(env, jarname));
  707.     NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str));
  708.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest",
  709.                       "()Ljava/util/jar/Manifest;"));
  710.     man = (*env)->CallObjectMethod(env, jar, mid);
  711.     if (man != 0) {
  712.     NULL_CHECK0(mid = (*env)->GetMethodID(env,
  713.                     (*env)->GetObjectClass(env, man),
  714.                     "getMainAttributes",
  715.                     "()Ljava/util/jar/Attributes;"));
  716.     attr = (*env)->CallObjectMethod(env, man, mid);
  717.     if (attr != 0) {
  718.         NULL_CHECK0(mid = (*env)->GetMethodID(env,
  719.                     (*env)->GetObjectClass(env, attr),
  720.                     "getValue",
  721.                     "(Ljava/lang/String;)Ljava/lang/String;"));
  722.         NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS));
  723.         result = (*env)->CallObjectMethod(env, attr, mid, str);
  724.     }
  725.     }
  726.     return result;
  727. }
  728.  
  729. #ifdef JAVA_ARGS
  730. static char *java_args[] = JAVA_ARGS;
  731. static char *app_classpath[] = APP_CLASSPATH;
  732. #define NUM_ARGS (sizeof(java_args) / sizeof(char *))
  733. #define NUM_APP_CLASSPATH (sizeof(app_classpath) / sizeof(char *))
  734.  
  735. /*
  736.  * For tools convert 'javac -J-ms32m' to 'java -ms32m ...'
  737.  */
  738. static void
  739. TranslateDashJArgs(int *pargc, char ***pargv)
  740. {
  741.     int argc = *pargc;
  742.     char **argv = *pargv;
  743.     int nargc = argc + NUM_ARGS;
  744.     char **nargv = MemAlloc((nargc + 1) * sizeof(char *));
  745.     int i;
  746.  
  747.     *pargc = nargc;
  748.     *pargv = nargv;
  749.  
  750.     /* Copy the VM arguments (i.e. prefixed with -J) */
  751.     for (i = 0; i < NUM_ARGS; i++) {
  752.     char *arg = java_args[i];
  753.     if (arg[0] == '-' && arg[1] == 'J')
  754.         *nargv++ = arg + 2;
  755.     }
  756.  
  757.     for (i = 0; i < argc; i++) {
  758.     char *arg = argv[i];
  759.     if (arg[0] == '-' && arg[1] == 'J')
  760.         *nargv++ = arg + 2;
  761.     }
  762.  
  763.     /* Copy the rest of the arguments */
  764.     for (i = 0; i < NUM_ARGS; i++) {
  765.     char *arg = java_args[i];
  766.     if (arg[0] != '-' || arg[1] != 'J') {
  767.         *nargv++ = arg;
  768.     }
  769.     }
  770.     for (i = 0; i < argc; i++) {
  771.     char *arg = argv[i];
  772.     if (arg[0] != '-' || arg[1] != 'J') {
  773.         *nargv++ = arg;
  774.     }
  775.     }
  776.     *nargv = 0;
  777. }
  778.  
  779. /*
  780.  * For our tools, we try to add 3 VM options:
  781.  *    -Denv.class.path=<envcp>
  782.  *    -Dapplication.home=<apphome>
  783.  *    -Djava.class.path=<appcp>
  784.  * <envcp>   is the user's setting of CLASSPATH -- for instance the user
  785.  *           tells javac where to find binary classes through this environment
  786.  *           variable.  Notice that users will be able to compile against our
  787.  *           tools classes (sun.tools.javac.Main) only if they explicitly add
  788.  *           tools.jar to CLASSPATH.
  789.  * <apphome> is the directory where the application is installed.
  790.  * <appcp>   is the classpath to where our apps' classfiles are.
  791.  */
  792. static jboolean
  793. AddApplicationOptions()
  794. {
  795.     char *s, *envcp, *appcp, *apphome;
  796.     char home[MAXPATHLEN]; /* application home */
  797.     char separator[] = { PATH_SEPARATOR, '\0' };
  798.     int size, i;
  799.     int strlenHome;
  800.  
  801.     s = getenv("CLASSPATH");
  802.     if (s) {
  803.     /* 40 for -Denv.class.path= */
  804.     envcp = (char *)MemAlloc(strlen(s) + 40);
  805.     sprintf(envcp, "-Denv.class.path=%s", s);
  806.     AddOption(envcp, NULL);
  807.     }
  808.  
  809.     if (!GetApplicationHome(home, sizeof(home))) {
  810.     fprintf(stderr, "Can't determine application home\n");
  811.     return JNI_FALSE;
  812.     }
  813.  
  814.     /* 40 for '-Dapplication.home=' */
  815.     apphome = (char *)MemAlloc(strlen(home) + 40);
  816.     sprintf(apphome, "-Dapplication.home=%s", home);
  817.     AddOption(apphome, NULL);
  818.  
  819.     /* How big is the application's classpath? */
  820.     size = 40;                                 /* 40: "-Djava.class.path=" */
  821.     strlenHome = strlen(home);
  822.     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  823.     size += strlenHome + strlen(app_classpath[i]) + 1; /* 1: separator */
  824.     }
  825.     appcp = (char *)MemAlloc(size + 1);
  826.     strcpy(appcp, "-Djava.class.path=");
  827.     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  828.     strcat(appcp, home);            /* c:\program files\myapp */
  829.     strcat(appcp, app_classpath[i]);    /* \lib\myapp.jar      */
  830.     strcat(appcp, separator);        /* ;              */
  831.     }
  832.     appcp[strlen(appcp)-1] = '\0';  /* remove trailing path separator */
  833.     AddOption(appcp, NULL);
  834.     return JNI_TRUE;
  835. }
  836. #endif
  837.  
  838. /*
  839.  * Prints the version information from the java.version and other properties.
  840.  */
  841. static void
  842. PrintJavaVersion(JNIEnv *env)
  843. {
  844.     jclass ver;
  845.     jmethodID print;
  846.  
  847.     NULL_CHECK(ver = (*env)->FindClass(env, "sun/misc/Version"));
  848.     NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, "print", "()V"));
  849.  
  850.     (*env)->CallStaticVoidMethod(env, ver, print);
  851. }
  852.  
  853. /*
  854.  * Prints default usage message.
  855.  */
  856. static void
  857. PrintUsage(void)
  858. {
  859.     int i;
  860.     char jrepath[MAXPATHLEN], jvmpath[MAXPATHLEN];
  861.  
  862.     fprintf(stdout,
  863.     "Usage: %s [thread options] [other options] class [args...]\n"
  864. #ifndef OLDJAVA
  865.     "           (to execute a class)\n"
  866.     "   or  %s -jar [ABI/thread options] [other options] jarfile [args...]\n"
  867.     "           (to execute a jar file)\n"
  868. #endif
  869.     "\n"
  870.  
  871.     "Thread package options:\n"
  872.     "    -native           use POSIX threads (default)\n"
  873.     "    -green            use \"green threads\" (only with classic VM) \n"
  874.     "\n"
  875.  
  876.     "other options:\n",
  877. #ifndef OLDJAVA
  878.     progname,
  879. #endif
  880.     progname);
  881.  
  882.     /*
  883.      * Find out where the JRE is that we will be using.
  884.      * Loop through the known VMs, printing a line for each existing VM.
  885.      */
  886.     if (GetJREPath(jrepath, sizeof(jrepath))) {
  887.     for (i = 0; i < knownVMsCount; i++) {
  888.         const char *jvmtype = knownVMs[i]+1;
  889.  
  890.         const char *synonym = ReadJVMLink(jrepath, jvmtype,
  891.                           knownVMs, knownVMsCount);
  892.         if (synonym != NULL) {
  893.         if (synonym[0] != '\0') {
  894.             fprintf(stdout, "    %s\t  is a synonym for "
  895.                 "the \"%s\" VM  [deprecated]\n",
  896.                 knownVMs[i], synonym);
  897.         }
  898.         } else {
  899.         if (GetJVMPath(jrepath, jvmtype, jvmpath, sizeof(jvmpath))) {
  900.             fprintf(stdout, "    %s\t  to select the \"%s\" VM\n",
  901.                 knownVMs[i], knownVMs[i]+1);
  902.         }
  903.         }
  904.     }
  905.     fprintf(stdout,
  906.         "                  If present, the option to select the VM must be first.\n"
  907.         "                  The default VM is %s.\n\n", knownVMs[0]);
  908.     }
  909.  
  910.     fprintf(stdout,
  911. #ifdef OLDJAVA
  912.     "    -cp -classpath <directories and zip/jar files separated by %c>\n"
  913.     "                  set search path for classes and resources\n"
  914. #else
  915.     "    -cp -classpath <directories and zip/jar files separated by %c>\n"
  916.     "                  set search path for application classes and resources\n"
  917. #endif
  918.     "    -D<name>=<value>\n"
  919.     "                  set a system property\n"
  920.     "    -verbose[:class|gc|jni]\n"
  921.     "                  enable verbose output\n"
  922.     "    -version      print product version and exit\n"
  923.     "    -showversion  print product version and continue\n"
  924.     "    -? -help      print this help message\n"
  925.     "    -X            print help on non-standard options\n",
  926.     PATH_SEPARATOR);
  927. }
  928.  
  929. /*
  930.  * Print usage message for -X options.
  931.  */
  932. static jint
  933. PrintXUsage(void)
  934. {
  935.     char path[MAXPATHLEN];
  936.     char buf[128];
  937.     int n;
  938.     FILE *fp;
  939.  
  940.     GetXUsagePath(path, sizeof(path));
  941.     fp = fopen(path, "r");
  942.     if (fp == 0) {
  943.         fprintf(stderr, "Can't open %s\n", path);
  944.     return 1;
  945.     }
  946.     while ((n = fread(buf, 1, sizeof(buf), fp)) != 0) {
  947.         fwrite(buf, 1, n, stdout);
  948.     }
  949.     fclose(fp);
  950.     return 0;
  951. }
  952.  
  953. /*
  954.  * Read the jvm.cfg file and fill the knownJVMs[] array.
  955.  */
  956. static jint cfgLinesRead = 0;
  957.  
  958. static jint
  959. ReadKnownVMs(const char *jrepath)
  960. {
  961.     FILE *jvmCfg;
  962.     char jvmCfgName[MAXPATHLEN];
  963.     char line[MAXPATHLEN];
  964.     int cnt = 0;
  965.     int lineno = 0;
  966.     jlong start, end;
  967.  
  968.     if (debug) {
  969.     start = CounterGet();
  970.     }
  971.  
  972.     strcpy(jvmCfgName, jrepath);
  973.     strcat(jvmCfgName, JVM_CFG);
  974.  
  975.     jvmCfg = fopen(jvmCfgName, "r");
  976.     if (jvmCfg == NULL) {
  977.     fprintf(stderr, "Error: could not open `%s'\n", jvmCfgName);
  978.     return 0;
  979.     }
  980.     while (fgets(line, sizeof(line), jvmCfg) != NULL) {
  981.     lineno++;
  982.     if (line[0] == '#')
  983.         continue;
  984.     if (line[0] != '-') {
  985.         fprintf(stderr, "Warning: no leading - on line %d of `%s'\n",
  986.             lineno, jvmCfgName);
  987.     }
  988.     if (cnt >= MAX_KNOWN_VMS) {
  989.         fprintf(stderr,
  990.             "Warning: can't read more than %d entries from\n`%s'\n",
  991.             MAX_KNOWN_VMS, jvmCfgName);
  992.         break;
  993.     }
  994.     line[strlen(line)-1] = '\0'; /* remove trailing newline */
  995.     if (debug)
  996.         printf("jvm.cfg[%d] = ->%s<-\n", cnt, line);
  997.     knownVMs[cnt++] = strdup(line);
  998.     }
  999.     fclose(jvmCfg);
  1000.     cfgLinesRead = cnt;
  1001.  
  1002.     if (debug) {
  1003.     end   = CounterGet();
  1004.     printf("%ld micro seconds to parse jvm.cfg\n",
  1005.            (jint)Counter2Micros(end-start));
  1006.     }
  1007.  
  1008.     return cnt;
  1009. }
  1010.  
  1011.  
  1012. static void
  1013. FreeKnownVMs()
  1014. {
  1015.     int i;
  1016.     for (i = 0; i < cfgLinesRead; i++) {
  1017.     free(knownVMs[i]);
  1018.     knownVMs[i] = NULL;
  1019.     }
  1020. }
  1021.