Introduce Common readln() and readlnOrNull() top-level functions #KT-48456
This commit is contained in:
committed by
Space
parent
14b66872b5
commit
97eb28144f
@@ -0,0 +1,2 @@
|
|||||||
|
runtime/basic/readln*CR*.in binary
|
||||||
|
runtime/basic/readln*CR*.out binary
|
||||||
@@ -727,6 +727,61 @@ standaloneTest("hello2") {
|
|||||||
source = "runtime/basic/hello2.kt"
|
source = "runtime/basic/hello2.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
standaloneTest("readlnOrNull_empty") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readlnOrNull_empty.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_empty") {
|
||||||
|
useTestData = true
|
||||||
|
outputChecker = { s -> s.contains("ReadAfterEOFException") }
|
||||||
|
expectedExitStatusChecker = { it != 0 }
|
||||||
|
source = "runtime/basic/readln_empty.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_alone_CR") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_alone_CR.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_empty_new_line") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_empty_new_line.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_multiline") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_multiline.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_CR_and_CRLF") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_CR_and_CRLF.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_long_line") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_long_line.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_cyrillic") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_cyrillic.kt"
|
||||||
|
}
|
||||||
|
|
||||||
|
standaloneTest("readln_multiple_empty_new_lines") {
|
||||||
|
useGoldenData = true
|
||||||
|
useTestData = true
|
||||||
|
source = "runtime/basic/readln_multiple_empty_new_lines.kt"
|
||||||
|
}
|
||||||
|
|
||||||
task hello3(type: KonanLocalTest) {
|
task hello3(type: KonanLocalTest) {
|
||||||
useGoldenData = true
|
useGoldenData = true
|
||||||
source = "runtime/basic/hello3.kt"
|
source = "runtime/basic/hello3.kt"
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print("${readlnOrNull()}/${readlnOrNull()}/${readlnOrNull()}")
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
null/null/null
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
aaaaaa
bbb
|
||||||
|
c
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
aaaaaa
bbb
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Привет!
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Привет!
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
readln()
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
A very long line of input with length of more than initial buffer size
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
A very long line of input with length of more than initial buffer size
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Hello World
|
||||||
|
Second line
|
||||||
|
Third line
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print(readln())
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Hello World
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
first
|
||||||
|
second
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
print("${readln()}/${readln()}/${readln()}/${readln()}/${readlnOrNull()}")
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
first/second///null
|
||||||
@@ -13,6 +13,8 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "KAssert.h"
|
#include "KAssert.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
@@ -67,4 +69,35 @@ OBJ_GETTER0(Kotlin_io_Console_readLine) {
|
|||||||
RETURN_RESULT_OF(CreateStringFromCString, data);
|
RETURN_RESULT_OF(CreateStringFromCString, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBJ_GETTER0(Kotlin_io_Console_readlnOrNull) {
|
||||||
|
KStdVector<char> data;
|
||||||
|
data.reserve(16);
|
||||||
|
bool isEOF = false;
|
||||||
|
bool isError = false;
|
||||||
|
{
|
||||||
|
kotlin::ThreadStateGuard guard(kotlin::ThreadState::kNative);
|
||||||
|
while (true) {
|
||||||
|
int result = fgetc(stdin);
|
||||||
|
|
||||||
|
if (result == EOF || result == '\n') {
|
||||||
|
isEOF = (result == EOF);
|
||||||
|
isError = (ferror(stdin) != 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.push_back(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isError) {
|
||||||
|
ThrowIllegalStateException();
|
||||||
|
}
|
||||||
|
if (!isEOF && !data.empty() && data.back() == '\r') { // CRLF
|
||||||
|
data.pop_back();
|
||||||
|
}
|
||||||
|
if (data.empty() && isEOF) {
|
||||||
|
RETURN_OBJ(nullptr);
|
||||||
|
}
|
||||||
|
RETURN_RESULT_OF(StringFromUtf8Buffer, data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -29,6 +29,29 @@ public actual fun println(message: Any?) {
|
|||||||
@GCUnsafeCall("Kotlin_io_Console_println0")
|
@GCUnsafeCall("Kotlin_io_Console_println0")
|
||||||
public actual external fun println()
|
public actual external fun println()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a line of input from the standard input stream and returns it,
|
||||||
|
* or throws a [RuntimeException] if EOF has already been reached when [readln] is called.
|
||||||
|
*
|
||||||
|
* LF or CRLF is treated as the line terminator. Line terminator is not included in the returned string.
|
||||||
|
*
|
||||||
|
* The input is interpreted as UTF-8. Invalid bytes are replaced by the replacement character '\uFFFD'.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public actual fun readln(): String = readlnOrNull() ?: throw ReadAfterEOFException("EOF has already been reached")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a line of input from the standard input stream and returns it,
|
||||||
|
* or return `null` if EOF has already been reached when [readlnOrNull] is called.
|
||||||
|
*
|
||||||
|
* LF or CRLF is treated as the line terminator. Line terminator is not included in the returned string.
|
||||||
|
*
|
||||||
|
* The input is interpreted as UTF-8. Invalid bytes are replaced by the replacement character '\uFFFD'.
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
@GCUnsafeCall("Kotlin_io_Console_readlnOrNull")
|
||||||
|
public actual external fun readlnOrNull(): String?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a line of input from the standard input stream.
|
* Reads a line of input from the standard input stream.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,4 +2,10 @@ public fun print(message: kotlin.Any?): kotlin.Unit
|
|||||||
|
|
||||||
public fun println(): kotlin.Unit
|
public fun println(): kotlin.Unit
|
||||||
|
|
||||||
public fun println(message: kotlin.Any?): kotlin.Unit
|
public fun println(message: kotlin.Any?): kotlin.Unit
|
||||||
|
|
||||||
|
@kotlin.SinceKotlin(version = "1.6")
|
||||||
|
public fun readln(): kotlin.String
|
||||||
|
|
||||||
|
@kotlin.SinceKotlin(version = "1.6")
|
||||||
|
public fun readlnOrNull(): kotlin.String?
|
||||||
@@ -2,4 +2,10 @@ public fun print(message: kotlin.Any?): kotlin.Unit
|
|||||||
|
|
||||||
public fun println(): kotlin.Unit
|
public fun println(): kotlin.Unit
|
||||||
|
|
||||||
public fun println(message: kotlin.Any?): kotlin.Unit
|
public fun println(message: kotlin.Any?): kotlin.Unit
|
||||||
|
|
||||||
|
@kotlin.SinceKotlin(version = "1.6")
|
||||||
|
public fun readln(): kotlin.String
|
||||||
|
|
||||||
|
@kotlin.SinceKotlin(version = "1.6")
|
||||||
|
public fun readlnOrNull(): kotlin.String?
|
||||||
@@ -15,5 +15,29 @@ public expect fun println(message: Any?)
|
|||||||
/** Prints the given [message] to the standard output stream. */
|
/** Prints the given [message] to the standard output stream. */
|
||||||
public expect fun print(message: Any?)
|
public expect fun print(message: Any?)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a line of input from the standard input stream and returns it,
|
||||||
|
* or throws a [RuntimeException] if EOF has already been reached when [readln] is called.
|
||||||
|
*
|
||||||
|
* LF or CRLF is treated as the line terminator. Line terminator is not included in the returned string.
|
||||||
|
*
|
||||||
|
* Currently this function is not supported in Kotlin/JS and throws [UnsupportedOperationException].
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public expect fun readln(): String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a line of input from the standard input stream and returns it,
|
||||||
|
* or return `null` if EOF has already been reached when [readlnOrNull] is called.
|
||||||
|
*
|
||||||
|
* LF or CRLF is treated as the line terminator. Line terminator is not included in the returned string.
|
||||||
|
*
|
||||||
|
* Currently this function is not supported in Kotlin/JS and throws [UnsupportedOperationException].
|
||||||
|
*/
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public expect fun readlnOrNull(): String?
|
||||||
|
|
||||||
|
internal class ReadAfterEOFException(message: String?) : RuntimeException(message)
|
||||||
|
|
||||||
|
|
||||||
internal expect interface Serializable
|
internal expect interface Serializable
|
||||||
|
|||||||
@@ -104,3 +104,9 @@ public actual fun println(message: Any?) {
|
|||||||
public actual fun print(message: Any?) {
|
public actual fun print(message: Any?) {
|
||||||
output.print(message)
|
output.print(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public actual fun readln(): String = throw UnsupportedOperationException("readln is not supported in Kotlin/JS")
|
||||||
|
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public actual fun readlnOrNull(): String? = throw UnsupportedOperationException("readlnOrNull is not supported in Kotlin/JS")
|
||||||
@@ -149,7 +149,7 @@ public actual inline fun println() {
|
|||||||
* The input is decoded using the system default Charset. A [CharacterCodingException] is thrown if input is malformed.
|
* The input is decoded using the system default Charset. A [CharacterCodingException] is thrown if input is malformed.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.6")
|
@SinceKotlin("1.6")
|
||||||
public fun readln(): String = readlnOrNull() ?: throw ReadAfterEOFException("EOF has already been reached")
|
public actual fun readln(): String = readlnOrNull() ?: throw ReadAfterEOFException("EOF has already been reached")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a line of input from the standard input stream and returns it,
|
* Reads a line of input from the standard input stream and returns it,
|
||||||
@@ -160,9 +160,7 @@ public fun readln(): String = readlnOrNull() ?: throw ReadAfterEOFException("EOF
|
|||||||
* The input is decoded using the system default Charset. A [CharacterCodingException] is thrown if input is malformed.
|
* The input is decoded using the system default Charset. A [CharacterCodingException] is thrown if input is malformed.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.6")
|
@SinceKotlin("1.6")
|
||||||
public fun readlnOrNull(): String? = readLine()
|
public actual fun readlnOrNull(): String? = readLine()
|
||||||
|
|
||||||
private class ReadAfterEOFException(message: String?) : RuntimeException(message)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a line of input from the standard input stream.
|
* Reads a line of input from the standard input stream.
|
||||||
|
|||||||
@@ -48,6 +48,20 @@ class ConsoleTest {
|
|||||||
testReadLine("first${linuxLineSeparator}second", listOf("first", "second"))
|
testReadLine("first${linuxLineSeparator}second", listOf("first", "second"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun shouldReadMultipleEmptyLines() {
|
||||||
|
testReadLine(
|
||||||
|
"first${linuxLineSeparator}second${linuxLineSeparator}${linuxLineSeparator}${linuxLineSeparator}",
|
||||||
|
listOf("first", "second", "", "")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun shouldReadAloneCarriageReturn() {
|
||||||
|
val result = readLines("\r", Charsets.UTF_8)
|
||||||
|
assertEquals(listOf("\r"), result)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun shouldReadConsecutiveEmptyLines() {
|
fun shouldReadConsecutiveEmptyLines() {
|
||||||
testReadLine("$linuxLineSeparator$linuxLineSeparator", listOf("", ""))
|
testReadLine("$linuxLineSeparator$linuxLineSeparator", listOf("", ""))
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ public actual fun print(message: Any?) {
|
|||||||
println(message)
|
println(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public actual fun readln(): String = TODO("Wasm stdlib: IO")
|
||||||
|
|
||||||
|
@SinceKotlin("1.6")
|
||||||
|
public actual fun readlnOrNull(): String? = TODO("Wasm stdlib: IO")
|
||||||
|
|
||||||
|
|
||||||
internal actual interface Serializable
|
internal actual interface Serializable
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user