/src/tools/configuration/etc/liberty_etc_visitor_impl.e

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