home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / launcher / java.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-28  |  21.6 KB  |  821 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)java.c    1.54 98/11/19
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. /*
  16.  * Shared source for 'java' command line tool.
  17.  *
  18.  * If JAVA_ARGS is defined, then acts as a launcher for applications. For
  19.  * instance, the JDK command line tools such as javac and javadoc (see
  20.  * makefiles for more details) are built with this program.  Any arguments
  21.  * prefixed with '-J' will be passed directly to the 'java' command.
  22.  *
  23.  * If OLDJAVA is defined then enables old-style launcher behavior. In the
  24.  * old launcher, both application and system classes are loaded from the
  25.  * system class path.  In the new launcher, there is a separate class path
  26.  * and class loader for loading application classes.
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32.  
  33. #include <jni.h>
  34. #include "java.h"
  35.  
  36. #ifndef FULL_VERSION
  37. #define FULL_VERSION "1.2"
  38. #endif
  39.  
  40. static jboolean printVersion = JNI_FALSE;
  41. static char *progname;
  42. jboolean debug = JNI_FALSE;
  43.  
  44. /*
  45.  * List of VM options to be specified when the VM is created.
  46.  */
  47. static JavaVMOption *options;
  48. static int numOptions, maxOptions;
  49.  
  50. /*
  51.  * Prototypes for functions internal to launcher.
  52.  */
  53. static void AddOption(char *str, void *info);
  54. static void SetClassPath(char *s);
  55. static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile,
  56.                    char **pclassname, int *pret);
  57. static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
  58.                   InvocationFunctions *ifn);
  59. static void* MemAlloc(size_t size);
  60. static jstring NewPlatformString(JNIEnv *env, char *s);
  61. static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc);
  62. static jstring NewPlatformString(JNIEnv *env, char *s);
  63. static jclass LoadClass(JNIEnv *env, char *name);
  64. static jstring GetMainClassName(JNIEnv *env, char *jarname);
  65.  
  66. #ifdef JAVA_ARGS
  67. static void TranslateDashJArgs(int *pargc, char ***pargv);
  68. static jboolean AddApplicationOptions(void);
  69. #endif
  70.  
  71. static void PrintJavaVersion(JNIEnv *env);
  72. static void PrintUsage(void);
  73. static jint PrintXUsage(void);
  74.  
  75. /*
  76.  * Entry point.
  77.  */
  78. int
  79. main(int argc, char **argv)
  80. {
  81.     JavaVM *vm = 0;
  82.     JNIEnv *env = 0;
  83.     char *jarfile = 0;
  84.     char *classname = 0;
  85.     char *s = 0;
  86.     jclass mainClass;
  87.     jmethodID mainID;
  88.     jobjectArray mainArgs;
  89.     int ret;
  90.     InvocationFunctions ifn;
  91.     char *jvmtype = 0;
  92.     jboolean jvmspecified = JNI_FALSE;     /* Assume no option specified. */
  93.     jlong start, end;
  94.  
  95.     if (getenv("_JAVA_LAUNCHER_DEBUG") != 0) {
  96.     debug = JNI_TRUE;
  97.     printf("----_JAVA_LAUNCHER_DEBUG----\n");
  98.     }
  99.  
  100.     /* Did the user pass a -classic or -hotspot as the first option to
  101.      * the launcher? */
  102.     if (argc > 1) {
  103.     if (strcmp(argv[1], "-hotspot") == 0) {
  104.         jvmtype = "hotspot";
  105.         jvmspecified = JNI_TRUE;
  106.     } else if (strcmp(argv[1], "-classic") == 0) {
  107.         jvmtype = "classic";
  108.         jvmspecified = JNI_TRUE;
  109.     }
  110.     }
  111.     ifn.CreateJavaVM = 0; ifn.GetDefaultJavaVMInitArgs = 0;
  112.     if (!LoadJavaVM(jvmtype, &ifn))
  113.     return 1;
  114.  
  115.     /* Grab the program name */
  116.     progname = *argv++;
  117.     if ((s = strrchr(progname, FILE_SEPARATOR)) != 0) {
  118.     progname = s + 1;
  119.     }
  120.     --argc;
  121.  
  122.     /* Skip over a specified -classic/-hotspot option */
  123.     if (jvmspecified) {
  124.     argv++;
  125.     argc--;
  126.     }
  127.  
  128. #ifdef JAVA_ARGS
  129.     /* Preprocess wrapper arguments */
  130.     TranslateDashJArgs(&argc, &argv);
  131.     if (!AddApplicationOptions())
  132.     return 1;
  133. #endif
  134.  
  135.     /* Set default CLASSPATH */
  136.     if ((s = getenv("CLASSPATH")) == 0) {
  137.     s = ".";
  138.     }
  139. #ifdef OLDJAVA
  140.     /* Prepend system class path to default */
  141.     {
  142.     JDK1_1InitArgs args;
  143.     char *buf;
  144.     args.version = JNI_VERSION_1_1;
  145.     if (ifn.GetDefaultJavaVMInitArgs(&args) != JNI_OK ||
  146.         args.classpath == 0) {
  147.         fprintf(stderr, "Could not get default system class path.\n");
  148.         return 1;
  149.     }
  150.     buf = MemAlloc(strlen(args.classpath) + strlen(s) + 2);
  151.     sprintf(buf, "%s%c%s", args.classpath, PATH_SEPARATOR, s);
  152.     s = buf;
  153.     }
  154. #endif
  155. #ifndef JAVA_ARGS
  156.     SetClassPath(s);
  157. #endif
  158.  
  159.     /* Parse command line options */
  160.     if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret)) {
  161.     return ret;
  162.     }
  163.  
  164.     /* Override class path if -jar flag was specified */
  165.     if (jarfile != 0) {
  166.     SetClassPath(jarfile);
  167.     }
  168.  
  169.     /* Initialize the virtual machine */
  170.  
  171.     if (debug)
  172.     start = CounterGet();
  173.     if (!InitializeJVM(&vm, &env, &ifn)) {
  174.     fprintf(stderr, "Could not create the Java virtual machine.\n");
  175.     return 1;
  176.     }
  177.  
  178.     if (printVersion) {
  179.         PrintJavaVersion(env);
  180.     if ((*env)->ExceptionOccurred(env)) {
  181.         (*env)->ExceptionDescribe(env);
  182.         ret = 1;
  183.     } else {
  184.         ret = 0;
  185.     }
  186.     goto leave;
  187.     }
  188.  
  189.     /* If the user specified neither a class name or a JAR file */
  190.     if (jarfile == 0 && classname == 0) {
  191.     PrintUsage();
  192.     goto leave;
  193.     }
  194.  
  195.     if (debug) {
  196.     end   = CounterGet();
  197.     printf("%ld micro seconds to InitializeJVM\n",
  198.            (jint)Counter2Micros(end-start));
  199.     }
  200.  
  201.     /* At this stage, argc/argv have the applications' arguments */
  202.     if (debug) {
  203.     int i = 0;
  204.     printf("Main-Class is '%s'\n", classname ? classname : "");
  205.     printf("Apps' argc is %d\n", argc);
  206.     for (; i < argc; i++) {
  207.         printf("    argv[%2d] = '%s'\n", i, argv[i]);
  208.     }
  209.     }
  210.  
  211.     ret = 1;
  212.  
  213.     /* Get the application's main class */
  214.     if (jarfile != 0) {
  215.     jstring mainClassName = GetMainClassName(env, jarfile);
  216.     if (mainClassName == NULL) {
  217.         fprintf(stderr, "Failed to load Main-Class manifest attribute "
  218.             "from\n%s\n", jarfile);
  219.         goto leave;
  220.     }
  221.     if ((*env)->ExceptionOccurred(env)) {
  222.         (*env)->ExceptionDescribe(env);
  223.         goto leave;
  224.     }
  225.     classname = (char *)(*env)->GetStringUTFChars(env, mainClassName, 0);
  226.     if (classname == NULL) {
  227.         (*env)->ExceptionDescribe(env);
  228.         goto leave;
  229.     }
  230.     mainClass = LoadClass(env, classname);
  231.     (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
  232.     } else {
  233.     mainClass = LoadClass(env, classname);
  234.     }
  235.     if (mainClass == NULL) {
  236.         (*env)->ExceptionDescribe(env);
  237.     goto leave;
  238.     }
  239.  
  240.     /* Get the application's main method */
  241.     mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
  242.                        "([Ljava/lang/String;)V");
  243.     if (mainID == NULL) {
  244.     if ((*env)->ExceptionOccurred(env)) {
  245.         (*env)->ExceptionDescribe(env);
  246.     } else {
  247.         fprintf(stderr, "No main method found in specified class.\n");
  248.     }
  249.     goto leave;
  250.     }
  251.  
  252.     /* Build argument array */
  253.     mainArgs = NewPlatformStringArray(env, argv, argc);
  254.     if (mainArgs == NULL) {
  255.     (*env)->ExceptionDescribe(env);
  256.     goto leave;
  257.     }
  258.  
  259.     /* Invoke main method. */
  260.     (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
  261.     if ((*env)->ExceptionOccurred(env)) {
  262.     /* Formerly, we used to call the "uncaughtException" method of the
  263.        main thread group, but this was later shown to be unnecessary
  264.        since the default definition merely printed out the same exception
  265.        stack trace as ExceptionDescribe and could never actually be
  266.        overridden by application programs. */
  267.     (*env)->ExceptionDescribe(env);
  268.     goto leave;
  269.     }
  270.  
  271.     /*
  272.      * Detach the current thread so that it appears to have exited when
  273.      * the application's main method exits.
  274.      */
  275.     if ((*vm)->DetachCurrentThread(vm) != 0) {
  276.     fprintf(stderr, "Could not detach main thread.\n");
  277.     goto leave;
  278.     }
  279.     ret = 0;
  280.  
  281. leave:
  282.     (*vm)->DestroyJavaVM(vm);
  283.     return ret;
  284. }
  285.  
  286. /*
  287.  * Adds a new VM option with the given given name and value.
  288.  */
  289. static void
  290. AddOption(char *str, void *info)
  291. {
  292.     /*
  293.      * Expand options array if needed to accomodate at least one more
  294.      * VM option.
  295.      */
  296.     if (numOptions >= maxOptions) {
  297.     if (options == 0) {
  298.         maxOptions = 4;
  299.         options = MemAlloc(maxOptions * sizeof(JavaVMOption));
  300.     } else {
  301.         JavaVMOption *tmp;
  302.         maxOptions *= 2;
  303.         tmp = MemAlloc(maxOptions * sizeof(JavaVMOption));
  304.         memcpy(tmp, options, numOptions * sizeof(JavaVMOption));
  305.         free(options);
  306.         options = tmp;
  307.     }
  308.     }
  309.     options[numOptions].optionString = str;
  310.     options[numOptions++].extraInfo = info;
  311. }
  312.  
  313. static void
  314. SetClassPath(char *s)
  315. {
  316.     char *def = MemAlloc(strlen(s) + 40);
  317. #ifdef OLDJAVA
  318.     sprintf(def, "-Xbootclasspath:%s", s);
  319. #else
  320.     sprintf(def, "-Djava.class.path=%s", s);
  321. #endif
  322.     AddOption(def, NULL);
  323. }
  324.  
  325. /*
  326.  * Parses command line arguments.
  327.  */
  328. static jboolean
  329. ParseArguments(int *pargc, char ***pargv, char **pjarfile,
  330.                char **pclassname, int *pret)
  331. {
  332.     int argc = *pargc;
  333.     char **argv = *pargv;
  334.     jboolean jarflag = JNI_FALSE;
  335.     char *arg;
  336.  
  337.     *pret = 1;
  338.     while ((arg = *argv) != 0 && *arg == '-') {
  339.     argv++; --argc;
  340.     if (strcmp(arg, "-classpath") == 0 || strcmp(arg, "-cp") == 0) {
  341.         if (argc < 1) {
  342.         fprintf(stderr, "%s requires class path specification\n", arg);
  343.         PrintUsage();
  344.         return JNI_FALSE;
  345.         }
  346.         SetClassPath(*argv);
  347.         argv++; --argc;
  348. #ifndef OLDJAVA
  349.     } else if (strcmp(arg, "-jar") == 0) {
  350.         jarflag = JNI_TRUE;
  351. #endif
  352.     } else if (strcmp(arg, "-help") == 0 ||
  353.            strcmp(arg, "-h") == 0 ||
  354.            strcmp(arg, "-?") == 0) {
  355.         PrintUsage();
  356.         *pret = 0;
  357.         return JNI_FALSE;
  358.     } else if (strcmp(arg, "-version") == 0) {
  359.         printVersion = JNI_TRUE;
  360.         return JNI_TRUE;
  361.     } else if (strcmp(arg, "-X") == 0) {
  362.         *pret = PrintXUsage();
  363.         return JNI_FALSE;
  364. /*
  365.  * The following case provide backward compatibility with old-style
  366.  * command line options.
  367.  */
  368.     } else if (strcmp(arg, "-fullversion") == 0) {
  369.         fprintf(stderr, "%s full version \"%s\"\n", progname,
  370.             FULL_VERSION);
  371.         *pret = 0;
  372.         return JNI_FALSE;
  373.     } else if (strcmp(arg, "-verbosegc") == 0) {
  374.         AddOption("-verbose:gc", NULL);
  375.     } else if (strcmp(arg, "-t") == 0) {
  376.         AddOption("-Xt", NULL);
  377.     } else if (strcmp(arg, "-tm") == 0) {
  378.         AddOption("-Xtm", NULL);
  379.     } else if (strcmp(arg, "-debug") == 0) {
  380.         AddOption("-Xdebug", NULL);
  381.     } else if (strcmp(arg, "-noclassgc") == 0) {
  382.         AddOption("-Xnoclassgc", NULL);
  383.     } else if (strcmp(arg, "-Xfuture") == 0) {
  384.         AddOption("-Xverify:all", NULL);
  385.     } else if (strcmp(arg, "-verify") == 0) {
  386.         AddOption("-Xverify:all", NULL);
  387.     } else if (strcmp(arg, "-verifyremote") == 0) {
  388.         AddOption("-Xverify:remote", NULL);
  389.     } else if (strcmp(arg, "-noverify") == 0) {
  390.         AddOption("-Xverify:none", NULL);
  391.     } else if (strncmp(arg, "-prof", 5) == 0) {
  392.         char *p = arg + 5;
  393.         char *tmp = MemAlloc(strlen(arg) + 50);
  394.         if (*p) {
  395.             sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);
  396.         } else {
  397.             sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");
  398.         }
  399.         AddOption(tmp, NULL);
  400.     } else if (strncmp(arg, "-ss", 3) == 0 ||
  401.            strncmp(arg, "-oss", 4) == 0 ||
  402.            strncmp(arg, "-ms", 3) == 0 ||
  403.            strncmp(arg, "-mx", 3) == 0) {
  404.         char *tmp = MemAlloc(strlen(arg) + 6);
  405.         sprintf(tmp, "-X%s", arg + 1); /* skip '-' */
  406.         AddOption(tmp, NULL);
  407.     } else if (strcmp(arg, "-checksource") == 0 ||
  408.            strcmp(arg, "-cs") == 0 ||
  409.            strcmp(arg, "-noasyncgc") == 0) {
  410.         /* No longer supported */
  411.         fprintf(stderr,
  412.             "Warning: %s option is no longer supported.\n",
  413.             arg);
  414.     } else {
  415.         AddOption(arg, NULL);
  416.     }
  417.     }
  418.  
  419.     if (--argc >= 0) {
  420.         if (jarflag) {
  421.         *pjarfile = *argv++;
  422.         *pclassname = 0;
  423.     } else {
  424.         *pjarfile = 0;
  425.         *pclassname = *argv++;
  426.     }
  427.     *pargc = argc;
  428.     *pargv = argv;
  429.     }
  430.  
  431.     return JNI_TRUE;
  432. }
  433.  
  434. /*
  435.  * Initializes the Java Virtual Machine. Also frees options array when
  436.  * finished.
  437.  */
  438. static jboolean
  439. InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn)
  440. {
  441.     JavaVMInitArgs args;
  442.     jint r;
  443.  
  444. #ifdef OLDJAVA
  445.     /* Indicate that we are using the old-style launcher */
  446.     AddOption("-Xoldjava", NULL);
  447. #endif
  448.  
  449.     memset(&args, 0, sizeof(args));
  450.     args.version  = JNI_VERSION_1_2;
  451.     args.nOptions = numOptions;
  452.     args.options  = options;
  453.     args.ignoreUnrecognized = JNI_FALSE;
  454.  
  455.     if (debug) {
  456.     int i = 0;
  457.     printf("JavaVM args:\n    ");
  458.     printf("version 0x%08lx, ", args.version);
  459.     printf("ignoreUnrecognized is %s, ",
  460.            args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");
  461.     printf("nOptions is %ld\n", args.nOptions);
  462.     for (i = 0; i < numOptions; i++)
  463.         printf("    option[%2d] = '%s'\n",
  464.            i, args.options[i].optionString);
  465.     }
  466.  
  467.     r = ifn->CreateJavaVM(pvm, (void **)penv, &args);
  468.     free(options);
  469.     return r == JNI_OK;
  470. }
  471.  
  472.  
  473. #define NULL_CHECK0(e) if ((e) == 0) return 0
  474. #define NULL_CHECK(e) if ((e) == 0) return
  475.  
  476. /*
  477.  * Returns a pointer to a block of at least 'size' bytes of memory.
  478.  * Prints error message and exits if the memory could not be allocated.
  479.  */
  480. static void *
  481. MemAlloc(size_t size)
  482. {
  483.     void *p = malloc(size);
  484.     if (p == 0) {
  485.     perror("malloc");
  486.     exit(1);
  487.     }
  488.     return p;
  489. }
  490.  
  491. /*
  492.  * Returns a new Java string object for the specified platform string.
  493.  */
  494. static jstring
  495. NewPlatformString(JNIEnv *env, char *s)
  496. {
  497.     int len = strlen(s);
  498.     jclass cls;
  499.     jmethodID mid;
  500.     jbyteArray ary;
  501.  
  502.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  503.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>", "([B)V"));
  504.     ary = (*env)->NewByteArray(env, len);
  505.     if (ary != 0) {
  506.     jstring str = 0;
  507.     (*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
  508.     if (!(*env)->ExceptionOccurred(env)) {
  509.         str = (*env)->NewObject(env, cls, mid, ary);
  510.     }
  511.     (*env)->DeleteLocalRef(env, ary);
  512.     return str;
  513.     }
  514.     return 0;
  515. }
  516.  
  517. /*
  518.  * Returns a new array of Java string objects for the specified
  519.  * array of platform strings.
  520.  */
  521. static jobjectArray
  522. NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
  523. {
  524.     jarray cls;
  525.     jarray ary;
  526.     int i;
  527.  
  528.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/lang/String"));
  529.     NULL_CHECK0(ary = (*env)->NewObjectArray(env, strc, cls, 0));
  530.     for (i = 0; i < strc; i++) {
  531.     jstring str = NewPlatformString(env, *strv++);
  532.     NULL_CHECK0(str);
  533.     (*env)->SetObjectArrayElement(env, ary, i, str);
  534.     (*env)->DeleteLocalRef(env, str);
  535.     }
  536.     return ary;
  537. }
  538.  
  539. /*
  540.  * Loads a class, convert the '.' to '/'.
  541.  */
  542. static jclass
  543. LoadClass(JNIEnv *env, char *name)
  544. {
  545.     char *buf = MemAlloc(strlen(name) + 1);
  546.     char *s = buf, *t = name, c;
  547.     jclass cls;
  548.     jlong start, end;
  549.  
  550.     if (debug)
  551.     start = CounterGet();
  552.  
  553.     do {
  554.         c = *t++;
  555.     *s++ = (c == '.') ? '/' : c;
  556.     } while (c != '\0');
  557.     cls = (*env)->FindClass(env, buf);
  558.     free(buf);
  559.  
  560.     if (debug) {
  561.     end   = CounterGet();
  562.     printf("%ld micro seconds to load main class\n",
  563.            (jint)Counter2Micros(end-start));
  564.     printf("----_JAVA_LAUNCHER_DEBUG----\n");
  565.     }
  566.  
  567.     return cls;
  568. }
  569.  
  570. /*
  571.  * Returns the main class name for the specified jar file.
  572.  */
  573. static jstring
  574. GetMainClassName(JNIEnv *env, char *jarname)
  575. {
  576. #define MAIN_CLASS "Main-Class"
  577.     jclass cls;
  578.     jmethodID mid;
  579.     jobject jar, man, attr;
  580.     jstring str, result = 0;
  581.  
  582.     NULL_CHECK0(cls = (*env)->FindClass(env, "java/util/jar/JarFile"));
  583.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "<init>",
  584.                       "(Ljava/lang/String;)V"));
  585.     NULL_CHECK0(str = NewPlatformString(env, jarname));
  586.     NULL_CHECK0(jar = (*env)->NewObject(env, cls, mid, str));
  587.     NULL_CHECK0(mid = (*env)->GetMethodID(env, cls, "getManifest",
  588.                       "()Ljava/util/jar/Manifest;"));
  589.     man = (*env)->CallObjectMethod(env, jar, mid);
  590.     if (man != 0) {
  591.     NULL_CHECK0(mid = (*env)->GetMethodID(env,
  592.                     (*env)->GetObjectClass(env, man),
  593.                     "getMainAttributes",
  594.                     "()Ljava/util/jar/Attributes;"));
  595.     attr = (*env)->CallObjectMethod(env, man, mid);
  596.     if (attr != 0) {
  597.         NULL_CHECK0(mid = (*env)->GetMethodID(env,
  598.                     (*env)->GetObjectClass(env, attr),
  599.                     "getValue",
  600.                     "(Ljava/lang/String;)Ljava/lang/String;"));
  601.         NULL_CHECK0(str = NewPlatformString(env, MAIN_CLASS));
  602.         result = (*env)->CallObjectMethod(env, attr, mid, str);
  603.     }
  604.     }
  605.     return result;
  606. }
  607.  
  608. #ifdef JAVA_ARGS
  609. static char *java_args[] = JAVA_ARGS;
  610. static char *app_classpath[] = APP_CLASSPATH;
  611. #define NUM_ARGS (sizeof(java_args) / sizeof(char *))
  612. #define NUM_APP_CLASSPATH (sizeof(app_classpath) / sizeof(char *))
  613.  
  614. /*
  615.  * For tools convert 'javac -J-ms32m' to 'java -ms32m ...'
  616.  */
  617. static void
  618. TranslateDashJArgs(int *pargc, char ***pargv)
  619. {
  620.     int argc = *pargc;
  621.     char **argv = *pargv;
  622.     int nargc = argc + NUM_ARGS;
  623.     char **nargv = MemAlloc((nargc + 1) * sizeof(char *));
  624.     int i;
  625.  
  626.     *pargc = nargc;
  627.     *pargv = nargv;
  628.  
  629.     /* Copy the VM arguments (i.e. prefixed with -J) */
  630.     for (i = 0; i < NUM_ARGS; i++) {
  631.     char *arg = java_args[i];
  632.     if (arg[0] == '-' && arg[1] == 'J')
  633.         *nargv++ = arg + 2;
  634.     }
  635.  
  636.     for (i = 0; i < argc; i++) {
  637.     char *arg = argv[i];
  638.     if (arg[0] == '-' && arg[1] == 'J')
  639.         *nargv++ = arg + 2;
  640.     }
  641.  
  642.     /* Copy the rest of the arguments */
  643.     for (i = 0; i < NUM_ARGS; i++) {
  644.     char *arg = java_args[i];
  645.     if (arg[0] != '-' || arg[1] != 'J') {
  646.         *nargv++ = arg;
  647.     }
  648.     }
  649.     for (i = 0; i < argc; i++) {
  650.     char *arg = argv[i];
  651.     if (arg[0] != '-' || arg[1] != 'J') {
  652.         *nargv++ = arg;
  653.     }
  654.     }
  655.     *nargv = 0;
  656. }
  657.  
  658. /*
  659.  * For our tools, we try to add 3 VM options:
  660.  *    -Denv.class.path=<envcp>
  661.  *    -Dapplication.home=<apphome>
  662.  *    -Djava.class.path=<appcp>
  663.  * <envcp>   is the user's setting of CLASSPATH -- for instance the user
  664.  *           tells javac where to find binary classes through this environment
  665.  *           variable.  Notice that users will be able to compile against our
  666.  *           tools classes (sun.tools.javac.Main) only if they explicitly add
  667.  *           tools.jar to CLASSPATH.
  668.  * <apphome> is the directory where the application is installed.
  669.  * <appcp>   is the classpath to where our apps' classfiles are.
  670.  */
  671. static jboolean
  672. AddApplicationOptions()
  673. {
  674.     char *s, *envcp, *appcp, *apphome;
  675.     char home[MAXPATHLEN]; /* application home */
  676.     char separator[] = { PATH_SEPARATOR, '\0' };
  677.     int size, i;
  678.  
  679.     s = getenv("CLASSPATH");
  680.     if (s) {
  681.     /* 40 for -Denv.class.path= */
  682.     envcp = (char *)MemAlloc(strlen(s) + 40);
  683.     sprintf(envcp, "-Denv.class.path=%s", s);
  684.     AddOption(envcp, NULL);
  685.     }
  686.  
  687.     if (!GetApplicationHome(home, sizeof(home))) {
  688.     fprintf(stderr, "Can't determine application home\n");
  689.     return JNI_FALSE;
  690.     }
  691.  
  692.     /* 40 for '-Dapplication.home=' */
  693.     apphome = (char *)MemAlloc(strlen(home) + 40);
  694.     sprintf(apphome, "-Dapplication.home=%s", home);
  695.     AddOption(apphome, NULL);
  696.  
  697.     /* How big is the application's classpath? */
  698.     size = strlen(home) * NUM_APP_CLASSPATH + 40; /* 40: -Djava.class.path */
  699.     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  700.     size += strlen(app_classpath[i]);
  701.     }
  702.     appcp = (char *)MemAlloc(size + 1);
  703.     strcpy(appcp, "-Djava.class.path=");
  704.     for (i = 0; i < NUM_APP_CLASSPATH; i++) {
  705.     strcat(appcp, home);            /* c:\program files\myapp */
  706.     strcat(appcp, app_classpath[i]);    /* lib\myapp.jar      */
  707.     strcat(appcp, separator);        /* ;              */
  708.     }
  709.     appcp[strlen(appcp)-1] = '\0';  /* remove trailing path seperator */
  710.     AddOption(appcp, NULL);
  711.     return JNI_TRUE;
  712. }
  713. #endif
  714.  
  715. /*
  716.  * Prints the version information from the java.version and other properties.
  717.  */
  718. static void
  719. PrintJavaVersion(JNIEnv *env)
  720. {
  721.     jclass sysClass;
  722.     jmethodID getPropID;
  723.  
  724.     jstring java_version;
  725.     jstring java_vm_name;
  726.     jstring java_vm_info;
  727.  
  728.     char c_version[128];
  729.     char c_vm_name[256];
  730.     char c_vm_info[256];
  731.  
  732.     NULL_CHECK(sysClass = (*env)->FindClass(env, "java/lang/System"));
  733.     NULL_CHECK(getPropID = (*env)->GetStaticMethodID(env, sysClass,
  734.                              "getProperty",
  735.                  "(Ljava/lang/String;)Ljava/lang/String;"));
  736.  
  737.     NULL_CHECK(java_version = (*env)->NewStringUTF(env, "java.version"));
  738.     NULL_CHECK(java_vm_name = (*env)->NewStringUTF(env, "java.vm.name"));
  739.     NULL_CHECK(java_vm_info = (*env)->NewStringUTF(env, "java.vm.info"));
  740.  
  741.     NULL_CHECK(java_version =
  742.     (*env)->CallStaticObjectMethod(env, sysClass, getPropID, java_version));
  743.     NULL_CHECK(java_vm_name =
  744.     (*env)->CallStaticObjectMethod(env, sysClass, getPropID, java_vm_name));
  745.     NULL_CHECK(java_vm_info =
  746.     (*env)->CallStaticObjectMethod(env, sysClass, getPropID, java_vm_info));
  747.  
  748.     (*env)->GetStringUTFRegion(env, java_version, 0,
  749.                    (*env)->GetStringLength(env, java_version),
  750.                    c_version);
  751.     (*env)->GetStringUTFRegion(env, java_vm_name, 0,
  752.                    (*env)->GetStringLength(env, java_vm_name),
  753.                    c_vm_name);
  754.     (*env)->GetStringUTFRegion(env, java_vm_info, 0,
  755.                    (*env)->GetStringLength(env, java_vm_info),
  756.                    c_vm_info);
  757.  
  758.     fprintf(stderr, "java version \"%s\"\n", c_version);
  759.     fprintf(stderr, "%s (%s)\n", c_vm_name, c_vm_info);
  760. }
  761.  
  762. /*
  763.  * Prints default usage message.
  764.  */
  765. static void
  766. PrintUsage(void)
  767. {
  768.     fprintf(stdout,
  769.     "Usage: %s [-options] class [args...]\n"
  770. #ifndef OLDJAVA
  771.     "           (to execute a class)\n"
  772.     "   or  %s -jar [-options] jarfile [args...]\n"
  773.     "           (to execute a jar file)\n"
  774. #endif
  775.     "\n"
  776.     "where options include:\n"
  777. #ifdef OLDJAVA
  778.     "    -cp -classpath <directories and zip/jar files separated by %c>\n"
  779.     "              set search path for classes and resources\n"
  780. #else
  781.     "    -cp -classpath <directories and zip/jar files separated by %c>\n"
  782.     "              set search path for application classes and resources\n"
  783. #endif
  784.     "    -D<name>=<value>\n"
  785.     "              set a system property\n"
  786.     "    -verbose[:class|gc|jni]\n"
  787.     "              enable verbose output\n"
  788.     "    -version  print product version\n"
  789.     "    -? -help  print this help message\n"
  790.     "    -X        print help on non-standard options\n",
  791. #ifndef OLDJAVA
  792.     progname,
  793. #endif
  794.     progname, PATH_SEPARATOR
  795.     );
  796. }
  797.  
  798. /*
  799.  * Print usage message for -X options.
  800.  */
  801. static jint
  802. PrintXUsage(void)
  803. {
  804.     char path[MAXPATHLEN];
  805.     char buf[128];
  806.     int n;
  807.     FILE *fp;
  808.  
  809.     GetXUsagePath(path, sizeof(path));
  810.     fp = fopen(path, "r");
  811.     if (fp == 0) {
  812.         fprintf(stderr, "Can't open %s\n", path);
  813.     return 1;
  814.     }
  815.     while ((n = fread(buf, 1, sizeof(buf), fp)) != 0) {
  816.         fwrite(buf, 1, n, stdout);
  817.     }
  818.     fclose(fp);
  819.     return 0;
  820. }
  821.