Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ out/
/bin/
/src/test/ReadmeExampleCode.java

### Maven ###
target/

### Eclipse ###
.apt_generated
.classpath
Expand Down
105 changes: 105 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.github.AbUndMax</groupId>
<artifactId>java_argsparser</artifactId>
<version>6.0.1</version>
<packaging>jar</packaging>

<name>Java ArgsParser</name>
<description>Simple argument parsing library</description>
<url>https://github.com/AbUndMax/Java_ArgsParser</url>

<distributionManagement>
<repository>
<id>github</id>
<name>GitHub Packages for Java_ArgsParser</name>
<url>https://maven.pkg.github.com/AbUndMax/Java_ArgsParser</url>
</repository>
</distributionManagement>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<junit.jupiter.version>5.10.0</junit.jupiter.version>
</properties>

<dependencies>
<!-- JUnit Jupiter API und Test-Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Kompilieren mit Java 21 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>

<!-- Tests mit JUnit 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<includes>
<include>**/*Test*.java</include>
</includes>
</configuration>
</plugin>

<!-- Quelle‐JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- Javadoc‐JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -439,11 +439,7 @@ private Set<Parameter<?>> parseArguments(String[] args) throws UnknownFlagArgsEx

Set<Parameter<?>> givenParameters = new HashSet<>();

//check if the first argument provided is actually a flag or command
if (args.length > 0 && parameterMap.get(args[0]) == null && commandMap.get(args[0]) == null &&
!(args[0].equals("--help") || args[0].equals("-h"))) {
throw new UnknownFlagArgsException(args[0], parameterMap.keySet(), commandMap.keySet(), true);
}
validateInitialArg(args[0]);

Parameter<?> currentParameter = null;
boolean longFlagUsed = false;
Expand All @@ -463,54 +459,75 @@ private Set<Parameter<?>> parseArguments(String[] args) throws UnknownFlagArgsEx
boolean lastPositionWasFlag = i >= 1 && args[i - 1].startsWith("-");
boolean flagAlreadyProvided = false;
if (flagExists) flagAlreadyProvided = givenParameters.contains(currentParameter);
boolean isHelpCall = ("--help".equals(arg) || "-h".equals(arg));
boolean helpCallInWrongPosition = isHelpCall && (i > 1 || (i == 0 && args.length == 2));
boolean helpCallInWrongPosition = isHelpFlag(arg) && (i > 1 || (i == 0 && args.length == 2));

if (helpCallInWrongPosition) {
// --> if a -h or --help is in a not allowed position
throw new HelpAtWrongPositionArgsException();

} else if (currentPositionIsFlag && !flagExists) { // if flag is unknown
} else if (currentPositionIsFlag && !flagExists) {
// --> if flag is unknown
throw new UnknownFlagArgsException(arg, parameterMap.keySet(), commandMap.keySet(), false);

} else if (currentPositionIsFlag && flagAlreadyProvided) { // if the flag already was set
} else if (currentPositionIsFlag && flagAlreadyProvided) {
// --> if the flag already was set
throw new FlagAlreadyProvidedArgsException(currentParameter.getFullFlag(),
currentParameter.getShortFlag());

} else if (argumentSet && !currentPositionIsFlag && !currentPositionIsCommand) { // if two arguments are provided to a single flag
} else if (argumentSet && !currentPositionIsFlag && !currentPositionIsCommand) {
// --> if two arguments are provided to a single flag
throw new TooManyArgumentsArgsException(longFlagUsed ?
currentParameter.getFullFlag() :
currentParameter.getShortFlag());

} else if (currentPositionIsFlag && lastPositionWasFlag) { // if a flag follows another flag
} else if (currentPositionIsFlag && lastPositionWasFlag) {
// --> if a flag follows another flag
throw new MissingArgArgsException(args[i - 1]);

} else if (isLastEntry && currentPositionIsFlag) { //if last Flag has no argument
} else if (isLastEntry && currentPositionIsFlag) {
// --> if last Flag has no argument
throw new MissingArgArgsException(arg);

} else if (currentPositionIsCommand) { // if current position is a command
} else if (currentPositionIsCommand) {
// --> if current position is a command
commandMap.get(arg).setCommand(); // set the command to true

} else if (lastPositionWasFlag && currentParameterNotNull) { // if the current position is an argument

boolean isArrayParam = arrayParameters.contains(args[i - 1]);
if (isArrayParam) { // "collect" all following arguments after an array parameter in a StringBuilder
currentParameter.setArgument(args[i]);
while(i + 1 < args.length && !args[i + 1].startsWith("-") && !commandMap.containsKey(args[i + 1])) { // loop through all arguments
currentParameter.setArgument(args[++i]);
}

} else {
currentParameter.setArgument(arg);

}
currentParameter.setProvided();
} else if (lastPositionWasFlag && currentParameterNotNull) {
// --> if the current position is an argument
i = handleArgument(currentParameter, args, i);
givenParameters.add(currentParameter); // add parameter to the given Parameter Set
}
}

return givenParameters;
}

/**
* Validates the very first argument: it must be either a flag, a command, or help.
*
* @param arg the first raw command-line arguments
* @throws UnknownFlagArgsException if the first token is neither flag nor command nor help
*/
private void validateInitialArg(String arg) throws UnknownFlagArgsException {
if (parameterMap.get(arg) == null
&& commandMap .get(arg) == null
&& !isHelpFlag(arg)) {
throw new UnknownFlagArgsException(
arg, parameterMap.keySet(), commandMap.keySet(), true
);
}
}

/**
* Checks whether the provided token is the help flag.
*
* @param arg the argument token to check
* @return true if {@code arg} equals "--help" or "-h"
*/
private boolean isHelpFlag(String arg) {
return "--help".equals(arg) || "-h".equals(arg);
}

/**
* checks if all mandatory parameters were given in args!
* @param givenParameters a set of all Parameter instances created based on args
Expand All @@ -528,6 +545,47 @@ private void checkMandatoryArguments(Set<Parameter<?>> givenParameters) throws M
}
}


/**
* Consumes one or more argument values for the current parameter.
*
* @param currentParameter the flag's Parameter instance
* @param args the full args array
* @param i the index of the first value in args
* @return the new index after consuming all relevant values
* @throws NotExistingPathArgsException if a path parameter points to a non-existent path
* @throws InvalidArgTypeArgsException if a invalid argument type is set to the parameter
*/
private int handleArgument(Parameter<?> currentParameter, String[] args, int i)
throws NotExistingPathArgsException, InvalidArgTypeArgsException {

String arg = args[i];
boolean isArrayParam = arrayParameters.contains(args[i - 1]);
if (isArrayParam) { // if currentParameter is an array parameter
currentParameter.setArgument(arg);
// loop through all arguments and "collect" all following arguments until next flag or end
while(i + 1 < args.length && !args[i + 1].startsWith("-") && !commandMap.containsKey(args[i + 1])) {
currentParameter.setArgument(args[++i]);
}

} else {
currentParameter.setArgument(arg);

}
currentParameter.setProvided();
return i;
}


/**
* Validates that no more than one command in each toggle group has been provided.
* The parser maintains a list of mutually exclusive command groups (toggleList),
* where only one command per group may be active. This method iterates through each
* group and counts how many commands are marked as provided. If more than one command
* in the same group is provided, a ToggleArgsException is thrown.
*
* @throws ToggleArgsException if multiple commands from the same toggle group are provided
*/
private void checkToggles() throws ToggleArgsException{
for (Command[] toggle : toggleList) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,11 @@ private static String generateInformationLine(String fullName, String shortName,
private static String formatLastPartInLine(String informationLine, String lastPart) {
lastPart = lastPart.trim();
int fillSpace = 15 + longestFullSize + longestShortSize + longestUsedTypeSize;
String filler = String.format(String.format("#%%%ds", fillSpace), informationLine);
if (informationLine.length() + lastPart.length() <= consoleWidth) return filler + lastPart + "\n";
String firstPart = String.format(String.format("#%%%ds", fillSpace), informationLine);
String filler = "#" + " ".repeat(fillSpace);
if (informationLine.length() + lastPart.length() <= consoleWidth) return firstPart + lastPart + "\n";

StringBuilder fullPart = new StringBuilder(informationLine);
StringBuilder fullPart = new StringBuilder(firstPart);

int freeSpace = consoleWidth - filler.length();
while (lastPart.length() > freeSpace) {
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion src/test/TestAddParameterMethods.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ArgsParser.*;
import static org.junit.jupiter.api.Assertions.*;

import ArgsParser.ArgsExceptions.ToggleArgsException;
import ArgsParser.ParameterTypes.*;
import org.junit.jupiter.api.Test;

Expand Down
10 changes: 5 additions & 5 deletions src/test/TestArgsExceptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -482,11 +482,11 @@ public void testHelpWithNewLineInDescription() {
# [s]=String
# (!)=mandatory | ( )=optional | (/)=command
#
## --longString -ls [s] ( ) This description is so long, it will force the automatic help
### --longString -ls [s] ( ) printout to introduce a new line and still have a nice look :)
default: this/path/is/so/long/it/is/actually/longer/than/any/existing/path/
# default: that/I/have/on/my/PC/Do/You/Know/The/WordOberwesedampfschifffahrts
# default: gesellschaftskapitän
### --longString -ls [s] ( ) This description is so long, it will force the automatic help
# printout to introduce a new line and still have a nice look :)
# default: this/path/is/so/long/it/is/actually/longer/than/any/existing/path/
# that/I/have/on/my/PC/Do/You/Know/The/WordOberwesedampfschifffahrts
# gesellschaftskapitän
#
####################################################################################################
""";
Expand Down