diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 02a71a6c1..287225589 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 = "c6eb7bdc7"; + public static final String gitCommitId = "d5085fda8"; /** * 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 29 2026 22:10:32"; + public static final String buildTimestamp = "Apr 30 2026 08:15:13"; // Prevent instantiation private Configuration() { diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/CompressZlib.java b/src/main/java/org/perlonjava/runtime/perlmodule/CompressZlib.java index 27ccf688e..f8f953642 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/CompressZlib.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/CompressZlib.java @@ -594,10 +594,21 @@ public static RuntimeList gzopen(RuntimeArray args, int ctx) { self.put("_eof", new RuntimeScalar(0)); if (mode.startsWith("r")) { - // Read mode - InputStream fis = new FileInputStream(filename); - GZIPInputStream gis = new GZIPInputStream(fis); - self.put("_stream", new RuntimeScalar(gis)); + // Read mode. zlib's gzopen transparently reads non-gzip files + // in 'rb' mode, so detect the gzip magic and fall back to a + // plain InputStream when the file isn't actually gzip-compressed. + InputStream fis = new BufferedInputStream(new FileInputStream(filename)); + fis.mark(2); + int b1 = fis.read(); + int b2 = fis.read(); + fis.reset(); + InputStream is; + if (b1 == 0x1F && b2 == 0x8B) { + is = new GZIPInputStream(fis); + } else { + is = fis; + } + self.put("_stream", new RuntimeScalar(is)); } else if (mode.startsWith("w")) { // Write mode - check for compression level OutputStream fos = new FileOutputStream(filename); diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/TimePiece.java b/src/main/java/org/perlonjava/runtime/perlmodule/TimePiece.java index 03da56b03..18dd3341f 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/TimePiece.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/TimePiece.java @@ -73,6 +73,20 @@ public static RuntimeList _strptime(RuntimeArray args, int ctx) { boolean isLocal = args.get(2).getBoolean(); RuntimeHash locales = args.size() > 3 ? args.get(3).hashDeref() : null; + // Special-case %s (epoch seconds) — Java's DateTimeFormatter has no + // direct strftime-style %s token, so handle it explicitly. + if (format.trim().equals("%s")) { + try { + long epoch = Long.parseLong(dateString.trim()); + ZonedDateTime zdt = isLocal + ? Instant.ofEpochSecond(epoch).atZone(ZoneId.systemDefault()) + : Instant.ofEpochSecond(epoch).atZone(ZoneOffset.UTC); + return buildTimeArray(zdt, isLocal); + } catch (NumberFormatException e) { + return new RuntimeList(); + } + } + // Convert strftime format to Java DateTimeFormatter pattern String javaPattern = convertStrftimeToJava(format, locales); diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java index 091f9dc66..5fadac3ff 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java @@ -301,7 +301,12 @@ public RuntimeScalar set(RuntimeScalar value) { // Note: \@array and \%hash come in as ARRAYREFERENCE/HASHREFERENCE types, // not REFERENCE, so they are handled above in their respective cases. if (value.value instanceof RuntimeScalar) { - GlobalVariable.aliasGlobalVariable(this.globName, (RuntimeScalar) value.value); + // Update all glob aliases so that earlier `*A = *B` + // (which makes A and B share their SCALAR slot) keeps both + // names pointing at the new aliased scalar after `*A = \$x`. + for (String aliasedName : GlobalVariable.getGlobAliasGroup(this.globName)) { + GlobalVariable.aliasGlobalVariable(aliasedName, (RuntimeScalar) value.value); + } // Mark as explicitly declared for strict vars (e.g., Exporter imports) GlobalVariable.declareGlobalVariable(this.globName); }