1(*
2
3A testbed file for the module Scanf.
4
5*)
6
7open Testing;;
8
9open Scanf;;
10
11(* The ``continuation'' that returns the scanned value. *)
12let id x = x;;
13
14(* Testing space scanning. *)
15let test0 () =
16  (sscanf "" "" id) 1 +
17  (sscanf "" " " id) 2 +
18  (sscanf " " " " id) 3 +
19  (sscanf "\t" " " id) 4 +
20  (sscanf "\n" " " id) 5 +
21  (sscanf "\n\t 6" " %d" id)
22;;
23
24test (test0 () = 21)
25;;
26
27(* Testing integer scanning %i and %d. *)
28let test1 () =
29  sscanf "1" "%d" id +
30  sscanf " 2" " %d" id +
31  sscanf " -2" " %d" id +
32  sscanf " +2" " %d" id +
33  sscanf " 2a " " %da" id
34;;
35
36test (test1 () = 5)
37;;
38
39let test2 () =
40  sscanf "123" "%2i" id +
41  sscanf "245" "%d" id +
42  sscanf " 2a " " %1da" id
43;;
44
45test (test2 () = 259)
46;;
47
48let test3 () =
49  sscanf "0xff" "%3i" id +
50  sscanf "0XEF" "%3i" id +
51  sscanf "x=-245" " x = %d" id +
52  sscanf " 2a " " %1da" id
53;;
54
55test (test3 () = -214)
56;;
57
58(* Testing float scanning. *)
59(* f style. *)
60let test4 () =
61  bscanf (Scanning.from_string "1")
62    "%f" (fun b0 -> b0 = 1.0) &&
63  bscanf (Scanning.from_string "-1")
64    "%f" (fun b0 -> b0 = -1.0) &&
65  bscanf (Scanning.from_string "+1")
66    "%f" (fun b0 -> b0 = 1.0) &&
67  bscanf (Scanning.from_string "1.")
68    "%f" (fun b0 -> b0 = 1.0) &&
69  bscanf (Scanning.from_string ".1")
70    "%f" (fun b0 -> b0 = 0.1) &&
71  bscanf (Scanning.from_string "-.1")
72    "%f" (fun b0 -> b0 = -0.1) &&
73  bscanf (Scanning.from_string "+.1")
74    "%f" (fun b0 -> b0 = 0.1) &&
75  bscanf (Scanning.from_string "+1.")
76    "%f" (fun b0 -> b0 = 1.0) &&
77  bscanf (Scanning.from_string "-1.")
78    "%f" (fun b0 -> b0 = -1.0) &&
79  bscanf (Scanning.from_string "0 1. 1.3")
80    "%f %f %f" (fun b0 b1 b2 -> b0 = 0.0 && b1 = 1.0 && b2 = 1.3) &&
81  bscanf (Scanning.from_string "0.113")
82    "%4f" (fun b0 -> b0 = 0.11) &&
83  bscanf (Scanning.from_string "0.113")
84    "%5f" (fun b0 -> b0 = 0.113) &&
85  bscanf (Scanning.from_string "000.113")
86    "%15f" (fun b0 -> b0 = 0.113) &&
87  bscanf (Scanning.from_string "+000.113")
88    "%15f" (fun b0 -> b0 = 0.113) &&
89  bscanf (Scanning.from_string "-000.113")
90    "%15f" (fun b0 -> b0 = -0.113)
91;;
92test (test4 ())
93;;
94
95let same_float x y =
96  let is_nan z = (z <> z) in
97  if is_nan x then is_nan y
98  else Int64.bits_of_float y = Int64.bits_of_float x
99;;
100
101(* e style. *)
102let test5 () =
103  bscanf (Scanning.from_string "1e1")
104    "%e" (fun b -> b = 10.0) &&
105  bscanf (Scanning.from_string "1e+1")
106    "%e" (fun b -> b = 10.0) &&
107  bscanf (Scanning.from_string "10e-1")
108    "%e" (fun b -> b = 1.0) &&
109  bscanf (Scanning.from_string "10.e-1")
110    "%e" (fun b -> b = 1.0) &&
111  bscanf (Scanning.from_string "1e1 1.e+1 1.3e-1")
112    "%e %e %e" (fun b1 b2 b3 -> b1 = 10.0 && b2 = b1 && b3 = 0.13) &&
113
114(* g style. *)
115  bscanf (Scanning.from_string "1 1.1 0e+1 1.3e-1")
116    "%g %g %g %g"
117    (fun b1 b2 b3 b4 ->
118     b1 = 1.0 && b2 = 1.1 && b3 = 0.0 && b4 = 0.13)
119  &&
120(* F style *)
121  bscanf (Scanning.from_string "1.5 1.5e0 15e-1 0x1.8 0X1.8")
122    "%F %F %f %F %F"
123    (fun b1 b2 b3 b4 b5 -> b1 = b2 && b2 = b3 && b3 = b4 && b4 = b5)
124  &&
125(* h style *)
126  begin
127    let roundtrip x =
128      bscanf (Printf.ksprintf Scanning.from_string "%h" x) "%h" (same_float x)
129    in
130    roundtrip (+0.) &&
131    roundtrip (-0.) &&
132    roundtrip (+1.) &&
133    roundtrip (-1.) &&
134    roundtrip (+1024.) &&
135    roundtrip (-1024.) &&
136    roundtrip 0X123.456 &&
137    roundtrip 0X123456789ABCDE. &&
138    roundtrip epsilon_float &&
139    roundtrip (4. *. atan 1.) &&
140    (Sys.win32 ||
141     (* nan/infinity parsing fails on Windows? *)
142     (roundtrip nan &&
143      roundtrip infinity &&
144      roundtrip neg_infinity)) &&
145    true
146  end
147  &&
148
149  (* H style *)
150  begin
151    let roundtrip x =
152      bscanf (Printf.ksprintf Scanning.from_string "%H" x) "%H" (same_float x)
153    in
154    roundtrip (+0.) &&
155    roundtrip (-0.) &&
156    roundtrip (+1.) &&
157    roundtrip (-1.) &&
158    roundtrip (+1024.) &&
159    roundtrip (-1024.) &&
160    roundtrip 0X123.456 &&
161    roundtrip 0X123456789ABCDE. &&
162    roundtrip epsilon_float &&
163    roundtrip (4. *. atan 1.) &&
164    (Sys.win32 ||
165     (* nan/infinity parsing fails on Windows? *)
166     (roundtrip nan &&
167      roundtrip infinity &&
168      roundtrip neg_infinity)) &&
169    true
170  end
171;;
172
173test (test5 ())
174;;
175
176(* Testing boolean scanning. *)
177let test6 () =
178  bscanf (Scanning.from_string "truetrue") "%B%B"
179         (fun b1 b2 -> (b1, b2) = (true, true))  &&
180  bscanf (Scanning.from_string "truefalse") "%B%B"
181         (fun b1 b2 -> (b1, b2) = (true, false)) &&
182  bscanf (Scanning.from_string "falsetrue") "%B%B"
183         (fun b1 b2 -> (b1, b2) = (false, true)) &&
184  bscanf (Scanning.from_string "falsefalse") "%B%B"
185         (fun b1 b2 -> (b1, b2) = (false, false)) &&
186  bscanf (Scanning.from_string "true false") "%B %B"
187         (fun b1 b2 -> (b1, b2) = (true, false))
188;;
189
190test (test6 ())
191;;
192
193(* Testing char scanning. *)
194
195let test7 () =
196  bscanf (Scanning.from_string "'a' '\n' '\t' '\000' '\032'")
197         "%C %C %C %C %C"
198    (fun c1 c2 c3 c4 c5 ->
199       c1 = 'a' && c2 = '\n' && c3 = '\t' && c4 = '\000' && c5 = '\032') &&
200
201(* Here \n, \t, and \032 are skipped due to the space semantics of scanf. *)
202  bscanf (Scanning.from_string "a \n \t \000 \032b")
203         "%c %c %c "
204    (fun c1 c2 c3 ->
205       c1 = 'a' && c2 = '\000' && c3 = 'b')
206;;
207
208test (test7 ())
209;;
210
211let verify_read c =
212  let s = Printf.sprintf "%C" c in
213  let ib = Scanning.from_string s in
214  assert (bscanf ib "%C" id = c)
215;;
216
217let verify_scan_Chars () =
218  for i = 0 to 255 do verify_read (char_of_int i) done
219;;
220
221let test8 () = verify_scan_Chars () = ();;
222
223test (test8 ())
224;;
225
226(* Testing string scanning. *)
227
228(* %S and %s styles. *)
229let unit fmt s =
230  let ib = Scanning.from_string (Printf.sprintf "%S" s) in
231  Scanf.bscanf ib fmt id
232;;
233
234let test_fmt fmt s = unit fmt s = s;;
235
236let test9_string = "\239\187\191";;
237
238let test_S = test_fmt "%S";;
239let test9 () =
240  test_S "poi" &&
241  test_S "a\"b" &&
242  test_S "a\nb" &&
243  test_S "a\010b" &&
244  test_S "a\\\n\
245          b \\\n\
246          c\010\\\n\
247          b" &&
248  test_S "a\\\n\
249          \\\n\
250          \\\n\
251          b \\\n\
252          c\010\\\n\
253          b" &&
254  test_S "\xef" &&
255  test_S "\\xef" &&
256  Scanf.sscanf "\"\\xef\"" "%S" (fun s -> s) =
257                  "\xef" &&
258  Scanf.sscanf "\"\\xef\\xbb\\xbf\"" "%S" (fun s -> s) =
259                  test9_string &&
260  Scanf.sscanf "\"\\xef\\xbb\\xbf\"" "%S" (fun s -> s) =
261                  "\239\187\191" &&
262  Scanf.sscanf "\"\xef\xbb\xbf\"" "%S" (fun s -> s) =
263                  test9_string &&
264  Scanf.sscanf "\"\\\\xef\\\\xbb\\\\xbf\"" "%S" (fun s -> s) =
265                  "\\xef\\xbb\\xbf" &&
266  Scanf.sscanf "\"\ \"" "%S" (fun s -> s) =
267                  "\ "
268;;
269
270test (test9 ())
271;;
272
273let test10 () =
274  let unit s =
275    let ib = Scanning.from_string s in
276  Scanf.bscanf ib "%S" id in
277
278  let res =
279    sscanf "Une chaine: \"celle-ci\" et \"celle-la\"!"
280           "%s %s %S %s %S %s"
281           (fun s1 s2 s3 s4 s5 s6 -> s1 ^ s2 ^ s3 ^ s4 ^ s5 ^ s6) in
282  res = "Unechaine:celle-cietcelle-la!" &&
283  (* Testing the result of reading a %S string. *)
284  unit "\"a\\\n  b\"" = "ab" &&
285  unit "\"\\\n  ab\"" = "ab" &&
286  unit "\"\n\\\n  ab\"" = "\nab" &&
287  unit "\"\n\\\n  a\nb\"" = "\na\nb" &&
288  unit "\"\n\\\n  \\\n  a\nb\"" = "\na\nb" &&
289  unit "\"\n\\\n  a\n\\\nb\\\n\"" = "\na\nb" &&
290  unit "\"a\\\n  \"" = "a" &&
291  true
292;;
293
294test (test10 ())
295;;
296
297(* %[] style *)
298let test11 () =
299  sscanf "Pierre\tWeis\t70" "%s %s %s"
300    (fun prenom nom poids ->
301     prenom = "Pierre" && nom = "Weis" && int_of_string poids = 70)
302  &&
303  sscanf "Jean-Luc\tde Leage\t68" "%[^\t] %[^\t] %d"
304    (fun prenom nom poids ->
305     prenom = "Jean-Luc" && nom = "de Leage" && poids = 68)
306  &&
307  sscanf "Daniel\tde Rauglaudre\t66" "%s@\t %s@\t %d"
308    (fun prenom nom poids ->
309     prenom = "Daniel" && nom = "de Rauglaudre" && poids = 66)
310;;
311
312(* Empty string (end of input) testing. *)
313let test110 () =
314  sscanf "" " " (fun x -> x) "" = "" &&
315  sscanf "" "%s" (fun x -> x = "") &&
316  sscanf "" "%s%s" (fun x y -> x = "" && y = "") &&
317  sscanf "" "%s " (fun x -> x = "") &&
318  sscanf "" " %s" (fun x -> x = "") &&
319  sscanf "" " %s " (fun x -> x = "") &&
320  sscanf "" "%[^\n]" (fun x -> x = "") &&
321  sscanf "" "%[^\n] " (fun x -> x = "") &&
322  sscanf " " "%s" (fun x -> x = "") &&
323  sscanf " " "%s%s" (fun x y -> x = "" && y = "") &&
324  sscanf " " " %s " (fun x -> x = "") &&
325  sscanf " " " %s %s" (fun x y -> x = "" && x = y) &&
326  sscanf " " " %s@ %s" (fun x y -> x = "" && x = y) &&
327  sscanf " poi !" " %s@ %s@." (fun x y -> x = "poi" && y = "!") &&
328  sscanf " poi !" "%s@ %s@." (fun x y -> x = "" && y = "poi !")
329;;
330
331let test111 () = sscanf "" "%[^\n]@\n" (fun x -> x = "");;
332
333test (test11 () && test110 () && test111 ())
334;;
335
336(* Scanning lists. *)
337let ib () = Scanning.from_string "[1;2;3;4; ]";;
338
339(* Statically known lists can be scanned directly. *)
340let f ib =
341  bscanf ib " [" ();
342  bscanf ib " %i;" (fun i ->
343  bscanf ib " %i;" (fun j ->
344  bscanf ib " %i;" (fun k ->
345  bscanf ib " %i;" (fun l ->
346  bscanf ib " ]" ();
347  [i; j; k; l]))));;
348
349let test12 () = f (ib ()) = [1; 2; 3; 4];;
350
351test (test12 ())
352;;
353
354(* A general list scanner that always fails to succeed. *)
355let rec scan_elems ib accu =
356  try bscanf ib " %i;" (fun i -> scan_elems ib (i :: accu)) with
357  | _ -> accu
358;;
359
360let g ib = bscanf ib "[ " (); List.rev (scan_elems ib []);;
361
362let test13 () = g (ib ()) = [1; 2; 3; 4];;
363
364test (test13 ())
365;;
366
367(* A general int list scanner. *)
368let rec scan_int_list ib =
369  bscanf ib "[ " ();
370  let accu = scan_elems ib [] in
371  bscanf ib " ]" ();
372  List.rev accu
373;;
374
375let test14 () = scan_int_list (ib ()) = [1; 2; 3; 4];;
376
377test (test14 ())
378;;
379
380(* A general list scanner that always succeeds. *)
381let rec scan_elems ib accu =
382  bscanf ib " %i %c"
383    (fun i -> function
384     | ';' -> scan_elems ib (i :: accu)
385     | ']' -> List.rev (i :: accu)
386     | c -> failwith "scan_elems")
387;;
388
389let rec scan_int_list ib =
390  bscanf ib "[ " ();
391  scan_elems ib []
392;;
393
394let test15 () =
395  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1; 2; 3; 4];;
396
397test (test15 ())
398;;
399
400let rec scan_elems ib accu =
401  try
402  bscanf ib "%c %i"
403    (fun c i ->
404     match c with
405     | ';' -> scan_elems ib (i :: accu)
406     | ']' -> List.rev (i :: accu)
407     | '[' when accu = [] -> scan_elems ib (i :: accu)
408     | c -> print_endline (String.make 1 c); failwith "scan_elems")
409  with
410  | Scan_failure _ -> bscanf ib "]" (); accu
411  | End_of_file -> accu
412;;
413
414let scan_int_list ib = scan_elems ib [];;
415
416let test16 () =
417  scan_int_list (Scanning.from_string "[]") = List.rev [] &&
418  scan_int_list (Scanning.from_string "[1;2;3;4]") = List.rev [1;2;3;4] &&
419  scan_int_list (Scanning.from_string "[1;2;3;4; ]") = List.rev [1;2;3;4] &&
420  (* Should fail but succeeds! *)
421  scan_int_list (Scanning.from_string "[1;2;3;4") = List.rev [1;2;3;4];;
422
423test (test16 ())
424;;
425
426let rec scan_elems ib accu =
427  bscanf ib " %i%[]; \t\n\r]"
428    (fun i s ->
429     match s with
430     | ";" -> scan_elems ib (i :: accu)
431     | "]" -> List.rev (i :: accu)
432     | s -> List.rev (i :: accu))
433;;
434
435let scan_int_list ib =
436  bscanf ib " [" ();
437  scan_elems ib []
438;;
439
440let test17 () =
441  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
442  scan_int_list (Scanning.from_string "[1;2;3;4; ]") = [1;2;3;4] &&
443  (* Should fail but succeeds! *)
444  scan_int_list (Scanning.from_string "[1;2;3;4 5]") = [1;2;3;4];;
445
446test (test17 ())
447;;
448
449let rec scan_elems ib accu =
450  bscanf ib " %c " (fun c ->
451    match c with
452    | '[' when accu = [] ->
453        (* begginning of list: could find either
454           - an int, if the list is not empty,
455           - the char ], if the list is empty. *)
456        bscanf ib "%[]]"
457          (function
458           | "]" -> accu
459           | _ ->
460             bscanf ib " %i " (fun i ->
461               scan_rest ib (i :: accu)))
462    | _ -> failwith "scan_elems")
463
464and scan_rest ib accu =
465  bscanf ib " %c " (fun c ->
466    match c with
467    | ';' ->
468        bscanf ib "%[]]"
469          (function
470           | "]" -> accu
471           | _ ->
472             bscanf ib " %i " (fun i ->
473             scan_rest ib (i :: accu)))
474    | ']' -> accu
475    | _ -> failwith "scan_rest")
476;;
477
478let scan_int_list ib = List.rev (scan_elems ib []);;
479
480let test18 () =
481  scan_int_list (Scanning.from_string "[]") = [] &&
482  scan_int_list (Scanning.from_string "[ ]") = [] &&
483  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
484  scan_int_list (Scanning.from_string "[1;2;3;4; ]") = [1;2;3;4];;
485
486test (test18 ())
487;;
488
489(* Those properly fail *)
490
491let test19 () =
492  failure_test
493    scan_int_list (Scanning.from_string "[1;2;3;4 5]")
494    "scan_rest"
495;;
496
497(test19 ())
498;;
499
500let test20 () =
501  scan_failure_test
502    scan_int_list (Scanning.from_string "[1;2;3;4;; 5]");;
503
504(test20 ())
505;;
506
507let test21 () =
508  scan_failure_test
509    scan_int_list (Scanning.from_string "[1;2;3;4;;");;
510
511(test21 ())
512;;
513
514let rec scan_elems ib accu =
515  bscanf ib "%1[];]" (function
516  | "]" -> accu
517  | ";" -> scan_rest ib accu
518  | _ ->
519    failwith
520      (Printf.sprintf "scan_int_list" (*
521        "scan_int_list: char %i waiting for ']' or ';' but found %c"
522        (Scanning.char_count ib) (Scanning.peek_char ib)*)))
523
524and scan_rest ib accu =
525  bscanf ib "%[]]" (function
526  | "]" -> accu
527  | _ -> scan_elem ib accu)
528
529and scan_elem ib accu =
530  bscanf ib " %i " (fun i -> scan_elems ib (i :: accu))
531;;
532
533let scan_int_list ib =
534  bscanf ib " [ " ();
535  List.rev (scan_rest ib [])
536;;
537
538let test22 () =
539  scan_int_list (Scanning.from_string "[]") = [] &&
540  scan_int_list (Scanning.from_string "[ ]") = [] &&
541  scan_int_list (Scanning.from_string "[1]") = [1] &&
542  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
543  scan_int_list (Scanning.from_string "[1;2;3;4;]") = [1;2;3;4];;
544
545test (test22 ())
546;;
547
548(* Should work but does not with this version of scan_int_list!
549scan_int_list (Scanning.from_string "[1;2;3;4; ]");;
550(* Should lead to a bad input error. *)
551scan_int_list (Scanning.from_string "[1;2;3;4 5]");;
552scan_int_list (Scanning.from_string "[1;2;3;4;;");;
553scan_int_list (Scanning.from_string "[1;2;3;4;; 5]");;
554scan_int_list (Scanning.from_string "[1;2;3;4;; 23]");;
555*)
556
557let rec scan_elems ib accu =
558  try bscanf ib " %i %1[;]" (fun i s ->
559   if s = "" then i :: accu else scan_elems ib (i :: accu)) with
560  | Scan_failure _ -> accu
561;;
562
563(* The general int list scanner. *)
564let rec scan_int_list ib =
565  bscanf ib "[ " ();
566  let accu = scan_elems ib [] in
567  bscanf ib " ]" ();
568  List.rev accu
569;;
570
571(* The general HO list scanner.
572   This version does not fix the separator, nor the spacing before and after
573   the separator (it uses the functional argument [scan_elem] to parse the
574   separator, its spacing, and the item).
575 *)
576let rec scan_elems ib scan_elem accu =
577  try scan_elem ib (fun i s ->
578    let accu = i :: accu in
579    if s = "" then accu else scan_elems ib scan_elem accu) with
580  | Scan_failure _ -> accu
581;;
582
583let scan_list scan_elem ib =
584  bscanf ib "[ " ();
585  let accu = scan_elems ib scan_elem [] in
586  bscanf ib " ]" ();
587  List.rev accu
588;;
589
590(* Deriving particular list scanners from the HO list scanner. *)
591let scan_int_elem ib = bscanf ib " %i %1[;]";;
592let scan_int_list = scan_list scan_int_elem;;
593
594let test23 () =
595  scan_int_list (Scanning.from_string "[]") = [] &&
596  scan_int_list (Scanning.from_string "[ ]") = [] &&
597  scan_int_list (Scanning.from_string "[1]") = [1] &&
598  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
599  scan_int_list (Scanning.from_string "[1;2;3;4;]") = [1;2;3;4];;
600
601test (test23 ())
602;;
603
604let test24 () =
605  scan_failure_test scan_int_list (Scanning.from_string "[1;2;3;4 5]")
606and test25 () =
607  scan_failure_test scan_int_list (Scanning.from_string "[1;2;3;4;;")
608and test26 () =
609  scan_failure_test scan_int_list (Scanning.from_string "[1;2;3;4;; 5]")
610and test27 () =
611  scan_failure_test scan_int_list (Scanning.from_string "[1;2;3;4;; 23]");;
612
613 (test24 ()) &&
614 (test25 ()) &&
615 (test26 ()) &&
616 (test27 ())
617;;
618
619(* To scan an OCaml string:
620   the format is "\"%s@\"".
621   A better way would be to add a %S (String.escaped), a %C (Char.escaped).
622   This is now available. *)
623let scan_string_elem ib = bscanf ib " \"%s@\" %1[;]";;
624let scan_string_list = scan_list scan_string_elem;;
625
626let scan_String_elem ib = bscanf ib " %S %1[;]";;
627let scan_String_list = scan_list scan_String_elem;;
628
629let test28 () =
630  scan_string_list (Scanning.from_string "[]") = [] &&
631  scan_string_list (Scanning.from_string "[\"Le\"]") = ["Le"] &&
632  scan_string_list
633    (Scanning.from_string "[\"Le\";\"langage\";\"Objective\";\"Caml\"]") =
634    ["Le"; "langage"; "Objective"; "Caml"] &&
635  scan_string_list
636    (Scanning.from_string "[\"Le\";\"langage\";\"Objective\";\"Caml\"; ]") =
637    ["Le"; "langage"; "Objective"; "Caml"] &&
638
639  scan_String_list (Scanning.from_string "[]") = [] &&
640  scan_String_list (Scanning.from_string "[\"Le\"]") = ["Le"] &&
641  scan_String_list
642    (Scanning.from_string "[\"Le\";\"langage\";\"Objective\";\"Caml\"]") =
643    ["Le"; "langage"; "Objective"; "Caml"] &&
644  scan_String_list
645    (Scanning.from_string "[\"Le\";\"langage\";\"Objective\";\"Caml\"; ]") =
646    ["Le"; "langage"; "Objective"; "Caml"];;
647
648test (test28 ())
649;;
650
651(* The general HO list scanner with continuations. *)
652let rec scan_elems ib scan_elem accu =
653  scan_elem ib
654    (fun i s ->
655     let accu = i :: accu in
656     if s = "" then accu else scan_elems ib scan_elem accu)
657    (fun ib exc -> accu)
658;;
659
660let scan_list scan_elem ib =
661  bscanf ib "[ " ();
662  let accu = scan_elems ib scan_elem [] in
663  bscanf ib " ]" ();
664  List.rev accu
665;;
666
667(* Deriving particular list scanners from the HO list scanner. *)
668let scan_int_elem ib f ek = kscanf ib ek " %i %1[;]" f;;
669let scan_int_list = scan_list scan_int_elem;;
670
671let test29 () =
672  scan_int_list (Scanning.from_string "[]") = [] &&
673  scan_int_list (Scanning.from_string "[ ]") = [] &&
674  scan_int_list (Scanning.from_string "[1]") = [1] &&
675  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
676  scan_int_list (Scanning.from_string "[1;2;3;4;]") = [1;2;3;4];;
677
678test (test29 ())
679;;
680
681let scan_string_elem ib f ek = kscanf ib ek " %S %1[;]" f;;
682let scan_string_list = scan_list scan_string_elem;;
683
684let test30 () =
685  scan_string_list (Scanning.from_string "[]") = [] &&
686  scan_string_list (Scanning.from_string "[ ]") = [] &&
687  scan_string_list (Scanning.from_string "[ \"1\" ]") = ["1"] &&
688  scan_string_list
689    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\"]") =
690    ["1"; "2"; "3"; "4"] &&
691  scan_string_list
692    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\";]") =
693    ["1"; "2"; "3"; "4"];;
694
695test (test30 ())
696;;
697
698(* A generic polymorphic item scanner, *)
699let scan_elem fmt ib f ek = kscanf ib ek fmt f;;
700
701(* Derivation of list scanners from the generic polymorphic item scanner
702   applications. *)
703let scan_int_list = scan_list (scan_elem " %i %1[;]");;
704let scan_string_list = scan_list (scan_elem " %S %1[;]");;
705let scan_bool_list = scan_list (scan_elem " %B %1[;]");;
706let scan_char_list = scan_list (scan_elem " %C %1[;]");;
707let scan_float_list = scan_list (scan_elem " %f %1[;]");;
708
709(* In this version the [scan_elem] function should be a [kscanf] like
710   scanning function: we give it an error continuation.
711
712   The [scan_elem] argument, probably use some partial application of the
713   following generic [scan_elem]:
714
715   let scan_elem fmt ib f ek = kscanf ib ek fmt f;;
716
717   For instance, a suitable [scan_elem] for integers could be:
718
719   let scan_integer_elem = scan_elem " %i";;
720
721*)
722let rec scan_elems ib scan_elem accu =
723  scan_elem ib
724    (fun i ->
725     let accu = i :: accu in
726     kscanf ib
727      (fun ib exc -> accu)
728      " %1[;]"
729      (fun s -> if s = "" then accu else scan_elems ib scan_elem accu))
730  (fun ib exc -> accu)
731;;
732
733let scan_list scan_elem ib =
734  bscanf ib "[ " ();
735  let accu = scan_elems ib scan_elem [] in
736  bscanf ib " ]" ();
737  List.rev accu
738;;
739
740let scan_int_list = scan_list (scan_elem " %i");;
741let scan_string_list = scan_list (scan_elem " %S");;
742let scan_bool_list = scan_list (scan_elem " %B");;
743let scan_char_list = scan_list (scan_elem " %C");;
744let scan_float_list = scan_list (scan_elem " %f");;
745
746let test31 () =
747  scan_int_list (Scanning.from_string "[]") = [] &&
748  scan_int_list (Scanning.from_string "[ ]") = [] &&
749  scan_int_list (Scanning.from_string "[1]") = [1] &&
750  scan_int_list (Scanning.from_string "[1;2;3;4]") = [1;2;3;4] &&
751  scan_int_list (Scanning.from_string "[1;2;3;4;]") = [1;2;3;4];;
752
753test (test31 ())
754;;
755
756let test32 () =
757  scan_string_list (Scanning.from_string "[]") = [] &&
758  scan_string_list (Scanning.from_string "[ ]") = [] &&
759  scan_string_list (Scanning.from_string "[ \"1\" ]") = ["1"] &&
760  scan_string_list
761    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\"]") =
762    ["1"; "2"; "3"; "4"] &&
763  scan_string_list
764    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\";]") =
765    ["1"; "2"; "3"; "4"];;
766
767test (test32 ())
768;;
769
770(* Using [kscanf] only.
771
772   We use format values to stand for ``functional'' specifications to scan
773   the elements of lists.
774
775   The list item separator and the separator spacing are builtin into the
776   [scan_elems] iterator and thus are conveniently omitted from the
777   definitional format for item scanning.
778*)
779let rec scan_elems ib scan_elem_fmt accu =
780  kscanf ib (fun ib exc -> accu)
781    scan_elem_fmt
782    (fun i ->
783     let accu = i :: accu in
784     bscanf ib
785       " %1[;] "
786       (function
787        | "" -> accu
788        | _ -> scan_elems ib scan_elem_fmt accu)
789    )
790;;
791
792let scan_list scan_elem_fmt ib =
793  bscanf ib "[ " ();
794  let accu = scan_elems ib scan_elem_fmt [] in
795  bscanf ib " ]" ();
796  List.rev accu
797;;
798
799let scan_int_list = scan_list "%i";;
800let scan_string_list = scan_list "%S";;
801let scan_bool_list = scan_list "%B";;
802let scan_char_list = scan_list "%C";;
803let scan_float_list = scan_list "%f";;
804
805let test33 () =
806  scan_int_list (Scanning.from_string "[]") = [] &&
807  scan_int_list (Scanning.from_string "[ ]") = [] &&
808  scan_int_list (Scanning.from_string "[ 1 ]") = [1] &&
809  scan_int_list (Scanning.from_string "[ 1; 2; 3; 4 ]") = [1; 2; 3; 4] &&
810  scan_int_list (Scanning.from_string "[1;2;3;4;]") = [1; 2; 3; 4];;
811
812test (test33 ())
813;;
814
815let test34 () =
816  scan_string_list (Scanning.from_string "[]") = [] &&
817  scan_string_list (Scanning.from_string "[ ]") = [] &&
818  scan_string_list (Scanning.from_string "[ \"1\" ]") = ["1"] &&
819  scan_string_list
820    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\"]") =
821    ["1"; "2"; "3"; "4"] &&
822  scan_string_list
823    (Scanning.from_string "[\"1\"; \"2\"; \"3\"; \"4\";]") =
824    ["1"; "2"; "3"; "4"];;
825
826test (test34 ())
827;;
828
829(* Using kscanf only.
830
831   Same as the preceding functional, except that we no more use format values
832   to scan items: we use scanners that scan elements of the list on the
833   fly.
834*)
835(* This version cannot handle empty lists!
836let rec scan_elems ib scan_elem accu =
837  scan_elem ib
838    (fun elem ->
839     let accu = elem :: accu in
840     kscanf ib (fun ib exc -> accu)
841       " %1[;] "
842       (function
843        | "" -> accu
844        | _ -> scan_elems ib scan_elem accu))
845;;
846*)
847
848(* We use [kscanf] with a [%r] format ! *)
849let rec scan_elems scan_elem accu ib =
850  kscanf ib (fun ib exc -> accu)
851    "%r"
852    (function ib ->
853     scan_elem ib
854       (function elem ->
855        let accu = elem :: accu in
856        bscanf ib
857          " %1[;] "
858          (function
859           | "" -> accu
860           | _ -> scan_elems scan_elem accu ib)))
861    (function l -> l)
862;;
863
864let scan_list scan_elem ib =
865  bscanf ib "[ " ();
866  let accu = scan_elems scan_elem [] ib in
867  bscanf ib " ]" ();
868  List.rev accu
869;;
870
871(* We may also try a version with only one format:
872   We also changed the type of [scan_elem] to partially apply it to its
873   ``natural'' continuation.
874let rec scan_elems scan_elem accu ib =
875  (* We use [kscanf], so that:
876     if the element reader fails, we can return the list of elements read so
877     far. *)
878  kscanf ib (fun ib exc -> accu)
879    (* The format string for [kscanf]: we read an element using [scan_elem],
880       then find a semi-colon if any, in order to decide if we stop reading
881       or go on with other elements. *)
882    "%r %1[;] "
883    (* The reader: once an element has been read it returns the new accu. *)
884    (scan_elem (function elem -> elem :: accu))
885    (fun accu s ->
886     (* Cannot find a semi-colon: no more elements to read. *)
887     if s = "" then accu
888     (* We found a semi-colon: go on with the new accu. *)
889     else scan_elems scan_elem accu ib)
890;;
891
892let scan_list scan_elem ib =
893  bscanf ib "[ %r ]" (scan_elems scan_elem []) List.rev
894;;
895
896(* For instance:
897let scan_float f ib = Scanf.bscanf ib "%f" f;;
898# scan_list scan_float;;
899- : Scanf.Scanning.scanbuf -> float list = <fun>
900*)
901
902(* The element scanner builder. *)
903let make_scan_elem fmt f ib = Scanf.bscanf ib fmt f;;
904
905(* Promote an element reader format to an element list reader. *)
906let list_scanner fmt = scan_list (make_scan_elem fmt);;
907
908let scan_float = make_scan_elem "%f";;
909
910scan_list scan_float;;
911
912list_scanner "%f";;
913- : Scanf.Scanning.scanbuf -> float list = <fun>
914*)
915
916(* The prototype of a [scan_elem] function for the generic [scan_list]
917   functional.
918   This [scan_elem] scans a floating point number. *)
919let scan_float ib = Scanf.bscanf ib "%f";;
920let scan_float_list = scan_list scan_float;;
921
922(* In the following list scanners, we directly give the [scan_elem] function
923   as an immediate function value argument to the polymorphic
924   [scan_list]. *)
925let scan_int_list = scan_list (fun ib -> Scanf.bscanf ib "%i");;
926let scan_string_list = scan_list (fun ib -> Scanf.bscanf ib "%S");;
927let scan_bool_list = scan_list (fun ib -> Scanf.bscanf ib "%B");;
928let scan_char_list = scan_list (fun ib -> Scanf.bscanf ib "%C");;
929
930(* [scan_list] is truely polymorphic: scanning a list of lists of items
931   is a one liner!
932
933   Here we scan list of lists of floats. *)
934let scan_float_list_list =
935  scan_list
936    (fun ib k -> k (scan_list (fun ib -> Scanf.bscanf ib "%f") ib))
937;;
938
939let scan_float_list_list =
940  scan_list
941    (fun ib k -> k (scan_list scan_float ib))
942;;
943
944let scan_float_list_list =
945  scan_list
946    (fun ib k -> k (scan_float_list ib))
947;;
948
949(* The killer way to define [scan_float_list_list]. *)
950(* let scan_float_list_list = scan_list scan_float_list;; *)
951
952let test340 () =
953  scan_float_list_list
954   (Scanning.from_string "[[1.0] ; []; [2.0; 3; 5.0; 6.];]") =
955  [[1.]; []; [2.; 3.; 5.; 6.]]
956;;
957
958(* A general scan_list_list functional. *)
959let scan_list_list scan_elems ib =
960  scan_list
961    (fun ib k -> k (scan_elems ib)) ib
962;;
963
964let scan_float_list_list = scan_list_list scan_float_list;;
965
966(* Programming with continuations :) *)
967let scan_float_item ib k = k (scan_float ib (fun x -> x));;
968let scan_float_list ib k = k (scan_list scan_float_item ib);;
969let scan_float_list_list ib k = k (scan_list scan_float_list ib);;
970
971(* Testing the %N format. *)
972let test35 () =
973  sscanf "" "%N" (fun x -> x) = 0 &&
974  sscanf "456" "%N" (fun x -> x) = 0 &&
975  sscanf "456" "%d%N" (fun x y -> x, y) = (456, 1) &&
976  sscanf " " "%N%s%N" (fun x s y -> x, s, y) = (0, "", 1)
977;;
978
979test (test340 () && test35 ())
980;;
981
982(* The prefered reader functionnals. *)
983
984(* To read a list as in OCaml (elements are ``blank + semicolon + blank''
985   separated, and the list is enclosed in brackets). *)
986let rec read_elems read_elem accu ib =
987  kscanf ib (fun ib exc -> accu)
988    "%r %1[;] "
989    (read_elem (function elem -> elem :: accu))
990    (fun accu s -> if s = "" then accu else read_elems read_elem accu ib)
991;;
992
993let read_list read_elem ib =
994  bscanf ib "[ %r ]" (read_elems read_elem []) List.rev
995;;
996
997(* The element reader builder. *)
998let make_read_elem fmt f ib = Scanf.bscanf ib fmt f;;
999
1000(* Promote an element reader format to an element list reader. *)
1001let scan_List fmt = read_list (make_read_elem fmt);;
1002
1003(* Example for list of floatting point numbers. *)
1004(*
1005scan_List "%f";;
1006- : Scanf.Scanning.scanbuf -> float list = <fun>
1007
1008(* To read a list as a succession of elements separated by a blank. *)
1009let rec read_elems read_elem accu ib =
1010  kscanf ib (fun ib exc -> accu)
1011    "%r "
1012    (read_elem (function elem -> elem :: accu))
1013    (fun accu -> read_elems read_elem accu ib)
1014;;
1015
1016let read_list read_elem ib =
1017   List.rev (read_elems read_elem [] ib)
1018;;
1019
1020(* Promote an element reader format to an element list reader. *)
1021let scan_list fmt = read_list (make_read_elem fmt);;
1022
1023scan_list "%f";;
1024*)
1025
1026(* Testing the %n format. *)
1027let test36 () =
1028  sscanf "" "%n" (fun x -> x) = 0 &&
1029  sscanf "456" "%n" (fun x -> x) = 0 &&
1030  sscanf "456" "%d%n" (fun x y -> x, y) = (456, 3) &&
1031  sscanf " " "%n%s%n" (fun x s y -> x, s, y) = (0, "", 0)
1032;;
1033
1034test (test36 ())
1035;;
1036
1037(* Weird tests to empty strings or formats. *)
1038let test37 () =
1039  sscanf "" "" true &&
1040  sscanf "" "" (fun x -> x) 1 = 1 &&
1041  sscanf "123" "" (fun x -> x) 1 = 1
1042;;
1043
1044test (test37 ())
1045;;
1046
1047(* Testing end of input condition. *)
1048let test38 () =
1049  sscanf "a" "a%!" true &&
1050  sscanf "a" "a%!%!" true &&
1051  sscanf " a" " a%!" true &&
1052  sscanf "a " "a %!" true &&
1053  sscanf "" "%!" true &&
1054  sscanf " " " %!" true &&
1055  sscanf "" " %!" true &&
1056  sscanf "" " %!%!" true
1057;;
1058
1059test (test38 ())
1060;;
1061
1062(* Weird tests on empty buffers. *)
1063let test39 () =
1064  let is_empty_buff ib =
1065    Scanning.beginning_of_input ib &&
1066    Scanning.end_of_input ib in
1067
1068  let ib = Scanning.from_string "" in
1069  is_empty_buff ib &&
1070  (* Do it twice since testing empty buff could incorrectly
1071     thraw an exception or wrongly change the beginning_of_input condition. *)
1072  is_empty_buff ib
1073;;
1074
1075test (test39 ())
1076;;
1077
1078(* Testing ranges. *)
1079let test40 () =
1080 let s = "cba" in
1081 let ib = Scanning.from_string s in
1082 bscanf ib "%[^ab]%s%!" (fun s1 s2 -> s1 = "c" && s2 = "ba")
1083;;
1084
1085test (test40 ())
1086;;
1087
1088let test41 () =
1089 let s = "cba" in
1090 let ib = Scanning.from_string s in
1091 bscanf ib "%[^abc]%[cba]%!" (fun s1 s2 -> s1 = "" && s2 = "cba")
1092;;
1093
1094test (test41 ())
1095;;
1096
1097let test42 () =
1098 let s = "defcbaaghi" in
1099 let ib = Scanning.from_string s in
1100 bscanf ib "%[^abc]%[abc]%s%!" (fun s1 s2 s3 ->
1101   s1 = "def" && s2 = "cbaa" && s3 = "ghi") &&
1102 let ib = Scanning.from_string s in
1103 bscanf ib "%s@\t" (fun s -> s = "defcbaaghi")
1104;;
1105
1106test (test42 ())
1107;;
1108
1109(* Testing end of file condition (bug found). *)
1110let test43, test44 =
1111 let s = "" in
1112 let ib = Scanning.from_string s in
1113 (fun () -> bscanf ib "%i%!" (fun i -> i)),
1114 (fun () -> bscanf ib "%!%i" (fun i -> i))
1115;;
1116
1117test_raises_this_exc End_of_file test43 () &&
1118test_raises_this_exc End_of_file test44 ()
1119;;
1120
1121(* Testing small range scanning (bug found once). *)
1122let test45 () =
1123 let s = "12.2" in
1124 let ib = Scanning.from_string s in
1125 bscanf ib "%[0-9].%[0-9]%s%!" (fun s1 s2 s3 ->
1126   s1 = "12" && s2 = "2" && s3 = "")
1127;;
1128
1129test (test45 ())
1130;;
1131
1132(* Testing printing of meta formats. *)
1133
1134let test46, test47 =
1135  (fun () ->
1136     Printf.sprintf "%i %(%s%)."
1137       1 "spells one, %s" "in english"),
1138  (fun () ->
1139     Printf.sprintf "%i %{%s%}, %s."
1140       1 "spells one %s" "in english")
1141;;
1142
1143test (test46 () = "1 spells one, in english.")
1144;;
1145test (test47 () = "1 %s, in english.")
1146;;
1147
1148(* Testing scanning of meta formats. *)
1149let test48 () =
1150  (* Testing format_from_string. *)
1151  let test_meta_read s fmt efmt = format_from_string s fmt = efmt in
1152  (* Test if format %i is indeed read as %i. *)
1153  let s, fmt = "%i", format_of_string "%i" in
1154  test_meta_read s fmt fmt &&
1155  (* Test if format %i is compatible with %d and indeed read as %i. *)
1156  let s, fmt = "%i", format_of_string "%d" in
1157  test_meta_read s fmt "%i" &&
1158  (* Complex test of scanning a meta format specified in the scanner input
1159     format string and extraction of its specification from a string. *)
1160  sscanf "12 \"%i\"89 " "%i %{%d%}%s %!"
1161    (fun i f s -> i = 12 && f = "%i" && s = "89") &&
1162  (* Testing scanf format string replacement *)
1163  let k s =
1164    Scanf.sscanf s
1165      "%(%f%)" (fun _fmt i -> i) in
1166  k "\" : %1f\": 987654321" = 9.0  &&
1167  k "\" : %2f\": 987654321" = 98.0 &&
1168  k "\" : %3f\": 9.87654321" = 9.8 &&
1169  k "\" : %4f\": 9.87654321" = 9.87 &&
1170
1171  let h s =
1172    Scanf.sscanf s
1173      "Read integers with %(%i%)" (fun _fmt i -> i) in
1174  h "Read integers with \"%1d\"987654321" = 9  &&
1175  h "Read integers with \"%2d\"987654321" = 98 &&
1176  h "Read integers with \"%3u\"987654321" = 987 &&
1177  h "Read integers with \"%4x\"987654321" = 39030 &&
1178
1179  let i s =
1180    Scanf.sscanf s
1181      "with %(%i %s%)" (fun _fmt amount currency -> amount, currency) in
1182  i "with \" : %d %s\" :        21 euros" = (21, "euros")  &&
1183  i "with \" : %d %s\" : 987654321 dollars" = (987654321, "dollars") &&
1184  i "with \" : %u %s\" :     54321 pounds" = (54321, "pounds") &&
1185  i "with \" : %x %s\" :       321 yens" = (801, "yens") &&
1186
1187  let j s =
1188    Scanf.sscanf s
1189      "with %(%i %_s %s%)" (fun _fmt amount currency -> amount, currency) in
1190  j "with \" : %1d %_s %s\" : 987654321 euros" = (9, "euros")  &&
1191  j "with \" : %2d %_s %s\" : 987654321 dollars" = (98, "dollars") &&
1192  j "with \" : %3u %_s %s\" : 987654321 pounds" = (987, "pounds") &&
1193  j "with \" : %4x %_s %s\" : 987654321 yens" = (39030, "yens")
1194;;
1195
1196test (test48 ())
1197;;
1198
1199(* Testing stoppers after ranges. *)
1200let test49 () =
1201  sscanf "as" "%[\\]" (fun s -> s = "") &&
1202  sscanf "as" "%[\\]%s" (fun s t -> s = "" && t = "as") &&
1203  sscanf "as" "%[\\]%s%!" (fun s t -> s = "" && t = "as") &&
1204  sscanf "as" "%[a..z]" (fun s -> s = "a") &&
1205  sscanf "as" "%[a-z]" (fun s -> s = "as") &&
1206  sscanf "as" "%[a..z]%s" (fun s t -> s = "a" && t = "s") &&
1207  sscanf "as" "%[a-z]%s" (fun s t -> s = "as" && t = "") &&
1208  sscanf "-as" "%[-a-z]" (fun s -> s = "-as") &&
1209  sscanf "-as" "%[-a-z]@s" (fun s -> s = "-a") &&
1210  sscanf "-as" "-%[a]@s" (fun s -> s = "a") &&
1211  sscanf "-asb" "-%[a]@sb%!" (fun s -> s = "a") &&
1212  sscanf "-asb" "-%[a]@s%s" (fun s t -> s = "a" && t = "b")
1213;;
1214
1215test (test49 ())
1216;;
1217
1218(* Testing buffers defined via functions
1219   + co-routines that read and write from the same buffers
1220   + range chars and proper handling of \n
1221   + the end of file condition. *)
1222let next_char ob () =
1223  let s = Buffer.contents ob in
1224  let len = String.length s in
1225  if len = 0 then raise End_of_file else
1226  let c = s.[0] in
1227  Buffer.clear ob;
1228  Buffer.add_string ob (String.sub s 1 (len - 1));
1229  c
1230;;
1231
1232let send_string ob s =
1233  Buffer.add_string ob s; Buffer.add_char ob '\n';;
1234let send_int ob i = send_string ob (string_of_int i);;
1235
1236let rec reader =
1237  let count = ref 0 in
1238  (fun ib ob ->
1239    if Scanf.Scanning.beginning_of_input ib then begin
1240      count := 0; send_string ob "start"; writer ib ob end else
1241    Scanf.bscanf ib "%[^\n]\n" (function
1242    | "stop" -> send_string ob "stop"; writer ib ob
1243    | s ->
1244      let l = String.length s in
1245      count := l + !count;
1246      if !count >= 100 then begin
1247        send_string ob "stop";
1248        send_int ob !count
1249        end else
1250      send_int ob l;
1251      writer ib ob))
1252
1253and writer ib ob =
1254  Scanf.bscanf ib "%s\n" (function
1255    | "start" -> send_string ob "Hello World!"; reader ib ob
1256    | "stop" -> Scanf.bscanf ib "%i" (function i -> i)
1257    | s -> send_int ob (int_of_string s); reader ib ob);;
1258
1259let go () =
1260  let ob = Buffer.create 17 in
1261  let ib = Scanf.Scanning.from_function (next_char ob) in
1262  reader ib ob
1263;;
1264
1265let test50 () = go () = 100;;
1266
1267test (test50 ())
1268;;
1269
1270(* Simple tests may also fail!
1271   Ensure this is not the case with the current version for module [Scanf]. *)
1272let test51 () =
1273 sscanf "Hello" "%s" id = "Hello" &&
1274 sscanf "Hello\n" "%s\n" id = "Hello" &&
1275 sscanf "Hello\n" "%s%s\n" (fun s1 s2 ->
1276   s1 = "Hello" && s2 = "") &&
1277 sscanf "Hello\nWorld" "%s\n%s%!" (fun s1 s2 ->
1278   s1 = "Hello" && s2 = "World") &&
1279 sscanf "Hello\nWorld!" "%s\n%s" (fun s1 s2 ->
1280   s1 = "Hello" && s2 = "World!") &&
1281 sscanf "Hello\n" "%s@\n%s" (fun s1 s2 ->
1282   s1 = "Hello" && s2 = "") &&
1283 sscanf "Hello \n" "%s@\n%s" (fun s1 s2 ->
1284   s1 = "Hello " && s2 = "")
1285;;
1286
1287test (test51 ())
1288;;
1289
1290(* Tests that indeed the [%s@c] format works properly.
1291   Also tests the difference between [\n] and [@\n] is correctly handled.
1292   In particular, tests that if no [c] character can be found in the
1293   input, then the token obtained for [%s@c] spreads to the end of
1294   input. *)
1295let test52 () =
1296 sscanf "Hello\n" "%s@\n" id = "Hello" &&
1297 sscanf "Hello" "%s@\n" id = "Hello" &&
1298 sscanf "Hello" "%s%s@\n" (fun s1 s2 ->
1299   s1 = "Hello" && s2 = "") &&
1300 sscanf "Hello\nWorld" "%s@\n%s%!" (fun s1 s2 ->
1301   s1 = "Hello" && s2 = "World") &&
1302 sscanf "Hello\nWorld!" "%s@\n%s@\n" (fun s1 s2 ->
1303   s1 = "Hello" && s2 = "World!") &&
1304 sscanf "Hello\n" "%s@\n%s" (fun s1 s2 ->
1305   s1 = "Hello" && s2 = "") &&
1306 sscanf "Hello \n" "%s%s@\n" (fun s1 s2 ->
1307   s1 = "Hello" && s2 = " ") &&
1308sscanf "Hello \n" "%s%s%_1[ ]\n" (fun s1 s2 ->
1309         s1 = "Hello" && s2 = "") &&
1310 sscanf "Hello \n" "%s%_1[ ]%s\n" (fun s1 s2 ->
1311   s1 = "Hello" && s2 = "") &&
1312 sscanf "Hello\nWorld" "%s\n%s%!" (fun s1 s2 ->
1313      s1 = "Hello" && s2 = "World") &&
1314 sscanf "Hello\nWorld!" "%s\n%s%!" (fun s1 s2 ->
1315      s1 = "Hello" && s2 = "World!") &&
1316 sscanf "Hello\nWorld!" "%s\n%s@!%!" (fun s1 s2 ->
1317      s1 = "Hello" && s2 = "World") &&
1318 (* PR#6791 *)
1319 sscanf "Hello{foo}" "%s@{%s" (fun s1 s2 ->
1320   s1 = "Hello" && s2 = "foo}") &&
1321 sscanf "Hello[foo]" "%s@[%s" (fun s1 s2 ->
1322   s1 = "Hello" && s2 = "foo]")
1323;;
1324
1325test (test52 ())
1326;;
1327
1328(* Reading native, int32 and int64 numbers. *)
1329let test53 () =
1330 sscanf "123" "%nd" id = 123n &&
1331 sscanf "124" "%nd" (fun i -> Nativeint.pred i = 123n) &&
1332
1333 sscanf "123" "%ld" id = 123l &&
1334 sscanf "124" "%ld" (fun i -> Int32.succ i = 125l) &&
1335
1336 sscanf "123" "%Ld" id = 123L &&
1337 sscanf "124" "%Ld" (fun i -> Int64.pred i = 123L)
1338;;
1339
1340test (test53 ())
1341;;
1342
1343(* Routines to create the file that tscanf uses as a testbed case. *)
1344let create_tscanf_data ob lines =
1345  let add_line (p, e) =
1346    Buffer.add_string ob (Printf.sprintf "%S" p);
1347    Buffer.add_string ob " -> ";
1348    Buffer.add_string ob (Printf.sprintf "%S" e);
1349    Buffer.add_string ob ";\n" in
1350  List.iter add_line lines
1351;;
1352
1353let write_tscanf_data_file fname lines =
1354  let oc = open_out fname in
1355  let ob = Buffer.create 42 in
1356  create_tscanf_data ob lines;
1357  Buffer.output_buffer oc ob;
1358  close_out oc
1359;;
1360
1361(* The tscanf testbed case file name. *)
1362let tscanf_data_file = "tscanf_data";;
1363(* The contents of the tscanf testbed case file. *)
1364let tscanf_data_file_lines = [
1365    "Objective", "Caml";
1366]
1367;;
1368(* We write the tscanf testbed case file. *)
1369write_tscanf_data_file tscanf_data_file tscanf_data_file_lines
1370;;
1371
1372(* Then we verify that its contents is indeed correct:
1373   the lines written into the [tscanf_data] file should be the same as the
1374   lines read from it. *)
1375
1376(* Reading back tscanf_data_file_lines (hence, testing data file reading as
1377   well). *)
1378let get_lines fname =
1379  let ib = Scanf.Scanning.from_file fname in
1380  let l = ref [] in
1381  try
1382    while not (Scanf.Scanning.end_of_input ib) do
1383      Scanf.bscanf ib " %S -> %S; " (fun x y ->
1384        l := (x, y) :: !l)
1385    done;
1386    List.rev !l
1387  with
1388  | Scanf.Scan_failure s ->
1389    failwith (Printf.sprintf "in file %s, %s" fname s)
1390  | End_of_file ->
1391    failwith (Printf.sprintf "in file %s, unexpected end of file" fname)
1392;;
1393
1394(* Simply test that the list of lines read from the file is the list of lines
1395   written to it!. *)
1396let test54 () =
1397  get_lines tscanf_data_file = tscanf_data_file_lines
1398;;
1399
1400test (test54 ())
1401;;
1402
1403(* Creating digests for files. *)
1404let add_digest_ib ob ib =
1405  let digest s = String.uppercase_ascii (Digest.to_hex (Digest.string s)) in
1406  let scan_line ib f = Scanf.bscanf ib "%[^\n\r]\n" f in
1407  let output_line_digest s =
1408    Buffer.add_string ob s;
1409    Buffer.add_char ob '#'; Buffer.add_string ob (digest s);
1410    Buffer.add_char ob '\n' in
1411  try while true do scan_line ib output_line_digest done; with
1412  | End_of_file -> ()
1413;;
1414
1415let digest_file fname =
1416  let ib = Scanf.Scanning.from_file fname in
1417  let ob = Buffer.create 42 in
1418  add_digest_ib ob ib;
1419  Buffer.contents ob
1420;;
1421
1422let test55 () =
1423  let ob = Buffer.create 42 in
1424  let ib =
1425    create_tscanf_data ob tscanf_data_file_lines;
1426    let s = Buffer.contents ob in
1427    Buffer.clear ob;
1428    Scanning.from_string s in
1429  let tscanf_data_file_lines_digest = add_digest_ib ob ib; Buffer.contents ob in
1430  digest_file tscanf_data_file = tscanf_data_file_lines_digest
1431;;
1432
1433test (test55 ())
1434;;
1435
1436(* Testing the number of characters read. *)
1437let test56 () =
1438   let g s = Scanf.sscanf s "%d%n" (fun i n -> (i, n)) in
1439   g "99" = (99, 2) &&
1440   g "99 syntaxes all in a row" = (99, 2) &&
1441   g "-20 degrees Celsius" = (-20, 3)
1442;;
1443
1444test (test56 ())
1445;;
1446
1447(* Testing the scanning of formats. *)
1448let test57 () =
1449  (* Testing format_from_string. *)
1450  let test_format_scan s fmt efmt =
1451    format_from_string s fmt = efmt in
1452  (* Test if format %i is indeed read as %i. *)
1453  let s, fmt = " %i ", format_of_string "%i" in
1454  test_format_scan s fmt " %i " &&
1455  (* Test if format %i is compatible with %d and indeed read as %i. *)
1456  let s, fmt = "%i", format_of_string "%d" in
1457  test_format_scan s fmt "%i" &&
1458
1459  let s, fmt =
1460    "Read an int %i then a string %s.",
1461    format_of_string "Spec%difi%scation" in
1462  test_format_scan s fmt "Read an int %i then a string %s." &&
1463
1464  let s, fmt =
1465    "Read an int %i then a string \"%s\".",
1466    format_of_string "Spec%difi%Scation" in
1467  test_format_scan s fmt "Read an int %i then a string \"%s\"." &&
1468
1469  let s, fmt =
1470    "Read an int %i then a string \"%s\".",
1471    format_of_string "Spec%difi%scation" in
1472  test_format_scan s fmt "Read an int %i then a string \"%s\"." &&
1473
1474  (* Complex test of scanning a meta format specified in the scanner input
1475     format string and extraction of its specification from a string. *)
1476  sscanf "12 \"%i\"89 " "%i %{%d%}%s %!"
1477    (fun i f s -> i = 12 && f = "%i" && s = "89")
1478;;
1479
1480test (test57 ())
1481;;
1482
1483let test58 () =
1484     sscanf "string1%string2" "%s@%%s" id = "string1"
1485  && sscanf "string1%string2" "%s@%%%s" (^) = "string1string2"
1486  && sscanf "string1@string2" "%[a-z0-9]@%s" (^) = "string1string2"
1487  && sscanf "string1@%string2" "%[a-z0-9]%@%%%s" (^) = "string1string2"
1488;;
1489
1490test (test58 ())
1491;;
1492
1493(* skip test number "59" which is commented below *)
1494let () = test (true);;
1495(*
1496let test59 () =
1497;;
1498
1499test (test59 ())
1500;;
1501*)
1502
1503(* To be continued ...
1504(* Trying to scan records. *)
1505let rec scan_fields ib scan_field accu =
1506  kscanf ib (fun ib exc -> accu)
1507   scan_field
1508   (fun i ->
1509      let accu = i :: accu in
1510      kscanf ib (fun ib exc -> accu)
1511       " %1[;] "
1512       (fun s ->
1513          if s = "" then accu else scan_fields ib scan_field accu))
1514;;
1515
1516let scan_record scan_field ib =
1517  bscanf ib "{ " ();
1518  let accu = scan_fields ib scan_field [] in
1519  bscanf ib " }" ();
1520  List.rev accu
1521;;
1522
1523let scan_field ib =
1524  bscanf ib "%s = %[^;]" (fun finame ficont -> finame, ficont);;
1525*)
1526
1527(* testing formats that do not consume their input *)
1528let test60 () =
1529  sscanf "abc" "%0c%0c%c%n" (fun c1 c2 c3 n ->
1530    c1 = 'a' && c2 = 'a' && c3 = 'a' && n = 1)
1531  &&
1532  sscanf "abc" "%0s%s" (fun s1 s2 -> s1 = "" && s2 = "abc")
1533  &&
1534  sscanf "abc" "%1s%s" (fun s1 s2 -> s1 = "a" && s2 = "bc")
1535;;
1536
1537test (test60 ());
1538