/src/tools/configuration/etc/liberty_etc_visitor_impl.e
Specman e | 843 lines | 747 code | 81 blank | 15 comment | 31 complexity | 52dd43f1620b1032ad5f664060344ddb MD5 | raw file
1-- This file is part of Liberty Eiffel. 2-- 3-- Liberty Eiffel is free software: you can redistribute it and/or modify 4-- it under the terms of the GNU General Public License as published by 5-- the Free Software Foundation, version 3 of the License. 6-- 7-- Liberty Eiffel is distributed in the hope that it will be useful, 8-- but WITHOUT ANY WARRANTY; without even the implied warranty of 9-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10-- GNU General Public License for more details. 11-- 12-- You should have received a copy of the GNU General Public License 13-- along with Liberty Eiffel. If not, see <http://www.gnu.org/licenses/>. 14-- 15class LIBERTY_ETC_VISITOR_IMPL 16 17inherit 18 LIBERTY_ETC_VISITOR 19 20create {ANY} 21 make 22 23feature {LIBERTY_ETC} 24 tool_name: FIXED_STRING 25 26 clusters: MAP[LIBERTY_ETC_CLUSTER, FIXED_STRING] is 27 do 28 Result := all_clusters 29 end 30 31 check_validity is 32 local 33 fix_point: BOOLEAN; mark: INTEGER 34 do 35 from 36 all_clusters.do_all(agent {LIBERTY_ETC_CLUSTER}.check_validity(clusters)) 37 all_clusters.do_all(agent {LIBERTY_ETC_CLUSTER}.check_cycles) 38 check not fix_point end 39 until 40 fix_point 41 loop 42 mark := mark + 1 43 if mark > 1024 then 44 std_error.put_line("No fix point after 1024 iterations, clusters graph too complex?") 45 die_with_code(1) 46 end 47 fix_point := not all_clusters.exists(agent {LIBERTY_ETC_CLUSTER}.fix_depth(mark)) 48 end 49 end 50 51feature {LIBERTY_ETC_FACTORY} -- Lists 52 visit_environment_variable_list (list: LIBERTY_ETC_LIST) is 53 do 54 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 55 end 56 57 visit_cluster_list (list: LIBERTY_ETC_LIST) is 58 do 59 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 60 end 61 62 visit_cluster_configuration_list (list: LIBERTY_ETC_LIST) is 63 do 64 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 65 end 66 67 visit_debug_configuration_list (list: LIBERTY_ETC_LIST) is 68 do 69 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 70 end 71 72 visit_debug_key_list (list: LIBERTY_ETC_LIST) is 73 do 74 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 75 end 76 77 visit_location_list (list: LIBERTY_ETC_LIST) is 78 do 79 create last_locations.with_capacity(2) 80 list.do_all(agent {EIFFEL_NODE}.accept(Current)) 81 end 82 83feature {LIBERTY_ETC_FACTORY} -- Non-Terminals 84 visit_master (nt: LIBERTY_ETC_NON_TERMINAL) is 85 local 86 t: EIFFEL_TERMINAL_NODE 87 do 88 check 89 nt.lower = 0 90 nt.name_at(1).is_equal(once "KW entity name") 91 nt.name_at(2).is_equal(once "Environment") 92 nt.name_at(3).is_equal(once "Clusters") 93 end 94 t ::= nt.node_at(1) 95 if not t.image.image.is_equal(tool_name) then 96 errors.set(errors.level_fatal_error, "Invalid file content: bad Master name " + t.image.image 97 + " (expected " + tool_name + ")") 98 check 99 dead: False 100 end 101 end 102 nt.node_at(2).accept(Current) 103 nt.node_at(3).accept(Current) 104 end 105 106 visit_cluster_definition (nt: LIBERTY_ETC_NON_TERMINAL) is 107 local 108 cluster_name: EIFFEL_TERMINAL_NODE 109 cluster_definition_name: FIXED_STRING 110 do 111 check 112 nt.lower = 0 113 nt.name_at(1).is_equal(once "KW cluster name") 114 nt.name_at(2).is_equal(once "Version") 115 nt.name_at(3).is_equal(once "Locations") 116 nt.name_at(4).is_equal(once "Needs") 117 nt.name_at(5).is_equal(once "Concurrency") 118 nt.name_at(6).is_equal(once "Assertion") 119 nt.name_at(7).is_equal(once "Debug") 120 nt.name_at(8).is_equal(once "Environment") 121 nt.name_at(9).is_equal(once "Clusters") 122 end 123 124 check 125 current_cluster = Void 126 end 127 cluster_name ::= nt.node_at(1) 128 cluster_definition_name := cluster_name.image.image.intern 129 if current_cluster_name = Void then 130 current_cluster_name := cluster_definition_name 131 elseif current_cluster_name /= cluster_definition_name then 132 errors.set(errors.level_fatal_error, "Invalid file content: bad cluster name " + cluster_definition_name 133 + " (expected " + current_cluster_name + ")") 134 check 135 dead: False 136 end 137 end 138 if all_clusters.fast_has(cluster_definition_name) then 139 errors.set(errors.level_fatal_error, "Invalid file content: duplicate cluster name " + cluster_definition_name) 140 check 141 dead: False 142 end 143 end 144 145 nt.node_at(8).accept(Current) 146 nt.node_at(9).accept(Current) 147 nt.node_at(3).accept(Current) 148 149 set_current_cluster_from_last_locations 150 151 nt.node_at(2).accept(Current) 152 nt.node_at(4).accept(Current) 153 nt.node_at(5).accept(Current) 154 nt.node_at(6).accept(Current) 155 nt.node_at(7).accept(Current) 156 157 check 158 current_cluster /= Void 159 end 160 end 161 162 visit_environment (nt: LIBERTY_ETC_NON_TERMINAL) is 163 do 164 if not nt.is_empty then 165 nt.node_at(1).accept(Current) 166 end 167 end 168 169 visit_environment_variable (nt: LIBERTY_ETC_NON_TERMINAL) is 170 local 171 entity_name, entity_value: EIFFEL_TERMINAL_NODE 172 entity_value_image: TYPED_EIFFEL_IMAGE[STRING] 173 do 174 check 175 nt.lower = 0 176 nt.name_at(0).is_equal(once "KW entity name") 177 nt.name_at(2).is_equal(once "KW string") 178 end 179 entity_name ::= nt.node_at(0) 180 entity_value ::= nt.node_at(2) 181 entity_value_image ::= entity_value.image 182 env.set(entity_name.image.image, entity_value_image.decoded) 183 end 184 185 visit_clusters (nt: LIBERTY_ETC_NON_TERMINAL) is 186 do 187 if not nt.is_empty then 188 check 189 nt.lower = 0 190 nt.name_at(1).is_equal(once "Cluster*") 191 end 192 nt.node_at(1).accept(Current) 193 end 194 end 195 196 visit_cluster (nt: LIBERTY_ETC_NON_TERMINAL) is 197 local 198 cluster_name: EIFFEL_TERMINAL_NODE 199 previous_cluster: like current_cluster 200 previous_cluster_name: like current_cluster_name 201 location: EIFFEL_TERMINAL_NODE 202 location_image: TYPED_EIFFEL_IMAGE[STRING] 203 descriptor: STRING 204 do 205 check 206 nt.lower = 0 207 nt.name_at(0).is_equal(once "KW cluster name") 208 nt.name_at(2).is_equal(once "KW string") 209 nt.name_at(3).is_equal(once "Configure") 210 end 211 cluster_name ::= nt.node_at(0) 212 previous_cluster_name := current_cluster_name 213 previous_cluster := current_cluster 214 current_cluster_name := cluster_name.image.image.intern 215 current_cluster := Void 216 217 location ::= nt.node_at(2) 218 location_image ::= location.image 219 descriptor := location_image.decoded 220 env.substitute(descriptor) 221 set_current_cluster_from_location(canonical_location(descriptor)) 222 if current_cluster.name /= current_cluster_name then 223 -- an aliased cluster, usually for the PROGRAM_LOADPATH / PROGRAM_LOADPATH_ pair 224 225 if all_clusters.fast_has(current_cluster_name) then 226 errors.set(errors.level_fatal_error, "Invalid file content: duplicate cluster name " + current_cluster_name) 227 check 228 dead: False 229 end 230 end 231 232 all_clusters.add(current_cluster, current_cluster_name) 233 end 234 nt.node_at(3).accept(Current) 235 current_cluster := previous_cluster 236 current_cluster_name := previous_cluster_name 237 end 238 239 visit_configure (nt: LIBERTY_ETC_NON_TERMINAL) is 240 do 241 end 242 243 visit_locations (nt: LIBERTY_ETC_NON_TERMINAL) is 244 do 245 check 246 nt.lower = 0 247 nt.name_at(1).is_equal(once "Location+") 248 end 249 nt.node_at(1).accept(Current) 250 end 251 252 visit_location (nt: LIBERTY_ETC_NON_TERMINAL) is 253 local 254 location: EIFFEL_TERMINAL_NODE 255 location_image: TYPED_EIFFEL_IMAGE[STRING] 256 descriptor: STRING 257 do 258 check 259 nt.lower = 0 260 nt.name_at(0).is_equal(once "KW string") 261 end 262 location ::= nt.node_at(0) 263 location_image ::= location.image 264 descriptor := once "" 265 descriptor.copy(location_image.decoded) 266 env.substitute(descriptor) 267 last_locations.add_last(canonical_location(descriptor)) 268 end 269 270 set_current_cluster_from_last_locations is 271 require 272 current_cluster = Void 273 not last_locations.is_empty 274 local 275 i: INTEGER; must_scan_loadpath: BOOLEAN 276 do 277 from 278 i := last_locations.lower 279 until 280 i > last_locations.upper 281 loop 282 if not files.is_directory(last_locations.item(i)) then 283 dir.compute_short_name_of(last_locations.item(i)) 284 inspect 285 dir.last_entry 286 when "loadpath.se" then 287 must_scan_loadpath := True 288 else 289 std_error.put_line(last_locations.item(i) + " is not a directory") 290 die_with_code(1) 291 end 292 end 293 i := i + 1 294 end 295 if must_scan_loadpath then 296 scan_loadpath(last_locations) 297 end 298 299 create current_cluster.make(current_cluster_name, last_locations) 300 all_clusters.add(current_cluster, current_cluster_name) 301 from 302 i := last_locations.lower 303 until 304 i > last_locations.upper 305 loop 306 cluster_per_location.add(current_cluster, last_locations.item(i)) 307 i := i + 1 308 end 309 last_locations := Void 310 ensure 311 current_cluster /= Void 312 last_locations = Void 313 end 314 315 set_current_cluster_from_location (location: ABSTRACT_STRING) is 316 require 317 current_cluster = Void 318 location /= Void 319 dir.system_notation.is_absolute_path(location.out) 320 local 321 descriptor: STRING 322 do 323 if files.is_directory(location) then 324 dir.compute_file_path_with(location, once "cluster.rc") 325 if not dir.last_entry.is_empty and then files.file_exists(dir.last_entry) and then files.is_file(dir.last_entry) then 326 set_current_cluster_from_cluster_rc(dir.last_entry.intern) 327 else 328 dir.compute_file_path_with(location, once "loadpath.se") 329 if not dir.last_entry.is_empty and then files.file_exists(dir.last_entry) and then files.is_file(dir.last_entry) then 330 set_current_cluster_from_loadpath_se(dir.last_entry.intern) 331 else 332 descriptor := once "" 333 descriptor.make_from_string(location) 334 dir.system_notation.to_directory_path(descriptor) 335 set_current_cluster_from_directory(descriptor.intern) 336 end 337 end 338 elseif files.is_file(location) then 339 dir.compute_short_name_of(location) 340 inspect 341 dir.last_entry 342 when "cluster.rc" then 343 set_current_cluster_from_cluster_rc(location.intern) 344 when "loadpath.se" then 345 set_current_cluster_from_loadpath_se(location.intern) 346 else 347 std_error.put_line("Unknown file format: " + location) 348 die_with_code(1) 349 end 350 else 351 std_error.put_line("Strange file: " + location 352 + " is neither a directory nor a regular file - cannot create the cluster") 353 breakpoint 354 die_with_code(1) 355 end 356 ensure 357 current_cluster /= Void 358 end 359 360 visit_version (nt: LIBERTY_ETC_NON_TERMINAL) is 361 local 362 version: EIFFEL_TERMINAL_NODE 363 version_image: TYPED_EIFFEL_IMAGE[STRING] 364 do 365 check 366 nt.lower = 0 367 nt.name_at(1).is_equal(once "KW string") 368 end 369 version ::= nt.node_at(1) 370 version_image ::= version.image 371 current_cluster.set_version(version_image.decoded.intern) 372 end 373 374 visit_needs (nt: LIBERTY_ETC_NON_TERMINAL) is 375 do 376 if not nt.is_empty then 377 check 378 nt.lower = 0 379 nt.name_at(1).is_equal(once "Cluster_Configuration*") 380 end 381 nt.node_at(1).accept(Current) 382 end 383 end 384 385 visit_cluster_configuration (nt: LIBERTY_ETC_NON_TERMINAL) is 386 local 387 needed_cluster: EIFFEL_TERMINAL_NODE 388 needed_cluster_name: FIXED_STRING 389 do 390 check 391 nt.lower = 0 392 nt.name_at(0).is_equal(once "KW cluster name") 393 nt.name_at(1).is_equal(once "Cluster_Constraints") 394 end 395 needed_cluster ::= nt.node_at(0) 396 create {FAST_ARRAY[LIBERTY_ETC_CONSTRAINT]} last_cluster_constraints.with_capacity(1) 397 nt.node_at(1).accept(Current) 398 needed_cluster_name := needed_cluster.image.image.intern 399 current_cluster.add_needs(create {LIBERTY_ETC_NEEDS}.make(needed_cluster_name, all_clusters.fast_reference_at(needed_cluster_name), last_cluster_constraints)) 400 last_cluster_constraints := Void 401 end 402 403 visit_cluster_constraints (nt: LIBERTY_ETC_NON_TERMINAL) is 404 do 405 if not nt.is_empty then 406 check 407 nt.lower = 0 408 nt.name_at(1).is_equal(once "Cluster_Version_Constraint") 409 end 410 nt.node_at(1).accept(Current) 411 end 412 end 413 414 visit_cluster_version_constraint (nt: LIBERTY_ETC_NON_TERMINAL) is 415 local 416 version: EIFFEL_TERMINAL_NODE 417 version_image: TYPED_EIFFEL_IMAGE[STRING] 418 do 419 check 420 nt.name_at(1).is_equal(once "Version_Operator") 421 nt.name_at(2).is_equal(once "KW string") 422 end 423 nt.node_at(1).accept(Current) 424 version ::= nt.node_at(2) 425 version_image ::= version.image 426 last_cluster_constraints.add_last(create {LIBERTY_ETC_VERSION_CONSTRAINT}.make(last_version_operator, version_image.decoded.intern)) 427 end 428 429 visit_version_operator (nt: LIBERTY_ETC_NON_TERMINAL) is 430 do 431 check 432 nt.lower = 0 433 end 434 inspect 435 nt.name_at(0) 436 when "KW =" then 437 last_version_operator := agent_version_eq 438 when "KW <=" then 439 last_version_operator := agent_version_le 440 when "KW >=" then 441 last_version_operator := agent_version_ge 442 when "KW /=" then 443 last_version_operator := agent_version_ne 444 when "KW <" then 445 last_version_operator := agent_version_lt 446 when "KW >" then 447 last_version_operator := agent_version_gt 448 end 449 end 450 451 visit_assertion (nt: LIBERTY_ETC_NON_TERMINAL) is 452 do 453 end 454 455 visit_assertion_level (nt: LIBERTY_ETC_NON_TERMINAL) is 456 do 457 end 458 459 visit_debug (nt: LIBERTY_ETC_NON_TERMINAL) is 460 do 461 end 462 463 visit_debug_configuration (nt: LIBERTY_ETC_NON_TERMINAL) is 464 do 465 end 466 467 visit_debug_key (nt: LIBERTY_ETC_NON_TERMINAL) is 468 do 469 end 470 471 visit_concurrency (nt: LIBERTY_ETC_NON_TERMINAL) is 472 do 473 end 474 475feature {} 476 cluster_per_location: DICTIONARY[LIBERTY_ETC_CLUSTER, FIXED_STRING] 477 478 set_current_cluster_from_cluster_rc (cluster_rc: FIXED_STRING) is 479 require 480 dir.system_notation.is_absolute_path(cluster_rc.out) 481 current_cluster = Void 482 local 483 etc: LIBERTY_ETC 484 previous_directory: like current_directory 485 do 486 current_cluster := cluster_per_location.fast_reference_at(cluster_rc) 487 if current_cluster = Void then 488 check 489 etc.visitor = Current 490 end 491 previous_directory := current_directory 492 dir.compute_parent_directory_of(cluster_rc) 493 current_directory := dir.last_entry.intern 494 495 etc.configure_cluster_rc(cluster_rc) 496 cluster_per_location.add(current_cluster, cluster_rc) 497 498 current_directory := previous_directory 499 end 500 ensure 501 current_cluster /= Void 502 current_cluster = cluster_per_location.fast_reference_at(cluster_rc) 503 end 504 505 set_current_cluster_from_loadpath_se (loadpath_se: FIXED_STRING) is 506 require 507 dir.system_notation.is_absolute_path(loadpath_se.out) 508 current_cluster = Void 509 local 510 locations: FAST_ARRAY[FIXED_STRING] 511 i, n: INTEGER 512 do 513 std_error.put_line(once "loadpath.se support is limited and will be removed.") 514 std_error.put_line(loadpath_se) 515 std_error.put_line(once "Consider using a cluster.rc file instead.") 516 517 current_cluster := cluster_per_location.fast_reference_at(loadpath_se) 518 if current_cluster = Void then 519 if all_clusters.fast_has(current_cluster_name) then 520 errors.set(errors.level_fatal_error, "Invalid file content: duplicate cluster name " + current_cluster_name) 521 check 522 dead: False 523 end 524 end 525 526 locations := {FAST_ARRAY[FIXED_STRING] << loadpath_se >> } 527 from 528 until 529 n = locations.count 530 loop 531 i := i + 1 532 if i > 500 then 533 std_error.put_line("loadpath nesting too deep starting from " + loadpath_se) 534 die_with_code(1) 535 end 536 n := locations.count 537 scan_loadpath(locations) 538 end 539 create current_cluster.make(current_cluster_name, locations) 540 all_clusters.add(current_cluster, current_cluster_name) 541 cluster_per_location.add(current_cluster, loadpath_se) 542 end 543 ensure 544 current_cluster /= Void 545 current_cluster = cluster_per_location.fast_reference_at(loadpath_se) 546 end 547 548 scan_loadpath (locations: FAST_ARRAY[FIXED_STRING]) is 549 require 550 not locations.is_empty 551 local 552 i: INTEGER; location: STRING; file: FIXED_STRING 553 do 554 location := once "" 555 from 556 i := locations.lower 557 until 558 i > locations.upper 559 loop 560 location.make_from_string(locations.item(i)) 561 env.substitute(location) 562 file := canonical_location(location) 563 if files.is_directory(file) then 564 i := i + 1 565 elseif files.is_file(file) then 566 locations.remove(i) 567 import_loadpath(locations, file) 568 else 569 std_error.put_line("Strange file: " + locations.item(i) 570 + " is neither a directory nor a regular file - ignored") 571 breakpoint 572 locations.remove(i) 573 end 574 end 575 end 576 577 import_loadpath (locations: FAST_ARRAY[FIXED_STRING]; loadpath: FIXED_STRING) is 578 require 579 dir.system_notation.is_absolute_path(loadpath.out) 580 local 581 directory: FIXED_STRING 582 do 583 tfr.connect_to(loadpath) 584 if not tfr.is_connected then 585 std_error.put_line("Could not open " + loadpath) 586 die_with_code(1) 587 end 588 589 dir.compute_parent_directory_of(loadpath) 590 directory := dir.last_entry.intern 591 592 from 593 tfr.read_line 594 until 595 tfr.end_of_input 596 loop 597 import_loadpath_line(locations, directory, tfr.last_string) 598 tfr.read_line 599 end 600 import_loadpath_line(locations, directory, tfr.last_string) 601 tfr.disconnect 602 end 603 604 import_loadpath_line (locations: FAST_ARRAY[FIXED_STRING]; directory: FIXED_STRING; loadpath_line: STRING) is 605 require 606 dir.system_notation.is_absolute_path(directory.out) 607 local 608 loadpath_entry: STRING 609 do 610 if not is_comment(loadpath_line) then 611 loadpath_entry := once "" 612 loadpath_entry.make_from_string(loadpath_line) 613 env.substitute(loadpath_entry) 614 if dir.system_notation.is_absolute_path(loadpath_entry) then 615 locations.add_last(loadpath_entry.intern) 616 else 617 dir.compute_file_path_with(directory, loadpath_entry) 618 if files.file_exists(dir.last_entry) then 619 locations.add_last(dir.last_entry.intern) 620 else 621 dir.compute_subdirectory_with(directory, loadpath_entry) 622 locations.add_last(dir.last_entry.intern) 623 end 624 end 625 end 626 end 627 628 is_comment (loadpath_line: STRING): BOOLEAN is 629 local 630 i: INTEGER; found: BOOLEAN 631 do 632 from 633 Result := True 634 i := loadpath_line.lower 635 until 636 found or else i > loadpath_line.upper 637 loop 638 inspect 639 loadpath_line.item(i) 640 when ' ', '%T' then 641 check Result end 642 when '-' then 643 Result := i < loadpath_line.upper and then loadpath_line.item(i+1) = '-' 644 found := True 645 else 646 Result := False 647 found := True 648 end 649 i := i + 1 650 end 651 end 652 653 set_current_cluster_from_directory (directory: FIXED_STRING) is 654 require 655 dir.system_notation.is_absolute_path(directory.out) 656 current_cluster = Void 657 do 658 current_cluster := cluster_per_location.fast_reference_at(directory) 659 if current_cluster = Void then 660 create current_cluster.make(current_cluster_name, {FAST_ARRAY[FIXED_STRING] << directory >> }) 661 all_clusters.add(current_cluster, current_cluster_name) 662 cluster_per_location.add(current_cluster, directory) 663 end 664 ensure 665 current_cluster /= Void 666 current_cluster = cluster_per_location.fast_reference_at(directory) 667 end 668 669 canonical_location (descriptor: STRING): FIXED_STRING is 670 local 671 buffer: STRING 672 do 673 buffer := once "" 674 buffer.make_from_string(current_directory) 675 dir.system_notation.to_absolute_path_in(buffer, descriptor) 676 Result := buffer.intern 677 end 678 679feature {} 680 agent_version_eq: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 681 once 682 Result := agent version_eq 683 end 684 685 agent_version_le: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 686 once 687 Result := agent version_le 688 end 689 690 agent_version_ge: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 691 once 692 Result := agent version_ge 693 end 694 695 agent_version_ne: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 696 once 697 Result := agent version_ne 698 end 699 700 agent_version_lt: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 701 once 702 Result := agent version_lt 703 end 704 705 agent_version_gt: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] is 706 once 707 Result := agent version_gt 708 end 709 710 version_eq (v1, v2: FIXED_STRING): BOOLEAN is 711 do 712 Result := v1.is_equal(v2) 713 end 714 715 version_le (v1, v2: FIXED_STRING): BOOLEAN is 716 do 717 Result := not version_lt(v2, v1) 718 end 719 720 version_ge (v1, v2: FIXED_STRING): BOOLEAN is 721 do 722 Result := not version_lt(v1, v2) 723 end 724 725 version_ne (v1, v2: FIXED_STRING): BOOLEAN is 726 do 727 Result := not v1.is_equal(v2) 728 end 729 730 version_lt (v1, v2: FIXED_STRING): BOOLEAN is 731 local 732 previous_dot1, dot1, previous_dot2, dot2: INTEGER 733 finished: BOOLEAN 734 version1, version2: INTEGER 735 do 736 from 737 until 738 finished 739 loop 740 dot1 := v1.index_of('.', previous_dot1 + 1) 741 dot2 := v2.index_of('.', previous_dot2 + 1) 742 743 if not v1.valid_index(dot1) then 744 dot1 := v1.upper + 1 745 finished := True 746 end 747 if not v2.valid_index(dot2) then 748 dot2 := v2.upper + 1 749 finished := True 750 end 751 752 version1 := extract_integer(v1, previous_dot1 + 1, dot1 - 1) 753 version2 := extract_integer(v2, previous_dot2 + 1, dot2 - 1) 754 if version1 < version2 then 755 Result := True 756 finished := True 757 elseif version1 > version2 then 758 check not Result end 759 dot1 := 0 760 dot2 := 0 761 check 762 not v1.valid_index(dot1) 763 not v2.valid_index(dot2) 764 end 765 finished := True 766 else 767 previous_dot1 := dot1 768 previous_dot2 := dot2 769 end 770 end 771 772 if not Result then 773 check finished end 774 if v1.valid_index(dot1) then 775 check not Result end 776 elseif v2.valid_index(dot2) then 777 Result := True 778 else 779 check not Result end 780 end 781 end 782 end 783 784 version_gt (v1, v2: FIXED_STRING): BOOLEAN is 785 do 786 Result := version_lt(v2, v1) 787 end 788 789 extract_integer (v: FIXED_STRING; low, up: INTEGER): INTEGER is 790 require 791 v.valid_index(low) 792 v.valid_index(up) 793 low <= up 794 local 795 i: INTEGER 796 do 797 from 798 i := low 799 until 800 i > up 801 loop 802 Result := Result*10 + (v.item(i).code - '0'.code) 803 i := i + 1 804 end 805 end 806 807feature {} 808 make (a_tool_name: ABSTRACT_STRING) is 809 require 810 a_tool_name /= Void 811 do 812 tool_name := a_tool_name.intern 813 create all_clusters.make 814 create {HASHED_DICTIONARY[LIBERTY_ETC_CLUSTER, FIXED_STRING]} cluster_per_location.make 815 current_directory := dir.current_working_directory 816 ensure 817 tool_name = a_tool_name.intern 818 end 819 820 errors: LIBERTY_ERRORS 821 env: LIBERTY_ENVIRONMENT 822 all_clusters: HASHED_DICTIONARY[LIBERTY_ETC_CLUSTER, FIXED_STRING] 823 current_directory: FIXED_STRING 824 current_cluster_name: FIXED_STRING 825 current_cluster: LIBERTY_ETC_CLUSTER 826 827 last_locations: FAST_ARRAY[FIXED_STRING] 828 last_cluster_constraints: COLLECTION[LIBERTY_ETC_CONSTRAINT] 829 last_version_operator: PREDICATE[TUPLE[FIXED_STRING, FIXED_STRING]] 830 831 dir: BASIC_DIRECTORY 832 files: FILE_TOOLS 833 834 tfr: TEXT_FILE_READ is 835 once 836 create Result.make 837 end 838 839invariant 840 all_clusters /= Void 841 tool_name /= Void 842 843end -- class LIBERTY_ETC_VISITOR_IMPL