* [PATCH] case: Implement fallthrough (;&) operator
@ 2026-08-23 18:26 svav2021
0 siblings, 0 replies; only message in thread
From: svav2021 @ 2026-08-23 18:26 UTC (permalink / raw)
To: herbert; +Cc: dash, Arav Verma
From: Arav Verma <svav2021@gmail.com>
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 <svav2021@gmail.com>
---
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
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-23 18:27 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23 18:26 [PATCH] case: Implement fallthrough (;&) operator svav2021
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox