Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: fix some (z) splitting oddities



No question of these being special syntactic markers, they were just
plain wrong and inconsistent; see the new test for the cases I fixed.

I've take the easy way out when fixing them on the basis that the results
are at least consistent if not necessarily ideal.

Index: Src/hist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/hist.c,v
retrieving revision 1.101
diff -p -u -r1.101 hist.c
--- Src/hist.c	2 Oct 2010 21:03:04 -0000	1.101
+++ Src/hist.c	5 Oct 2010 21:04:59 -0000
@@ -2869,6 +2869,7 @@ bufferwords(LinkList list, char *buf, in
     int num = 0, cur = -1, got = 0, ne = noerrs;
     int owb = wb, owe = we, oadx = addedx, ozp = zleparse, onc = nocomments;
     int ona = noaliases, ocs = zlemetacs, oll = zlemetall;
+    int forloop = 0;
     char *p, *addedspaceptr;
 
     if (!list)
@@ -2942,25 +2943,84 @@ bufferwords(LinkList list, char *buf, in
 	ctxtlex();
 	if (tok == ENDINPUT || tok == LEXERR)
 	    break;
-	if (tokstr && *tokstr) {
-	    untokenize((p = dupstring(tokstr)));
-	    if (ingetptr() == addedspaceptr + 1) {
-		/*
-		 * Whoops, we've read past the space we added, probably
-		 * because we were expecting a terminator but when
-		 * it didn't turn up we shrugged our shoulders thinking
-		 * it might as well be a complete string anyway.
-		 * So remove the space.  C.f. below for the case
-		 * where the missing terminator caused a lex error.
-		 * We use the same paranoid test.
-		 */
-		int plen = strlen(p);
-		if (plen && p[plen-1] == ' ' &&
-		    (plen == 1 || p[plen-2] != Meta))
-		    p[plen-1] = '\0';
+	if (tok == FOR) {
+	    /*
+	     * The way for (( expr1 ; expr2; expr3 )) is parsed is:
+	     * - a FOR tok
+	     * - a DINPAR with no tokstr
+	     * - two DINPARS with tokstr's expr1, expr2.
+	     * - a DOUTPAR with tokstr expr3.
+	     *
+	     * We'll decrement the variable forloop as we verify
+	     * the various stages.
+	     *
+	     * Don't ask me, ma'am, I'm just the programmer.
+	     */
+	    forloop = 5;
+	} else {
+	    switch (forloop) {
+	    case 1:
+		if (tok != DOUTPAR)
+		    forloop = 0;
+		break;
+
+	    case 2:
+	    case 3:
+	    case 4:
+		if (tok != DINPAR)
+		    forloop = 0;
+		break;
+
+	    default:
+		/* nothing to do */
+		break;
+	    }
+	}
+	if (tokstr) {
+	    switch (tok) {
+	    case ENVARRAY:
+		p = dyncat(tokstr, "=(");
+		break;
+
+	    case DINPAR:
+		if (forloop) {
+		    /* See above. */
+		    p = dyncat(tokstr, ";");
+		} else {
+		    /*
+		     * Mathematical expressions analysed as a single
+		     * word.  That's correct because it behaves like
+		     * double quotes.  Whitespace in the middle is
+		     * similarly retained, so just add the parentheses back.
+		     */
+		    p = tricat("((", tokstr, "))");
+		}
+		break;
+
+	    default:
+		p = dupstring(tokstr);
+		break;
+	    }
+	    if (*p) {
+		untokenize(p);
+		if (ingetptr() == addedspaceptr + 1) {
+		    /*
+		     * Whoops, we've read past the space we added, probably
+		     * because we were expecting a terminator but when
+		     * it didn't turn up we shrugged our shoulders thinking
+		     * it might as well be a complete string anyway.
+		     * So remove the space.  C.f. below for the case
+		     * where the missing terminator caused a lex error.
+		     * We use the same paranoid test.
+		     */
+		    int plen = strlen(p);
+		    if (plen && p[plen-1] == ' ' &&
+			(plen == 1 || p[plen-2] != Meta))
+			p[plen-1] = '\0';
+		}
+		addlinknode(list, p);
+		num++;
 	    }
-	    addlinknode(list, p);
-	    num++;
 	} else if (buf) {
 	    if (IS_REDIROP(tok) && tokfd >= 0) {
 		char b[20];
@@ -2973,6 +3033,16 @@ bufferwords(LinkList list, char *buf, in
 		num++;
 	    }
 	}
+	if (forloop) {
+	    if (forloop == 1) {
+		/*
+		 * Final "))" of for loop to match opening,
+		 * since we've just added the preceding element.
+ 		 */
+		addlinknode(list, dupstring("))"));
+	    }
+	    forloop--;
+	}
 	if (!got && !zleparse) {
 	    got = 1;
 	    cur = num - 1;
Index: Test/D04parameter.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/D04parameter.ztst,v
retrieving revision 1.43
diff -p -u -r1.43 D04parameter.ztst
--- Test/D04parameter.ztst	12 May 2010 10:17:58 -0000	1.43
+++ Test/D04parameter.ztst	5 Oct 2010 21:04:59 -0000
@@ -389,6 +389,34 @@
 >)
 >ten( more
 
+  strings=(
+    'foo=(1 2 3)'
+    '(( 3 + 1 == 8 / 2 ))'
+    'for (( i = 1 ; i < 10 ; i++ ))'
+  )
+  for string in $strings; do
+    array=(${(z)string})
+    for (( i = 1; i <= ${#array}; i++ )); do
+      print -r -- "${i}:${array[i]}:"
+    done
+  done
+0:Some syntactical expressions that are hard to split into words with (z).
+>1:foo=(:
+>2:1:
+>3:2:
+>4:3:
+>5:):
+>1:(( 3 + 1 == 8 / 2 )):
+>1:for:
+>2:((:
+# Leading whitespace is removed, because the word proper hasn't started;
+# trailing whitespace is left because the word is terminated by the
+# semicolon or double parentheses.  Bit confusing but sort of consistent.
+>3:i = 1 ;:
+>4:i < 10 ;:
+>5:i++ :
+>6:)):
+
   psvar=(dog)
   setopt promptsubst
   foo='It shouldn'\''t $(happen) to a %1v.'


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author