@@ -17,6 +17,7 @@ use tokio_util::sync::CancellationToken;
17
17
18
18
use crate :: parser:: AssignmentOp ;
19
19
use crate :: parser:: BinaryOp ;
20
+ use crate :: parser:: CaseClause ;
20
21
use crate :: parser:: Condition ;
21
22
use crate :: parser:: ConditionInner ;
22
23
use crate :: parser:: ElsePart ;
@@ -649,6 +650,10 @@ async fn execute_command(
649
650
)
650
651
. await
651
652
}
653
+ CommandInner :: Case ( case_clause) => {
654
+ execute_case_clause ( case_clause, & mut state, stdin, stdout, stderr)
655
+ . await
656
+ }
652
657
CommandInner :: ArithmeticExpression ( arithmetic) => {
653
658
// The state can be changed
654
659
match execute_arithmetic_expression ( arithmetic, & mut state) . await {
@@ -742,6 +747,104 @@ async fn execute_while_clause(
742
747
}
743
748
}
744
749
750
+ fn pattern_matches ( pattern : & str , word_value : & str ) -> bool {
751
+ let patterns: Vec < & str > = pattern. split ( '|' ) . collect ( ) ;
752
+
753
+ for pat in patterns {
754
+ match glob:: Pattern :: new ( pat) {
755
+ Ok ( glob) if glob. matches ( word_value) => return true ,
756
+ _ => continue ,
757
+ }
758
+ }
759
+
760
+ false
761
+ }
762
+
763
+ async fn execute_case_clause (
764
+ case_clause : CaseClause ,
765
+ state : & mut ShellState ,
766
+ stdin : ShellPipeReader ,
767
+ stdout : ShellPipeWriter ,
768
+ mut stderr : ShellPipeWriter ,
769
+ ) -> ExecuteResult {
770
+ let mut changes = Vec :: new ( ) ;
771
+ let mut last_exit_code = 0 ;
772
+ let mut async_handles = Vec :: new ( ) ;
773
+
774
+ // Evaluate the word to match against
775
+ let word_value = match evaluate_word (
776
+ case_clause. word . clone ( ) ,
777
+ state,
778
+ stdin. clone ( ) ,
779
+ stderr. clone ( ) ,
780
+ )
781
+ . await
782
+ {
783
+ Ok ( word_value) => word_value,
784
+ Err ( err) => return err. into_exit_code ( & mut stderr) ,
785
+ } ;
786
+
787
+ // Find the first matching case pattern
788
+ for ( all_pattern, body) in case_clause. cases {
789
+ let mut result_matched = false ;
790
+ for pattern in all_pattern {
791
+ let pattern_value = match evaluate_word (
792
+ pattern. clone ( ) ,
793
+ state,
794
+ stdin. clone ( ) ,
795
+ stderr. clone ( ) ,
796
+ )
797
+ . await
798
+ {
799
+ Ok ( pattern_value) => pattern_value,
800
+ Err ( err) => return err. into_exit_code ( & mut stderr) ,
801
+ } ;
802
+
803
+ // Check if pattern matches word_value
804
+ if pattern_matches ( & pattern_value. value , & word_value. value ) {
805
+ result_matched = true ;
806
+ let exec_result = execute_sequential_list (
807
+ body,
808
+ state. clone ( ) ,
809
+ stdin. clone ( ) ,
810
+ stdout. clone ( ) ,
811
+ stderr. clone ( ) ,
812
+ AsyncCommandBehavior :: Yield ,
813
+ )
814
+ . await ;
815
+
816
+ match exec_result {
817
+ ExecuteResult :: Exit ( code, env_changes, handles) => {
818
+ state. apply_changes ( & env_changes) ;
819
+ changes. extend ( env_changes) ;
820
+ async_handles. extend ( handles) ;
821
+ last_exit_code = code;
822
+ break ;
823
+ }
824
+ ExecuteResult :: Continue ( code, env_changes, handles) => {
825
+ state. apply_changes ( & env_changes) ;
826
+ changes. extend ( env_changes) ;
827
+ async_handles. extend ( handles) ;
828
+ last_exit_code = code;
829
+ break ;
830
+ }
831
+ }
832
+ }
833
+ }
834
+ if result_matched {
835
+ break ;
836
+ }
837
+ }
838
+
839
+ state. apply_changes ( & changes) ;
840
+
841
+ if state. exit_on_error ( ) && last_exit_code != 0 {
842
+ ExecuteResult :: Exit ( last_exit_code, changes, async_handles)
843
+ } else {
844
+ ExecuteResult :: Continue ( last_exit_code, changes, async_handles)
845
+ }
846
+ }
847
+
745
848
async fn execute_for_clause (
746
849
for_clause : ForLoop ,
747
850
state : & mut ShellState ,
0 commit comments