diff options
| author | Damien Doligez <damien.doligez-inria.fr> | 2015-03-11 18:41:15 +0000 |
|---|---|---|
| committer | Damien Doligez <damien.doligez-inria.fr> | 2015-03-11 18:41:15 +0000 |
| commit | e60a2db81c19bfa391107b921841c0abec30c458 (patch) | |
| tree | 4dbd97cf7e30527c848a365c1fb6dd3bf4c63f71 | |
| parent | 654521cbd41e93676375919fa35dfec0ea2647e0 (diff) | |
| download | ocaml-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-- | Changes | 2 | ||||
| -rwxr-xr-x | boot/ocamlc | bin | 1748516 -> 1771772 bytes | |||
| -rwxr-xr-x | boot/ocamldep | bin | 537079 -> 540198 bytes | |||
| -rwxr-xr-x | boot/ocamllex | bin | 256366 -> 258562 bytes | |||
| -rw-r--r-- | byterun/str.c | 18 | ||||
| -rw-r--r-- | stdlib/bytes.ml | 25 | ||||
| -rw-r--r-- | stdlib/bytes.mli | 2 | ||||
| -rw-r--r-- | stdlib/char.ml | 8 | ||||
| -rw-r--r-- | stdlib/char.mli | 6 | ||||
| -rw-r--r-- | stdlib/string.ml | 4 | ||||
| -rw-r--r-- | stdlib/string.mli | 19 | ||||
| -rw-r--r-- | testsuite/tests/lib-string/Makefile | 19 | ||||
| -rw-r--r-- | testsuite/tests/lib-string/test_string.ml | 35 | ||||
| -rw-r--r-- | testsuite/tests/lib-string/test_string.reference | 0 |
14 files changed, 89 insertions, 49 deletions
@@ -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 Binary files differindex 659084ba60..09984ea492 100755 --- a/boot/ocamlc +++ b/boot/ocamlc diff --git a/boot/ocamldep b/boot/ocamldep Binary files differindex c5452cb0fd..5f36ae2460 100755 --- a/boot/ocamldep +++ b/boot/ocamldep diff --git a/boot/ocamllex b/boot/ocamllex Binary files differindex 5d399cc609..da06c45cf0 100755 --- a/boot/ocamllex +++ b/boot/ocamllex 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 |
