Skip to content

Commit

Permalink
8340133: Add concise usage message to the java executable
Browse files Browse the repository at this point in the history
Reviewed-by: jpai, alanb, ihse, rriggs
  • Loading branch information
lahodaj committed Dec 2, 2024
1 parent 0b0f83c commit c7be41e
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 61 deletions.
9 changes: 9 additions & 0 deletions src/java.base/share/classes/sun/launcher/LauncherHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,15 @@ static void printXUsageMessage(boolean printToStderr) {
}
}

/**
* Prints the short usage text to the desired output stream.
*/
static void printConciseUsageMessage(boolean printToStderr) {
initOutput(printToStderr);
ostream.println(getLocalizedMessage("java.launcher.opt.concise.header",
File.pathSeparator));
}

static void initOutput(boolean printToStderr) {
ostream = (printToStderr) ? System.err : System.out;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
# Translators please note do not translate the options themselves
java.launcher.opt.header = Usage: {0} [options] <mainclass> [args...]\n\
\ (to execute a class)\n\
\ or {0} [options] -jar <jarfile> [args...]\n\
\ or {0} [options] -jar <jarfile>.jar [args...]\n\
\ (to execute a jar file)\n\
\ or {0} [options] -m <module>[/<mainclass>] [args...]\n\
\ {0} [options] --module <module>[/<mainclass>] [args...]\n\
\ (to execute the main class in a module)\n\
\ or {0} [options] <sourcefile> [args]\n\
\ or {0} [options] <sourcefile>.java [args]\n\
\ (to execute a source-file program)\n\n\
\ Arguments following the main class, source file, -jar <jarfile>,\n\
\ Arguments following the main class, source file, -jar <jarfile>.jar,\n\
\ -m or --module <module>/<mainclass> are passed as the arguments to\n\
\ main class.\n\n\
\ where options include:\n\n
Expand All @@ -46,15 +46,15 @@ java.launcher.opt.footer = \
\ -cp <class search path of directories and zip/jar files>\n\
\ -classpath <class search path of directories and zip/jar files>\n\
\ --class-path <class search path of directories and zip/jar files>\n\
\ A {0} separated list of directories, JAR archives,\n\
\ A "{0}"-separated list of directories, JAR archives,\n\
\ and ZIP archives to search for class files.\n\
\ -p <module path>\n\
\ --module-path <module path>...\n\
\ A {0} separated list of elements, each element is a file path\n\
\ A "{0}"-separated list of elements, each element is a file path\n\
\ to a module or a directory containing modules. Each module is either\n\
\ a modular JAR or an exploded-module directory.\n\
\ --upgrade-module-path <module path>...\n\
\ A {0} separated list of elements, each element is a file path\n\
\ A "{0}"-separated list of elements, each element is a file path\n\
\ to a module or a directory containing modules to replace\n\
\ upgradeable modules in the runtime image. Each module is either\n\
\ a modular JAR or an exploded-module directory.\n\
Expand Down Expand Up @@ -232,6 +232,23 @@ The following options are macOS specific:\n\
\ -Xdock:icon=<path to icon file>\n\
\ override default icon displayed in dock\n\n

# Translators please note do not translate the options themselves
java.launcher.opt.concise.header = Usage: java [java options...] <application> [application arguments...]\n\n\
\Where <application> is one of:\n\
\ <mainclass> to execute the main method of a compiled main class\n\
\ -jar <jarfile>.jar to execute the main class of a JAR archive\n\
\ -m <module>[/<mainclass>] to execute the main class of a module\n\
\ <sourcefile>.java to compile and execute a source-file program\n\n\
\Where key java options include:\n\
\ --class-path <class path>\n\
\ where <class path> is a list of directories and JAR archives to search for class files, separated by "{0}"\n\
\ --module-path <module path>\n\
\ where <module path> is a list of directories and JAR archives to search for modules, separated by "{0}"\n\
\ -version\n\
\ to print product version to the error stream and exit\n\n\
\For additional help on usage: java --help\n\
\For an interactive Java environment: jshell

java.launcher.bad.option=\
\n\
Unrecognized showSettings option: {0}\n\
Expand Down
127 changes: 72 additions & 55 deletions src/java.base/share/native/libjli/java.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,17 @@
#define USE_STDERR JNI_TRUE /* we usually print to stderr */
#define USE_STDOUT JNI_FALSE

enum HelpKind {
HELP_NONE,
HELP_CONCISE,
HELP_FULL,
HELP_EXTRA
};

static jboolean printVersion = JNI_FALSE; /* print and exit */
static jboolean showVersion = JNI_FALSE; /* print but continue */
static jboolean printUsage = JNI_FALSE; /* print and exit*/
static enum HelpKind printUsageKind = HELP_NONE; /* if not NONE, print specified usage and exit*/
static jboolean printTo = USE_STDERR; /* where to print version/usage */
static jboolean printXUsage = JNI_FALSE; /* print and exit*/
static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */
static char *showSettings = NULL; /* print but continue */
static jboolean showResolvedModules = JNI_FALSE;
Expand Down Expand Up @@ -120,7 +126,7 @@ static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc,
static jboolean AddApplicationOptions(int cpathc, const char **cpathv);

static void PrintJavaVersion(JNIEnv *env);
static void PrintUsage(JNIEnv* env, jboolean doXUsage);
static void PrintUsage(JNIEnv* env, enum HelpKind printUsageKind);
static void ShowSettings(JNIEnv* env, char *optString);
static void ShowResolvedModules(JNIEnv* env);
static void ListModules(JNIEnv* env);
Expand Down Expand Up @@ -179,7 +185,7 @@ static jboolean IsWildCardEnabled();
do { \
if (!AC_ok) { \
JLI_ReportErrorMessage(AC_failure_message, AC_questionable_arg); \
printUsage = JNI_FALSE; \
printUsageKind = HELP_NONE; \
*pret = 1; \
return JNI_FALSE; \
} \
Expand All @@ -189,7 +195,7 @@ static jboolean IsWildCardEnabled();
do { \
if (AC_arg_count < 1) { \
JLI_ReportErrorMessage(AC_failure_message, AC_questionable_arg); \
printUsage = JNI_TRUE; \
printUsageKind = HELP_FULL; \
*pret = 1; \
return JNI_TRUE; \
} \
Expand Down Expand Up @@ -537,8 +543,8 @@ JavaMain(void* _args)
}

/* If the user specified neither a class name nor a JAR file */
if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) {
PrintUsage(env, printXUsage);
if (printUsageKind != HELP_NONE) {
PrintUsage(env, printUsageKind);
CHECK_EXCEPTION_LEAVE(1);
LEAVE();
}
Expand Down Expand Up @@ -1235,10 +1241,10 @@ ParseArguments(int *pargc, char ***pargv,
} else if (JLI_StrCmp(arg, "-help") == 0 ||
JLI_StrCmp(arg, "-h") == 0 ||
JLI_StrCmp(arg, "-?") == 0) {
printUsage = JNI_TRUE;
printUsageKind = HELP_FULL;
return JNI_TRUE;
} else if (JLI_StrCmp(arg, "--help") == 0) {
printUsage = JNI_TRUE;
printUsageKind = HELP_FULL;
printTo = USE_STDOUT;
return JNI_TRUE;
} else if (JLI_StrCmp(arg, "-version") == 0) {
Expand All @@ -1256,10 +1262,10 @@ ParseArguments(int *pargc, char ***pargv,
} else if (JLI_StrCmp(arg, "--dry-run") == 0) {
dryRun = JNI_TRUE;
} else if (JLI_StrCmp(arg, "-X") == 0) {
printXUsage = JNI_TRUE;
printUsageKind = HELP_EXTRA;
return JNI_TRUE;
} else if (JLI_StrCmp(arg, "--help-extra") == 0) {
printXUsage = JNI_TRUE;
printUsageKind = HELP_EXTRA;
printTo = USE_STDOUT;
return JNI_TRUE;
/*
Expand Down Expand Up @@ -1350,6 +1356,7 @@ ParseArguments(int *pargc, char ***pargv,
/* LM_UNKNOWN okay for options that exit */
if (!listModules && !describeModule && !validateModules && !dumpSharedSpaces) {
*pret = 1;
printUsageKind = HELP_CONCISE;
}
} else if (mode == LM_UNKNOWN) {
if (!_have_classpath) {
Expand Down Expand Up @@ -1919,58 +1926,68 @@ DescribeModule(JNIEnv *env, char *optString)
* Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java
*/
static void
PrintUsage(JNIEnv* env, jboolean doXUsage)
PrintUsage(JNIEnv* env, enum HelpKind printUsageKind)
{
jmethodID initHelp, vmSelect, vmSynonym, printHelp, printXUsageMessage;
jmethodID initHelp, vmSelect, vmSynonym;
jmethodID printHelp, printConciseUsageMessage, printXUsageMessage;
jstring jprogname, vm1, vm2;
int i;
jclass cls = GetLauncherHelperClass(env);
NULL_CHECK(cls);
if (doXUsage) {
NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,
"printXUsageMessage", "(Z)V"));
(*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, printTo);
} else {
NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,
"initHelpMessage", "(Ljava/lang/String;)V"));

NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage",
"(Ljava/lang/String;Ljava/lang/String;)V"));

NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls,
"appendVmSynonymMessage",
"(Ljava/lang/String;Ljava/lang/String;)V"));

NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls,
"printHelpMessage", "(Z)V"));

NULL_CHECK(jprogname = (*env)->NewStringUTF(env, _program_name));

/* Initialize the usage message with the usual preamble */
(*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname);
CHECK_EXCEPTION_RETURN();


/* Assemble the other variant part of the usage */
for (i=1; i<knownVMsCount; i++) {
if (knownVMs[i].flag == VM_KNOWN) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1));
(*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);
CHECK_EXCEPTION_RETURN();
switch (printUsageKind) {
case HELP_NONE: break;
case HELP_CONCISE:
NULL_CHECK(printConciseUsageMessage = (*env)->GetStaticMethodID(env, cls,
"printConciseUsageMessage", "(Z)V"));
(*env)->CallStaticVoidMethod(env, cls, printConciseUsageMessage, printTo);
break;
case HELP_EXTRA:
NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,
"printXUsageMessage", "(Z)V"));
(*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, printTo);
break;
case HELP_FULL:
NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,
"initHelpMessage", "(Ljava/lang/String;)V"));

NULL_CHECK(vmSelect = (*env)->GetStaticMethodID(env, cls, "appendVmSelectMessage",
"(Ljava/lang/String;Ljava/lang/String;)V"));

NULL_CHECK(vmSynonym = (*env)->GetStaticMethodID(env, cls,
"appendVmSynonymMessage",
"(Ljava/lang/String;Ljava/lang/String;)V"));

NULL_CHECK(printHelp = (*env)->GetStaticMethodID(env, cls,
"printHelpMessage", "(Z)V"));

NULL_CHECK(jprogname = (*env)->NewStringUTF(env, _program_name));

/* Initialize the usage message with the usual preamble */
(*env)->CallStaticVoidMethod(env, cls, initHelp, jprogname);
CHECK_EXCEPTION_RETURN();


/* Assemble the other variant part of the usage */
for (i=1; i<knownVMsCount; i++) {
if (knownVMs[i].flag == VM_KNOWN) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].name+1));
(*env)->CallStaticVoidMethod(env, cls, vmSelect, vm1, vm2);
CHECK_EXCEPTION_RETURN();
}
}
}
for (i=1; i<knownVMsCount; i++) {
if (knownVMs[i].flag == VM_ALIASED_TO) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1));
(*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2);
CHECK_EXCEPTION_RETURN();
for (i=1; i<knownVMsCount; i++) {
if (knownVMs[i].flag == VM_ALIASED_TO) {
NULL_CHECK(vm1 = (*env)->NewStringUTF(env, knownVMs[i].name));
NULL_CHECK(vm2 = (*env)->NewStringUTF(env, knownVMs[i].alias+1));
(*env)->CallStaticVoidMethod(env, cls, vmSynonym, vm1, vm2);
CHECK_EXCEPTION_RETURN();
}
}
}

/* Complete the usage message and print to stderr*/
(*env)->CallStaticVoidMethod(env, cls, printHelp, printTo);
/* Complete the usage message and print to stderr*/
(*env)->CallStaticVoidMethod(env, cls, printHelp, printTo);
break;
}
return;
}
Expand Down

0 comments on commit c7be41e

Please sign in to comment.