about summary refs log tree commit diff
path: root/Src/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/lex.c')
-rw-r--r--Src/lex.c107
1 files changed, 83 insertions, 24 deletions
diff --git a/Src/lex.c b/Src/lex.c
index 15da85a93..700af2da1 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -937,8 +937,8 @@ static enum lextok
 gettokstr(int c, int sub)
 {
     int bct = 0, pct = 0, brct = 0, seen_brct = 0, fdpar = 0;
-    int intpos = 1, in_brace_param = 0;
-    int inquote, unmatched = 0;
+    int intpos = 1, in_brace_param = 0, cmdsubst = 0;
+    int inquote, unmatched = 0, in_pattern = 0;
     enum lextok peek;
 #ifdef DEBUG
     int ocmdsp = cmdsp;
@@ -1135,7 +1135,7 @@ gettokstr(int c, int sub)
 	    c = Inpar;
 	    break;
 	case LX2_INBRACE:
-	    if (isset(IGNOREBRACES) || sub)
+	    if ((isset(IGNOREBRACES) && !cmdsubst) || sub)
 		c = '{';
 	    else {
 		if (!lexbuf.len && incmdpos) {
@@ -1157,8 +1157,11 @@ gettokstr(int c, int sub)
 	    if (in_brace_param) {
 		cmdpop();
 	    }
-	    if (bct-- == in_brace_param)
-		in_brace_param = 0;
+	    if (bct-- == in_brace_param) {
+		if (cmdsubst)
+		    cmdpop();
+		in_brace_param = cmdsubst = in_pattern = 0;
+	    }
 	    c = Outbrace;
 	    break;
 	case LX2_COMMA:
@@ -1230,7 +1233,7 @@ gettokstr(int c, int sub)
 		    else {
 			int sav = *lexbuf.ptr;
 			*lexbuf.ptr = '\0';
-			t = itype_end(t, IIDENT, 0);
+			t = itype_end(t, INAMESPC, 0);
 			if (t < lexbuf.ptr) {
 			    skipparens(Inbrack, Outbrack, &t);
 			} else {
@@ -1306,7 +1309,8 @@ gettokstr(int c, int sub)
 			    lexbuf.ptr--, lexbuf.len--;
 			else
 			    break;
-		    }
+		    } else if (in_pattern && c == '/')
+			add(Bnull);
 		    add(c);
 		}
 		ALLOWHIST
@@ -1394,27 +1398,45 @@ gettokstr(int c, int sub)
 	     */
 	    c = Dash;
            break;
-       case LX2_BANG:
-           /*
-            * Same logic as Dash, for ! to perform negation in range.
-            */
-           if (seen_brct)
-               c = Bang;
-           else
-               c = '!';
-       }
-       add(c);
-       c = hgetc();
+	case LX2_BANG:
+	    /*
+	     * Same logic as Dash, for ! to perform negation in range.
+	     */
+	    if (seen_brct)
+		c = Bang;
+	    else
+		c = '!';
+	case LX2_OTHER:
+	    if (in_brace_param) {
+		if (c == '/') {
+		    if (in_pattern == 0)
+			in_pattern = 2;
+		    else
+			--in_pattern;
+		}
+	    }
+	}
+	add(c);
+	c = hgetc();
 	if (intpos)
 	    intpos--;
 	if (lexstop)
 	    break;
+	if (!cmdsubst && in_brace_param && act == LX2_STRING &&
+	    (c == '|' || c == Bar || c == '{' || c == Inbrace || inblank(c))) {
+	    cmdsubst = in_brace_param;
+	    cmdpush(CS_CURSH);
+	} else if (in_pattern == 2 && c != '/')
+	    in_pattern = 1;
     }
   brk:
     if (errflag) {
 	if (in_brace_param) {
-	    while(bct-- >= in_brace_param)
+	    while(bct >= in_brace_param) {
+		if (bct-- == cmdsubst)
+		    cmdpop();
 		cmdpop();
+	    }
 	}
 	return LEXERR;
     }
@@ -1422,8 +1444,11 @@ gettokstr(int c, int sub)
     if (unmatched && !(lexflags & LEXFLAGS_ACTIVE))
 	zerr("unmatched %c", unmatched);
     if (in_brace_param) {
-	while(bct-- >= in_brace_param)
+	while(bct >= in_brace_param) {
+	    if (bct-- == cmdsubst)
+		cmdpop();
 	    cmdpop();
+	}
 	zerr("closing brace expected");
     } else if (unset(IGNOREBRACES) && !sub && lexbuf.len > 1 &&
 	       peek == STRING && lexbuf.ptr[-1] == '}' &&
@@ -1459,8 +1484,8 @@ gettokstr(int c, int sub)
 static int
 dquote_parse(char endchar, int sub)
 {
-    int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
-    int c;
+    int pct = 0, brct = 0, bct = 0, intick = 0, err = 0, cmdsubst = 0;
+    int c, bskip = 0;
     int math = endchar == ')' || endchar == ']' || infor;
     int zlemath = math && zlemetacs > zlemetall + addedx - inbufct;
 
@@ -1529,11 +1554,25 @@ dquote_parse(char endchar, int sub)
 		c = Qstring;
 	    }
 	    break;
+	case '{':
+	    if (cmdsubst && !intick) {
+		/* In nofork substitution, tokenize as if unquoted */
+		c = Inbrace;
+		bskip++;
+	    }
+	    break;
 	case '}':
 	    if (intick || !bct)
 		break;
 	    c = Outbrace;
-	    bct--;
+	    if (bskip) {
+		bskip--;
+		break;
+	    }
+	    if (bct-- == cmdsubst) {
+		cmdsubst = 0;
+		cmdpop();
+	    }
 	    cmdpop();
 	    break;
 	case '`':
@@ -1588,14 +1627,34 @@ dquote_parse(char endchar, int sub)
 	if (err || lexstop)
 	    break;
 	add(c);
+	if (!cmdsubst && c == Inbrace) {
+	    /* Check for ${|...} nofork command substitution */
+	    if ((c = hgetc()) && !lexstop) {
+		if (c == '|' || inblank(c)) {
+		    cmdsubst = bct;
+		    cmdpush(CS_CURSH);
+		}
+		hungetc(c);
+	    }
+	}
     }
     if (intick == 2)
 	ALLOWHIST
     if (intick) {
 	cmdpop();
     }
-    while (bct--)
+    while (bct) {
+	if (bct-- == cmdsubst) {
+	    /*
+	     * You would think this is an error, but if we call it one,
+	     * parsestrnoerr() returns nonzero to subst_parse_str() and
+	     * subsequently "bad substitution" is not reported
+	     */
+	    /* err = 1 */
+	    cmdpop();
+	}
 	cmdpop();
+    }
     if (lexstop)
 	err = intick || endchar || err;
     else if (err == 1) {