Skip to content

Instantly share code, notes, and snippets.

@L-Briand
Last active January 24, 2024 13:16
Show Gist options
  • Save L-Briand/15ddf5787ba8e78f842b3de90c3bf10c to your computer and use it in GitHub Desktop.
Save L-Briand/15ddf5787ba8e78f842b3de90c3bf10c to your computer and use it in GitHub Desktop.
Parse arguments with gnu syntax in Kotlin.
/**
* Parse arguments with gnu syntax.
*
* When parsing, the name given to [onArgument] can be:
* - `null` if found value has no hyphen.
* - A short option if the value starts with a hyphen. (`-s`)
* - A long option if the value starts with a double hyphen. (`--long`)
*
* The `getValue` can be used to get the next non-hyphen value
* (-p**8080**, -p **8080**, --port **8080**).
* It can be used to get multiple values (-i input1 input2)
* It returns null if it founds a value starting with a hyphen or reaches the end of the argument list.
*
* @param args arguments from command line.
* @param onArgument a lambda to catch read arguments.
*
* @return the number of elements in [args] read until "--" or `args.length` if it reaches the end.
*/
inline fun gnuParse(
args: Array<String>,
onArgument: (name: String?, getNextValue: () -> String?) -> Unit
): Int {
var index = 0
while (true) {
if (index > args.lastIndex) return index
val arg = args[index++]
when {
arg.startsWith("--") -> {
if (arg.length == 2) return index
val name = arg.substring(2, arg.length)
onArgument(name) {
if (index > args.lastIndex) return@onArgument null
val argument = args[index]
if (argument.startsWith('-')) return@onArgument null
index++
argument
}
}
arg.startsWith('-') -> {
var j = 1
while (j < arg.length) {
onArgument(arg[j++].toString()) {
if (j == arg.length) {
if (index > args.lastIndex) return@onArgument null
val argument = args[index]
if (argument.startsWith('-')) return@onArgument null
index++
argument
}
else {
val value = arg.substring(j, arg.length)
j = arg.length
value
}
}
}
}
else -> {
var first = true
onArgument(null) {
if (!first) {
if (index > args.lastIndex) return@onArgument null
val argument = args[index]
if (argument.startsWith('-')) return@onArgument null
index++
argument
}
else {
first = false
arg
}
}
}
}
}
}
fun main(args: String) {
var name: String? = null
var enable: Boolean
gnuParse(args) { name, getValue ->
when(name) {
"n", "name" -> getValue()?.let { name = it }
"e", "enable" -> bar = true
}
}
println("> ${name ?: "default"} is $bar")
}
$./program -nfoo -e
> foo is true
$./program -n foo --enable
> foo is true
$./program --name foo
> foo is false
$./program
> default is false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment