2
0
Fork 0
mirror of https://github.com/ethauvin/bld.git synced 2025-04-25 16:27:11 -07:00

Added a command line tokenizer

This commit is contained in:
Erik C. Thauvin 2024-08-04 20:17:26 -07:00
parent a06ce8eaaa
commit d42d2d6fa0
Signed by: erik
GPG key ID: 776702A6A2DA330E
2 changed files with 119 additions and 37 deletions

View file

@ -6,12 +6,15 @@ package rife.bld.operations;
import rife.bld.operations.exceptions.ExitStatusException; import rife.bld.operations.exceptions.ExitStatusException;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Scanner;
import java.util.spi.ToolProvider; import java.util.spi.ToolProvider;
/** /**
@ -73,23 +76,6 @@ public abstract class AbstractToolProviderOperation<T extends AbstractToolProvid
return (T) this; return (T) this;
} }
/**
* Adds arguments to pass to the tool.
*
* @param args the argument-value pairs to add
* @return this operation
*/
@SuppressWarnings({"unchecked", "UnusedReturnValue"})
protected T toolArgs(Map<String, String> args) {
args.forEach((k, v) -> {
toolArgs_.add(k);
if (v != null && !v.isEmpty()) {
toolArgs_.add(v);
}
});
return (T) this;
}
/** /**
* Adds arguments to pass to the tool. * Adds arguments to pass to the tool.
* *
@ -119,28 +105,122 @@ public abstract class AbstractToolProviderOperation<T extends AbstractToolProvid
* @throws FileNotFoundException if a file cannot be found * @throws FileNotFoundException if a file cannot be found
*/ */
@SuppressWarnings({"unchecked", "UnusedReturnValue"}) @SuppressWarnings({"unchecked", "UnusedReturnValue"})
public T toolArgsFromFile(List<String> files) throws FileNotFoundException { public T toolArgsFromFile(List<String> files) throws IOException {
var list = new ArrayList<String>(); var args = new ArrayList<String>();
for (var option : files) { for (var file : files) {
try (var scanner = new Scanner(new File(option))) { try (var reader = Files.newBufferedReader(Paths.get(file), Charset.defaultCharset())) {
while (scanner.hasNext()) { var tokenizer = new CommandLineTokenizer(reader);
var splitLine = scanner.nextLine().split("--"); String token;
for (String args : splitLine) { while ((token = tokenizer.nextToken()) != null) {
if (!args.isBlank()) { args.add(token);
var splitArgs = args.split(" ", 2);
list.add("--" + splitArgs[0]);
if (splitArgs.length > 1 && !splitArgs[1].isBlank()) {
list.add(splitArgs[1]);
}
}
}
} }
} }
} }
toolArgs(list); toolArgs(args);
return (T) this; return (T) this;
} }
/**
* Adds arguments to pass to the tool.
*
* @param args the argument-value pairs to add
* @return this operation
*/
@SuppressWarnings({"unchecked", "UnusedReturnValue"})
protected T toolArgs(Map<String, String> args) {
args.forEach((k, v) -> {
toolArgs_.add(k);
if (v != null && !v.isEmpty()) {
toolArgs_.add(v);
}
});
return (T) this;
}
/**
* Tokenize command line arguments.
*
* <ul>
* <li>Arguments containing spaces should be quoted</li>
* <li>Escape sequences and comments are supported</li>
* </ul>
*/
public static class CommandLineTokenizer {
private final StringBuilder buf_ = new StringBuilder();
private final Reader input_;
private int ch_;
public CommandLineTokenizer(Reader input) throws IOException {
input_ = input;
ch_ = input.read();
}
public String nextToken() throws IOException {
skipWhitespaceOrComments();
if (ch_ == -1) {
return null;
}
buf_.setLength(0); // reset buffer
char quote = 0;
while (ch_ != -1) {
if (Character.isWhitespace(ch_)) { // whitespaces
if (quote == 0) {
break;
}
buf_.append((char) ch_);
} else if (ch_ == '\'' || ch_ == '"') { // quotes
if (quote == 0) {
quote = (char) ch_;
} else if (quote == ch_) {
quote = 0;
} else {
buf_.append((char) ch_);
}
} else if (ch_ == '\\') { // escaped
ch_ = input_.read();
buf_.append(handleEscapeSequence());
} else {
buf_.append((char) ch_);
}
ch_ = input_.read();
}
return buf_.toString();
}
private char handleEscapeSequence() {
if (ch_ == -1) {
return '\\';
}
return switch (ch_) {
case 'n' -> '\n';
case 'r' -> '\r';
case 't' -> '\t';
case 'f' -> '\f';
default -> (char) ch_;
};
}
private void skipWhitespaceOrComments() throws IOException {
while (ch_ != -1) {
if (Character.isWhitespace(ch_)) { // Skip whitespaces
ch_ = input_.read();
} else if (ch_ == '#') {
// Skip the entire comment until a new line or end of input
do {
ch_ = input_.read();
} while (ch_ != -1 && ch_ != '\n' && ch_ != '\r');
} else {
return;
}
}
}
}
} }

View file

@ -1,2 +1,4 @@
--verbose --version --verbose --version #foo
--list-plugins --module-path "foo bar" --list-plugins
# bar