package erjang.boot;
import erjang.ErjangConfig;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/** Processing of VM parameter list.
* The steps in this are as follows:
* 1. Coalesce argument sources:
* - ERL_AFLAGS (TODO)
* - ERL_FLAGS (TODO)
* - ERL_ZFLAGS (TODO)
* - Command line arguments
* 2. Handle -args_list and -extra, i.e. argument file inclusion and partitioning
* into regular and extra/plain arguments.
* 3. Handle special arguments (especially kernel flags)
*/
public class CommandLineParser {
public static List<String> parseArgumentList(String[] args, ArrayList<String> base_args, ArrayList<String> extra_args) throws IOException {
// Step 1: Handle -args_file inclusion and extra/regular partitioning.
processArgsInto(args, base_args, extra_args);
// Step 2: Handle and strip out any special arguments.
handleSpecialArguments(base_args);
if (ErjangConfig.hasString("erjang.boot.show_args")) {
showArguments(base_args, extra_args);
}
List<String> res = new ArrayList<>(base_args);
if (!extra_args.isEmpty()) {
res.add("-extra");
res.addAll(extra_args);
}
return res;
}
/** Process argument list, handling "-args_file" includes and partitioning into regular and extra arguments. */
private static void processArgsInto(String[] args, List<String> base_args, List<String> extra_args) throws IOException {
List<String> dest = base_args;
for (int i=0; i<args.length; i++) {
String arg = args[i];
if (arg.equals("-args_file")) {
i++;
if (i == args.length) throw new RuntimeException("Bad command line: -args_file at end of line");
parseArgsFile(args[i], base_args, extra_args);
} else if ("-extra".equals(arg)) {
// Change to extra_args for the rest of the command line
dest = extra_args;
} else {
dest.add(arg);
}
}
}
private static void handleSpecialArguments(ArrayList<String> args) {
for (int i=0; i<args.size(); i++) {
String arg = args.get(i);
if (arg.equals("-noinput") || arg.equals("-noshell")) {
//special handling for -noshell / -noinput:
//in this case we suppress the Progress wheel since it might break the output
System.setProperty("erjang.progress.suppress", "true");
// Keep.
} else if (arg.startsWith("+")) {
switch (arg.charAt(1)) {
case 'a':
case 'e': // strip erts version too
case 'A':
case 'B':
case 'K':
case 'M':
case 'P':
case 'R':
case 'S':
case 's':
case 't':
case 'T':
case 'W':
char flag = arg.charAt(1);
final String value;
if (arg.length() >= 2) {
value = arg.substring(2);
args.remove(i);
} else {
value = args.get(i+1);
args.remove(i);
args.remove(i);
}
System.setProperty("erjang.beam.option."+flag, value);
i--;
break;
case 'h': // And others?
default:
System.setProperty("erjang.beam.option."+arg.substring(1), "true");
args.remove(i);
i--;
break;
}
}
}
}
private static void parseArgsFile(String filename, List<String> args, List<String> extra_args) throws IOException {
try (BufferedReader file = new BufferedReader(new FileReader(filename))) {
String line;
List<String> tokens = new ArrayList();
while ((line = file.readLine()) != null) {
tokenizeInto(line, tokens);
}
List<String> dest = args;
for (String token : tokens) {
if ("-extra".equals(token)) {
// Change to extra_args for the rest of the file
dest = extra_args;
} else {
dest.add(token);
}
}
}
}
private static void tokenizeInto(String line, List<String> dest) throws IOException {
// Slow but simple
StringBuilder sb = new StringBuilder();
for (int i=0; i<line.length(); i++) {
char c = line.charAt(i);
if (c=='\\') { // Handle character quoting
i++;
if (i==line.length()) throw new IOException("Syntax error: '\\' at end of line");
sb.append(line.charAt(i));
} else if (Character.isWhitespace(c)) { // End of token
if (sb.length()>0) dest.add(sb.toString());
sb.setLength(0);
} else if (c=='#') { // Rest of line is comment
break;
}else { // Normal character
sb.append(c);
}
}
if (sb.length()>0) dest.add(sb.toString());
}
private static void showArguments(List<String> base_args, List<String> extra_args) {
System.err.println("*** VM arguments:");
System.err.println(" * Regular arguments:");
for (String arg : base_args) {
System.err.println(" "+arg);
}
System.err.println(" * Extra arguments:");
for (String arg : extra_args) {
System.err.println(" " + arg);
}
System.err.println();
}
}