This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git


The following commit(s) were added to refs/heads/2.3-gae by this push:
     new ea1c5eaf Mostly CFormat-related code cleanup (things spotted during 
forward porting into FM3)
ea1c5eaf is described below

commit ea1c5eafe494399b3066ad1ecb62e7ab9b8ae42a
Author: ddekany <[email protected]>
AuthorDate: Sun Jan 1 14:29:33 2023 +0100

    Mostly CFormat-related code cleanup (things spotted during forward porting 
into FM3)
---
 .../java/freemarker/core/ArithmeticEngine.java     |  2 +-
 .../freemarker/core/CTemplateNumberFormat.java     |  6 +-
 src/main/java/freemarker/core/Configurable.java    | 88 +++++++++++-----------
 src/main/java/freemarker/core/Environment.java     | 31 ++++----
 .../java/freemarker/core/MarkupOutputFormat.java   |  2 +-
 ...andardCLanguages.java => StandardCFormats.java} | 21 +++---
 .../java/freemarker/ext/beans/BeansWrapper.java    |  6 +-
 .../ext/beans/BeansWrapperConfiguration.java       |  2 +-
 .../java/freemarker/template/_TemplateAPI.java     |  2 +-
 .../template/utility/CollectionUtils.java          |  2 +
 .../freemarker/template/utility/StringUtil.java    | 31 ++++++--
 src/manual/en_US/book.xml                          |  6 +-
 src/manual/zh_CN/book.xml                          |  7 +-
 .../core/BooleanFormatEnvironmentCachingTest.java  |  5 +-
 .../java/freemarker/core/CFormatTemplateTest.java  |  6 ++
 src/test/java/freemarker/core/NumberBiTest.java    |  4 -
 .../freemarker/template/ConfigurationTest.java     | 18 +++--
 17 files changed, 132 insertions(+), 107 deletions(-)

diff --git a/src/main/java/freemarker/core/ArithmeticEngine.java 
b/src/main/java/freemarker/core/ArithmeticEngine.java
index 468f5e40..dc946d2c 100644
--- a/src/main/java/freemarker/core/ArithmeticEngine.java
+++ b/src/main/java/freemarker/core/ArithmeticEngine.java
@@ -116,7 +116,7 @@ public abstract class ArithmeticEngine {
         @Override
         public int compareNumbers(Number first, Number second) {
             // We try to find the result based on the sign (+/-/0) first, 
because:
-            // - It's much faster than converting to BigDecial, and comparing 
to 0 is the most common comparison.
+            // - It's much faster than converting to BigDecimal, and comparing 
to 0 is the most common comparison.
             // - It doesn't require any type conversions, and thus things like 
"Infinity > 0" won't fail.
             int firstSignum = NumberUtil.getSignum(first); 
             int secondSignum = NumberUtil.getSignum(second);
diff --git a/src/main/java/freemarker/core/CTemplateNumberFormat.java 
b/src/main/java/freemarker/core/CTemplateNumberFormat.java
index dc662b7a..3df4177d 100644
--- a/src/main/java/freemarker/core/CTemplateNumberFormat.java
+++ b/src/main/java/freemarker/core/CTemplateNumberFormat.java
@@ -136,11 +136,10 @@ final class CTemplateNumberFormat extends 
TemplateNumberFormat {
             BigDecimal bd = ((BigDecimal) num).stripTrailingZeros();
             int scale = bd.scale();
             if (scale <= 0) {
-                // A whole number. Myabe a long ID in a database or other 
system, and for those exponential form is not
+                // A whole number. Maybe a long ID in a database or other 
system, and for those exponential form is not
                 // expected generally, so we avoid that. But then, it becomes 
too easy to write something like
                 // 1e1000000000000 and kill the server with a terra byte long 
rendering of the number, so for lengths
-                // that
-                // realistically aren't ID-s or such, we use exponential 
format after all:
+                // that realistically aren't ID-s or such, we use exponential 
format after all:
                 if (scale <= -100) {
                     return bd.toString(); // Will give exponential form for 
this scale
                 }
@@ -196,5 +195,4 @@ final class CTemplateNumberFormat extends 
TemplateNumberFormat {
         return "c";
     }
 
-
 }
diff --git a/src/main/java/freemarker/core/Configurable.java 
b/src/main/java/freemarker/core/Configurable.java
index 0e03b220..a70e247e 100644
--- a/src/main/java/freemarker/core/Configurable.java
+++ b/src/main/java/freemarker/core/Configurable.java
@@ -66,6 +66,7 @@ import freemarker.template.TemplateModel;
 import freemarker.template.Version;
 import freemarker.template._TemplateAPI;
 import freemarker.template._VersionInts;
+import freemarker.template.utility.CollectionUtils;
 import freemarker.template.utility.NullArgumentException;
 import freemarker.template.utility.StringUtil;
 
@@ -82,7 +83,7 @@ import freemarker.template.utility.StringUtil;
  * object.
  */
 public class Configurable {
-    static final String C_TRUE_FALSE = "true,false";
+    static final String BOOLEAN_FORMAT_LEGACY_DEFAULT = "true,false";
     static final String C_FORMAT_STRING = "c";
 
     private static final String NULL = "null";
@@ -386,8 +387,6 @@ public class Configurable {
     private TimeZone sqlDataAndTimeTimeZone;
     private boolean sqlDataAndTimeTimeZoneSet;
     private String booleanFormat;
-    private String booleanFormatCommaSplitTrueSide;  // deduced from 
booleanFormat
-    private String booleanFormatCommaSplitFalseSide;  // deduced from 
booleanFormat
     private Integer classicCompatible;
     private TemplateExceptionHandler templateExceptionHandler;
     private AttemptExceptionReporter attemptExceptionReporter;
@@ -493,7 +492,7 @@ public class Configurable {
         // outputEncoding and urlEscapingCharset defaults to null,
         // which means "not specified"
 
-        setBooleanFormat(C_TRUE_FALSE);
+        setBooleanFormat(BOOLEAN_FORMAT_LEGACY_DEFAULT);
         
         customAttributes = new HashMap();
         
@@ -697,12 +696,13 @@ public class Configurable {
     }
 
     /**
-     * Sets the format (usually a computer language) used for the {@code c}, 
{@code cn} built-ins, and for the
+     * Sets the format (usually a computer language) used for {@code ?c}, 
{@code ?cn}, and for the
      * {@code "c"} ({@code "computer"} before 2.3.32) {@link 
#setNumberFormat(String) number_format}, and the
      * {@code "c"} {@link #setBooleanFormat(String) boolean_format}.
      *
      * <p>The default value depends on {@link 
Configuration#Configuration(Version) incompatible_improvements}.
-     * If that's 2.3.32 or higher, then it's {@code "JavaScript or JSON"}, 
otherwise it's {@code "legacy"}.
+     * If that's 2.3.32 or higher, then it's {@link 
JavaScriptOrJSONCFormat#INSTANCE "JavaScript or JSON"},
+     * otherwise it's {@link LegacyCFormat#INSTANCE "legacy"}.
      *
      * @since 2.3.32
      */
@@ -863,7 +863,7 @@ public class Configurable {
      *   <li>{@code "c"} (recognized since 2.3.32): The number format used by 
FTL's {@code c} built-in (like in
      *       {@code someNumber?c}). So with this <code>${someNumber}</code> 
will output the same as
      *       <code>${someNumber?c}</code>. This should only be used if the 
template solely generates source code,
-     *       configuration file, or other content that's nor read by normal 
users. If the template contains parts that's
+     *       configuration file, or other content that's not read by normal 
users. If the template contains parts that's
      *       read by normal users (like typical a web page), you are not 
supposed to use this.</li>
      *   <li>{@code "computer"}: The old (deprecated) name for {@code "c"}. 
Recognized by all FreeMarker versions.</li>
      *   <li>{@code "currency"}: The number format returned by {@link 
NumberFormat#getCurrencyInstance(Locale)}</li>
@@ -882,8 +882,7 @@ public class Configurable {
      *       <code><i>parameters</i></code> is parsed by the custom {@link 
TemplateNumberFormat}.
      *   </li>
      * </ul>
-     * 
-     *   
+     *
      * <p>Defaults to <tt>"number"</tt>.
      */
     public void setNumberFormat(String numberFormat) {
@@ -1034,11 +1033,38 @@ public class Configurable {
      * only influenced the result of {@code myBool?string}. 
      */
     public void setBooleanFormat(String booleanFormat) {
+        validateBooleanFormat(booleanFormat);
+        this.booleanFormat = booleanFormat;
+        properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat);
+    }
+
+    /**
+     * @throws IllegalArgumentException If the format string has unrecognized 
format
+     */
+    private static void validateBooleanFormat(String booleanFormat) {
+        parseOrValidateBooleanFormat(booleanFormat, true);
+    }
+
+    /**
+     * @return {@code null} for legacy default (not set in effect), empty 
array if the {@link CFormat} should be used,
+     * and an array of {@code [trueString, falseString]} otherwise.
+     *
+     * @throws IllegalArgumentException If the format string has unrecognized 
format
+     */
+    static String[] parseBooleanFormat(String booleanFormat) {
+        return parseOrValidateBooleanFormat(booleanFormat, false);
+    }
+
+    private static String[] parseOrValidateBooleanFormat(String booleanFormat, 
boolean validateOnly) {
         NullArgumentException.check("booleanFormat", booleanFormat);
 
-        if (booleanFormat.equals(C_TRUE_FALSE) || 
booleanFormat.equals(C_FORMAT_STRING)) {
-            booleanFormatCommaSplitTrueSide = null;
-            booleanFormatCommaSplitFalseSide = null;
+        if (booleanFormat.equals(C_FORMAT_STRING)) {
+            if (validateOnly) {
+                return null;
+            }
+            return CollectionUtils.EMPTY_STRING_ARRAY;
+        } else if (booleanFormat.equals(BOOLEAN_FORMAT_LEGACY_DEFAULT)) {
+            return null;
         } else {
             int commaIdx = booleanFormat.indexOf(',');
             if (commaIdx == -1) {
@@ -1047,12 +1073,14 @@ public class Configurable {
                                 "or it must be \"" + C_FORMAT_STRING + "\", 
but it was " +
                                 StringUtil.jQuote(booleanFormat) + ".");
             }
-            booleanFormatCommaSplitTrueSide = booleanFormat.substring(0, 
commaIdx);
-            booleanFormatCommaSplitFalseSide = 
booleanFormat.substring(commaIdx + 1);
+            if (validateOnly) {
+                return null;
+            }
+            return new String[] {
+                    booleanFormat.substring(0, commaIdx),
+                    booleanFormat.substring(commaIdx + 1)
+            };
         }
-
-        this.booleanFormat = booleanFormat;
-        properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat);
     }
     
     /**
@@ -1062,32 +1090,6 @@ public class Configurable {
         return booleanFormat != null ? booleanFormat : 
parent.getBooleanFormat(); 
     }
 
-    /**
-     * Non-{@code null} if the {@link #setBooleanFormat(String)} 
boolean_format} setting is comma separated true, and
-     * false strings.
-     *
-     * @since 2.3.32
-     */
-    String getBooleanFormatCommaSplitTrueSide() {
-        if (booleanFormat != null) {
-            return booleanFormatCommaSplitTrueSide;
-        }
-        return parent != null ? parent.getBooleanFormatCommaSplitTrueSide() : 
null;
-    }
-
-    /**
-     * Non-{@code null} if the {@link #setBooleanFormat(String)} 
boolean_format} setting is comma separated true, and
-     * false strings.
-     *
-     * @since 2.3.32
-     */
-    String getBooleanFormatCommaSplitFalseSide() {
-        if (booleanFormat != null) {
-            return booleanFormatCommaSplitFalseSide;
-        }
-        return parent != null ? parent.getBooleanFormatCommaSplitFalseSide() : 
null;
-    }
-
     /**
      * Tells if this setting is set directly in this object or its value is 
coming from the {@link #getParent() parent}.
      *  
diff --git a/src/main/java/freemarker/core/Environment.java 
b/src/main/java/freemarker/core/Environment.java
index a56d9ddf..0bd264bb 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -1691,9 +1691,9 @@ public final class Environment extends Configurable {
     }
 
     /**
-     * Returns the {@link TemplateNumberFormat} used for the <tt>c</tt> 
built-in currently uses in this environment.
+     * Returns the {@link TemplateNumberFormat} that {@code ?c}/{@code ?cn} 
uses.
      * Calling this method for many times is fine, as it internally caches the 
result object.
-     * Remember that {@link TemplateNumberFormat}-s are not thread-safe 
objects, so the resulting object should only
+     * Remember that {@link TemplateNumberFormat}-s aren't thread-safe 
objects, so the resulting object should only
      * be used in the same thread where this {@link Environment} runs.
      *
      * @since 2.3.32
@@ -1729,6 +1729,7 @@ public final class Environment extends Configurable {
         if (prevCFormat != cFormat) {
             cTemplateNumberFormat = null;
             cTemplateNumberFormatWithPre2331IcIBug = null;
+            cNumberFormat = null;
             if (cachedTemplateNumberFormats != null) {
                 cachedTemplateNumberFormats.remove(C_FORMAT_STRING);
                 cachedTemplateNumberFormats.remove(COMPUTER_FORMAT_STRING);
@@ -1812,7 +1813,7 @@ public final class Environment extends Configurable {
         return new _ErrorDescriptionBuilder(
                 "Can't convert boolean to string automatically, because the 
\"", BOOLEAN_FORMAT_KEY ,"\" setting was ",
                 new _DelayedJQuote(getBooleanFormat()),
-                (getBooleanFormat().equals(C_TRUE_FALSE)
+                (getBooleanFormat().equals(BOOLEAN_FORMAT_LEGACY_DEFAULT)
                         ? ", which is the legacy deprecated default, and we 
treat it as if no format was set. "
                         + "This is the default configuration; you should 
provide the format explicitly for each "
                         + "place where you print a boolean."
@@ -1869,17 +1870,19 @@ public final class Environment extends Configurable {
     }
 
     private void cacheTrueAndFalseStrings() {
-        String spitTrueSide = getBooleanFormatCommaSplitTrueSide();
-        if (spitTrueSide != null) {
-            cachedTrueString = spitTrueSide;
-            cachedFalseString = getBooleanFormatCommaSplitFalseSide();
-        } else if (getBooleanFormat().equals(C_FORMAT_STRING)) {
-            CFormat cFormat = getCFormat();
-            cachedTrueString = cFormat.getTrueString();
-            cachedFalseString = cFormat.getFalseString();
+        String[] parsedBooleanFormat = parseBooleanFormat(getBooleanFormat());
+        if (parsedBooleanFormat != null) {
+            if (parsedBooleanFormat.length == 0) {
+                CFormat cFormat = getCFormat();
+                cachedTrueString = cFormat.getTrueString();
+                cachedFalseString = cFormat.getFalseString();
+            } else {
+                cachedTrueString = parsedBooleanFormat[0];
+                cachedFalseString = parsedBooleanFormat[1];
+            }
         } else {
-            // This happens for C_TRUE_FALSE deliberately. That's the default 
for BC, but it's not a good default for human
-            // audience formatting, so we pretend that it wasn't set.
+            // This happens for BOOLEAN_FORMAT_LEGACY_DEFAULT deliberately. 
That's the default for BC, but it's not a
+            // good default for human audience formatting, so we pretend that 
it wasn't set.
             cachedTrueString = null;
             cachedFalseString = null;
         }
@@ -2410,7 +2413,7 @@ public final class Environment extends Configurable {
     }
 
     /**
-     * Similar to {@link #getLocalVariable(String)}, but might returns {@link 
TemplateNullModel}. Only used internally,
+     * Similar to {@link #getLocalVariable(String)}, but might return {@link 
TemplateNullModel}. Only used internally,
      * as {@link TemplateNullModel} is internal.
      *
      * @since 2.3.29
diff --git a/src/main/java/freemarker/core/MarkupOutputFormat.java 
b/src/main/java/freemarker/core/MarkupOutputFormat.java
index e8b3d969..c947c93e 100644
--- a/src/main/java/freemarker/core/MarkupOutputFormat.java
+++ b/src/main/java/freemarker/core/MarkupOutputFormat.java
@@ -91,7 +91,7 @@ public abstract class MarkupOutputFormat<MO extends 
TemplateMarkupOutputModel> e
 
     /**
      * Returns the content as markup text; never {@code null}. If this {@link 
TemplateMarkupOutputModel} was created
-     * with {@link #fromMarkup(String)}, it might returns the original markup 
text literally, but this is not required
+     * with {@link #fromMarkup(String)}, it might return the original markup 
text literally, but this is not required
      * as far as the returned markup means the same. If this {@link 
TemplateMarkupOutputModel} wasn't created
      * with {@link #fromMarkup(String)} and it doesn't yet have the markup, it 
has to generate the markup now.
      */
diff --git a/src/main/java/freemarker/core/_StandardCLanguages.java 
b/src/main/java/freemarker/core/StandardCFormats.java
similarity index 58%
rename from src/main/java/freemarker/core/_StandardCLanguages.java
rename to src/main/java/freemarker/core/StandardCFormats.java
index 9a22e7ca..aa56ccb1 100644
--- a/src/main/java/freemarker/core/_StandardCLanguages.java
+++ b/src/main/java/freemarker/core/StandardCFormats.java
@@ -19,6 +19,7 @@
 
 package freemarker.core;
 
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -26,18 +27,20 @@ final class StandardCFormats {
     private StandardCFormats() {
     }
 
-    static final Map<String, CFormat> STANDARD_C_FORMATS = new 
LinkedHashMap<>();
+    static final Map<String, CFormat> STANDARD_C_FORMATS;
     static {
-        addStandardCFormat(JavaScriptOrJSONCFormat.INSTANCE);
-        addStandardCFormat(JSONCFormat.INSTANCE);
-        addStandardCFormat(JavaScriptCFormat.INSTANCE);
-        addStandardCFormat(JavaCFormat.INSTANCE);
-        addStandardCFormat(XSCFormat.INSTANCE);
-        addStandardCFormat(LegacyCFormat.INSTANCE);
+        Map<String, CFormat> map = new LinkedHashMap<>();
+        addStandardCFormat(map, JavaScriptOrJSONCFormat.INSTANCE);
+        addStandardCFormat(map, JSONCFormat.INSTANCE);
+        addStandardCFormat(map, JavaScriptCFormat.INSTANCE);
+        addStandardCFormat(map, JavaCFormat.INSTANCE);
+        addStandardCFormat(map, XSCFormat.INSTANCE);
+        addStandardCFormat(map, LegacyCFormat.INSTANCE);
+        STANDARD_C_FORMATS = Collections.unmodifiableMap(map);
     }
 
-    private static void addStandardCFormat(CFormat cFormat) {
-        STANDARD_C_FORMATS.put(cFormat.getName(), cFormat);
+    private static void addStandardCFormat(Map<String, CFormat> map, CFormat 
cFormat) {
+        map.put(cFormat.getName(), cFormat);
     }
 
 }
diff --git a/src/main/java/freemarker/ext/beans/BeansWrapper.java 
b/src/main/java/freemarker/ext/beans/BeansWrapper.java
index 5ac4ea1f..47eb5c72 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapper.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapper.java
@@ -152,7 +152,7 @@ public class BeansWrapper implements RichObjectWrapper, 
WriteProtectable {
     /**
      * {@link String} class name to {@link StaticModel} cache.
      * This object only belongs to a single {@link BeansWrapper}.
-     * This has to be final as {@link #getStaticModels()} might returns it any 
time and then it has to remain a good
+     * This has to be final as {@link #getStaticModels()} might return it any 
time and then it has to remain a good
      * reference.
      */
     private final StaticModels staticModels;
@@ -160,7 +160,7 @@ public class BeansWrapper implements RichObjectWrapper, 
WriteProtectable {
     /**
      * {@link String} class name to {@link EnumerationModel} cache.
      * This object only belongs to a single {@link BeansWrapper}.
-     * This has to be final as {@link #getStaticModels()} might returns it any 
time and then it has to remain a good
+     * This has to be final as {@link #getStaticModels()} might return it any 
time and then it has to remain a good
      * reference.
      */
     private final ClassBasedModelFactory enumModels;
@@ -260,7 +260,7 @@ public class BeansWrapper implements RichObjectWrapper, 
WriteProtectable {
      *   </ul>
      *   
      *   <p>Note that the version will be normalized to the lowest version 
where the same incompatible
-     *   {@link BeansWrapper} improvements were already present, so {@link 
#getIncompatibleImprovements()} might returns
+     *   {@link BeansWrapper} improvements were already present, so {@link 
#getIncompatibleImprovements()} might return
      *   a lower version than what you have specified.
      *
      * @since 2.3.21
diff --git a/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java 
b/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
index ff43033d..5daaa909 100644
--- a/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
+++ b/src/main/java/freemarker/ext/beans/BeansWrapperConfiguration.java
@@ -63,7 +63,7 @@ public abstract class BeansWrapperConfiguration implements 
Cloneable {
      *            See the corresponding parameter of {@link 
BeansWrapper#BeansWrapper(Version)}. Not {@code null}. Note
      *            that the version will be normalized to the lowest version 
where the same incompatible
      *            {@link BeansWrapper} improvements were already present, so 
for the returned instance
-     *            {@link #getIncompatibleImprovements()} might returns a lower 
version than what you have specified
+     *            {@link #getIncompatibleImprovements()} might return a lower 
version than what you have specified
      *            here.
      * @param isIncompImprsAlreadyNormalized
      *            Tells if the {@code incompatibleImprovements} parameter 
contains an <em>already normalized</em> value.
diff --git a/src/main/java/freemarker/template/_TemplateAPI.java 
b/src/main/java/freemarker/template/_TemplateAPI.java
index 0f7f23b4..8fa3250d 100644
--- a/src/main/java/freemarker/template/_TemplateAPI.java
+++ b/src/main/java/freemarker/template/_TemplateAPI.java
@@ -41,7 +41,7 @@ import freemarker.template.utility.NullArgumentException;
  */
 public class _TemplateAPI {
     // ATTENTION! Don't refer to other classes in the static initializer of 
this class! Fields that need that must be
-    // moved into separate class, as it was done in _VersionInts, and 
_ObjectWrappers, to avoid class init deadlocks.
+    // moved into a separate class, to avoid class init deadlocks.
 
     public static void checkVersionNotNullAndSupported(Version 
incompatibleImprovements) {
         NullArgumentException.check("incompatibleImprovements", 
incompatibleImprovements);
diff --git a/src/main/java/freemarker/template/utility/CollectionUtils.java 
b/src/main/java/freemarker/template/utility/CollectionUtils.java
index 814fd1f0..a164286a 100644
--- a/src/main/java/freemarker/template/utility/CollectionUtils.java
+++ b/src/main/java/freemarker/template/utility/CollectionUtils.java
@@ -26,6 +26,8 @@ public class CollectionUtils {
 
     public static final Object[] EMPTY_OBJECT_ARRAY = new Object[] { };
 
+    public static final String[] EMPTY_STRING_ARRAY = new String[] { };
+
     public static final Class[] EMPTY_CLASS_ARRAY = new Class[] { };
 
     /**
diff --git a/src/main/java/freemarker/template/utility/StringUtil.java 
b/src/main/java/freemarker/template/utility/StringUtil.java
index 51f22a73..6d5f3fa0 100644
--- a/src/main/java/freemarker/template/utility/StringUtil.java
+++ b/src/main/java/freemarker/template/utility/StringUtil.java
@@ -933,7 +933,7 @@ public class StringUtil {
             } else {
                 b.append(c);
             }
-        } // for each characters
+        } // for each character
         b.append('"');
         return b.toString();
     }
@@ -1316,24 +1316,26 @@ public class StringUtil {
                     c = s.charAt(i);
                 }
             } // if has to be escaped
-        } // for each characters
+        } // for each character
         return quote ? '"' + s + '"' : s;
     }
     
     /**
      * Escapes a {@link String} to be safely insertable into a JavaScript 
string literal; for more see
-     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation) jsStringEnc(s, false, QuotationMode.NONE)}.
+     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation)
+     * jsStringEnc(s, JsStringEncCompatibility.JAVA_SCRIPT, null)}.
      */
     public static String javaScriptStringEnc(String s) {
-        return jsStringEnc(s, false);
+        return jsStringEnc(s, JsStringEncCompatibility.JAVA_SCRIPT);
     }
 
     /**
      * Escapes a {@link String} to be safely insertable into a JSON string 
literal; for more see
-     * {@link #jsStringEnc(String, boolean) jsStringEnc(s, true)}.
+     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation)
+     * jsStringEnc(s, JsStringEncCompatibility.JSON, null)}.
      */
     public static String jsonStringEnc(String s) {
-        return jsStringEnc(s, true);
+        return jsStringEnc(s, JsStringEncCompatibility.JSON);
     }
 
     private static final int NO_ESC = 0;
@@ -1342,14 +1344,27 @@ public class StringUtil {
     
     /**
      * Escapes a {@link String} to be safely insertable into a JSON or 
JavaScript string literal; for more see
-     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation) jsStringEnc(s, json, QuotationMode.NONE)}.
+     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation)
+     * jsStringEnc(s, json ? JsStringEncCompatibility.JSON : 
JsStringEncCompatibility.JAVA_SCRIPT, null)}.
      *
      * @since 2.3.20
+     * @deprecated Use {@link #jsStringEnc(String, JsStringEncCompatibility)} 
instead.
      */
+    @Deprecated
     public static String jsStringEnc(String s, boolean json) {
         return jsStringEnc(s, json ? JsStringEncCompatibility.JSON : 
JsStringEncCompatibility.JAVA_SCRIPT, null);
     }
 
+    /**
+     * Escapes a {@link String} to be safely insertable into a JSON or 
JavaScript string literal; for more see
+     * {@link #jsStringEnc(String, JsStringEncCompatibility, 
JsStringEncQuotation) jsStringEnc(s, compatibility, null)}.
+     *
+     * @since 2.3.32
+     */
+    public static String jsStringEnc(String s, JsStringEncCompatibility 
compatibility) {
+        return jsStringEnc(s, compatibility, null);
+    }
+
     /**
      * Escapes a {@link String} to be safely insertable into a JavaScript or a 
JSON string literal, and if the 3rd
      * argument is {@code true}, also adds quotation marks around it.
@@ -1520,7 +1535,7 @@ public class StringUtil {
             // Needs no escaping
                 
             if (sb != null) sb.append(c);
-        } // for each characters
+        } // for each character
 
         if (quotation != null) {
             sb.append(quotation.getSymbol());
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 2f9d3b7d..8569625e 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -10604,7 +10604,7 @@ cfg.setNumberFormat("@ua 0.####;; 
roundingMode=halfUp");</programlisting>
         linkend="gloss.unicode">UNICODE</link> text" (UTF-16). Nonetheless,
         there are situations when it must deal with <link
         linkend="gloss.charset">charsets</link>, because it has to exchange
-        data with the outer world that may uses various other charsets.</para>
+        data with the outer world that may use various other charsets.</para>
 
         <section>
           <title>The charset of the input</title>
@@ -16269,7 +16269,7 @@ rif: foo XYr baar</programlisting>
           <title>is_infinite</title>
 
           <indexterm>
-            <primary>is_infinte built-in</primary>
+            <primary>is_infinite built-in</primary>
           </indexterm>
 
           <indexterm>
@@ -28786,7 +28786,7 @@ End book</programlisting>
           <answer>
             <para>FreeMarker uses the locale-sensitive number formatting
             capability of the Java platform. The default number format for
-            your locale may uses grouping or other formatting. If you don't
+            your locale may use grouping or other formatting. If you don't
             want that, you have to override the number format suggested by the
             Java platform with the <literal>number_format</literal> <link
             linkend="pgui_config_settings">FreeMarker setting</link>. For
diff --git a/src/manual/zh_CN/book.xml b/src/manual/zh_CN/book.xml
index 81ef7fb4..e03ff448 100644
--- a/src/manual/zh_CN/book.xml
+++ b/src/manual/zh_CN/book.xml
@@ -20,10 +20,7 @@
 <book conformance="docgen" version="5.0" xml:lang="en"
       xmlns="http://docbook.org/ns/docbook";
       xmlns:xlink="http://www.w3.org/1999/xlink";
-      xmlns:ns5="http://www.w3.org/1999/xhtml";
-      xmlns:ns4="http://www.w3.org/2000/svg";
-      xmlns:ns3="http://www.w3.org/1998/Math/MathML";
-      xmlns:ns="http://docbook.org/ns/docbook";>
+>
   <info>
     <title>FreeMarker 手册</title>
 
@@ -11427,7 +11424,7 @@ rif: foo XYr baar</programlisting>
           <title>is_infinite</title>
 
           <indexterm>
-            <primary>is_infinte built-in</primary>
+            <primary>is_infinite built-in</primary>
           </indexterm>
 
           <indexterm>
diff --git 
a/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java 
b/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
index d8ca4d81..0feb90c8 100644
--- a/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
+++ b/src/test/java/freemarker/core/BooleanFormatEnvironmentCachingTest.java
@@ -45,13 +45,12 @@ public class BooleanFormatEnvironmentCachingTest extends 
TemplateTest {
                         + "<#setting cFormat='JSON'>${true} ${true} ${false} 
${false} "
                         + "<#setting booleanFormat='y,n'>${true} ${true} 
${false} ${false} "
                         + "<#setting cFormat='Java'>${true} ${true} ${false} 
${false} "
-                        + "<#setting booleanFormat='c'>${true} ${true} 
${false} ${false} ",
+                        + "<#setting booleanFormat='c'>${true} ${true} 
${false} ${false}",
                 ""
                         + "TRUE TRUE FALSE FALSE "
                         + "true true false false "
                         + "y y n n "
                         + "y y n n "
-                        + "true true false false "
-                        + "");
+                        + "true true false false");
     }
 }
\ No newline at end of file
diff --git a/src/test/java/freemarker/core/CFormatTemplateTest.java 
b/src/test/java/freemarker/core/CFormatTemplateTest.java
index 414a9011..fd8a66fa 100644
--- a/src/test/java/freemarker/core/CFormatTemplateTest.java
+++ b/src/test/java/freemarker/core/CFormatTemplateTest.java
@@ -70,4 +70,10 @@ public class CFormatTemplateTest extends TemplateTest {
                         + "Java: \"a'b\\\"c\\u0001\" ");
     }
 
+    @Test
+    public void testUnsafeSetting() throws TemplateException, IOException {
+        assertErrorContains("<#setting 
c_format='com.example.ExploitCFormat()'>", "not allowed");
+        assertErrorContains("<#setting 
cFormat='com.example.ExploitCFormat()'>", "not allowed");
+    }
+
 }
diff --git a/src/test/java/freemarker/core/NumberBiTest.java 
b/src/test/java/freemarker/core/NumberBiTest.java
index 3f3bd446..e4c1a8ce 100644
--- a/src/test/java/freemarker/core/NumberBiTest.java
+++ b/src/test/java/freemarker/core/NumberBiTest.java
@@ -51,10 +51,6 @@ public class NumberBiTest extends TemplateTest {
         assertNumberBi("+1", "1");
     }
 
-    private void assertThrowsNumberFormatException(String s) {
-        assertErrorContains("${'" + s + "'?number}", 
NonNumericalException.class, "\"" + s + "\"");
-    }
-
     private final void assertNumberBi(String input, String output) throws 
TemplateException, IOException {
         assertOutput("${'" + input + "'?number?c}", output);
     }
diff --git a/src/test/java/freemarker/template/ConfigurationTest.java 
b/src/test/java/freemarker/template/ConfigurationTest.java
index 756b3fae..72287e66 100644
--- a/src/test/java/freemarker/template/ConfigurationTest.java
+++ b/src/test/java/freemarker/template/ConfigurationTest.java
@@ -314,7 +314,7 @@ public class ConfigurationTest extends TestCase {
         assertTrue(cfg.isCFormatExplicitlySet());
         //
         cfg.unsetCFormat();
-        assertFalse(cfg.isTemplateLookupStrategyExplicitlySet());
+        assertFalse(cfg.isCFormatExplicitlySet());
     }
     
     public void testTemplateLoadingErrors() throws Exception {
@@ -1877,8 +1877,10 @@ public class ConfigurationTest extends TestCase {
             assertEquals(3, alg.getDefaultTerminatorLength());
             assertNull(alg.getDefaultMTerminator());
             assertNull(alg.getDefaultMTerminatorLength());
-            
assertEquals(DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
-                    alg.getWordBoundaryMinLength());
+            assertEquals(
+                    
DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
+                    alg.getWordBoundaryMinLength(),
+                    0);
         }
 
         {
@@ -1895,8 +1897,10 @@ public class ConfigurationTest extends TestCase {
             assertEquals("markupOutput(format=HTML, markup=<span 
class=trunc>...</span>)",
                     alg.getDefaultMTerminator().toString());
             assertEquals(Integer.valueOf(3), 
alg.getDefaultMTerminatorLength());
-            
assertEquals(DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
-                    alg.getWordBoundaryMinLength());
+            assertEquals(
+                    
DefaultTruncateBuiltinAlgorithm.DEFAULT_WORD_BOUNDARY_MIN_LENGTH,
+                    alg.getWordBoundaryMinLength(),
+                    0);
         }
 
         {
@@ -1931,8 +1935,8 @@ public class ConfigurationTest extends TestCase {
 
         for (CFormat standardCFormat : new CFormat[] {
                         LegacyCFormat.INSTANCE,
-                        JSONCFormat.INSTANCE, JavaScriptCFormat.INSTANCE, 
JavaCFormat.INSTANCE,
-                        XSCFormat.INSTANCE
+                        JSONCFormat.INSTANCE, JavaScriptCFormat.INSTANCE, 
JavaScriptOrJSONCFormat.INSTANCE,
+                        JavaCFormat.INSTANCE, XSCFormat.INSTANCE
                 }) {
             cfg.setSetting(Configuration.C_FORMAT_KEY, 
standardCFormat.getName());
             assertSame(standardCFormat, cfg.getCFormat());

Reply via email to