zsh-workers
 help / color / mirror / code / Atom feed
From: dana <dana@dana.is>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: [RFC] Teach getopts to handle -o and +o separately
Date: Wed, 10 Oct 2018 20:33:48 -0500	[thread overview]
Message-ID: <9A1ABCB6-0FF1-4E8E-83BE-3B8D84954525@dana.is> (raw)

I really like that zsh's getopts handles both -o and +o option variants, but a
major limitation is that the two variants are linked by the one letter
specification — there's no way to tell zsh that you don't want one or the other,
and more importantly there's no way to specify that one variant should take an
argument and one should not.

I'd like to propose that a - or + following an option letter (or preceding it,
if that seems nicer) restrict that letter specification to the - or + variant
respectively. With this change, the following sort of thing becomes possible:

  % which testopts
  testopts () {
  local OPTARG OPTIND opt
    while getopts a-a:+bc opt
    do
      print -r - $opt${OPTARG:+:$OPTARG}
    done
  }

  % testopts -a +a
  a
  testopts:2: argument expected after +a option
  :

  % testopts -bab +bab
  b
  a
  b
  +b
  +a:b

Of course, this eliminates - and + as valid 'letters' in the optstring. But it
seems unlikely that anyone actually needs +-, -+, or ++ (-- is already
effectively unusable for obvious reasons). Also, POSIX says:

  >The use of other option characters that are not alphanumeric produces
  >unspecified results.

So we're fine there.

Below is a kind of silly-looking patch that implements the change. If the idea
is sound i can try to make it nicer (along with adding docs and tests obv), but
in any case i think it can be done without too many LOC and without touching the
scarier parts of that function.

Does this seem viable at all?

dana


diff --git a/Src/builtin.c b/Src/builtin.c
index 8dcdcc024..f099e3263 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5512,7 +5512,8 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
     optbuf[lenoptbuf - 1] = opch;
 
     /* check for legality */
-    if(opch == ':' || !(p = memchr(optstr, opch, lenoptstr))) {
+    if(opch == ':' || opch == '?' || opch == '-' || opch == '+'
+	|| !(p = memchr(optstr, opch, lenoptstr))) {
 	p = "?";
     err:
 	zsfree(zoptarg);
@@ -5528,6 +5529,19 @@ bin_getopts(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int fun
 	return 0;
     }
 
+    scan:
+	if (!p) {
+	    p = "?";
+	    goto err;
+	}
+	if ((lenoptbuf == 1 && (p[1] == '+' || (p[1] == ':' && p[2] == '+')))
+	    || (lenoptbuf == 2 && (p[1] == '-' || (p[1] == ':' && p[2] == '-')))
+	    ) {
+	    p++;
+	    p = memchr(p, opch, strlen(p));
+	    goto scan;
+	}
+
     /* check for required argument */
     if(p[1] == ':') {
 	if(optcind == lenstr) {


             reply	other threads:[~2018-10-11  1:34 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-11  1:33 dana [this message]
2018-10-11 20:26 ` Daniel Shahaf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9A1ABCB6-0FF1-4E8E-83BE-3B8D84954525@dana.is \
    --to=dana@dana.is \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).