From 86505b22ea6f4c3516b6e7ba3a5bd7fe5c77647e Mon Sep 17 00:00:00 2001 From: Flavio Soibelmann Glock Date: Tue, 21 Apr 2026 16:33:12 +0200 Subject: [PATCH] fix(sysseek): return new file position instead of success flag sysseek was aliased to seek, which returns 1 on success. Perl's sysseek is documented to return the new position (with "0 but true" for position 0). File::Tail relies on sysseek($fh, 0, SEEK_END) to detect new data; with the old behavior it always saw endpos=1 and its polling loop hung forever. Gave sysseek its own implementation in IOOperator (seek + tell, mapping position 0 to "0 but true") and updated OperatorHandler to dispatch "sysseek" to the new method. Verified with jcpan -t File::Tail (Files=3, Tests=15, Result: PASS). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../org/perlonjava/core/Configuration.java | 4 +-- .../runtime/operators/IOOperator.java | 25 ++++++++++++++++++- .../runtime/operators/OperatorHandler.java | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 090062a5e..d890f8464 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java +++ b/src/main/java/org/perlonjava/core/Configuration.java @@ -33,7 +33,7 @@ public final class Configuration { * Automatically populated by Gradle/Maven during build. * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String gitCommitId = "38f2feac1"; + public static final String gitCommitId = "5ab2ed282"; /** * Git commit date of the build (ISO format: YYYY-MM-DD). @@ -48,7 +48,7 @@ public final class Configuration { * Parsed by App::perlbrew and other tools via: perl -V | grep "Compiled at" * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String buildTimestamp = "Apr 21 2026 14:44:58"; + public static final String buildTimestamp = "Apr 21 2026 16:09:03"; // Prevent instantiation private Configuration() { diff --git a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java index 3bd964d96..79234c533 100644 --- a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java @@ -419,6 +419,26 @@ public static RuntimeScalar seek(RuntimeScalar fileHandle, RuntimeList runtimeLi } } + /** + * sysseek returns the new file position, or undef on failure. + * A position of zero is returned as the string "0 but true". + */ + public static RuntimeScalar sysseek(RuntimeScalar fileHandle, RuntimeList runtimeList) { + RuntimeScalar seekResult = seek(fileHandle, runtimeList); + if (!seekResult.getBoolean()) { + return seekResult; + } + RuntimeScalar pos = tell(fileHandle); + long p = pos.getLong(); + if (p < 0) { + return RuntimeIO.handleIOError("sysseek: could not determine position"); + } + if (p == 0) { + return new RuntimeScalar("0 but true"); + } + return pos; + } + public static RuntimeScalar getc(int ctx, RuntimeBase... args) { RuntimeScalar fileHandle; if (args.length < 1) { @@ -3039,7 +3059,10 @@ public static RuntimeScalar readline(int ctx, RuntimeBase... args) { } public static RuntimeScalar sysseek(int ctx, RuntimeBase... args) { - return seek(ctx, args); + if (args.length < 3) throw new PerlCompilerException("Not enough arguments for sysseek"); + RuntimeList list = new RuntimeList(); + for (int i = 1; i < args.length; i++) list.add(args[i]); + return sysseek(args[0].scalar(), list); } public static RuntimeScalar read(int ctx, RuntimeBase... args) { diff --git a/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java b/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java index 296917bf1..d45ef4ae9 100644 --- a/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java +++ b/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java @@ -151,7 +151,7 @@ public record OperatorHandler(String className, String methodName, int methodTyp put("getc", "getc", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); put("binmode", "binmode", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Lorg/perlonjava/runtime/runtimetypes/RuntimeList;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); put("seek", "seek", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Lorg/perlonjava/runtime/runtimetypes/RuntimeList;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); - put("sysseek", "seek", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Lorg/perlonjava/runtime/runtimetypes/RuntimeList;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); + put("sysseek", "sysseek", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;Lorg/perlonjava/runtime/runtimetypes/RuntimeList;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); put("select", "select", "org/perlonjava/runtime/operators/IOOperator", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeList;I)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); put("truncate", "truncate", "org/perlonjava/runtime/operators/IOOperator", "(I[Lorg/perlonjava/runtime/runtimetypes/RuntimeBase;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"); put("flock", "flock", "org/perlonjava/runtime/operators/IOOperator", "(I[Lorg/perlonjava/runtime/runtimetypes/RuntimeBase;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;");