diff --git a/src/main/java/org/perlonjava/frontend/parser/PrototypeArgs.java b/src/main/java/org/perlonjava/frontend/parser/PrototypeArgs.java index bb45a56c7..b3c5b424e 100644 --- a/src/main/java/org/perlonjava/frontend/parser/PrototypeArgs.java +++ b/src/main/java/org/perlonjava/frontend/parser/PrototypeArgs.java @@ -482,7 +482,7 @@ private static void handleListOrHashArgument(Parser parser, ListNode args, boole parser.tokenIndex = saveIndex; } - ListNode argList = ListParser.parseZeroOrMoreList(parser, 0, false, true, false, false); + ListNode argList = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false); // @ and % consume remaining arguments in LIST context // for (Node element : argList.elements) { // element.setAnnotation("context", "LIST"); diff --git a/src/main/java/org/perlonjava/runtime/io/CustomFileChannel.java b/src/main/java/org/perlonjava/runtime/io/CustomFileChannel.java index cb9e8dc84..1fda20e8a 100644 --- a/src/main/java/org/perlonjava/runtime/io/CustomFileChannel.java +++ b/src/main/java/org/perlonjava/runtime/io/CustomFileChannel.java @@ -354,14 +354,10 @@ public RuntimeScalar sysread(int length) { return new RuntimeScalar(""); } - // Convert bytes to string representation buffer.flip(); - StringBuilder result = new StringBuilder(bytesRead); - while (buffer.hasRemaining()) { - result.append((char) (buffer.get() & 0xFF)); - } - - return new RuntimeScalar(result.toString()); + byte[] readBytes = new byte[buffer.remaining()]; + buffer.get(readBytes); + return new RuntimeScalar(readBytes); } catch (IOException e) { getGlobalVariable("main::!").set(e.getMessage()); return new RuntimeScalar(); // undef diff --git a/src/main/java/org/perlonjava/runtime/io/InternalPipeHandle.java b/src/main/java/org/perlonjava/runtime/io/InternalPipeHandle.java index c2f176e90..47487f898 100644 --- a/src/main/java/org/perlonjava/runtime/io/InternalPipeHandle.java +++ b/src/main/java/org/perlonjava/runtime/io/InternalPipeHandle.java @@ -178,13 +178,9 @@ public RuntimeScalar sysread(int length) { return new RuntimeScalar(""); } - // Convert bytes to string representation - StringBuilder result = new StringBuilder(bytesRead); - for (int i = 0; i < bytesRead; i++) { - result.append((char) (buffer[i] & 0xFF)); - } - - return new RuntimeScalar(result.toString()); + byte[] readBytes = new byte[bytesRead]; + System.arraycopy(buffer, 0, readBytes, 0, bytesRead); + return new RuntimeScalar(readBytes); } catch (IOException e) { isEOF = true; getGlobalVariable("main::!").set(e.getMessage()); diff --git a/src/main/java/org/perlonjava/runtime/io/PipeInputChannel.java b/src/main/java/org/perlonjava/runtime/io/PipeInputChannel.java index 5f10b345c..05e1dbce2 100644 --- a/src/main/java/org/perlonjava/runtime/io/PipeInputChannel.java +++ b/src/main/java/org/perlonjava/runtime/io/PipeInputChannel.java @@ -332,13 +332,9 @@ public RuntimeScalar sysread(int length) { return new RuntimeScalar(""); } - // Convert bytes to string representation - StringBuilder result = new StringBuilder(bytesRead); - for (int i = 0; i < bytesRead; i++) { - result.append((char) (buffer[i] & 0xFF)); - } - - return new RuntimeScalar(result.toString()); + byte[] readBytes = new byte[bytesRead]; + System.arraycopy(buffer, 0, readBytes, 0, bytesRead); + return new RuntimeScalar(readBytes); } catch (IOException e) { getGlobalVariable("main::!").set(e.getMessage()); return new RuntimeScalar(); // undef diff --git a/src/main/java/org/perlonjava/runtime/io/StandardIO.java b/src/main/java/org/perlonjava/runtime/io/StandardIO.java index a246558d3..705a40fcf 100644 --- a/src/main/java/org/perlonjava/runtime/io/StandardIO.java +++ b/src/main/java/org/perlonjava/runtime/io/StandardIO.java @@ -285,13 +285,9 @@ public RuntimeScalar sysread(int length) { return new RuntimeScalar(""); } - // Convert bytes to string representation - StringBuilder result = new StringBuilder(bytesRead); - for (int i = 0; i < bytesRead; i++) { - result.append((char) (buffer[i] & 0xFF)); - } - - return new RuntimeScalar(result.toString()); + byte[] readBytes = new byte[bytesRead]; + System.arraycopy(buffer, 0, readBytes, 0, bytesRead); + return new RuntimeScalar(readBytes); } catch (IOException e) { getGlobalVariable("main::!").set(e.getMessage()); return new RuntimeScalar(); // undef diff --git a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java index 78aeb24d1..a0f8e610a 100644 --- a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java @@ -726,6 +726,9 @@ public static RuntimeScalar sysread(int ctx, RuntimeBase... args) { newValue.append(data); target.set(newValue.toString()); + if (result.type == RuntimeScalarType.BYTE_STRING && target.type != RuntimeScalarType.TIED_SCALAR) { + target.type = RuntimeScalarType.BYTE_STRING; + } return new RuntimeScalar(bytesRead); } @@ -874,7 +877,7 @@ public static RuntimeScalar syswrite(int ctx, RuntimeBase... args) { /** * Checks if the handle has a :utf8 layer. */ - private static boolean hasUtf8Layer(RuntimeIO fh) { + public static boolean hasUtf8Layer(RuntimeIO fh) { IOHandle handle = fh.ioHandle; while (handle instanceof LayeredIOHandle layered) { String layers = layered.getCurrentLayers(); @@ -2139,7 +2142,18 @@ public static RuntimeScalar sysseek(int ctx, RuntimeBase... args) { } public static RuntimeScalar read(int ctx, RuntimeBase... args) { - return sysread(ctx, args); + RuntimeScalar result = sysread(ctx, args); + if (args.length >= 2) { + RuntimeScalar fileHandle = args[0].scalar(); + RuntimeIO fh = fileHandle.getRuntimeIO(); + if (fh != null && hasUtf8Layer(fh)) { + RuntimeScalar target = args[1].scalar().scalarDeref(); + if (target.type != RuntimeScalarType.TIED_SCALAR) { + target.type = RuntimeScalarType.STRING; + } + } + } + return result; } } diff --git a/src/main/java/org/perlonjava/runtime/operators/Operator.java b/src/main/java/org/perlonjava/runtime/operators/Operator.java index d6f8716ad..7160304ba 100644 --- a/src/main/java/org/perlonjava/runtime/operators/Operator.java +++ b/src/main/java/org/perlonjava/runtime/operators/Operator.java @@ -290,7 +290,11 @@ public static RuntimeScalar substr(int ctx, RuntimeBase... args) { String extractedSubstring = result; lvalue.set(replacement); // Return the extracted substring, not the lvalue (which now contains the replacement) - return new RuntimeScalar(extractedSubstring); + RuntimeScalar extracted = new RuntimeScalar(extractedSubstring); + if (((RuntimeScalar) args[0]).type == RuntimeScalarType.BYTE_STRING) { + extracted.type = RuntimeScalarType.BYTE_STRING; + } + return extracted; } return lvalue; diff --git a/src/main/java/org/perlonjava/runtime/operators/Readline.java b/src/main/java/org/perlonjava/runtime/operators/Readline.java index 8d5b7ba65..69da9d1cc 100644 --- a/src/main/java/org/perlonjava/runtime/operators/Readline.java +++ b/src/main/java/org/perlonjava/runtime/operators/Readline.java @@ -360,6 +360,9 @@ public static RuntimeScalar read(RuntimeList args) { // Update the scalar with the new value scalar.set(scalarValue.toString()); + if (!IOOperator.hasUtf8Layer(fh)) { + scalar.type = RuntimeScalarType.BYTE_STRING; + } // Return the number of characters read return new RuntimeScalar(charsRead); diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeSubstrLvalue.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeSubstrLvalue.java index 5fe125bc3..85f898f3e 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeSubstrLvalue.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeSubstrLvalue.java @@ -28,7 +28,7 @@ public RuntimeSubstrLvalue(RuntimeScalar parent, String str, int offset, int len this.offset = offset; this.length = length; - this.type = RuntimeScalarType.STRING; + this.type = (parent.type == RuntimeScalarType.BYTE_STRING) ? RuntimeScalarType.BYTE_STRING : RuntimeScalarType.STRING; this.value = str; }