zsh-users
 help / color / mirror / code / Atom feed
* Replacing getopts with zparseopts
@ 2011-05-15 14:34 Thorsten Kampe
  2011-05-15 18:00 ` Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Thorsten Kampe @ 2011-05-15 14:34 UTC (permalink / raw)
  To: zsh-users

Hi,

"From Bash to Z Shell" mentions that one could possibly use zparseopts 
instead of getopts - for instance to get long GNU style options ("--
long-option"). Unfortunately neither the book nor the man page were too 
helpful (my fault) in "translating" the standard option case.

Could someone help me to create the below simple construct with 
zparseopts and making sure that "-d" and "--debug", "-h" and "--help", 
and "-v" and "--verbose" refer to the same option?!

##
while getopts dhv opt
    do case $opt in
           (d)  setopt xtrace;;

           (h)  print_help
                exit;;

           (v)  print_version
                exit;;

           (\?) print_usage >&2
                exit 1;;
       esac
done
##

Thanks in advance,
Thorsten


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Replacing getopts with zparseopts
  2011-05-15 14:34 Replacing getopts with zparseopts Thorsten Kampe
@ 2011-05-15 18:00 ` Bart Schaefer
  2011-05-15 18:49   ` Thorsten Kampe
  0 siblings, 1 reply; 4+ messages in thread
From: Bart Schaefer @ 2011-05-15 18:00 UTC (permalink / raw)
  To: zsh-users

On May 15,  4:34pm, Thorsten Kampe wrote:
}
} Could someone help me to create the below simple construct with 
} zparseopts and making sure that "-d" and "--debug", "-h" and "--help", 
} and "-v" and "--verbose" refer to the same option?!

This depends on what you intend by "refer to the same option."

All zparseopts does is read (and possibly strip) the options from the
command line and place their values in parameters.  It's then up to
later code to interpret the parameters correctly.

For example with "zparseopts -A opthash ..." there isn't any direct
way to tell zparseopts that both "-d" and "--debug" should place a
value in $opthash[d].  If you want to use the -A form, you have to
later check for ${opthash[(i)-d|--debug]} or in some other way check
for both/either.

If you use individual arrays for each option, then you can do this:

    local -a debug help vers usage
    zparseopts d=debug -debug=debug \
               h=help -help=help \
	       v=vers -version=vers \
	       \?=usage

and e.g. $+debug[1] indicates whether one of -d or --debug was used,
and the value in $debug will tell you which one.  However, if *both*
were used, $debug will contain both, whereas if -d were used twice,
it would appear in $debug only once.

Compare this to "zparseopts -d+=debug" in which two uses of -d places
two array elements in $debug.

} ##
} while getopts dhv opt
}     do case $opt in
}            (d)  setopt xtrace;;
} 
}            (h)  print_help
}                 exit;;
} 
}            (v)  print_version
}                 exit;;
} 
}            (\?) print_usage >&2
}                 exit 1;;
}        esac
} done
} ##

It's probably obvious but to conclude the example begun above:

    [[ -n $debug ]] && setopt xtrace
    [[ -n $help ]] && { print_help; exit }
    [[ -n $version ]] && { print_version; exit }
    [[ -n $usage ]] && { print_usage >&2; exit 1 }

Note here we don't know in what *order* the options were given, so
when both -h and -v appear in either order it'll always print the
help and then exit.  You could instead write --

    [[ -n $version ]] && print_version
    [[ -n $help ]] && print_help
    [[ -n "$help$version" ]] && exit

-- to print both the version and the help when -h and -v are both used
in any order.

For this simple a case, zparseopts doesn't really save you any effort;
in fact it's probably a bit worse than getopts except that it handles
the long option forms.  Where zparseopts really gets useful is when for
example you are writing a wrapper function for another command.  In
that case you can create a zparseopts description of the options taken
by the wrapped command, and use "zparseopts -D ..." to strip them out
of the command line so the wrapper can manipulate what's left.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Replacing getopts with zparseopts
  2011-05-15 18:00 ` Bart Schaefer
@ 2011-05-15 18:49   ` Thorsten Kampe
  2011-05-16 18:44     ` Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Thorsten Kampe @ 2011-05-15 18:49 UTC (permalink / raw)
  To: zsh-users

* Bart Schaefer (Sun, 15 May 2011 11:00:05 -0700)
> On May 15,  4:34pm, Thorsten Kampe wrote:
> } Could someone help me to create the below simple construct with 
> } zparseopts and making sure that "-d" and "--debug", "-h" and "--help", 
> } and "-v" and "--verbose" refer to the same option?!
[...]
> For this simple a case, zparseopts doesn't really save you any effort;
> in fact it's probably a bit worse than getopts except that it handles
> the long option forms.

So zparseopts is not a "better getopts". So what do people use to be 
able to use (and parse) long options??

Thorsten


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Replacing getopts with zparseopts
  2011-05-15 18:49   ` Thorsten Kampe
@ 2011-05-16 18:44     ` Bart Schaefer
  0 siblings, 0 replies; 4+ messages in thread
From: Bart Schaefer @ 2011-05-16 18:44 UTC (permalink / raw)
  To: zsh-users

On May 15,  8:49pm, Thorsten Kampe wrote:
}
} So zparseopts is not a "better getopts". So what do people use to be 
} able to use (and parse) long options??

This might be helpful.  With the patch below, one can e.g. do

    zparseopts -M d=opt_d -debug=d

and have both the -d and the --debug options stashed in the $opt_d
array.  There's a remaining buglet here that I haven't decided how
to handle:  Given the above spec, the $d array is also created (or
reset) but is always empty.  The most straightforward fix for this
would be simply to assert that -M always implies -K.

The patch also fixes this bug:

torch% zparseopts -- -debug=d
zparseopts: missing option descriptions

The problem is that the generic command parser handles "--" natively,
removing it from the arguments passed to bin_zparseopts(), which
then caused "-debug=d" to be ignored.

Index: Doc/Zsh/mod_zutil.yo
===================================================================
diff -c -r1.6 mod_zutil.yo
--- Doc/Zsh/mod_zutil.yo	26 Nov 2007 17:38:13 -0000	1.6
+++ Doc/Zsh/mod_zutil.yo	16 May 2011 17:39:16 -0000
@@ -178,7 +178,7 @@
 This implements some internals of the tt(_regex_arguments) function.
 )
 findex(zparseopts)
-item(tt(zparseopts) [ tt(-D) ] [ tt(-K) ] [ tt(-E) ] [ tt(-a) var(array) ] [
tt(-A) var(assoc) ] var(specs))(
+item(tt(zparseopts) [ tt(-D) ] [ tt(-K) ] [ tt(-M) ] [ tt(-E) ] [ tt(-a)
var(array) ] [ tt(-A) var(assoc) ] var(specs))(
 This builtin simplifies the parsing of options in positional parameters,
 i.e. the set of arguments given by tt($*).  Each var(spec) describes one
 option and must be of the form `var(opt)[tt(=)var(array)]'.  If an option
@@ -255,6 +255,15 @@
 of the var(specs) for them is used.  This allows assignment of default
 values to them before calling tt(zparseopts).
 )
+item(tt(-M))(
+This changes the assignment rules to implement a map among equivalent
+option names.  If any var(spec) uses the `tt(=)var(array)' form, the
+string var(array) is interpreted as the name of another var(spec),
+which is used to choose where to store the values.  If no other var(spec)
+is found, the values are stored as usual.  This changes only the way the
+values are stored, not the way tt($*) is parsed, so results may be
+unpredicable if the `var(name)tt(+)' specifier is used inconsistently.
+)
 item(tt(-E))(
 This changes the parsing rules to em(not) stop at the first string
 that isn't described by one of the var(spec)s.  It can be used to test
@@ -288,5 +297,15 @@
 
 I.e., the option tt(-b) and its arguments are taken from the
 positional parameters and put into the array tt(bar).
+
+The tt(-M) option can be used like this:
+
+example(set -- -a -bx -c y -cz baz -cend
+zparseopts -A bar -M a=foo b+: c:=b)
+
+to have the effect of
+
+example(foo=(-a)
+bar=(-a '' -b xyz))
 )
 enditem()
Index: Src/Modules/zutil.c
===================================================================
diff -c -r1.11 zutil.c
--- Src/Modules/zutil.c	21 Dec 2010 16:41:16 -0000	1.11
+++ Src/Modules/zutil.c	16 May 2011 18:15:53 -0000
@@ -1405,6 +1405,7 @@
 #define ZOF_OPT  2
 #define ZOF_MULT 4
 #define ZOF_SAME 8
+#define ZOF_MAP 16
 
 struct zoptarr {
     Zoptarr next;
@@ -1466,6 +1467,12 @@
     char *n = dyncat("-", d->name);
     int new = 0;
 
+    while (d->flags & ZOF_MAP) {
+	Zoptdesc map = get_opt_desc(d->arr->name);
+	if (!map || !strcmp(map->name, n+1))
+	    break;
+	d = map;
+    }
     if (!(d->flags & ZOF_MULT))
 	v = d->vals;
     if (!v) {
@@ -1513,7 +1520,7 @@
 bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 {
     char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np;
-    int del = 0, f, extract = 0, keep = 0;
+    int del = 0, flags = 0, extract = 0, keep = 0;
     Zoptdesc sopts[256], d;
     Zoptarr a, defarr = NULL;
     Zoptval v;
@@ -1531,6 +1538,7 @@
 	    case '-':
 		if (o[2])
 		    args--;
+		/* else unreachable, default parsing removes "--" */
 		o = NULL;
 		break;
 	    case 'D':
@@ -1557,6 +1565,14 @@
 		}
 		keep = 1;
 		break;
+	    case 'M':
+		if (o[2]) {
+		    args--;
+		    o = NULL;
+		    break;
+		}
+		flags |= ZOF_MAP;
+		break;
 	    case 'a':
 		if (defarr) {
 		    zwarnnam(nam, "default array given more than once");
@@ -1578,6 +1594,10 @@
 		opt_arrs = defarr;
 		break;
 	    case 'A':
+		if (assoc) {
+		    zwarnnam(nam, "associative array given more than once");
+		    return 1;
+		}
 		if (o[2]) 
 		    assoc = o + 2;
 		else if (*args)
@@ -1587,6 +1607,11 @@
 		    return 1;
 		}
 		break;
+	    default:
+		/* Anything else is an option description */
+		args--;
+		o = NULL;
+		break;
 	    }
 	    if (!o) {
 		o = "";
@@ -1602,11 +1627,11 @@
 	return 1;
     }
     while ((o = dupstring(*args++))) {
+	int f = 0;
 	if (!*o) {
 	    zwarnnam(nam, "invalid option description: %s", o);
 	    return 1;
 	}
-	f = 0;
 	for (p = o; *p; p++) {
 	    if (*p == '\\' && p[1])
 		p++;
@@ -1633,6 +1658,7 @@
 	a = NULL;
 	if (*p == '=') {
 	    *p++ = '\0';
+	    f |= flags;
 	    if (!(a = get_opt_arr(p))) {
 		a = (Zoptarr) zhalloc(sizeof(*a));
 		a->name = p;


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-05-16 18:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-15 14:34 Replacing getopts with zparseopts Thorsten Kampe
2011-05-15 18:00 ` Bart Schaefer
2011-05-15 18:49   ` Thorsten Kampe
2011-05-16 18:44     ` Bart Schaefer

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).