@@ -17,6 +17,7 @@ use tokio_util::sync::CancellationToken;
1717
1818use crate :: parser:: AssignmentOp ;
1919use crate :: parser:: BinaryOp ;
20+ use crate :: parser:: CaseClause ;
2021use crate :: parser:: Condition ;
2122use crate :: parser:: ConditionInner ;
2223use crate :: parser:: ElsePart ;
@@ -649,6 +650,10 @@ async fn execute_command(
649650 )
650651 . await
651652 }
653+ CommandInner :: Case ( case_clause) => {
654+ execute_case_clause ( case_clause, & mut state, stdin, stdout, stderr)
655+ . await
656+ }
652657 CommandInner :: ArithmeticExpression ( arithmetic) => {
653658 // The state can be changed
654659 match execute_arithmetic_expression ( arithmetic, & mut state) . await {
@@ -742,6 +747,104 @@ async fn execute_while_clause(
742747 }
743748}
744749
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+
745848async fn execute_for_clause (
746849 for_clause : ForLoop ,
747850 state : & mut ShellState ,
0 commit comments