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