[PATCH] case: Implement fallthrough (;&) operator

[email protected]
Newsgroups org.kernel.vger.dash
Message-ID <[email protected]>
From: Arav Verma <[email protected]>

Add support for the fallthrough operator, as specified
in POSIX.1-2024, (defect 449). The ;& operator allows
execution to continue to the next case pattern without
re-evaluating the switch expression

Signed-off-by: Arav Verma <[email protected]>
---
 src/eval.c   | 35 +++++++++++++++++++++++++----------
 src/mktokens |  1 +
 src/parser.c | 14 ++++++++++----
 3 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/src/eval.c b/src/eval.c
index 0f2a7ba..f9acea5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -451,6 +451,7 @@ evalcase(union node *n, int flags)
 	union node *patp;
 	struct arglist arglist;
 	int status = 0;
+	int fallthrough = 0;
 
 	errlinno = lineno = n->ncase.linno;
 	if (funcline)
@@ -460,19 +461,33 @@ evalcase(union node *n, int flags)
 	expandarg(n->ncase.expr, &arglist, FNMATCH_IS_ENABLED ? EXP_TILDE :
 					   EXP_TILDE | EXP_MBCHAR);
 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
-		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
-			if (casematch(patp, arglist.list->text)) {
-				/* Ensure body is non-empty as otherwise
-				 * EV_EXIT may prevent us from setting the
-				 * exit status.
-				 */
-				if (evalskip == 0 && cp->nclist.body) {
-					status = evaltree(cp->nclist.body,
-							  flags);
+		int matched = 0;
+		
+		if (fallthrough) {
+			matched = 1;
+		} else {
+			for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+				if (casematch(patp, arglist.list->text)) {
+					matched = 1;
+					break;
 				}
-				goto out;
 			}
 		}
+		if (matched) {
+			int terminator = cp->type >> 8;
+			if (evalskip == 0 && cp->nclist.body) {
+				int eval_flags = flags;
+				if (terminator == TFALLTHRU)
+					eval_flags &= ~EV_EXIT;
+				status = evaltree(cp->nclist.body, eval_flags);
+				if (terminator != TFALLTHRU)
+					goto out;
+			} else if (terminator != TFALLTHRU)
+				goto out;
+			
+			if (terminator == TFALLTHRU)
+				fallthrough = 1;
+		}
 	}
 out:
 	return status;
diff --git a/src/mktokens b/src/mktokens
index dcef676..b7cd0ff 100644
--- a/src/mktokens
+++ b/src/mktokens
@@ -51,6 +51,7 @@ TPIPE	0	"|"
 TLP	0	"("
 TRP	1	")"
 TENDCASE 1	";;"
+TFALLTHRU 1    ";&"
 TENDBQUOTE 1	"`"
 TREDIR	0	redirection
 TWORD	0	word
diff --git a/src/parser.c b/src/parser.c
index e44b3c3..ede908f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -463,10 +463,12 @@ next_case:
 
 			checkkwd = CHKNL | CHKKWD;
 			if ((t = readtoken()) != TESAC) {
-				if (t != TENDCASE)
+				if (t != TENDCASE && t != TFALLTHRU)
 					synexpect(TENDCASE);
-				else
+				else {
+					cp->type = NCLIST | (t << 8);
 					goto next_case;
+				}
 			}
 		}
 		*cpp = NULL;
@@ -833,11 +835,15 @@ xxreadtoken(void)
 				RETURN(TOR);
 			pungetc();
 			RETURN(TPIPE);
-		case ';':
-			if (pgetc_eatbnl() == ';')
+		case ';': {
+			int nextc = pgetc_eatbnl();
+			if (nextc == ';')
 				RETURN(TENDCASE);
+			else if (nextc == '&')
+				RETURN(TFALLTHRU);
 			pungetc();
 			RETURN(TSEMI);
+		}
 		case '(':
 			RETURN(TLP);
 		case ')':
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.