mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-4906: Implement @image-opt. Have local-gdb use it. Fix 'null'.
This commit is contained in:
parent
e476b20476
commit
d5a25fa6a3
31 changed files with 497 additions and 462 deletions
|
@ -124,7 +124,7 @@ public abstract class AbstractScriptTraceRmiLaunchOffer extends AbstractTraceRmi
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresImage() {
|
||||
return !attrs.noImage();
|
||||
public LaunchParameter<?> imageParameter() {
|
||||
return attrs.imageOpt();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ import ghidra.util.task.Task;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer {
|
||||
public static final String PARAM_DISPLAY_IMAGE = "Image";
|
||||
public static final String PREFIX_PARAM_EXTTOOL = "env:GHIDRA_LANG_EXTTOOL_";
|
||||
|
||||
public static final int DEFAULT_TIMEOUT_MILLIS = 10000;
|
||||
|
@ -299,15 +298,10 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
protected Map<String, ValStr<?>> generateDefaultLauncherArgs(
|
||||
Map<String, LaunchParameter<?>> params) {
|
||||
Map<String, ValStr<?>> map = new LinkedHashMap<>();
|
||||
ImageParamSetter imageSetter = null;
|
||||
for (Entry<String, LaunchParameter<?>> entry : params.entrySet()) {
|
||||
LaunchParameter<?> param = entry.getValue();
|
||||
map.put(entry.getKey(), ValStr.cast(Object.class, param.defaultValue()));
|
||||
if (PARAM_DISPLAY_IMAGE.equals(param.display())) {
|
||||
imageSetter = ImageParamSetter.get(param);
|
||||
// May still be null if type is not supported
|
||||
}
|
||||
else if (param.name().startsWith(PREFIX_PARAM_EXTTOOL)) {
|
||||
if (param.name().startsWith(PREFIX_PARAM_EXTTOOL)) {
|
||||
String tool = param.name().substring(PREFIX_PARAM_EXTTOOL.length());
|
||||
List<String> names =
|
||||
program.getLanguage().getLanguageDescription().getExternalNames(tool);
|
||||
|
@ -328,7 +322,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
}
|
||||
}
|
||||
}
|
||||
if (imageSetter != null && program != null) {
|
||||
if (supportsImage() && program != null) {
|
||||
ImageParamSetter imageSetter = ImageParamSetter.get(imageParameter());
|
||||
imageSetter.setImage(map, program);
|
||||
}
|
||||
return map;
|
||||
|
@ -559,9 +554,18 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
return auto == null ? ByModuleAutoMapSpec.instance() : auto.getAutoMapSpec(trace);
|
||||
}
|
||||
|
||||
protected void initializeMonitor(TaskMonitor monitor) {
|
||||
protected boolean providesImage(Map<String, ValStr<?>> args) {
|
||||
LaunchParameter<?> param = imageParameter();
|
||||
if (param == null) {
|
||||
return false;
|
||||
}
|
||||
return !"".equals(param.get(args).str());
|
||||
}
|
||||
|
||||
protected void updateMonitorMax(TaskMonitor monitor, Map<String, ValStr<?>> args) {
|
||||
AutoMapSpec spec = getAutoMapSpec();
|
||||
if (requiresImage() && spec.hasTask()) {
|
||||
boolean image = args == null ? supportsImage() : providesImage(args);
|
||||
if (image && spec.hasTask()) {
|
||||
monitor.setMaximum(6);
|
||||
}
|
||||
else {
|
||||
|
@ -621,7 +625,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
Trace trace = null;
|
||||
Throwable lastExc = null;
|
||||
|
||||
initializeMonitor(monitor);
|
||||
updateMonitorMax(monitor, null);
|
||||
while (true) {
|
||||
try {
|
||||
monitor.setMessage("Gathering arguments");
|
||||
|
@ -633,6 +637,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
return new LaunchResult(program, sessions, acceptor, connection, trace,
|
||||
lastExc);
|
||||
}
|
||||
updateMonitorMax(monitor, args);
|
||||
monitor.increment();
|
||||
|
||||
acceptor = null;
|
||||
|
|
|
@ -44,45 +44,46 @@ public abstract class ScriptAttributesParser {
|
|||
public static final String ENV_GHIDRA_TRACE_RMI_HOST = "GHIDRA_TRACE_RMI_HOST";
|
||||
public static final String ENV_GHIDRA_TRACE_RMI_PORT = "GHIDRA_TRACE_RMI_PORT";
|
||||
|
||||
public static final String AT_TITLE = "@title";
|
||||
public static final String AT_DESC = "@desc";
|
||||
public static final String AT_MENU_PATH = "@menu-path";
|
||||
public static final String AT_MENU_GROUP = "@menu-group";
|
||||
public static final String AT_MENU_ORDER = "@menu-order";
|
||||
public static final String AT_ICON = "@icon";
|
||||
public static final String AT_HELP = "@help";
|
||||
public static final String AT_ENUM = "@enum";
|
||||
public static final String AT_ENV = "@env";
|
||||
public static final String AT_ARG = "@arg";
|
||||
public static final String AT_ARGS = "@args";
|
||||
public static final String AT_TTY = "@tty";
|
||||
public static final String AT_DESC = "@desc";
|
||||
public static final String AT_ENUM = "@enum";
|
||||
public static final String AT_ENV = "@env";
|
||||
public static final String AT_HELP = "@help";
|
||||
public static final String AT_ICON = "@icon";
|
||||
public static final String AT_IMAGE_OPT = "@image-opt";
|
||||
public static final String AT_MENU_GROUP = "@menu-group";
|
||||
public static final String AT_MENU_ORDER = "@menu-order";
|
||||
public static final String AT_MENU_PATH = "@menu-path";
|
||||
public static final String AT_TITLE = "@title";
|
||||
public static final String AT_TIMEOUT = "@timeout";
|
||||
public static final String AT_NOIMAGE = "@no-image";
|
||||
public static final String AT_TTY = "@tty";
|
||||
|
||||
public static final String PREFIX_ENV = "env:";
|
||||
public static final String PREFIX_ARG = "arg:";
|
||||
public static final String KEY_ARGS = "args";
|
||||
public static final String PREFIX_ARG = "arg:";
|
||||
public static final String PREFIX_ENV = "env:";
|
||||
|
||||
public static final String MSGPAT_INVALID_HELP_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use Topic#anchor";
|
||||
public static final String MSGPAT_INVALID_ENUM_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use NAME:type Choice1 [ChoiceN...]";
|
||||
public static final String MSGPAT_INVALID_ENV_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use NAME:type=default \"Display\" \"Tool Tip\"";
|
||||
public static final String MSGPAT_DUPLICATE_TAG = "%s: Duplicate %s";
|
||||
public static final String MSGPAT_INVALID_ARG_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use :type \"Display\" \"Tool Tip\"";
|
||||
public static final String MSGPAT_INVALID_ARGS_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use \"Display\" \"Tool Tip\"";
|
||||
public static final String MSGPAT_INVALID_TTY_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use TTY_TARGET [if env:OPT [== VAL]]";
|
||||
public static final String MSGPAT_INVALID_ENUM_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use NAME:type Choice1 [ChoiceN...]";
|
||||
public static final String MSGPAT_INVALID_ENV_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use NAME:type=default \"Display\" \"Tool Tip\"";
|
||||
public static final String MSGPAT_INVALID_HELP_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use Topic#anchor";
|
||||
public static final String MSGPAT_INVALID_TIMEOUT_SYNTAX = "" +
|
||||
"%s: Invalid %s syntax. Use [milliseconds]";
|
||||
public static final String MSGPAT_INVALID_TTY_BAD_VAL =
|
||||
"%s: In %s: Parameter '%s' has type %s, but '%s' cannot be parsed as such";
|
||||
public static final String MSGPAT_INVALID_TTY_NO_PARAM =
|
||||
"%s: In %s: No such parameter '%s'";
|
||||
public static final String MSGPAT_INVALID_TTY_NOT_BOOL =
|
||||
"%s: In %s: Parameter '%s' must have bool type";
|
||||
public static final String MSGPAT_INVALID_TTY_BAD_VAL =
|
||||
"%s: In %s: Parameter '%s' has type %s, but '%s' cannot be parsed as such";
|
||||
public static final String MSGPAT_INVALID_TIMEOUT_SYNTAX = "" +
|
||||
"%s: Invalid %s syntax. Use [milliseconds]";
|
||||
public static final String MSGPAT_INVALID_TTY_SYNTAX =
|
||||
"%s: Invalid %s syntax. Use TTY_TARGET [if env:OPT [== VAL]]";
|
||||
|
||||
public static class ParseException extends Exception {
|
||||
private Location loc;
|
||||
|
@ -289,8 +290,9 @@ public abstract class ScriptAttributesParser {
|
|||
return tac.withCastDefault(new ValStr<>(value, defaultString));
|
||||
}
|
||||
|
||||
public LaunchParameter<T> createParameter(String name, String display, String description) {
|
||||
return type.createParameter(name, display, description, false, defaultValue);
|
||||
public LaunchParameter<T> createParameter(String name, String display, String description,
|
||||
boolean required) {
|
||||
return type.createParameter(name, display, description, required, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,7 +342,7 @@ public abstract class ScriptAttributesParser {
|
|||
public record ScriptAttributes(String title, String description, List<String> menuPath,
|
||||
String menuGroup, String menuOrder, Icon icon, HelpLocation helpLocation,
|
||||
Map<String, LaunchParameter<?>> parameters, Map<String, TtyCondition> extraTtys,
|
||||
int timeoutMillis, boolean noImage) {}
|
||||
int timeoutMillis, LaunchParameter<?> imageOpt) {}
|
||||
|
||||
/**
|
||||
* Convert an arguments map into a command line and environment variables
|
||||
|
@ -371,7 +373,7 @@ public abstract class ScriptAttributesParser {
|
|||
LaunchParameter<?> param;
|
||||
for (int i = 1; (param = parameters.get("arg:" + i)) != null; i++) {
|
||||
// Don't use ValStr.str here. I'd like the script's input normalized
|
||||
commandLine.add(Objects.toString(param.get(args).val()));
|
||||
commandLine.add(param.get(args).normStr());
|
||||
}
|
||||
|
||||
param = parameters.get("args");
|
||||
|
@ -384,29 +386,24 @@ public abstract class ScriptAttributesParser {
|
|||
if (key.startsWith(PREFIX_ENV)) {
|
||||
String varName = key.substring(PREFIX_ENV.length());
|
||||
ValStr<?> val = ent.getValue().get(args);
|
||||
if (val == null || val.val() == null) {
|
||||
env.put(varName, "");
|
||||
}
|
||||
else {
|
||||
env.put(varName, Objects.toString(val.val()));
|
||||
}
|
||||
env.put(varName, ValStr.normStr(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int argc = 0;
|
||||
private int argc;
|
||||
private String title;
|
||||
private StringBuilder description;
|
||||
private List<String> menuPath;
|
||||
private String menuGroup;
|
||||
private String menuOrder;
|
||||
private String iconId;
|
||||
private HelpLocation helpLocation;
|
||||
private String menuGroup;
|
||||
private String menuOrder;
|
||||
private List<String> menuPath;
|
||||
private final Map<String, UserType<?>> userTypes = new HashMap<>();
|
||||
private final Map<String, LaunchParameter<?>> parameters = new LinkedHashMap<>();
|
||||
private final Map<String, TtyCondition> extraTtys = new LinkedHashMap<>();
|
||||
private int timeoutMillis = AbstractTraceRmiLaunchOffer.DEFAULT_TIMEOUT_MILLIS;
|
||||
private boolean noImage = false;
|
||||
private String imageOptKey;
|
||||
|
||||
/**
|
||||
* Check if a line should just be ignored, e.g., blank lines, or the "shebang" line on UNIX.
|
||||
|
@ -489,36 +486,66 @@ public abstract class ScriptAttributesParser {
|
|||
return;
|
||||
}
|
||||
if (parts.length == 1) {
|
||||
switch (parts[0].trim()) {
|
||||
case AT_NOIMAGE -> parseNoImage(loc);
|
||||
default -> parseUnrecognized(loc, comment);
|
||||
}
|
||||
parseUnrecognized(loc, comment);
|
||||
}
|
||||
else {
|
||||
switch (parts[0].trim()) {
|
||||
case AT_TITLE -> parseTitle(loc, parts[1]);
|
||||
case AT_DESC -> parseDesc(loc, parts[1]);
|
||||
case AT_MENU_PATH -> parseMenuPath(loc, parts[1]);
|
||||
case AT_MENU_GROUP -> parseMenuGroup(loc, parts[1]);
|
||||
case AT_MENU_ORDER -> parseMenuOrder(loc, parts[1]);
|
||||
case AT_ICON -> parseIcon(loc, parts[1]);
|
||||
case AT_HELP -> parseHelp(loc, parts[1]);
|
||||
case AT_ENUM -> parseEnum(loc, parts[1]);
|
||||
case AT_ENV -> parseEnv(loc, parts[1]);
|
||||
case AT_ARG -> parseArg(loc, parts[1], ++argc);
|
||||
case AT_ARGS -> parseArgs(loc, parts[1]);
|
||||
case AT_TTY -> parseTty(loc, parts[1]);
|
||||
case AT_DESC -> parseDesc(loc, parts[1]);
|
||||
case AT_ENUM -> parseEnum(loc, parts[1]);
|
||||
case AT_ENV -> parseEnv(loc, parts[1]);
|
||||
case AT_HELP -> parseHelp(loc, parts[1]);
|
||||
case AT_ICON -> parseIcon(loc, parts[1]);
|
||||
case AT_IMAGE_OPT -> parseImageOpt(loc, parts[1]);
|
||||
case AT_MENU_GROUP -> parseMenuGroup(loc, parts[1]);
|
||||
case AT_MENU_ORDER -> parseMenuOrder(loc, parts[1]);
|
||||
case AT_MENU_PATH -> parseMenuPath(loc, parts[1]);
|
||||
case AT_TIMEOUT -> parseTimeout(loc, parts[1]);
|
||||
case AT_TITLE -> parseTitle(loc, parts[1]);
|
||||
case AT_TTY -> parseTty(loc, parts[1]);
|
||||
default -> parseUnrecognized(loc, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseTitle(Location loc, String str) {
|
||||
if (title != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_TITLE));
|
||||
protected void parseArg(Location loc, String str, int argNum) {
|
||||
List<String> parts = ShellUtils.parseArgs(str);
|
||||
if (parts.size() != 3) {
|
||||
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
|
||||
return;
|
||||
}
|
||||
String colonType = parts.get(0).trim();
|
||||
if (!colonType.startsWith(":")) {
|
||||
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
|
||||
return;
|
||||
}
|
||||
OptType<?> type;
|
||||
boolean required = colonType.endsWith("!");
|
||||
int endType = required ? colonType.length() - 1 : colonType.length();
|
||||
try {
|
||||
type = OptType.parse(loc, colonType.substring(1, endType), userTypes);
|
||||
String name = PREFIX_ARG + argNum;
|
||||
parameters.put(name, type.createParameter(name, parts.get(1), parts.get(2), required,
|
||||
new ValStr<>(null, "")));
|
||||
}
|
||||
catch (ParseException e) {
|
||||
reportError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseArgs(Location loc, String str) {
|
||||
List<String> parts = ShellUtils.parseArgs(str);
|
||||
if (parts.size() != 2) {
|
||||
reportError(MSGPAT_INVALID_ARGS_SYNTAX.formatted(loc, AT_ARGS));
|
||||
return;
|
||||
}
|
||||
|
||||
LaunchParameter<String> parameter = BaseType.STRING.createParameter(
|
||||
"args", parts.get(0), parts.get(1), false, ValStr.str(""));
|
||||
if (parameters.put(KEY_ARGS, parameter) != null) {
|
||||
reportWarning("%s: Duplicate %s. Replaced".formatted(loc, AT_ARGS));
|
||||
}
|
||||
title = str;
|
||||
}
|
||||
|
||||
protected void parseDesc(Location loc, String str) {
|
||||
|
@ -529,54 +556,6 @@ public abstract class ScriptAttributesParser {
|
|||
description.append("\n");
|
||||
}
|
||||
|
||||
protected void parseMenuPath(Location loc, String str) {
|
||||
if (menuPath != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_PATH));
|
||||
}
|
||||
menuPath = List.of(str.trim().split("\\."));
|
||||
if (menuPath.isEmpty()) {
|
||||
reportError(
|
||||
"%s: Empty %s. Ignoring.".formatted(loc, AT_MENU_PATH));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseMenuGroup(Location loc, String str) {
|
||||
if (menuGroup != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_GROUP));
|
||||
}
|
||||
menuGroup = str;
|
||||
}
|
||||
|
||||
protected void parseMenuOrder(Location loc, String str) {
|
||||
if (menuOrder != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_MENU_ORDER));
|
||||
}
|
||||
menuOrder = str;
|
||||
}
|
||||
|
||||
protected void parseIcon(Location loc, String str) {
|
||||
if (iconId != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_ICON));
|
||||
}
|
||||
iconId = str.trim();
|
||||
if (!Gui.hasIcon(iconId)) {
|
||||
reportError(
|
||||
"%s: Icon id %s not registered in the theme".formatted(loc, iconId));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseHelp(Location loc, String str) {
|
||||
if (helpLocation != null) {
|
||||
reportWarning("%s: Duplicate %s".formatted(loc, AT_HELP));
|
||||
}
|
||||
String[] parts = str.trim().split("#", 2);
|
||||
if (parts.length != 2) {
|
||||
reportError(MSGPAT_INVALID_HELP_SYNTAX.formatted(loc, AT_HELP));
|
||||
return;
|
||||
}
|
||||
helpLocation = new HelpLocation(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
|
||||
protected <T> UserType<T> parseEnumChoices(Location loc, BaseType<T> baseType,
|
||||
List<String> choiceParts) {
|
||||
List<T> choices = new ArrayList<>();
|
||||
|
@ -642,10 +621,14 @@ public abstract class ScriptAttributesParser {
|
|||
reportError(MSGPAT_INVALID_ENV_SYNTAX.formatted(loc, AT_ENV));
|
||||
return;
|
||||
}
|
||||
String typePart = tadParts[0].trim();
|
||||
boolean required = typePart.endsWith("!");
|
||||
int endType = required ? typePart.length() - 1 : typePart.length();
|
||||
try {
|
||||
TypeAndDefault<?> tad =
|
||||
TypeAndDefault.parse(loc, tadParts[0].trim(), tadParts[1].trim(), userTypes);
|
||||
LaunchParameter<?> param = tad.createParameter(name, parts.get(1), parts.get(2));
|
||||
TypeAndDefault<?> tad = TypeAndDefault.parse(loc, typePart.substring(0, endType),
|
||||
tadParts[1].trim(), userTypes);
|
||||
LaunchParameter<?> param =
|
||||
tad.createParameter(name, parts.get(1), parts.get(2), required);
|
||||
if (parameters.put(name, param) != null) {
|
||||
reportWarning("%s: Duplicate %s %s. Replaced.".formatted(loc, AT_ENV, trimmed));
|
||||
}
|
||||
|
@ -655,42 +638,75 @@ public abstract class ScriptAttributesParser {
|
|||
}
|
||||
}
|
||||
|
||||
protected void parseArg(Location loc, String str, int argNum) {
|
||||
List<String> parts = ShellUtils.parseArgs(str);
|
||||
if (parts.size() != 3) {
|
||||
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
|
||||
protected void parseHelp(Location loc, String str) {
|
||||
if (helpLocation != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_HELP));
|
||||
}
|
||||
String[] parts = str.trim().split("#", 2);
|
||||
if (parts.length != 2) {
|
||||
reportError(MSGPAT_INVALID_HELP_SYNTAX.formatted(loc, AT_HELP));
|
||||
return;
|
||||
}
|
||||
String colonType = parts.get(0).trim();
|
||||
if (!colonType.startsWith(":")) {
|
||||
reportError(MSGPAT_INVALID_ARG_SYNTAX.formatted(loc, AT_ARG));
|
||||
return;
|
||||
helpLocation = new HelpLocation(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
|
||||
protected void parseIcon(Location loc, String str) {
|
||||
if (iconId != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_ICON));
|
||||
}
|
||||
OptType<?> type;
|
||||
try {
|
||||
type = OptType.parse(loc, colonType.substring(1), userTypes);
|
||||
String name = PREFIX_ARG + argNum;
|
||||
parameters.put(name,
|
||||
type.createParameter(name, parts.get(1), parts.get(2), true,
|
||||
new ValStr<>(null, "")));
|
||||
}
|
||||
catch (ParseException e) {
|
||||
reportError(e.getMessage());
|
||||
iconId = str.trim();
|
||||
if (!Gui.hasIcon(iconId)) {
|
||||
reportError(
|
||||
"%s: Icon id %s not registered in the theme".formatted(loc, iconId));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseArgs(Location loc, String str) {
|
||||
List<String> parts = ShellUtils.parseArgs(str);
|
||||
if (parts.size() != 2) {
|
||||
reportError(MSGPAT_INVALID_ARGS_SYNTAX.formatted(loc, AT_ARGS));
|
||||
return;
|
||||
protected void parseImageOpt(Location loc, String str) {
|
||||
if (imageOptKey != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_IMAGE_OPT));
|
||||
}
|
||||
imageOptKey = str.strip();
|
||||
}
|
||||
|
||||
LaunchParameter<String> parameter = BaseType.STRING.createParameter(
|
||||
"args", parts.get(0), parts.get(1), false, ValStr.str(""));
|
||||
if (parameters.put(KEY_ARGS, parameter) != null) {
|
||||
reportWarning("%s: Duplicate %s. Replaced".formatted(loc, AT_ARGS));
|
||||
protected void parseMenuGroup(Location loc, String str) {
|
||||
if (menuGroup != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_GROUP));
|
||||
}
|
||||
menuGroup = str;
|
||||
}
|
||||
|
||||
protected void parseMenuOrder(Location loc, String str) {
|
||||
if (menuOrder != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_ORDER));
|
||||
}
|
||||
menuOrder = str;
|
||||
}
|
||||
|
||||
protected void parseMenuPath(Location loc, String str) {
|
||||
if (menuPath != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_MENU_PATH));
|
||||
}
|
||||
menuPath = List.of(str.trim().split("\\."));
|
||||
if (menuPath.isEmpty()) {
|
||||
reportError(
|
||||
"%s: Empty %s. Ignoring.".formatted(loc, AT_MENU_PATH));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseTimeout(Location loc, String str) {
|
||||
try {
|
||||
timeoutMillis = Integer.parseInt(str);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
reportError(MSGPAT_INVALID_TIMEOUT_SYNTAX.formatted(loc, AT_TIMEOUT));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseTitle(Location loc, String str) {
|
||||
if (title != null) {
|
||||
reportWarning(MSGPAT_DUPLICATE_TAG.formatted(loc, AT_TITLE));
|
||||
}
|
||||
title = str;
|
||||
}
|
||||
|
||||
protected void putTty(Location loc, String name, TtyCondition condition) {
|
||||
|
@ -749,19 +765,6 @@ public abstract class ScriptAttributesParser {
|
|||
reportError(MSGPAT_INVALID_TTY_SYNTAX.formatted(loc, AT_TTY));
|
||||
}
|
||||
|
||||
protected void parseTimeout(Location loc, String str) {
|
||||
try {
|
||||
timeoutMillis = Integer.parseInt(str);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
reportError(MSGPAT_INVALID_TIMEOUT_SYNTAX.formatted(loc, AT_TIMEOUT));
|
||||
}
|
||||
}
|
||||
|
||||
protected void parseNoImage(Location loc) {
|
||||
noImage = true;
|
||||
}
|
||||
|
||||
protected void parseUnrecognized(Location loc, String line) {
|
||||
reportWarning("%s: Unrecognized metadata: %s".formatted(loc, line));
|
||||
}
|
||||
|
@ -784,10 +787,18 @@ public abstract class ScriptAttributesParser {
|
|||
if (iconId == null) {
|
||||
iconId = "icon.debugger";
|
||||
}
|
||||
LaunchParameter<?> imageOpt = null;
|
||||
if (imageOptKey != null) {
|
||||
imageOpt = parameters.get(imageOptKey);
|
||||
if (imageOpt == null) {
|
||||
reportError("%s: %s refers to %s, which is not a parameter name".formatted(fileName,
|
||||
AT_IMAGE_OPT, imageOptKey));
|
||||
}
|
||||
}
|
||||
return new ScriptAttributes(title, getDescription(), List.copyOf(menuPath), menuGroup,
|
||||
menuOrder, new GIcon(iconId), helpLocation,
|
||||
Collections.unmodifiableMap(new LinkedHashMap<>(parameters)),
|
||||
Collections.unmodifiableMap(new LinkedHashMap<>(extraTtys)), timeoutMillis, noImage);
|
||||
Collections.unmodifiableMap(new LinkedHashMap<>(extraTtys)), timeoutMillis, imageOpt);
|
||||
}
|
||||
|
||||
private String getDescription() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue