about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/exec.c10
-rw-r--r--Src/loop.c65
-rw-r--r--Src/params.c2
-rw-r--r--Src/parse.c38
-rw-r--r--Src/prompt.c4
-rw-r--r--Src/text.c28
-rw-r--r--Src/zsh.h11
7 files changed, 150 insertions, 8 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 418e8c67f..04e0e19ad 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -137,10 +137,10 @@ static char *STTYval;
 
 /* Execution functions. */
 
-static int (*execfuncs[]) _((Estate, int)) = {
+static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = {
     execcursh, exectime, execfuncdef, execfor, execselect,
     execwhile, execrepeat, execcase, execif, execcond,
-    execarith, execautofn
+    execarith, execautofn, exectry
 };
 
 /* structure for command builtin for when it is used with -v or -V */
@@ -325,6 +325,9 @@ execcursh(Estate state, int do_exec)
 {
     Wordcode end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
 
+    /* Skip word only used for try/always */
+    state->pc++;
+
     if (!list_pipe && thisjob != list_pipe_job && !hasprocs(thisjob))
 	deletejob(jobtab + thisjob);
     cmdpush(CS_CURSH);
@@ -2475,6 +2478,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
                 subsh_close = -1;
 		/* If we're forked (and we should be), no need to return */
 		DPUTS(last1 != 1 && !forked, "BUG: not exiting?");
+		DPUTS(type != WC_SUBSH, "Not sure what we're doing.");
+		/* Skip word only used for try/always blocks */
+		state->pc++;
 		execlist(state, 0, 1);
 	    }
 	}
diff --git a/Src/loop.c b/Src/loop.c
index f52f5e74e..4c45c1f78 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -616,3 +616,68 @@ execcase(Estate state, int do_exec)
 
     return lastval;
 }
+
+/*
+ * Errflag from `try' block, may be reset in `always' block.
+ * Accessible from an integer parameter, so needs to be a zlong.
+ */
+
+/**/
+zlong
+try_errflag = -1;
+
+/**/
+int
+exectry(Estate state, int do_exec)
+{
+    Wordcode end, always;
+    int endval;
+    int save_retflag, save_breaks, save_loops, save_contflag;
+    zlong save_try_errflag;
+
+    end = state->pc + WC_TRY_SKIP(state->pc[-1]);
+    always = state->pc + 1 + WC_TRY_SKIP(*state->pc);
+    state->pc++;
+    pushheap();
+    cmdpush(CS_CURSH);
+
+    /* The :try clause */
+    execlist(state, 1, do_exec);
+
+    /* Don't record errflag here, may be reset. */
+    endval = lastval;
+
+    freeheap();
+
+    cmdpop();
+    cmdpush(CS_ALWAYS);
+
+    /* The always clause. */
+    save_try_errflag = try_errflag;
+    try_errflag = (zlong)errflag;
+    errflag = 0;
+    save_retflag = retflag;
+    retflag = 0;
+    save_breaks = breaks;
+    breaks = 0;
+    save_loops = loops;
+    loops = 0;
+    save_contflag = contflag;
+    contflag = 0;
+
+    state->pc = always;
+    execlist(state, 1, do_exec);
+
+    errflag = try_errflag ? 1 : 0;
+    try_errflag = save_try_errflag;
+    retflag = save_retflag;
+    breaks = save_breaks;
+    loops = save_loops;
+    contflag = save_contflag;
+
+    cmdpop();
+    popheap();
+    state->pc = end;
+
+    return endval;
+}
diff --git a/Src/params.c b/Src/params.c
index 8b0c87dac..9d9d39778 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -106,6 +106,7 @@ struct timeval shtimer;
  
 /* 0 if this $TERM setup is usable, otherwise it contains TERM_* flags */
 
+
 /**/
 mod_export int termflags;
  
@@ -191,6 +192,7 @@ IPDEF5("COLUMNS", &columns, zlevarsetfn),
 IPDEF5("LINES", &lines, zlevarsetfn),
 IPDEF5("OPTIND", &zoptind, intvarsetfn),
 IPDEF5("SHLVL", &shlvl, intvarsetfn),
+IPDEF5("TRY_BLOCK_ERROR", &try_errflag, intvarsetfn),
 
 #define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(strvarsetfn),GFN(strvargetfn),stdunsetfn,0,NULL,NULL,NULL,0}
 IPDEF7("OPTARG", &zoptarg),
diff --git a/Src/parse.c b/Src/parse.c
index 2f9319977..6bef195f8 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1330,25 +1330,55 @@ par_repeat(int *complex)
 }
 
 /*
- * subsh	: ( INPAR | INBRACE ) list ( OUTPAR | OUTBRACE )
+ * subsh	: INPAR list OUTPAR |
+ *                INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ]
  */
 
 /**/
 static void
 par_subsh(int *complex)
 {
-    int oecused = ecused, otok = tok, p;
+    int oecused = ecused, otok = tok, p, pp;
 
     p = ecadd(0);
+    /* Extra word only needed for always block */
+    pp = ecadd(0);
     yylex();
     par_list(complex);
     ecadd(WCB_END());
     if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE))
 	YYERRORV(oecused);
-    ecbuf[p] = (otok == INPAR ? WCB_SUBSH(ecused - 1 - p) :
-		WCB_CURSH(ecused - 1 - p));
     incmdpos = 1;
     yylex();
+
+    /* Optional always block.  No intervening SEPERs allowed. */
+    if (otok == INBRACE && tok == STRING && !strcmp(tokstr, "always")) {
+	ecbuf[pp] = WCB_TRY(ecused - 1 - pp);
+	incmdpos = 1;
+	do {
+	    yylex();
+	} while (tok == SEPER);
+
+	if (tok != INBRACE)
+	    YYERRORV(oecused);
+	cmdpop();
+	cmdpush(CS_ALWAYS);
+
+	yylex();
+	par_save_list(complex);
+	while (tok == SEPER)
+	    yylex();
+
+	incmdpos = 1;
+
+	if (tok != OUTBRACE)
+	    YYERRORV(oecused);
+	yylex();
+	ecbuf[p] = WCB_TRY(ecused - 1 - p);
+    } else {
+	ecbuf[p] = (otok == INPAR ? WCB_SUBSH(ecused - 1 - p) :
+		    WCB_CURSH(ecused - 1 - p));
+    }
 }
 
 /*
diff --git a/Src/prompt.c b/Src/prompt.c
index a889f7cd3..56d6a76fd 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -49,7 +49,7 @@ int cmdsp;
 
 /* parser states, for %_ */
 
-static char *cmdnames[] = {
+static char *cmdnames[CS_COUNT] = {
     "for",      "while",     "repeat",    "select",
     "until",    "if",        "then",      "else",
     "elif",     "math",      "cond",      "cmdor",
@@ -57,7 +57,7 @@ static char *cmdnames[] = {
     "case",     "function",  "subsh",     "cursh",
     "array",    "quote",     "dquote",    "bquote",
     "cmdsubst", "mathsubst", "elif-then", "heredoc",
-    "heredocd", "brace",     "braceparam",
+    "heredocd", "brace",     "braceparam", "always",
 };
  
 /* The buffer into which an expanded and metafied prompt is being written, *
diff --git a/Src/text.c b/Src/text.c
index 794a04df9..f7d80ae73 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -350,6 +350,8 @@ gettext2(Estate state)
 		taddnl();
 		n = tpush(code, 1);
 		n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
+		/* skip word only use for try/always */
+		state->pc++;
 	    } else {
 		state->pc = s->u._subsh.end;
 		tindent--;
@@ -365,6 +367,8 @@ gettext2(Estate state)
 		taddnl();
 		n = tpush(code, 1);
 		n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
+		/* skip word only use for try/always */
+		state->pc++;
 	    } else {
 		state->pc = s->u._subsh.end;
 		tindent--;
@@ -721,6 +725,30 @@ gettext2(Estate state)
 	    taddstr("))");
 	    stack = 1;
 	    break;
+	case WC_TRY:
+	    if (!s) {
+		taddstr("{");
+		tindent++;
+		taddnl();
+		n = tpush(code, 0);
+		state->pc++;
+		/* this is the end of the try block alone */
+		n->u._subsh.end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
+	    } else if (!s->pop) {
+		state->pc = s->u._subsh.end;
+		tindent--;
+		taddnl();
+		taddstr("} always {");
+		tindent++;
+		taddnl();
+		s->pop = 1;
+	    } else {
+		tindent--;
+		taddnl();
+		taddstr("}");
+		stack = 1;
+	    }
+	    break;
 	case WC_END:
 	    stack = 1;
 	    break;
diff --git a/Src/zsh.h b/Src/zsh.h
index a455c4f93..c64632f4e 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -580,6 +580,10 @@ struct eccstr {
 #define WC_COND    17
 #define WC_ARITH   18
 #define WC_AUTOFN  19
+#define WC_TRY     20
+
+/* increment as necessary */
+#define WC_COUNT   21
 
 #define WCB_END()           wc_bld(WC_END, 0)
 
@@ -657,6 +661,9 @@ struct eccstr {
 #define WC_REPEAT_SKIP(C)   wc_data(C)
 #define WCB_REPEAT(O)       wc_bld(WC_REPEAT, (O))
 
+#define WC_TRY_SKIP(C)	    wc_data(C)
+#define WCB_TRY(O)	    wc_bld(WC_TRY, (O))
+
 #define WC_CASE_TYPE(C)     (wc_data(C) & 3)
 #define WC_CASE_HEAD        0
 #define WC_CASE_OR          1
@@ -1695,6 +1702,10 @@ struct ttyinfo {
 #define CS_HEREDOCD    28
 #define CS_BRACE       29
 #define CS_BRACEPAR    30
+#define CS_ALWAYS      31
+
+/* Increment as necessary */
+#define CS_COUNT       32
 
 /*********************
  * Memory management *