Commit 5b55e2b7 authored by Pietro Abate's avatar Pietro Abate

[r2003-05-10 14:44:29 by cvscast] Start Unicode support. Remove more generic comparisons

Original author: cvscast
Date: 2003-05-10 14:44:30+00:00
parent 12f6a97c
......@@ -42,7 +42,7 @@ XWEBIFACE = $(WEBIFACE:.cmo=.cmx)
DEBUG = -g
PACKAGES = pxp-engine,pxp-lex-iso88591,wlexing,camlp4,num,cgi
PACKAGES = pxp-engine,pxp-lex-iso88591,pxp-wlex-utf8,wlexing,camlp4,num,cgi
OCAMLCP = ocamlc
OCAMLC = ocamlfind $(OCAMLCP) -package $(PACKAGES)
OCAMLOPT = ocamlfind ocamlopt -package $(PACKAGES)
......
......@@ -11,13 +11,15 @@ parser/ast.cmx: types/ident.cmx parser/location.cmx types/types.cmx
parser/location.cmo: parser/location.cmi
parser/location.cmx: parser/location.cmi
parser/parser.cmo: parser/ast.cmo types/atoms.cmi types/builtin.cmo \
types/chars.cmi types/ident.cmo types/intervals.cmi parser/location.cmi \
types/sequence.cmi types/types.cmi parser/wlexer.cmo parser/parser.cmi
types/chars.cmi misc/encodings.cmi types/ident.cmo types/intervals.cmi \
parser/location.cmi types/sequence.cmi types/types.cmi parser/wlexer.cmo \
parser/parser.cmi
parser/parser.cmx: parser/ast.cmx types/atoms.cmx types/builtin.cmx \
types/chars.cmx types/ident.cmx types/intervals.cmx parser/location.cmx \
types/sequence.cmx types/types.cmx parser/wlexer.cmx parser/parser.cmi
parser/wlexer.cmo: parser/location.cmi
parser/wlexer.cmx: parser/location.cmx
types/chars.cmx misc/encodings.cmx types/ident.cmx types/intervals.cmx \
parser/location.cmx types/sequence.cmx types/types.cmx parser/wlexer.cmx \
parser/parser.cmi
parser/wlexer.cmo: misc/encodings.cmi parser/location.cmi
parser/wlexer.cmx: misc/encodings.cmx parser/location.cmx
typing/typed.cmo: types/ident.cmo parser/location.cmi types/patterns.cmi \
types/types.cmi
typing/typed.cmx: types/ident.cmx parser/location.cmx types/patterns.cmx \
......@@ -80,18 +82,18 @@ runtime/print_xml.cmo: types/atoms.cmi types/chars.cmi types/ident.cmo \
types/sequence.cmi runtime/value.cmi
runtime/print_xml.cmx: types/atoms.cmx types/chars.cmx types/ident.cmx \
types/sequence.cmx runtime/value.cmx
runtime/run_dispatch.cmo: types/atoms.cmi types/chars.cmi types/ident.cmo \
types/patterns.cmi types/types.cmi runtime/value.cmi \
runtime/run_dispatch.cmo: types/atoms.cmi types/chars.cmi misc/encodings.cmi \
types/ident.cmo types/patterns.cmi types/types.cmi runtime/value.cmi \
runtime/run_dispatch.cmi
runtime/run_dispatch.cmx: types/atoms.cmx types/chars.cmx types/ident.cmx \
types/patterns.cmx types/types.cmx runtime/value.cmx \
runtime/run_dispatch.cmx: types/atoms.cmx types/chars.cmx misc/encodings.cmx \
types/ident.cmx types/patterns.cmx types/types.cmx runtime/value.cmx \
runtime/run_dispatch.cmi
runtime/value.cmo: types/atoms.cmi types/builtin.cmo types/chars.cmi \
types/ident.cmo types/intervals.cmi types/sequence.cmi types/types.cmi \
runtime/value.cmi
misc/encodings.cmi types/ident.cmo types/intervals.cmi types/sequence.cmi \
types/types.cmi runtime/value.cmi
runtime/value.cmx: types/atoms.cmx types/builtin.cmx types/chars.cmx \
types/ident.cmx types/intervals.cmx types/sequence.cmx types/types.cmx \
runtime/value.cmi
misc/encodings.cmx types/ident.cmx types/intervals.cmx types/sequence.cmx \
types/types.cmx runtime/value.cmi
driver/cduce.cmo: parser/ast.cmo types/builtin.cmo runtime/eval.cmi \
types/ident.cmo parser/location.cmi parser/parser.cmi types/patterns.cmi \
misc/state.cmi typing/typed.cmo typing/typer.cmi types/types.cmi \
......@@ -123,5 +125,5 @@ types/types.cmi: types/atoms.cmi types/chars.cmi types/ident.cmo \
runtime/eval.cmi: types/ident.cmo typing/typed.cmo runtime/value.cmi
runtime/load_xml.cmi: runtime/value.cmi
runtime/run_dispatch.cmi: types/patterns.cmi runtime/value.cmi
runtime/value.cmi: types/atoms.cmi types/chars.cmi types/ident.cmo \
types/intervals.cmi types/types.cmi
runtime/value.cmi: types/atoms.cmi types/chars.cmi misc/encodings.cmi \
types/ident.cmo types/intervals.cmi types/types.cmi
type uchar = int
module type T =
sig
val get: string -> int -> uchar
val next: string -> int -> int
val put: string -> int -> uchar -> int
val bytes: uchar -> int
end
module Iso88591 =
struct
let get s i = Char.code s.[i]
let next s i = succ i
let put s i c = s.[i] <- Char.chr i; succ i
let bytes c = 1
end
module Utf8 =
struct
type ustring = string
type uindex = int
let start_index s = 0
let end_index s = String.length s
let equal_index = (==)
let mk s = s
let get_str s = s
let get_idx i = i
(* TODO: handle 5,6 bytes chars; report malformed UTF-8 *)
let get s i =
match s.[i] with
......@@ -39,18 +31,71 @@ struct
((Char.code s.[i+3] - 128))
| _ -> failwith "Malformed UTF-8 bufffer"
let next s i =
match s.[i] with
| '\000'..'\127' as c ->
Char.code c, i + 1
| '\192'..'\223' as c ->
((Char.code c - 192) lsl 6) lor
((Char.code s.[i+1] - 128)), i + 2
| '\224'..'\239' as c ->
((Char.code c - 192) lsl 12) lor
((Char.code s.[i+1] - 128) lsl 6) lor
((Char.code s.[i+2] - 128)), i + 3
| '\240'..'\248' as c ->
((Char.code c - 192) lsl 18) lor
((Char.code s.[i+1] - 128) lsl 12) lor
((Char.code s.[i+2] - 128) lsl 6) lor
((Char.code s.[i+3] - 128)), i + 4
| _ -> failwith "Malformed UTF-8 bufffer"
let advance s i =
match s.[i] with
| '\000'..'\127' as c -> i + 1
| '\192'..'\223' as c -> i + 2
| '\224'..'\239' as c -> i + 3
| '\240'..'\248' as c -> i + 4
| _ -> failwith "Malformed UTF-8 bufffer"
(*
let width = Array.create 256 1
let () =
for i = 192 to 223 do width.(i) <- 2 done;
for i = 224 to 249 do width.(i) <- 3 done;
for i = 240 to 248 do width.(i) <- 4 done
let next s i =
let len s i =
Array.unsafe_get width (Char.code s.[i])
*)
let store b p =
(* Adapted from Netstring's netconversion.ml/write_utf8 *)
if p <= 127 then
Buffer.add_char b (Char.chr p)
else if p <= 0x7ff then (
Buffer.add_char b (Char.chr (0xc0 lor (p lsr 6)));
Buffer.add_char b (Char.chr (0x80 lor (p land 0x3f)))
)
else if p <= 0xffff then (
(* Refuse writing surrogate pairs, and fffe, ffff *)
if (p >= 0xd800 & p < 0xe000) or (p >= 0xfffe) then
failwith "Encodings.Utf8.store";
Buffer.add_char b (Char.chr (0xe0 lor (p lsr 12)));
Buffer.add_char b (Char.chr (0x80 lor ((p lsr 6) land 0x3f)));
Buffer.add_char b (Char.chr (0x80 lor (p land 0x3f)))
)
else if p <= 0x10ffff then (
Buffer.add_char b (Char.chr (0xf0 lor (p lsr 18)));
Buffer.add_char b (Char.chr (0x80 lor ((p lsr 12) land 0x3f)));
Buffer.add_char b (Char.chr (0x80 lor ((p lsr 6) land 0x3f)));
Buffer.add_char b (Char.chr (0x80 lor (p land 0x3f)))
)
else
(* Higher code points are not possible in XML: *)
failwith "Encodings.Utf8.store"
let put s i c =
failwith "Encodings.Utf8.put: not yet implemented"
let copy b s i j =
Buffer.add_substring b s i (j - i)
let bytes c =
failwith "Encodings.Utf8.bytes: not yet implemented"
let get_substr s i j =
String.sub s i (j - i)
end
type uchar = int
module type T =
module Utf8 :
sig
val get: string -> int -> uchar
val next: string -> int -> int
type ustring
type uindex
val put: string -> int -> uchar -> int
val bytes: uchar -> int
end
val end_index: ustring -> uindex
val start_index: ustring -> uindex
val equal_index: uindex -> uindex -> bool
val mk: string -> ustring
val get_str: ustring -> string
val get_idx: uindex -> int
val get: ustring -> uindex -> uchar
val advance: ustring -> uindex -> uindex
val next: ustring -> uindex -> uchar * uindex
module Iso88591 : T
module Utf8 : T
val store: Buffer.t -> uchar -> unit
val copy: Buffer.t -> ustring -> uindex -> uindex -> unit
val get_substr: ustring -> uindex -> uindex -> string
end
......@@ -36,12 +36,16 @@ let string_regexp = Star (Elem char)
let cst_nil = mknoloc (Cst (Types.Atom Sequence.nil_atom))
let seq_of_string pos s =
let s = Encodings.Utf8.mk s in
(* What about locations when input file is not Utf8 ? *)
let (pos,_) = pos in
let rec aux accu i =
if (i = 0)
then accu
else aux (((pos+i,pos+i+1),s.[i-1])::accu) (i-1) in
aux [] (String.length s)
let rec aux pos i j =
if Encodings.Utf8.equal_index i j then []
else
let (c,i) = Encodings.Utf8.next s i in
((pos,pos+1),c)::(aux (pos+1) i j)
in
aux pos (Encodings.Utf8.start_index s) (Encodings.Utf8.end_index s)
exception Error of string
let error (i,j) s = Location.raise_loc i j (Error s)
......@@ -50,14 +54,14 @@ let make_record loc r =
LabelMap.from_list (fun _ _ -> error loc "Duplicated record field") r
let parse_char loc s =
(* TODO: Unicode *)
if String.length s <> 1 then
error loc "Character litteral must have length 1";
s.[0]
let s = seq_of_string loc s in
match s with
| [_,c] -> c
| _ -> error loc "Character litteral must have length 1"
let char_list pos s =
let s = seq_of_string pos s in
List.map (fun (loc,c) -> mk loc (Cst (Types.Char (Chars.mk_char c)))) s
List.map (fun (loc,c) -> mk loc (Cst (Types.Char (Chars.mk_int c)))) s
let include_stack = ref []
......@@ -285,14 +289,14 @@ EXTEND
Elem (mk loc (Constant ((ident a,c))))
| UIDENT "PCDATA" -> string_regexp
| i = STRING1; "--"; j = STRING1 ->
let i = Chars.mk_char (parse_char loc i)
and j = Chars.mk_char (parse_char loc j) in
let i = Chars.mk_int (parse_char loc i)
and j = Chars.mk_int (parse_char loc j) in
Elem (mk loc (Internal (Types.char (Chars.char_class i j))))
| s = STRING1 ->
let s = seq_of_string loc s in
List.fold_right
(fun (loc,c) accu ->
let c = Chars.mk_char c in
let c = Chars.mk_int c in
let c = Chars.atom c in
Seq (Elem (mk loc (Internal (Types.char c))), accu))
s
......@@ -356,7 +360,7 @@ EXTEND
mk loc (Internal
(Types.char
(Chars.atom
(Chars.mk_char c))))) s in
(Chars.mk_int c))))) s in
let s = s @ [mk loc (Internal (Sequence.nil_type))] in
multi_prod loc s
]
......@@ -375,8 +379,7 @@ EXTEND
char:
[
[ c = STRING1 -> Chars.mk_char (parse_char loc c)
| "!"; i = INT -> Chars.mk_int (int_of_string i) ]
[ c = STRING1 -> Chars.mk_int (parse_char loc c) ]
];
......
This diff is collapsed.
......@@ -19,28 +19,34 @@ classes
exception Unterminated_string_in_comment
(* Buffer for string literals *)
(* Buffer for string literals : always encoded in Utf8 *)
let string_buff = Buffer.create 1024
let store_char = Buffer.add_char string_buff
let store_ascii = Buffer.add_char string_buff
let store_char = Buffer.add_string string_buff
let store_code = Encodings.Utf8.store string_buff
let get_stored_string () =
let s = Buffer.contents string_buff in
Buffer.clear string_buff;
s
let store_special = function
| 'n' -> store_char '\n'
| 'r' -> store_char '\r'
| 't' -> store_char '\t'
| 'n' -> store_ascii '\n'
| 'r' -> store_ascii '\r'
| 't' -> store_ascii '\t'
| c -> raise (Illegal_character '\\')
let string_start_pos = ref 0;;
let comment_start_pos : int list ref = ref [];;
let char_for_decimal_code s =
let s = String.sub s 1 (String.length s - 1) in
let c = int_of_string s in
assert ( c < 256 ); (* TODO: handle Unicode *)
Char.chr c
let numeric_char s =
int_of_string (String.sub s 1 (String.length s - 2))
let hexa_char s =
let rec aux i accu =
if i = String.length s - 1 then accu
else aux (succ i) (accu * 16 + Char.code s.[i] - Char.code '0')
in
aux 0 0
let rec tag_of_tag s i =
match s.[i] with
......@@ -53,6 +59,8 @@ classes
let identchar = lowercase | uppercase | ascii_digit | '_' | '\'' | '-'
let ident = identchar* ( ':' identchar+)*
let numeric_char = '\\' ascii_digit+ ';'
rule token = parse
blank+ { token engine lexbuf }
| (lowercase | '_') ident {
......@@ -75,7 +83,7 @@ rule token = parse
{ let string_start = Lexing.lexeme_start lexbuf in
string_start_pos := string_start;
let double_quote = Lexing.lexeme_char lexbuf 0 = '"' in
if double_quote then string2 engine lexbuf else string1 engine lexbuf;
string (Lexing.lexeme lexbuf) engine lexbuf;
lexbuf.Lexing.lex_start_pos <-
string_start - lexbuf.Lexing.lex_abs_pos;
(if double_quote then "STRING2" else "STRING1"),
......@@ -104,9 +112,8 @@ and comment = parse
}
| '"' | "'"
{ string_start_pos := Lexing.lexeme_start lexbuf;
let string =
if Lexing.lexeme_char lexbuf 0 = '"' then string2 else string1 in
(try string engine lexbuf
let ender = Lexing.lexeme lexbuf in
(try string ender engine lexbuf
with Location.Location (_,Unterminated_string) ->
let st = List.hd !comment_start_pos in
error st (st+2) Unterminated_string_in_comment);
......@@ -119,42 +126,35 @@ and comment = parse
| _
{ comment engine lexbuf }
and string2 = parse
'"'
{ () }
and string ender = parse
| '"' | "'"
{
let c = Lexing.lexeme lexbuf in
if c = ender then ()
else (store_char (Lexing.lexeme lexbuf); string ender engine lexbuf)
}
| '\\' ['\\' '"']
{ store_char (Lexing.lexeme_char lexbuf 1);
string2 engine lexbuf }
{ store_ascii (Lexing.lexeme_char lexbuf 1);
string ender engine lexbuf }
| '\\' lowercase {
store_special (Lexing.lexeme_char lexbuf 1);
string1 engine lexbuf }
| '\\' ascii_digit+
{ store_char (char_for_decimal_code (Lexing.lexeme lexbuf));
string2 engine lexbuf }
let c = Lexing.lexeme_char lexbuf 1 in
if c = 'x' then parse_hexa_char engine lexbuf else store_special c;
string ender engine lexbuf }
| numeric_char
{ store_code (numeric_char (Lexing.lexeme lexbuf));
string ender engine lexbuf }
| eof
{ error !string_start_pos (!string_start_pos+1) Unterminated_string }
| _
{ store_char (Lexing.lexeme_char lexbuf 0);
(* TODO: Unicode *)
string2 engine lexbuf }
and string1 = parse
"'"
{ () }
| '\\' ['\\' '\'']
{ store_char (Lexing.lexeme_char lexbuf 1);
string1 engine lexbuf }
| '\\' lowercase {
store_special (Lexing.lexeme_char lexbuf 1);
string1 engine lexbuf }
| '\\' ascii_digit+
{ store_char (char_for_decimal_code (Lexing.lexeme lexbuf));
string1 engine lexbuf }
| eof
{ error !string_start_pos (!string_start_pos+1) Unterminated_string }
{ store_code (Char.code (Lexing.lexeme_char lexbuf 0)); (* Adapt when source is UTF8 *)
string ender engine lexbuf }
and parse_hexa_char = parse
| ascii_digit+ ';'
{ store_code (hexa_char (Lexing.lexeme lexbuf)) }
| _
{ store_char (Lexing.lexeme_char lexbuf 0);
string1 engine lexbuf }
{ store_char "\\x";
store_char (Lexing.lexeme lexbuf); }
{
......
......@@ -11,7 +11,7 @@ let enter_global x v = global_env := Env.add x v !global_env
let exn_int_of = CDuceExn (Pair (
Atom (Atoms.mk "Invalid_argument"),
string "int_of"))
string_latin1 "int_of"))
......@@ -113,7 +113,7 @@ and eval_map env brs = function
| Pair (x,y) ->
let x = eval_branches env brs x in
Pair (x, eval_map env brs y)
| String (_,_,_,_) as v -> eval_map env brs (normalize v)
| String_latin1 (_,_,_,_) | String_utf8 (_,_,_,_) as v -> eval_map env brs (normalize v)
| q -> q
and eval_flatten = function
......@@ -124,7 +124,7 @@ and eval_transform env brs = function
| Pair (x,y) ->
let x = eval_branches env brs x in
eval_concat x (eval_transform env brs y)
| String (_,_,_,_) as v -> eval_transform env brs (normalize v)
| String_latin1 (_,_,_,_) | String_utf8 (_,_,_,_) as v -> eval_transform env brs (normalize v)
| q -> q
and eval_ttree env brs = function
......@@ -142,13 +142,14 @@ and eval_ttree env brs = function
| Xml (_,_) -> assert false
| x -> x in
Pair (x,y))
| String (_,_,_,_) as v -> eval_ttree env brs (normalize v)
| String_latin1 (_,_,_,_) | String_utf8 (_,_,_,_) as v -> eval_ttree env brs (normalize v)
(* TODO: optimize for strings, to avoid decomposing compound String values *)
| q -> q
and eval_concat l1 l2 = match l1 with
| Pair (x,y) -> Pair (x, eval_concat y l2)
| String (s,i,j,q) -> String (s,i,j, eval_concat q l2)
| String_latin1 (s,i,j,q) -> String_latin1 (s,i,j, eval_concat q l2)
| String_utf8 (s,i,j,q) -> String_utf8 (s,i,j, eval_concat q l2)
| q -> l2
and eval_dot l = function
......@@ -181,38 +182,38 @@ and eval_mod x y = match (x,y) with
| _ -> assert false
and eval_load_xml e =
Load_xml.load_xml (get_string e)
Load_xml.load_xml (get_string_latin1 e)
and eval_load_html e =
Load_xml.load_html (get_string e)
Load_xml.load_html (get_string_latin1 e)
and eval_load_file e =
Location.protect_op "load_file";
let ic = open_in (get_string e) in
let ic = open_in (get_string_latin1 e) in
let len = in_channel_length ic in
let s = String.create len in
really_input ic s 0 len;
close_in ic;
Value.string s
Value.string_latin1 s
and eval_int_of e =
let s = get_string e in
let s = get_string_latin1 e in
try Integer (Intervals.mk s)
with Failure _ -> raise exn_int_of
and eval_print_xml v =
string (Print_xml.string_of_xml v)
string_latin1 (Print_xml.string_of_xml v)
and eval_print v =
Location.protect_op "print";
print_string (get_string v);
print_string (get_string_latin1 v);
flush stdout;
Value.nil
and eval_dump_to_file f v =
Location.protect_op "dump_to_file";
let oc = open_out (get_string f) in
output_string oc (get_string v);
let oc = open_out (get_string_latin1 f) in
output_string oc (get_string_latin1 v);
close_out oc;
Value.nil
......@@ -222,7 +223,7 @@ and eval_string_of v =
let ppf = Format.formatter_of_buffer b in
Value.print ppf v;
Format.pp_print_flush ppf ();
string (Buffer.contents b)
string_latin1 (Buffer.contents b)
and eval_equal v1 v2 =
let c = Value.compare v1 v2 in
......
......@@ -17,18 +17,22 @@ let is_ws s =
check (String.length s - 1)
let string s q =
String (0,String.length s,s,q)
let string_latin1 s q =
String_latin1 (0,String.length s,s,q)
let attrib att =
let att = List.map (fun (l,v) -> LabelPool.mk l, string v nil) att in
let att = List.map (fun (l,v) -> LabelPool.mk l, string_latin1 v nil) att in
LabelMap.from_list (fun _ _ -> assert false) att
let elem tag att child =
Xml (Atom (Atoms.mk tag), Pair (Record (attrib att), child))
class warner = object method warn w = print_endline ("PXP WARNING: " ^ w) end
let load_xml_aux s =
let config = { default_config with
(* warner = new warner; *)
(* encoding = `Enc_utf8; *)
store_element_positions = false;
drop_ignorable_whitespace = true
}
......@@ -57,7 +61,7 @@ let load_xml_aux s =
and dump_txt q =
let data = Buffer.contents txt in
Buffer.clear txt;
if (is_ws data) then q () else string data (q ())
if (is_ws data) then q () else string_latin1 data (q ())
and parse_seq () =
match !curr with
......@@ -96,7 +100,7 @@ let load_xml s =
let load_html s =
let rec val_of_doc q = function
| Nethtml.Data data ->
if (is_ws data) then q else string data q
if (is_ws data) then q else string_latin1 data q
| Nethtml.Element (tag, att, child) ->
Pair (elem tag att (val_of_docs child), q)
and val_of_docs = function
......@@ -104,7 +108,7 @@ let load_html s =
| h::t -> val_of_doc (val_of_docs t) h
in
Location.protect_op "load_xml";
Location.protect_op "load_html";
let ic = open_in s in
let doc = Nethtml.parse_document
~dtd:Nethtml.relaxed_html40_dtd
......
......@@ -7,7 +7,7 @@ open Ident
let exn_print_xml = CDuceExn (Pair (
Atom (Atoms.mk "Invalid_argument"),
string "print_xml"))
string_latin1 "print_xml"))
let to_enc = `Enc_iso88591
......@@ -20,9 +20,9 @@ let string_of_xml v=
~to_enc
(`Out_buffer buffer)
and wds =
and wds ?(from_enc=`Enc_iso88591) =
write_data_string
~from_enc:`Enc_iso88591
~from_enc
~to_enc
(`Out_buffer buffer)
in
......@@ -46,7 +46,7 @@ let string_of_xml v=
let attrs = LabelMap.mapi_to_list
(fun n v ->
if not (is_str v) then raise exn_print_xml;
(LabelPool.value n,get_string v)) attrs in
(LabelPool.value n,get_string_latin1 v)) attrs in
(match content with
| Atom a when a = Sequence.nil_atom -> empty_element tag attrs
| _ ->
......@@ -57,9 +57,12 @@ let string_of_xml v=
wds (String.make 1 (Chars.to_char x)); (* TODO: opt *)
| _ -> raise exn_print_xml
and print_content = function
| String (i,j,s,q) ->
| String_latin1 (i,j,s,q) ->
wds (String.sub s i (j - i));
print_content q
| String_utf8 (i,j,s,q) ->
wds ~from_enc:`Enc_utf8 (Encodings.Utf8.get_substr s i j);
print_content q
| Pair (elt, q) ->
print_elt elt;
print_content q
......
......@@ -8,6 +8,7 @@
open Value
open Ident
open Patterns.Compile
open Encodings
let buffer = ref (Array.create 127 Absent)
......@@ -83,23 +84,23 @@ let make_result_char ch (code,r) =
cursor := !cursor + n;
code )
let tail_string i j s q =
if i + 1 = j then q else String (i + 1,j,s,q)
let tail_string_latin1 i j s q =
if i + 1 = j then q else String_latin1 (i + 1,j,s,q)
let make_result_string i j s q r1 r2 (code,r) =
let make_result_string_latin1 i j s q r1 r2 (code,r) =