summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Doligez <damien.doligez-inria.fr>2015-03-11 18:41:15 +0000
committerDamien Doligez <damien.doligez-inria.fr>2015-03-11 18:41:15 +0000
commite60a2db81c19bfa391107b921841c0abec30c458 (patch)
tree4dbd97cf7e30527c848a365c1fb6dd3bf4c63f71
parent654521cbd41e93676375919fa35dfec0ea2647e0 (diff)
downloadocaml-e60a2db81c19bfa391107b921841c0abec30c458.tar.gz
PR#6521: {Bytes,Char,String}.escaped are locale-dependent
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@15901 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
-rw-r--r--Changes2
-rwxr-xr-xboot/ocamlcbin1748516 -> 1771772 bytes
-rwxr-xr-xboot/ocamldepbin537079 -> 540198 bytes
-rwxr-xr-xboot/ocamllexbin256366 -> 258562 bytes
-rw-r--r--byterun/str.c18
-rw-r--r--stdlib/bytes.ml25
-rw-r--r--stdlib/bytes.mli2
-rw-r--r--stdlib/char.ml8
-rw-r--r--stdlib/char.mli6
-rw-r--r--stdlib/string.ml4
-rw-r--r--stdlib/string.mli19
-rw-r--r--testsuite/tests/lib-string/Makefile19
-rw-r--r--testsuite/tests/lib-string/test_string.ml35
-rw-r--r--testsuite/tests/lib-string/test_string.reference0
14 files changed, 89 insertions, 49 deletions
diff --git a/Changes b/Changes
index e0f16abf91..0b0b9596d0 100644
--- a/Changes
+++ b/Changes
@@ -76,6 +76,8 @@ Bug fixes:
- PR#6171: Error message confusing when a type escapes its scope.
- PR#6340: Incorrect handling of \r when processing "Windows" source files
(Damien Doligez, report by David Allsopp)
+* PR#6521: String.escaped and Char.escaped are locale-dependent
+ (Damien Doligez, report by Jun Furuse)
- PR#6526: ocamllex warning: unescaped newline in comment string
(Damien Doligez, report by user 'dhekir')
- PR#6560: Wrong failure message for {Int32,Int64,NativeInt}.of_string
diff --git a/boot/ocamlc b/boot/ocamlc
index 659084ba60..09984ea492 100755
--- a/boot/ocamlc
+++ b/boot/ocamlc
Binary files differ
diff --git a/boot/ocamldep b/boot/ocamldep
index c5452cb0fd..5f36ae2460 100755
--- a/boot/ocamldep
+++ b/boot/ocamldep
Binary files differ
diff --git a/boot/ocamllex b/boot/ocamllex
index 5d399cc609..da06c45cf0 100755
--- a/boot/ocamllex
+++ b/boot/ocamllex
Binary files differ
diff --git a/byterun/str.c b/byterun/str.c
index e03dda6f53..5ad4e29419 100644
--- a/byterun/str.c
+++ b/byterun/str.c
@@ -21,9 +21,6 @@
#include "caml/fail.h"
#include "caml/mlvalues.h"
#include "caml/misc.h"
-#ifdef HAS_LOCALE
-#include <locale.h>
-#endif
/* returns a number of bytes (chars) */
CAMLexport mlsize_t caml_string_length(value s)
@@ -279,21 +276,6 @@ CAMLprim value caml_fill_string(value s, value offset, value len, value init)
return Val_unit;
}
-CAMLprim value caml_is_printable(value chr)
-{
- int c;
-
-#ifdef HAS_LOCALE
- static int locale_is_set = 0;
- if (! locale_is_set) {
- setlocale(LC_CTYPE, "");
- locale_is_set = 1;
- }
-#endif
- c = Int_val(chr);
- return Val_bool(isprint(c));
-}
-
CAMLprim value caml_bitvect_test(value bv, value n)
{
int pos = Int_val(n);
diff --git a/stdlib/bytes.ml b/stdlib/bytes.ml
index 193c3ceea1..32d4468c34 100644
--- a/stdlib/bytes.ml
+++ b/stdlib/bytes.ml
@@ -122,7 +122,6 @@ let cat s1 s2 =
r
;;
-external is_printable: char -> bool = "caml_is_printable"
external char_code: char -> int = "%identity"
external char_chr: int -> char = "%identity"
@@ -151,7 +150,8 @@ let escaped s =
n := !n +
(match unsafe_get s i with
| '"' | '\\' | '\n' | '\t' | '\r' | '\b' -> 2
- | c -> if is_printable c then 1 else 4)
+ | ' ' .. '~' -> 1
+ | _ -> 4)
done;
if !n = length s then copy s else begin
let s' = create !n in
@@ -168,19 +168,16 @@ let escaped s =
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'r'
| '\b' ->
unsafe_set s' !n '\\'; incr n; unsafe_set s' !n 'b'
+ | (' ' .. '~') as c -> unsafe_set s' !n c
| c ->
- if is_printable c then
- unsafe_set s' !n c
- else begin
- let a = char_code c in
- unsafe_set s' !n '\\';
- incr n;
- unsafe_set s' !n (char_chr (48 + a / 100));
- incr n;
- unsafe_set s' !n (char_chr (48 + (a / 10) mod 10));
- incr n;
- unsafe_set s' !n (char_chr (48 + a mod 10))
- end
+ let a = char_code c in
+ unsafe_set s' !n '\\';
+ incr n;
+ unsafe_set s' !n (char_chr (48 + a / 100));
+ incr n;
+ unsafe_set s' !n (char_chr (48 + (a / 10) mod 10));
+ incr n;
+ unsafe_set s' !n (char_chr (48 + a mod 10));
end;
incr n
done;
diff --git a/stdlib/bytes.mli b/stdlib/bytes.mli
index e9f713b912..621c619f78 100644
--- a/stdlib/bytes.mli
+++ b/stdlib/bytes.mli
@@ -179,6 +179,8 @@ val trim : bytes -> bytes
val escaped : bytes -> bytes
(** Return a copy of the argument, with special characters represented
by escape sequences, following the lexical conventions of OCaml.
+ All characters outside the ASCII printable range (32..126) are
+ escaped, as well as backslash and double-quote.
Raise [Invalid_argument] if the result is longer than
{!Sys.max_string_length} bytes. *)
diff --git a/stdlib/char.ml b/stdlib/char.ml
index 56aa5d4924..58afbc7585 100644
--- a/stdlib/char.ml
+++ b/stdlib/char.ml
@@ -19,8 +19,6 @@ external unsafe_chr: int -> char = "%identity"
let chr n =
if n < 0 || n > 255 then invalid_arg "Char.chr" else unsafe_chr n
-external is_printable: char -> bool = "caml_is_printable"
-
external string_create: int -> string = "caml_create_string"
external string_unsafe_get : string -> int -> char = "%string_unsafe_get"
external string_unsafe_set : string -> int -> char -> unit
@@ -33,12 +31,11 @@ let escaped = function
| '\t' -> "\\t"
| '\r' -> "\\r"
| '\b' -> "\\b"
- | c ->
- if is_printable c then begin
+ | ' ' .. '~' as c ->
let s = string_create 1 in
string_unsafe_set s 0 c;
s
- end else begin
+ | c ->
let n = code c in
let s = string_create 4 in
string_unsafe_set s 0 '\\';
@@ -46,7 +43,6 @@ let escaped = function
string_unsafe_set s 2 (unsafe_chr (48 + (n / 10) mod 10));
string_unsafe_set s 3 (unsafe_chr (48 + n mod 10));
s
- end
let lowercase c =
if (c >= 'A' && c <= 'Z')
diff --git a/stdlib/char.mli b/stdlib/char.mli
index 9eca9a297d..a5ad202114 100644
--- a/stdlib/char.mli
+++ b/stdlib/char.mli
@@ -23,8 +23,10 @@ val chr : int -> char
val escaped : char -> string
(** Return a string representing the given character,
- with special characters escaped following the lexical conventions
- of OCaml. *)
+ with special characters escaped following the lexical conventions
+ of OCaml.
+ All characters outside the ASCII printable range (32..126) are
+ escaped, as well as backslash, double-quote, and single-quote. *)
val lowercase : char -> char
[@@ocaml.deprecated "Use Char.lowercase_ascii instead."]
diff --git a/stdlib/string.ml b/stdlib/string.ml
index 0cea7acb74..ecb1be3c3b 100644
--- a/stdlib/string.ml
+++ b/stdlib/string.ml
@@ -73,8 +73,6 @@ let mapi f s =
copy, but String.mli spells out some cases where we are not allowed
to make a copy. *)
-external is_printable: char -> bool = "caml_is_printable"
-
let is_space = function
| ' ' | '\012' | '\n' | '\r' | '\t' -> true
| _ -> false
@@ -90,7 +88,7 @@ let escaped s =
if i >= length s then false else
match unsafe_get s i with
| '"' | '\\' | '\n' | '\t' | '\r' | '\b' -> true
- | c when is_printable c -> needs_escape (i+1)
+ | ' ' .. '~' -> needs_escape (i+1)
| _ -> true
in
if needs_escape 0 then
diff --git a/stdlib/string.mli b/stdlib/string.mli
index 82b26a3879..5b1233a6cf 100644
--- a/stdlib/string.mli
+++ b/stdlib/string.mli
@@ -158,13 +158,20 @@ val trim : string -> string
val escaped : string -> string
(** Return a copy of the argument, with special characters
- represented by escape sequences, following the lexical
- conventions of OCaml. If there is no special
- character in the argument, return the original string itself,
- not a copy. Its inverse function is Scanf.unescaped.
+ represented by escape sequences, following the lexical
+ conventions of OCaml.
+ All characters outside the ASCII printable range (32..126) are
+ escaped, as well as backslash and double-quote.
- Raise [Invalid_argument] if the result is longer than
- {!Sys.max_string_length} bytes. *)
+ If there is no special character in the argument that needs
+ escaping, return the original string itself, not a copy.
+
+ Raise [Invalid_argument] if the result is longer than
+ {!Sys.max_string_length} bytes.
+
+ The function {!Scanf.unescaped} is a left inverse of [escaped],
+ i.e. [Scanf.unescaped (escaped s) = s] for any string [s] (unless
+ [escape s] fails). *)
val index : string -> char -> int
(** [String.index s c] returns the index of the first
diff --git a/testsuite/tests/lib-string/Makefile b/testsuite/tests/lib-string/Makefile
new file mode 100644
index 0000000000..6ae7266b0c
--- /dev/null
+++ b/testsuite/tests/lib-string/Makefile
@@ -0,0 +1,19 @@
+#########################################################################
+# #
+# OCaml #
+# #
+# Xavier Clerc, SED, INRIA Rocquencourt #
+# #
+# Copyright 2010 Institut National de Recherche en Informatique et #
+# en Automatique. All rights reserved. This file is distributed #
+# under the terms of the Q Public License version 1.0. #
+# #
+#########################################################################
+
+BASEDIR=../..
+LIBRARIES=str
+ADD_COMPFLAGS=-I $(OTOPDIR)/otherlibs/str
+LD_PATH=$(TOPDIR)/otherlibs/str
+
+include $(BASEDIR)/makefiles/Makefile.several
+include $(BASEDIR)/makefiles/Makefile.common
diff --git a/testsuite/tests/lib-string/test_string.ml b/testsuite/tests/lib-string/test_string.ml
new file mode 100644
index 0000000000..4ead7028be
--- /dev/null
+++ b/testsuite/tests/lib-string/test_string.ml
@@ -0,0 +1,35 @@
+(***********************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Damien Doligez, Jane Street Capital *)
+(* *)
+(* Copyright 2015 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+let rec build_string f n accu =
+ if n <= 0
+ then String.concat "" accu
+ else build_string f (n-1) (f (n-1) :: accu)
+;;
+
+let char n = String.make 1 (Char.chr n);;
+
+let reference n =
+ if n = 8 then "\\b"
+ else if n = 9 then "\\t"
+ else if n = 10 then "\\n"
+ else if n = 13 then "\\r"
+ else if n = Char.code '"' then "\\\""
+ else if n = Char.code '\\' then "\\\\"
+ else if n < 32 || n > 126 then Printf.sprintf "\\%03d" n
+ else char n
+;;
+
+let raw_string = build_string char 256 [];;
+let ref_string = build_string reference 256 [];;
+
+if String.escaped raw_string <> ref_string then failwith "test:String.escaped";;
diff --git a/testsuite/tests/lib-string/test_string.reference b/testsuite/tests/lib-string/test_string.reference
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/lib-string/test_string.reference