diff --git a/.idea/artifacts/util_js_0_3_0_beta_4.xml b/.idea/artifacts/util_js_0_3_0_beta_4.xml new file mode 100644 index 0000000..b612884 --- /dev/null +++ b/.idea/artifacts/util_js_0_3_0_beta_4.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/build/libs + + + + + \ No newline at end of file diff --git a/.idea/artifacts/util_jvm_0_3_0_beta_4.xml b/.idea/artifacts/util_jvm_0_3_0_beta_4.xml new file mode 100644 index 0000000..e64ce9a --- /dev/null +++ b/.idea/artifacts/util_jvm_0_3_0_beta_4.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/build/libs + + + + + \ No newline at end of file diff --git a/.idea/artifacts/util_wasm_js_0_3_0_beta_4.xml b/.idea/artifacts/util_wasm_js_0_3_0_beta_4.xml new file mode 100644 index 0000000..971f2c1 --- /dev/null +++ b/.idea/artifacts/util_wasm_js_0_3_0_beta_4.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/build/libs + + + + + \ No newline at end of file diff --git a/.idea/artifacts/util_wasm_wasi_0_3_0_beta_4.xml b/.idea/artifacts/util_wasm_wasi_0_3_0_beta_4.xml new file mode 100644 index 0000000..ff662b4 --- /dev/null +++ b/.idea/artifacts/util_wasm_wasi_0_3_0_beta_4.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/build/libs + + + + + \ No newline at end of file diff --git a/buildnumber.properties b/buildnumber.properties index ba32cd2..4e78d91 100644 --- a/buildnumber.properties +++ b/buildnumber.properties @@ -1,3 +1,3 @@ #auto generated -#Sun Jan 18 17:59:47 CET 2026 -build.number=111 +#Sun Jan 18 23:38:13 CET 2026 +build.number=114 diff --git a/settings.gradle.kts b/settings.gradle.kts index 840bafb..066964c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,7 +19,7 @@ dependencyResolutionManagement { versionCatalogs { create("masterLibs") { // from(files("gradle/masterlibs.versions.toml")) - from("net.keinekekse:version-catalog:110") + from("net.keinekekse:version-catalog:113") } } } diff --git a/src/commonMain/kotlin/net/keinekekse/args/impl.kt b/src/commonMain/kotlin/net/keinekekse/args/impl.kt index a8705ec..cedcab5 100644 --- a/src/commonMain/kotlin/net/keinekekse/args/impl.kt +++ b/src/commonMain/kotlin/net/keinekekse/args/impl.kt @@ -2,8 +2,28 @@ package net.keinekekse.args import net.keinekekse.version.Version +/** + * Terminates the currently running application with the specified exit code. + * This function does not return as it stops the application process. + * + * Works only for JVM and macOS-/Linux-native targets. + * + * @param rc The exit code to return when the application terminates. Defaults to 0, + * indicating normal termination. + * @return This function does not return as the application is terminated. + */ expect fun exitApplication(rc: Int = 0): Nothing +/** + * Checks if standard input is ready for reading. + * This function is used to determine if there is data available to be read from standard input. + * + * Works only for JVM and macOS-/Linux-native targets. + * + * @return True if standard input is ready for reading, false otherwise. + */ +expect fun isStdInputReady(): Boolean + class VerifyParameterException(message: String) : RuntimeException(message) fun showParsingError(msg: String): Nothing { @@ -196,7 +216,12 @@ class CommandLine( val resultSubCommand = parseSubCommand(remaining) validateMandatoryParameters(resultSubCommand) - if (resultSubCommand.additionalParameters.isNotEmpty() && remainingDescription == null) { + if (remainingDescription != null) { + val additionalFromPipe = getRemainingParametersFromPipe() + if (additionalFromPipe.isNotEmpty()) { + resultSubCommand.additionalParameters += additionalFromPipe + } + } else if (resultSubCommand.additionalParameters.isNotEmpty()) { throw ArgumentParserException.noMoreOptions() } @@ -261,6 +286,19 @@ class CommandLine( } } + private fun getRemainingParametersFromPipe(): List { + if (isStdInputReady()) { + var input: String? + val pipe = mutableListOf() + do { + input = readlnOrNull() + input?.let { pipe.add(it) } + } while (!input.isNullOrEmpty()) + return pipe + } + return emptyList() + } + private fun checkExecutors() { globalSubCommand.obj.checkExecutors() subCommands.values.forEach { it.checkExecutors() } @@ -282,7 +320,7 @@ class CommandLine( val globalParam = globalSubCommand.obj.params.isNotEmpty() val remain = remainingDescription != null - println("${programVersion.displayName} ${programVersion.version}, ${programVersion.copyright}\n") + println("${programVersion.displayName} ${programVersion.version} ${programVersion.copyright}\n") println(programVersion.description) println() println( @@ -346,7 +384,7 @@ class CommandLine( } private fun showVersion(): Nothing { - println("${programVersion.displayName} ${programVersion.fullVersion}, ${programVersion.copyright}\n") + println("${programVersion.displayName} ${programVersion.fullVersion} ${programVersion.copyright}\n") exitApplication(0) } diff --git a/src/commonMain/kotlin/net/keinekekse/util/Version.kt b/src/commonMain/kotlin/net/keinekekse/util/Version.kt index 460fd0c..bb52d5d 100644 --- a/src/commonMain/kotlin/net/keinekekse/util/Version.kt +++ b/src/commonMain/kotlin/net/keinekekse/util/Version.kt @@ -3,14 +3,14 @@ package net.keinekekse.util import net.keinekekse.version.Version object VERSION: Version { - override val version = "0.3.0-beta.2+build.111" - override val fullVersion = "0.3.0-beta.2+build.111" + override val version = "0.3.0-beta.5+build.114" + override val fullVersion = "0.3.0-beta.5+build.114" override val major = 0 override val minor = 3 override val patch = 0 - override val preRelease = "beta.2" - override val buildMetadata = "build.111" - override val buildDate = "2026-01-18T16:59:47.995114Z" + override val preRelease = "beta.5" + override val buildMetadata = "build.114" + override val buildDate = "2026-01-18T22:38:13.309402Z" override val displayName = "Utility Library" override val copyright = "Copyright (c) 2025-2026 Hartmut Bauer" override val name = "util" diff --git a/src/jvmMain/kotlin/net/keinekekse/args/impl.jvm.kt b/src/jvmMain/kotlin/net/keinekekse/args/impl.jvm.kt new file mode 100644 index 0000000..b9dccb4 --- /dev/null +++ b/src/jvmMain/kotlin/net/keinekekse/args/impl.jvm.kt @@ -0,0 +1,9 @@ +package net.keinekekse.args + +import kotlin.system.exitProcess + +actual fun isStdInputReady(): Boolean = + (System.`in`.available() > 0) + +actual fun exitApplication(rc: Int): Nothing = + exitProcess(rc) diff --git a/src/jvmMain/kotlin/net/keinekekse/args/priv.jvm.kt b/src/jvmMain/kotlin/net/keinekekse/args/priv.jvm.kt deleted file mode 100644 index e2687e7..0000000 --- a/src/jvmMain/kotlin/net/keinekekse/args/priv.jvm.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.keinekekse.args - -import kotlin.system.exitProcess - -actual fun exitApplication(rc: Int): Nothing { - exitProcess(rc) -} diff --git a/src/linuxX64Main/kotlin/net/keinekekse/args/priv.linuxX64.kt b/src/linuxX64Main/kotlin/net/keinekekse/args/priv.linuxX64.kt deleted file mode 100644 index 4a5b50e..0000000 --- a/src/linuxX64Main/kotlin/net/keinekekse/args/priv.linuxX64.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.keinekekse.args - -import platform.posix.exit - -actual fun exitApplication(rc: Int): Nothing { - exit(rc) - return Unit as Nothing -} diff --git a/src/macosArm64Main/kotlin/net/keinekekse/args/priv.macosArm64.kt b/src/macosArm64Main/kotlin/net/keinekekse/args/priv.macosArm64.kt deleted file mode 100644 index 4a5b50e..0000000 --- a/src/macosArm64Main/kotlin/net/keinekekse/args/priv.macosArm64.kt +++ /dev/null @@ -1,8 +0,0 @@ -package net.keinekekse.args - -import platform.posix.exit - -actual fun exitApplication(rc: Int): Nothing { - exit(rc) - return Unit as Nothing -} diff --git a/src/nativeMain/kotlin/net/keinekekse/args/impl.native.kt b/src/nativeMain/kotlin/net/keinekekse/args/impl.native.kt new file mode 100644 index 0000000..aba074d --- /dev/null +++ b/src/nativeMain/kotlin/net/keinekekse/args/impl.native.kt @@ -0,0 +1,22 @@ +package net.keinekekse.args + +import kotlinx.cinterop.* +import platform.posix.* + +// macOS + Linux + +@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) +actual fun isStdInputReady(): Boolean { + return memScoped { + val pfd = alloc() + pfd.fd = STDIN_FILENO + pfd.events = POLLIN.toShort() + // timeout 0 means return immediately + poll(pfd.ptr.reinterpret(), 1u, 10) > 0 + } +} + +actual fun exitApplication(rc: Int): Nothing { + exit(rc) + return Unit as Nothing +} diff --git a/src/wasmWasiMain/kotlin/net/keinekekse/args/priv.wasmWasi.kt b/src/wasmWasiMain/kotlin/net/keinekekse/args/impl.wasmWasi.kt similarity index 58% rename from src/wasmWasiMain/kotlin/net/keinekekse/args/priv.wasmWasi.kt rename to src/wasmWasiMain/kotlin/net/keinekekse/args/impl.wasmWasi.kt index 66a21bd..71e7ed7 100644 --- a/src/wasmWasiMain/kotlin/net/keinekekse/args/priv.wasmWasi.kt +++ b/src/wasmWasiMain/kotlin/net/keinekekse/args/impl.wasmWasi.kt @@ -1,5 +1,9 @@ package net.keinekekse.args +actual fun isStdInputReady(): Boolean { + TODO("Not implemented on this platform") +} + actual fun exitApplication(rc: Int): Nothing { TODO("Not implemented on this platform") } diff --git a/src/webMain/kotlin/net/keinekekse/args/impl.web.kt b/src/webMain/kotlin/net/keinekekse/args/impl.web.kt new file mode 100644 index 0000000..024b93a --- /dev/null +++ b/src/webMain/kotlin/net/keinekekse/args/impl.web.kt @@ -0,0 +1,11 @@ +package net.keinekekse.args + +// js + wasmJs + +actual fun isStdInputReady(): Boolean { + TODO("Not implemented for this platform") +} + +actual fun exitApplication(rc: Int): Nothing { + TODO("Not implemented for this platform") +} diff --git a/src/webMain/kotlin/net/keinekekse/args/priv.web.kt b/src/webMain/kotlin/net/keinekekse/args/priv.web.kt deleted file mode 100644 index af5033f..0000000 --- a/src/webMain/kotlin/net/keinekekse/args/priv.web.kt +++ /dev/null @@ -1,5 +0,0 @@ -package net.keinekekse.args - -actual fun exitApplication(rc: Int): Nothing { - TODO("Not yet implemented") // js + wasmJs -}