Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/java/org/perlonjava/core/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "a671eccbf";
public static final String gitCommitId = "3e7654d5a";

/**
* Git commit date of the build (ISO format: YYYY-MM-DD).
Expand All @@ -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 27 2026 20:46:44";
public static final String buildTimestamp = "Apr 27 2026 21:36:05";

// Prevent instantiation
private Configuration() {
Expand Down
34 changes: 29 additions & 5 deletions src/main/java/org/perlonjava/runtime/operators/IOOperator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2890,8 +2890,22 @@ private static RuntimeIO duplicateFileHandle(RuntimeIO original) {
} else {
// First duplication — wrap both original and duplicate in DupIOHandles
// so they share a refcount and get distinct filenos.
// Get the original's fd from the registry, or from the IOHandle itself
// (e.g. StandardIO.fileno() returns 0/1/2 for stdin/stdout/stderr).

// If the original is a LayeredIOHandle (e.g. STDOUT after
// `binmode :encoding(utf8)`), we must preserve the layers on both
// sides of the dup. Otherwise PerlIO::get_layers loses the layers
// on the original and Test2::Util::clone_io drops them on the
// duplicate, leading to spurious "Wide character in print"
// warnings. We do this by dup'ing the LayeredIOHandle's inner
// delegate and re-wrapping each side in its own LayeredIOHandle
// that shares the same active layers.
LayeredIOHandle layeredWrapper = null;
IOHandle dupTarget = original.ioHandle;
if (original.ioHandle instanceof LayeredIOHandle lh) {
layeredWrapper = lh;
dupTarget = lh.getDelegate();
}

int origFd = original.getAssignedFileno();
if (origFd < 0) {
// Not in the registry — ask the IOHandle directly
Expand All @@ -2902,9 +2916,19 @@ private static RuntimeIO duplicateFileHandle(RuntimeIO original) {
// Still no fd — assign a new one
origFd = original.assignFileno();
}
DupIOHandle[] pair = DupIOHandle.createPair(original.ioHandle, origFd);
original.ioHandle = pair[0]; // Replace original's handle with refcounted wrapper
duplicate.ioHandle = pair[1]; // New handle with unique fd
DupIOHandle[] pair = DupIOHandle.createPair(dupTarget, origFd);

if (layeredWrapper != null) {
LayeredIOHandle origLayered = new LayeredIOHandle(pair[0]);
origLayered.activeLayers.addAll(layeredWrapper.activeLayers);
LayeredIOHandle dupLayered = new LayeredIOHandle(pair[1]);
dupLayered.activeLayers.addAll(layeredWrapper.activeLayers);
original.ioHandle = origLayered;
duplicate.ioHandle = dupLayered;
} else {
original.ioHandle = pair[0]; // Replace original's handle with refcounted wrapper
duplicate.ioHandle = pair[1]; // New handle with unique fd
}
}

// Register the duplicate's fd in RuntimeIO's fileno registry
Expand Down
1 change: 1 addition & 0 deletions src/main/perl/lib/Config.pm
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ $os_name =~ s/\s+/_/g;
perlpath => $^X, # Path to the perl interpreter (jperl)
startperl => '#!' . $^X, # Shebang line for Perl scripts
sharpbang => '#!', # Shebang prefix
eunicefix => ':', # No-op fixer (only used on EUNICE)

# Version info
version => '5.42.0',
Expand Down
33 changes: 29 additions & 4 deletions src/main/perl/lib/open.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,38 @@ use warnings;

our $VERSION = '1.14';

# The open pragma sets default PerlIO layers for input/output
# In PerlOnJava, UTF-8 is the default encoding
# The open pragma sets default PerlIO layers for input/output.
# PerlOnJava already defaults to UTF-8 internally for I/O, but we
# still need to apply the layers to STDIN/STDOUT/STDERR when
# C<:std> is used so that PerlIO::get_layers() reflects the layers.
# Code that introspects layers (e.g. Test2::Util::clone_io) relies on
# this so that cloned handles don't drop the :encoding/utf8 layer and
# emit spurious "Wide character in print" warnings.

sub import {
my $class = shift;
# For now, accept but ignore layer specifications
# PerlOnJava defaults to UTF-8 encoding

my @layers;
my $apply_to_std;
for my $arg (@_) {
if ($arg eq ':std') {
$apply_to_std = 1;
}
elsif ($arg =~ /^:/) {
push @layers, $arg;
}
else {
# IN / OUT / IO selector tokens are ignored for now;
# PerlOnJava applies the same layers to all directions.
}
}

if ($apply_to_std && @layers) {
my $spec = join('', @layers);
binmode(\*STDIN, $spec);
binmode(\*STDOUT, $spec);
binmode(\*STDERR, $spec);
}
}

1;
Loading