Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm
Precedence: bulk
X-No-Archive: yes
List-Id: Zsh Workers List <zsh-workers.zsh.org>
List-Post: <mailto:zsh-workers@zsh.org>
List-Help: <mailto:zsh-workers-help@zsh.org>
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on f.primenet.com.au
X-Spam-Level: 
X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,T_DKIM_INVALID
	autolearn=ham autolearn_force=no version=3.4.0
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=brasslantern-com.20150623.gappssmtp.com; s=20150623;
        h=from:message-id:date:in-reply-to:comments:references:to:subject
         :mime-version:content-type;
        bh=enTz9KnPFynYP4CccOuYWJESrkz0puPWEo4aOuiMZjE=;
        b=c0CgL93VEehBJgaBvXi7SgoFRxTrQT0Q3lO7o339rJbA2rQBv9joVNkLuQLJqSmer8
         TrDDtj8hwzc6iWZRkgs7ra0cH+/6R5G12kg7V1x3tZhl25iJzcbep6AlsphoaAdSFneg
         u7IlAXAXIMfHEc7i/RF/mpuGWxMhf6JhMixXeRJgw8Qkf207AETarWXmqHqFS1PaUHtx
         U147fibpWA23Qk1jMF/Bkw7eosPd4DWAnILr6xPwXjde8r+VtdviFFtAopmlfS+tyWN6
         nKXioyAVKUlvURTdbyYfVF9oHRr4waD/lYrwlF0hT8q0Mgb+5JSCgchjjDFWiqEngr+P
         mizw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=1e100.net; s=20130820;
        h=x-gm-message-state:from:message-id:date:in-reply-to:comments
         :references:to:subject:mime-version:content-type;
        bh=enTz9KnPFynYP4CccOuYWJESrkz0puPWEo4aOuiMZjE=;
        b=jat4u/DxR/JScOvGYNCVx3SD7cjHbNEDCgfP9cY2uv2NE4IYQCBqbHu4Y7sDEfFAHf
         bmjdMMJ1/O/lYVyBWusiupvpflJZz2/thuwdvSyYq49Az2//yPx3uLSUGT19OrH49iXo
         RChfEKuL1ut6QcjeerIkFuWXxrR0np4tGee52N5CmWf2FObqHEgThXwGl89zWj0HZEA6
         3Y6eyEk4Ld3JWGpYVggYaKdRKK4HMRHklZR6Fhu4Y0xiGuxWMRHWHKi5s+QceCWhSx8a
         TP2sDdKFnNyKgOVmnxAPvYWaQ0hVIUHPOderkrAjMX25vSN5qLXpXjM4t/lZT5lChqzR
         p1WA==
X-Gm-Message-State: AG10YORYf44YawMVHkKZ57qqLrFW5pZzAV2P9Sk5Ce/yrJwQR1m4YLXl9GnR6dnv141XJQ==
X-Received: by 10.98.44.66 with SMTP id s63mr40498957pfs.2.1453877726521;
        Tue, 26 Jan 2016 22:55:26 -0800 (PST)
From: Bart Schaefer <schaefer@brasslantern.com>
Message-Id: <160126225609.ZM3651@torch.brasslantern.com>
Date: Tue, 26 Jan 2016 22:56:09 -0800
In-Reply-To: <CAKc7PVDOgT0MSot6jVFhXdum3myjCCv1vhTiuatwZyYBmQ_iCQ@mail.gmail.com>
Comments: In reply to Sebastian Gniazdowski <sgniazdowski@gmail.com>
        "Re: Advanced option parsing across zsh commands" (Jan 26,  7:59pm)
References: <CAKc7PVAtu3Mvu2-rhqGiqqWZ34bOkP7mepPOoF-nZAejVUZoiA@mail.gmail.com> 
	<160126102847.ZM18281@torch.brasslantern.com> 
	<CAKc7PVDOgT0MSot6jVFhXdum3myjCCv1vhTiuatwZyYBmQ_iCQ@mail.gmail.com>
X-Mailer: OpenZMail Classic (0.9.2 24April2005)
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: Advanced option parsing across zsh commands
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Seq: zsh-workers 37810

On Jan 26,  7:59pm, Sebastian Gniazdowski wrote:
} Subject: Re: Advanced option parsing across zsh commands
}
} > zparseopts also doesn't handle "negated options" in the +X format
} 
} This sounded like if there would a workaround for +X. I tried the
} following: define option "+", which takes argument. Then replace "+X"
} with "-+X" in the command line. However:
} 
} % zparseopts -A opts -D -E b: c +:

That does not define an option "+" which takes an argument.  That in
fact defines an option (empty string) which may be repeated multiple
times and takes an argument, because the "+" invokes the NAME+ form
of option description.

There's not a lot of internal consistency checking in zparseopts.  Old
code that has not been reviewed since it was written.

To define an option named "+" instead of an option named "", you are
intended to use:

    zparseopts -A opts -D -E b: c '\+:'

However, because of a bug, you can't actually do that.  The backslash
causes everything after it to shift one character to the left, but
the NUL-terminator is not also shifted, so the above accidentally
defines the option "++" instead of the option "+".

torch% typeset -A opts
torch% set -- a -b something -++X -- -c
torch% zparseopts -A opts -D -E b: c \\+:
torch% print -lr -- $@
a
--
-c
torch% print -r -- ${(kv)opts}
-b something -++ X
torch% 

With the patch below, the very first character of the option spec is
always taken to be part of the option name (unless that first char is
is a backslash, in which case it is shifted off as usual).  So you
no longer need to escape a "+" (though it doesn't hurt to do so):

torch% typeset -A opts
torch% set -- a -b something -+X -- -c
torch% zparseopts -A opts -D -E b: c +:  
torch% print -r -- ${(kv)opts}         
-b something -+ X

And using "++" does the expected thing:

torch% typeset -A opts=()                     
torch% set -- a -b something -+X -+Y -+Z -- -c
torch% zparseopts -A opts -D -E b: c ++:      
torch% print -r -- ${(kv)opts}                
-b something -+ XYZ
torch% 

For pre-5.3 zsh I suggest you use a different character than "+" for
your proposed workaround, e.g.

    set -- a -b something -\*X -\*Y -\*Z -- -c
    zparseopts -A opts -D -E b: c '*+:'

should work.


diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index d98028a..12a4c03 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1745,13 +1745,15 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	for (p = o; *p; p++) {
 	    if (*p == '\\' && p[1])
 		p++;
-	    else if (*p == '+') {
-		f |= ZOF_MULT;
-		*p = '\0';
-		p++;
-		break;
-	    } else if (*p == ':' || *p == '=')
-		break;
+	    else if (p > o) {	/* At least one character of option name */
+		if (*p == '+') {
+		    f |= ZOF_MULT;
+		    *p = '\0';
+		    p++;
+		    break;
+		} else if (*p == ':' || *p == '=')
+		    break;
+	    }
 	}
 	if (*p == ':') {
 	    f |= ZOF_ARG;
@@ -1789,6 +1791,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 		p++;
 	    *n++ = *p;
 	}
+	*n = '\0';
 	if (get_opt_desc(o)) {
 	    zwarnnam(nam, "option defined more than once: %s", o);
 	    return 1;

