[PECL-CVS] [pecl-file_formats-yaml] yaml12-schema-support: address reviews

[email protected] (Rasmus Lerdorf) Fri, 10 Apr 2026 21:09:12 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
Author: Rasmus Lerdorf (rlerdorf)
Date: 2026-04-10T17:09:07-04:00

Commit: https://github.com/php/pecl-file_formats-yaml/commit/30b307fefc6671b78b31ad2f15166d1c3a48c133
Raw diff: https://github.com/php/pecl-file_formats-yaml/commit/30b307fefc6671b78b31ad2f15166d1c3a48c133.diff

address reviews

Changed paths:
  A  tests/yaml_parse_schema_12_edge_cases.phpt
  A  tests/yaml_parse_schema_12_not_numeric.phpt
  M  detect.c


Diff:

diff --git a/detect.c b/detect.c
index 5af2f72..63caa7e 100644
--- a/detect.c
+++ b/detect.c
@@ -674,11 +674,19 @@ scalar_is_bool_12(const char *value, size_t length, const yaml_event_t *event)
 
 	} else if (NULL != event &&
 			IS_NOT_IMPLICIT_AND_TAG_IS((*event), YAML_BOOL_TAG)) {
-		if (0 == length || (1 == length && '0' == *value)) {
-			return 0;
-		} else {
+		/* explicit !!bool tag: parse true/false values */
+		if (STR_EQ("true", value) || STR_EQ("True", value) ||
+				STR_EQ("TRUE", value) ||
+				(1 == length && '1' == *value)) {
 			return 1;
 		}
+		if (STR_EQ("false", value) || STR_EQ("False", value) ||
+				STR_EQ("FALSE", value) ||
+				0 == length || (1 == length && '0' == *value)) {
+			return 0;
+		}
+		/* unknown value with explicit bool tag, treat as true for compat */
+		return 1;
 	}
 
 	return -1;
@@ -811,6 +819,10 @@ scalar_is_numeric_12(const char *value, size_t length, zend_long *lval,
 		} else if (*value == '.') {
 			goto check_float_12;
 
+		} else if (*value == 'E' || *value == 'e') {
+			type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_DECIMAL;
+			goto check_exp_12;
+
 		} else {
 			/* bare 0 followed by other digits is not valid in 1.2 */
 			goto not_numeric_12;
@@ -838,17 +850,22 @@ scalar_is_numeric_12(const char *value, size_t length, zend_long *lval,
 		type = Y_SCALAR_IS_INT | Y_SCALAR_IS_DECIMAL;
 
 	} else if (*value == '.') {
-		/* float starting with dot: .[0-9]+ */
+		/* float starting with dot: .[0-9]+ requires digit after dot */
+		if (value + 1 >= end || *(value + 1) < '0' || *(value + 1) > '9') {
+			goto not_numeric_12;
+		}
 		*ptr++ = '0';
 
 check_float_12:
 		*ptr++ = *value++;
 		if (value == end) {
-			/* trailing dot with no digits - not a number */
-			goto not_numeric_12;
+			/* trailing dot (e.g., 1.) — accept as float */
+			*ptr++ = '0';
+			type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_DECIMAL;
+			goto terminate_12;
 		}
 
-		/* need at least one digit, or could be exponent directly */
+		/* parse fractional digits and optional exponent */
 		while (value < end) {
 			if (*value >= '0' && *value <= '9') {
 				*ptr++ = *value++;
diff --git a/tests/yaml_parse_schema_12_edge_cases.phpt b/tests/yaml_parse_schema_12_edge_cases.phpt
new file mode 100644
index 0000000..c54d089
--- /dev/null
+++ b/tests/yaml_parse_schema_12_edge_cases.phpt
@@ -0,0 +1,61 @@
+--TEST--
+Yaml 1.2 Core Schema - edge cases (0e5, trailing dot, explicit bool tag)
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+// Fix 1: 0e5 / 0E+10 should be valid floats
+// Fix 2: trailing dot (1., 0.) should be valid floats
+// Fix 3: explicit !!bool tag should parse true/false correctly
+var_dump(yaml_parse('
+# 0-prefixed exponent floats
+zero_exp: 0e5
+zero_exp_plus: 0E+10
+zero_exp_neg: 0e-3
+# trailing dot floats
+one_dot: 1.
+zero_dot: 0.
+neg_dot: -1.
+# trailing dot with exponent
+dot_exp: 1.e2
+# bare dot is NOT a float
+# explicit bool tags
+bool_false: !!bool "false"
+bool_true: !!bool "true"
+bool_FALSE: !!bool "FALSE"
+bool_TRUE: !!bool "TRUE"
+bool_zero: !!bool "0"
+bool_one: !!bool "1"
+'));
+?>
+--EXPECT--
+array(13) {
+  ["zero_exp"]=>
+  float(0)
+  ["zero_exp_plus"]=>
+  float(0)
+  ["zero_exp_neg"]=>
+  float(0)
+  ["one_dot"]=>
+  float(1)
+  ["zero_dot"]=>
+  float(0)
+  ["neg_dot"]=>
+  float(-1)
+  ["dot_exp"]=>
+  float(100)
+  ["bool_false"]=>
+  bool(false)
+  ["bool_true"]=>
+  bool(true)
+  ["bool_FALSE"]=>
+  bool(false)
+  ["bool_TRUE"]=>
+  bool(true)
+  ["bool_zero"]=>
+  bool(false)
+  ["bool_one"]=>
+  bool(true)
+}
diff --git a/tests/yaml_parse_schema_12_not_numeric.phpt b/tests/yaml_parse_schema_12_not_numeric.phpt
new file mode 100644
index 0000000..9c24892
--- /dev/null
+++ b/tests/yaml_parse_schema_12_not_numeric.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Yaml 1.2 Core Schema - values that are NOT numeric
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+// Ensure these edge cases are correctly treated as strings
+var_dump(yaml_parse('
+bare_dot: .
+dot_e: .e5
+bare_plus: +
+bare_minus: "-"
+'));
+?>
+--EXPECT--
+array(4) {
+  ["bare_dot"]=>
+  string(1) "."
+  ["dot_e"]=>
+  string(3) ".e5"
+  ["bare_plus"]=>
+  string(1) "+"
+  ["bare_minus"]=>
+  string(1) "-"
+}